aboutsummaryrefslogtreecommitdiffstats
path: root/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-11-06 16:48:53 +0000
committerEd Maste <emaste@FreeBSD.org>2013-11-06 16:48:53 +0000
commitf21a844f60ae6c74fcf1fddca32461acce3c1ee0 (patch)
tree56d79f94966870db1cecd65a7264510a25fd1cba /source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
parent37d22554be9f5a677dad2a95b7ef22fe59c66a8a (diff)
downloadsrc-f21a844f60ae6c74fcf1fddca32461acce3c1ee0.tar.gz
src-f21a844f60ae6c74fcf1fddca32461acce3c1ee0.zip
Import lldb as of SVN r194122vendor/lldb/lldb-r194122
Sponsored by: DARPA, AFRL
Notes
Notes: svn path=/vendor/lldb/dist/; revision=257752 svn path=/vendor/lldb/lldb-r194122/; revision=257753; tag=vendor/lldb/lldb-r194122
Diffstat (limited to 'source/Plugins/Process/Utility/DynamicRegisterInfo.cpp')
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp456
1 files changed, 440 insertions, 16 deletions
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index 0c95d66cef94..dc90b7ae02c3 100644
--- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -16,6 +16,9 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/DataFormatters/FormatManager.h"
#ifndef LLDB_DISABLE_PYTHON
#include "lldb/Interpreter/PythonDataObjects.h"
@@ -29,18 +32,24 @@ DynamicRegisterInfo::DynamicRegisterInfo () :
m_sets (),
m_set_reg_nums (),
m_set_names (),
- m_reg_data_byte_size (0)
+ m_value_regs_map (),
+ m_invalidate_regs_map (),
+ m_reg_data_byte_size (0),
+ m_finalized (false)
{
}
-DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict) :
+DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict, ByteOrder byte_order) :
m_regs (),
m_sets (),
m_set_reg_nums (),
m_set_names (),
- m_reg_data_byte_size (0)
+ m_value_regs_map (),
+ m_invalidate_regs_map (),
+ m_reg_data_byte_size (0),
+ m_finalized (false)
{
- SetRegisterInfo (dict);
+ SetRegisterInfo (dict, byte_order);
}
DynamicRegisterInfo::~DynamicRegisterInfo ()
@@ -49,8 +58,10 @@ DynamicRegisterInfo::~DynamicRegisterInfo ()
size_t
-DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict)
+DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict,
+ ByteOrder byte_order)
{
+ assert(!m_finalized);
#ifndef LLDB_DISABLE_PYTHON
PythonList sets (dict.GetItemForKey("sets"));
if (sets)
@@ -89,6 +100,12 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
PythonString gcc_pystr("gcc");
PythonString dwarf_pystr("dwarf");
PythonString generic_pystr("generic");
+ PythonString slice_pystr("slice");
+ PythonString composite_pystr("composite");
+ PythonString invalidate_regs_pystr("invalidate-regs");
+
+// typedef std::map<std::string, std::vector<std::string> > InvalidateNameMap;
+// InvalidateNameMap invalidate_map;
for (uint32_t i=0; i<num_regs; ++i)
{
PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
@@ -96,6 +113,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
{
// { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
RegisterInfo reg_info;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
bzero (&reg_info, sizeof(reg_info));
reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
@@ -111,16 +130,177 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
if (reg_info.byte_offset == UINT32_MAX)
{
- Clear();
- return 0;
+ // No offset for this register, see if the register has a value expression
+ // which indicates this register is part of another register. Value expressions
+ // are things like "rax[31:0]" which state that the current register's value
+ // is in a concrete register "rax" in bits 31:0. If there is a value expression
+ // we can calculate the offset
+ bool success = false;
+ const char *slice_cstr = reg_info_dict.GetItemForKeyAsString(slice_pystr);
+ if (slice_cstr)
+ {
+ // Slices use the following format:
+ // REGNAME[MSBIT:LSBIT]
+ // REGNAME - name of the register to grab a slice of
+ // MSBIT - the most significant bit at which the current register value starts at
+ // LSBIT - the least significant bit at which the current register value ends at
+ static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]");
+ RegularExpression::Match regex_match(3);
+ if (g_bitfield_regex.Execute(slice_cstr, &regex_match))
+ {
+ llvm::StringRef reg_name_str;
+ std::string msbit_str;
+ std::string lsbit_str;
+ if (regex_match.GetMatchAtIndex(slice_cstr, 1, reg_name_str) &&
+ regex_match.GetMatchAtIndex(slice_cstr, 2, msbit_str) &&
+ regex_match.GetMatchAtIndex(slice_cstr, 3, lsbit_str))
+ {
+ const uint32_t msbit = Args::StringToUInt32(msbit_str.c_str(), UINT32_MAX);
+ const uint32_t lsbit = Args::StringToUInt32(lsbit_str.c_str(), UINT32_MAX);
+ if (msbit != UINT32_MAX && lsbit != UINT32_MAX)
+ {
+ if (msbit > lsbit)
+ {
+ const uint32_t msbyte = msbit / 8;
+ const uint32_t lsbyte = lsbit / 8;
+
+ ConstString containing_reg_name(reg_name_str);
+
+ RegisterInfo *containing_reg_info = GetRegisterInfo (containing_reg_name);
+ if (containing_reg_info)
+ {
+ const uint32_t max_bit = containing_reg_info->byte_size * 8;
+ if (msbit < max_bit && lsbit < max_bit)
+ {
+ m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
+ m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
+ m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
+
+ if (byte_order == eByteOrderLittle)
+ {
+ success = true;
+ reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte;
+ }
+ else if (byte_order == eByteOrderBig)
+ {
+ success = true;
+ reg_info.byte_offset = containing_reg_info->byte_offset + msbyte;
+ }
+ else
+ {
+ assert(!"Invalid byte order");
+ }
+ }
+ else
+ {
+ if (msbit > max_bit)
+ printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, max_bit);
+ else
+ printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, max_bit);
+ }
+ }
+ else
+ {
+ printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString());
+ }
+ }
+ else
+ {
+ printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit);
+ }
+ }
+ else
+ {
+ printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit);
+ }
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to extract regex matches for parsing the register bitfield regex\n");
+
+ }
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to match against register bitfield regex\n");
+ }
+ }
+ else
+ {
+ PythonList composite_reg_list (reg_info_dict.GetItemForKey(composite_pystr));
+ if (composite_reg_list)
+ {
+ const size_t num_composite_regs = composite_reg_list.GetSize();
+ if (num_composite_regs > 0)
+ {
+ uint32_t composite_offset = UINT32_MAX;
+ for (uint32_t composite_idx=0; composite_idx<num_composite_regs; ++composite_idx)
+ {
+ PythonString composite_reg_name_pystr(composite_reg_list.GetItemAtIndex(composite_idx));
+ if (composite_reg_name_pystr)
+ {
+ ConstString composite_reg_name(composite_reg_name_pystr.GetString());
+ if (composite_reg_name)
+ {
+ RegisterInfo *composite_reg_info = GetRegisterInfo (composite_reg_name);
+ if (composite_reg_info)
+ {
+ if (composite_offset > composite_reg_info->byte_offset)
+ composite_offset = composite_reg_info->byte_offset;
+ m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
+ m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
+ m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString());
+ }
+ }
+ else
+ {
+ printf("error: 'composite' key contained an empty string\n");
+ }
+ }
+ else
+ {
+ printf("error: 'composite' list value wasn't a python string\n");
+ }
+ }
+ if (composite_offset != UINT32_MAX)
+ {
+ reg_info.byte_offset = composite_offset;
+ success = m_value_regs_map.find(i) != m_value_regs_map.end();
+ }
+ else
+ {
+ printf("error: 'composite' registers must specify at least one real register\n");
+ }
+ }
+ else
+ {
+ printf("error: 'composite' list was empty\n");
+ }
+ }
+ }
+
+
+ if (!success)
+ {
+ Clear();
+ return 0;
+ }
}
- reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8;
-
- if (reg_info.byte_size == 0)
+ const int64_t bitsize = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0);
+ if (bitsize == 0)
{
Clear();
return 0;
}
+
+ reg_info.byte_size = bitsize / 8;
const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
if (format_cstr)
@@ -132,13 +312,15 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
}
}
else
- reg_info.format = eFormatHex;
-
+ {
+ reg_info.format = (Format)reg_info_dict.GetItemForKeyAsInteger (format_pystr, eFormatHex);
+ }
+
const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
if (encoding_cstr)
reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
else
- reg_info.encoding = eEncodingUint;
+ reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint);
const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
if (set >= m_sets.size())
@@ -147,11 +329,75 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
return 0;
}
+ // Fill in the register numbers
reg_info.kinds[lldb::eRegisterKindLLDB] = i;
reg_info.kinds[lldb::eRegisterKindGDB] = i;
reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
- reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr));
+ const char *generic_cstr = reg_info_dict.GetItemForKeyAsString(generic_pystr);
+ if (generic_cstr)
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (generic_cstr);
+ else
+ reg_info.kinds[lldb::eRegisterKindGeneric] = reg_info_dict.GetItemForKeyAsInteger(generic_pystr, LLDB_INVALID_REGNUM);
+
+ // Check if this register invalidates any other register values when it is modified
+ PythonList invalidate_reg_list (reg_info_dict.GetItemForKey(invalidate_regs_pystr));
+ if (invalidate_reg_list)
+ {
+ const size_t num_regs = invalidate_reg_list.GetSize();
+ if (num_regs > 0)
+ {
+ for (uint32_t idx=0; idx<num_regs; ++idx)
+ {
+ PythonObject invalidate_reg_object (invalidate_reg_list.GetItemAtIndex(idx));
+ PythonString invalidate_reg_name_pystr(invalidate_reg_object);
+ if (invalidate_reg_name_pystr)
+ {
+ ConstString invalidate_reg_name(invalidate_reg_name_pystr.GetString());
+ if (invalidate_reg_name)
+ {
+ RegisterInfo *invalidate_reg_info = GetRegisterInfo (invalidate_reg_name);
+ if (invalidate_reg_info)
+ {
+ m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]);
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", invalidate_reg_name.GetCString(), reg_info.name);
+ }
+ }
+ else
+ {
+ printf("error: 'invalidate-regs' list value was an empty string\n");
+ }
+ }
+ else
+ {
+ PythonInteger invalidate_reg_num(invalidate_reg_object);
+
+ if (invalidate_reg_num)
+ {
+ const int64_t r = invalidate_reg_num.GetInteger();
+ if (r != UINT64_MAX)
+ m_invalidate_regs_map[i].push_back(r);
+ else
+ printf("error: 'invalidate-regs' list value wasn't a valid integer\n");
+ }
+ else
+ {
+ printf("error: 'invalidate-regs' list value wasn't a python string or integer\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ printf("error: 'invalidate-regs' contained an empty list\n");
+ }
+ }
+
+ // Calculate the register offset
const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
if (m_reg_data_byte_size < end_reg_offset)
m_reg_data_byte_size = end_reg_offset;
@@ -169,7 +415,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict
Finalize ();
}
#endif
- return 0;
+ return m_regs.size();
}
@@ -179,10 +425,22 @@ DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
ConstString &reg_alt_name,
ConstString &set_name)
{
+ assert(!m_finalized);
const uint32_t reg_num = m_regs.size();
reg_info.name = reg_name.AsCString();
assert (reg_info.name);
reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ uint32_t i;
+ if (reg_info.value_regs)
+ {
+ for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]);
+ }
+ if (reg_info.invalidate_regs)
+ {
+ for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]);
+ }
m_regs.push_back (reg_info);
uint32_t set = GetRegisterSetIndexByName (set_name, true);
assert (set < m_sets.size());
@@ -197,12 +455,99 @@ DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
void
DynamicRegisterInfo::Finalize ()
{
- for (uint32_t set = 0; set < m_sets.size(); ++set)
+ if (m_finalized)
+ return;
+
+ m_finalized = true;
+ const size_t num_sets = m_sets.size();
+ for (size_t set = 0; set < num_sets; ++set)
{
assert (m_sets.size() == m_set_reg_nums.size());
m_sets[set].num_registers = m_set_reg_nums[set].size();
m_sets[set].registers = &m_set_reg_nums[set][0];
}
+
+ // sort and unique all value registers and make sure each is terminated with
+ // LLDB_INVALID_REGNUM
+
+ for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(), end = m_value_regs_map.end();
+ pos != end;
+ ++pos)
+ {
+ if (pos->second.size() > 1)
+ {
+ std::sort (pos->second.begin(), pos->second.end());
+ reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end());
+ if (unique_end != pos->second.end())
+ pos->second.erase(unique_end, pos->second.end());
+ }
+ assert (!pos->second.empty());
+ if (pos->second.back() != LLDB_INVALID_REGNUM)
+ pos->second.push_back(LLDB_INVALID_REGNUM);
+ }
+
+ // Now update all value_regs with each register info as needed
+ const size_t num_regs = m_regs.size();
+ for (size_t i=0; i<num_regs; ++i)
+ {
+ if (m_value_regs_map.find(i) != m_value_regs_map.end())
+ m_regs[i].value_regs = m_value_regs_map[i].data();
+ else
+ m_regs[i].value_regs = NULL;
+ }
+
+ // Expand all invalidation dependencies
+ for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end();
+ pos != end;
+ ++pos)
+ {
+ const uint32_t reg_num = pos->first;
+
+ if (m_regs[reg_num].value_regs)
+ {
+ reg_num_collection extra_invalid_regs;
+ for (const uint32_t invalidate_reg_num : pos->second)
+ {
+ reg_to_regs_map::iterator invalidate_pos = m_invalidate_regs_map.find(invalidate_reg_num);
+ if (invalidate_pos != m_invalidate_regs_map.end())
+ {
+ for (const uint32_t concrete_invalidate_reg_num : invalidate_pos->second)
+ {
+ if (concrete_invalidate_reg_num != reg_num)
+ extra_invalid_regs.push_back(concrete_invalidate_reg_num);
+ }
+ }
+ }
+ pos->second.insert(pos->second.end(), extra_invalid_regs.begin(), extra_invalid_regs.end());
+ }
+ }
+
+ // sort and unique all invalidate registers and make sure each is terminated with
+ // LLDB_INVALID_REGNUM
+ for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end();
+ pos != end;
+ ++pos)
+ {
+ if (pos->second.size() > 1)
+ {
+ std::sort (pos->second.begin(), pos->second.end());
+ reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end());
+ if (unique_end != pos->second.end())
+ pos->second.erase(unique_end, pos->second.end());
+ }
+ assert (!pos->second.empty());
+ if (pos->second.back() != LLDB_INVALID_REGNUM)
+ pos->second.push_back(LLDB_INVALID_REGNUM);
+ }
+
+ // Now update all invalidate_regs with each register info as needed
+ for (size_t i=0; i<num_regs; ++i)
+ {
+ if (m_invalidate_regs_map.find(i) != m_invalidate_regs_map.end())
+ m_regs[i].invalidate_regs = m_invalidate_regs_map[i].data();
+ else
+ m_regs[i].invalidate_regs = NULL;
+ }
}
size_t
@@ -276,4 +621,83 @@ DynamicRegisterInfo::Clear()
m_sets.clear();
m_set_reg_nums.clear();
m_set_names.clear();
+ m_value_regs_map.clear();
+ m_invalidate_regs_map.clear();
+ m_reg_data_byte_size = 0;
+ m_finalized = false;
+}
+
+void
+DynamicRegisterInfo::Dump () const
+{
+ StreamFile s(stdout, false);
+ const size_t num_regs = m_regs.size();
+ s.Printf("%p: DynamicRegisterInfo contains %zu registers:\n", this, num_regs);
+ for (size_t i=0; i<num_regs; ++i)
+ {
+ s.Printf("[%3zu] name = %-10s", i, m_regs[i].name);
+ s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s",
+ m_regs[i].byte_size,
+ m_regs[i].byte_offset,
+ m_regs[i].encoding,
+ FormatManager::GetFormatAsCString (m_regs[i].format));
+ if (m_regs[i].kinds[eRegisterKindGDB] != LLDB_INVALID_REGNUM)
+ s.Printf(", gdb = %3u", m_regs[i].kinds[eRegisterKindGDB]);
+ if (m_regs[i].kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+ s.Printf(", dwarf = %3u", m_regs[i].kinds[eRegisterKindDWARF]);
+ if (m_regs[i].kinds[eRegisterKindGCC] != LLDB_INVALID_REGNUM)
+ s.Printf(", gcc = %3u", m_regs[i].kinds[eRegisterKindGCC]);
+ if (m_regs[i].kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
+ s.Printf(", generic = %3u", m_regs[i].kinds[eRegisterKindGeneric]);
+ if (m_regs[i].alt_name)
+ s.Printf(", alt-name = %s", m_regs[i].alt_name);
+ if (m_regs[i].value_regs)
+ {
+ s.Printf(", value_regs = [ ");
+ for (size_t j=0; m_regs[i].value_regs[j] != LLDB_INVALID_REGNUM; ++j)
+ {
+ s.Printf("%s ", m_regs[m_regs[i].value_regs[j]].name);
+ }
+ s.Printf("]");
+ }
+ if (m_regs[i].invalidate_regs)
+ {
+ s.Printf(", invalidate_regs = [ ");
+ for (size_t j=0; m_regs[i].invalidate_regs[j] != LLDB_INVALID_REGNUM; ++j)
+ {
+ s.Printf("%s ", m_regs[m_regs[i].invalidate_regs[j]].name);
+ }
+ s.Printf("]");
+ }
+ s.EOL();
+ }
+
+ const size_t num_sets = m_sets.size();
+ s.Printf("%p: DynamicRegisterInfo contains %zu register sets:\n", this, num_sets);
+ for (size_t i=0; i<num_sets; ++i)
+ {
+ s.Printf("set[%zu] name = %s, regs = [", i, m_sets[i].name);
+ for (size_t idx=0; idx<m_sets[i].num_registers; ++idx)
+ {
+ s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name);
+ }
+ s.Printf("]\n");
+ }
+}
+
+
+
+lldb_private::RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfo (const lldb_private::ConstString &reg_name)
+{
+ for (auto &reg_info : m_regs)
+ {
+ // We can use pointer comparison since we used a ConstString to set
+ // the "name" member in AddRegister()
+ if (reg_info.name == reg_name.GetCString())
+ {
+ return &reg_info;
+ }
+ }
+ return NULL;
}