summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp895
1 files changed, 335 insertions, 560 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a03c43b005f..0399634c274 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -26,11 +26,6 @@
#include <map>
#include <mutex>
-// Other libraries and framework includes
-#if defined( LIBXML2_DEFINED )
-#include <libxml/xmlreader.h>
-#endif
-
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/ArchSpec.h"
@@ -45,11 +40,13 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
+#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/XML.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
@@ -478,7 +475,7 @@ ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_
m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
}
- if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture().GetByteOrder()) > 0)
+ if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture()) > 0)
{
return true;
}
@@ -487,6 +484,25 @@ ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_
return false;
}
+static size_t
+SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> &regnums, int base)
+{
+ regnums.clear();
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = comma_separated_regiter_numbers;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, base);
+ if (reg != LLDB_INVALID_REGNUM)
+ regnums.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ return regnums.size();
+}
+
void
ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
@@ -494,8 +510,21 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
if (!force && m_register_info.GetNumRegisters() > 0)
return;
- char packet[128];
m_register_info.Clear();
+
+ // Check if qHostInfo specified a specific packet timeout for this connection.
+ // If so then lets update our setting so the user knows what the timeout is
+ // and can see it.
+ const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
+ if (host_packet_timeout)
+ {
+ GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout);
+ }
+
+ if (GetGDBServerRegisterInfo ())
+ return;
+
+ char packet[128];
uint32_t reg_offset = 0;
uint32_t reg_num = 0;
for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse;
@@ -610,33 +639,11 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
}
else if (name.compare("container-regs") == 0)
{
- std::pair<llvm::StringRef, llvm::StringRef> value_pair;
- value_pair.second = value;
- do
- {
- value_pair = value_pair.second.split(',');
- if (!value_pair.first.empty())
- {
- uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
- if (reg != LLDB_INVALID_REGNUM)
- value_regs.push_back (reg);
- }
- } while (!value_pair.second.empty());
+ SplitCommaSeparatedRegisterNumberString(value, value_regs, 16);
}
else if (name.compare("invalidate-regs") == 0)
{
- std::pair<llvm::StringRef, llvm::StringRef> value_pair;
- value_pair.second = value;
- do
- {
- value_pair = value_pair.second.split(',');
- if (!value_pair.first.empty())
- {
- uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
- if (reg != LLDB_INVALID_REGNUM)
- invalidate_regs.push_back (reg);
- }
- } while (!value_pair.second.empty());
+ SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16);
}
}
@@ -667,30 +674,19 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
}
}
- // Check if qHostInfo specified a specific packet timeout for this connection.
- // If so then lets update our setting so the user knows what the timeout is
- // and can see it.
- const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
- if (host_packet_timeout)
+ if (m_register_info.GetNumRegisters() > 0)
{
- GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout);
+ m_register_info.Finalize(GetTarget().GetArchitecture());
+ return;
}
-
- if (reg_num == 0)
+ FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();
+
+ if (target_definition_fspec)
{
- // try to extract information from servers target.xml
- if (GetGDBServerRegisterInfo ())
+ // See if we can get register definitions from a python file
+ if (ParsePythonTargetDefinition (target_definition_fspec))
return;
-
- FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();
-
- if (target_definition_fspec)
- {
- // See if we can get register definitions from a python file
- if (ParsePythonTargetDefinition (target_definition_fspec))
- return;
- }
}
// We didn't get anything if the accumulated reg_num is zero. See if we are
@@ -698,7 +694,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
// updated debugserver down on the devices.
// On the other hand, if the accumulated reg_num is positive, see if we can
// add composite registers to the existing primordial ones.
- bool from_scratch = (reg_num == 0);
+ bool from_scratch = (m_register_info.GetNumRegisters() == 0);
const ArchSpec &target_arch = GetTarget().GetArchitecture();
const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture();
@@ -724,7 +720,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
}
// At this point, we can finalize our register info.
- m_register_info.Finalize ();
+ m_register_info.Finalize (GetTarget().GetArchitecture());
}
Error
@@ -3595,420 +3591,208 @@ ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec,
return true;
}
-#if defined( LIBXML2_DEFINED )
namespace {
typedef std::vector<std::string> stringVec;
-typedef std::vector<xmlNodePtr> xmlNodePtrVec;
-
-struct GdbServerRegisterInfo
-{
-
- struct
- {
- bool m_has_name : 1;
- bool m_has_bitSize : 1;
- bool m_has_type : 1;
- bool m_has_group : 1;
- bool m_has_regNum : 1;
- }
- m_flags;
-
- std::string m_name;
- std::string m_group;
- uint32_t m_bitSize;
- uint32_t m_regNum;
-
- enum RegType
- {
- eUnknown ,
- eCodePtr ,
- eDataPtr ,
- eInt32 ,
- eI387Ext ,
- }
- m_type;
-
- void clear()
- {
- memset(&m_flags, 0, sizeof(m_flags));
- }
-};
typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec;
-
-struct GdbServerTargetInfo
+struct RegisterSetInfo
{
- std::string m_arch;
- std::string m_osabi;
+ ConstString name;
};
-// conversion table between gdb register type and enum
-struct
-{
- const char * m_name;
- GdbServerRegisterInfo::RegType m_type;
-}
-RegTypeTable[] =
+typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap;
+
+struct GdbServerTargetInfo
{
- { "int32" , GdbServerRegisterInfo::eInt32 },
- { "int" , GdbServerRegisterInfo::eInt32 },
- { "data_ptr", GdbServerRegisterInfo::eDataPtr },
- { "code_ptr", GdbServerRegisterInfo::eCodePtr },
- { "i387_ext", GdbServerRegisterInfo::eI387Ext }, // 80bit fpu
- { nullptr , GdbServerRegisterInfo::eUnknown } // sentinel
+ std::string arch;
+ std::string osabi;
+ stringVec includes;
+ RegisterSetMap reg_set_map;
+ XMLNode feature_node;
};
-
-// find the first sibling with a matching name
-xmlNodePtr
-xmlExFindSibling (xmlNodePtr node,
- const std::string & name)
-{
-
- if ( !node ) return nullptr;
- // iterate through all siblings
- for ( xmlNodePtr temp = node; temp; temp=temp->next ) {
- // we are looking for elements
- if ( temp->type != XML_ELEMENT_NODE )
- continue;
- // check element name matches
- if ( !temp->name ) continue;
- if ( std::strcmp((const char*)temp->name, name.c_str() ) == 0 )
- return temp;
- }
- // no sibling found
- return nullptr;
-}
-
-// find an element from a given element path
-xmlNodePtr
-xmlExFindElement (xmlNodePtr node,
- const stringVec & path)
-{
-
- if (!node)
- return nullptr;
- xmlNodePtr temp = node;
- // iterate all elements in path
- for (uint32_t i = 0; i < path.size(); i++)
- {
-
- // search for a sibling with this name
- temp = xmlExFindSibling(temp, path[i]);
- if (!temp)
- return nullptr;
- // enter this node if we still need to search
- if ((i + 1) < path.size())
- // enter the node we have found
- temp = temp->children;
- }
- // note: node may still be nullptr at this step
- return temp;
-}
-
-// locate a specific attribute in an element
-xmlAttr *
-xmlExFindAttribute (xmlNodePtr node,
- const std::string & name)
-{
-
- if (!node)
- return nullptr;
- if (node->type != XML_ELEMENT_NODE)
- return nullptr;
- // iterate over all attributes
- for (xmlAttrPtr attr = node->properties; attr != nullptr; attr=attr->next)
- {
- // check if name matches
- if (!attr->name)
- continue;
- if (std::strcmp((const char*) attr->name, name.c_str()) == 0)
- return attr;
- }
- return nullptr;
-}
-
-// find all child elements with given name and add them to a vector
-//
-// input: node = xml element to search
-// name = name used when matching child elements
-// output: out = list of matches
-// return: number of children added to 'out'
-int
-xmlExFindChildren (xmlNodePtr node,
- const std::string & name,
- xmlNodePtrVec & out)
-{
-
- if (!node)
- return 0;
- int count = 0;
- // iterate over all children
- for (xmlNodePtr child = node->children; child; child = child->next)
- {
- // if name matches
- if (!child->name)
- continue;
- if (std::strcmp((const char*) child->name, name.c_str()) == 0)
- {
- // add to output list
- out.push_back(child);
- ++count;
- }
- }
- return count;
-}
-
-// get the text content from an attribute
-std::string
-xmlExGetTextContent (xmlAttrPtr attr)
-{
- if (!attr)
- return std::string();
- if (attr->type != XML_ATTRIBUTE_NODE)
- return std::string();
- // check child is a text node
- xmlNodePtr child = attr->children;
- if (child->type != XML_TEXT_NODE)
- return std::string();
- // access the content
- assert(child->content != nullptr);
- return std::string((const char*) child->content);
-}
-
-// get the text content from an node
-std::string
-xmlExGetTextContent (xmlNodePtr node)
-{
- if (!node)
- return std::string();
- if (node->type != XML_ELEMENT_NODE)
- return std::string();
- // check child is a text node
- xmlNodePtr child = node->children;
- if (child->type != XML_TEXT_NODE)
- return std::string();
- // access the content
- assert(child->content != nullptr);
- return std::string((const char*) child->content);
-}
-
-// compile a list of xml includes from the target file
-// input: doc = target.xml
-// output: includes = list of .xml names specified in target.xml
-// return: number of .xml files specified in target.xml and added to includes
-int
-parseTargetIncludes (xmlDocPtr doc, stringVec & includes)
-{
- if (!doc)
- return 0;
- int count = 0;
- xmlNodePtr elm = xmlExFindElement(doc->children, {"target"});
- if (!elm)
- return 0;
- xmlNodePtrVec nodes;
- xmlExFindChildren(elm, "xi:include", nodes);
- // iterate over all includes
- for (uint32_t i = 0; i < nodes.size(); i++)
- {
- xmlAttrPtr attr = xmlExFindAttribute(nodes[i], "href");
- if (attr != nullptr)
- {
- std::string text = xmlExGetTextContent(attr);
- includes.push_back(text);
- ++count;
- }
- }
- return count;
-}
-
-// extract target arch information from the target.xml file
-// input: doc = target.xml document
-// output: out = remote target information
-// return: 'true' on success
-// 'false' on failure
-bool
-parseTargetInfo (xmlDocPtr doc, GdbServerTargetInfo & out)
-{
- if (!doc)
- return false;
- xmlNodePtr e1 = xmlExFindElement (doc->children, {"target", "architecture"});
- if (!e1)
- return false;
- out.m_arch = xmlExGetTextContent (e1);
-
- xmlNodePtr e2 = xmlExFindElement (doc->children, {"target", "osabi"});
- if (!e2)
- return false;
- out.m_osabi = xmlExGetTextContent (e2);
-
- return true;
-}
-
-// extract register information from one of the xml files specified in target.xml
-// input: doc = xml document
-// output: regList = list of extracted register info
-// return: 'true' on success
-// 'false' on failure
+
bool
-parseRegisters (xmlDocPtr doc, GDBServerRegisterVec & regList)
+ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info)
{
-
- if (!doc)
+ if (!feature_node)
return false;
- xmlNodePtr elm = xmlExFindElement (doc->children, {"feature"});
- if (!elm)
- return false;
-
- xmlAttrPtr attr = nullptr;
-
- xmlNodePtrVec regs;
- xmlExFindChildren (elm, "reg", regs);
- for (unsigned long i = 0; i < regs.size(); i++)
- {
-
- GdbServerRegisterInfo reg;
- reg.clear();
-
- if ((attr = xmlExFindAttribute(regs[i], "name")))
- {
- reg.m_name = xmlExGetTextContent(attr).c_str();
- reg.m_flags.m_has_name = true;
- }
-
- if ((attr = xmlExFindAttribute( regs[i], "bitsize")))
- {
- const std::string v = xmlExGetTextContent(attr);
- reg.m_bitSize = atoi(v.c_str());
- reg.m_flags.m_has_bitSize = true;
- }
-
- if ((attr = xmlExFindAttribute(regs[i], "type")))
- {
- const std::string v = xmlExGetTextContent(attr);
- reg.m_type = GdbServerRegisterInfo::eUnknown;
+
+ uint32_t prev_reg_num = 0;
+ uint32_t reg_offset = 0;
- // search the type table for a match
- for (int j = 0; RegTypeTable[j].m_name !=nullptr; ++j)
+ feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &prev_reg_num, &reg_offset](const XMLNode &reg_node) -> bool {
+ std::string name;
+ std::string gdb_group;
+ std::string gdb_type;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ bool encoding_set = false;
+ bool format_set = false;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ prev_reg_num, // GDB reg num
+ prev_reg_num // native register number
+ },
+ NULL,
+ NULL
+ };
+
+ reg_node.ForEachAttribute([&target_info, &name, &gdb_group, &gdb_type, &reg_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, &reg_info, &prev_reg_num, &reg_offset](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+ if (name == "name")
{
- if (RegTypeTable[j].m_name == v)
+ reg_name.SetString(value);
+ }
+ else if (name == "bitsize")
+ {
+ reg_info.byte_size = StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT;
+ }
+ else if (name == "type")
+ {
+ gdb_type = value.str();
+ }
+ else if (name == "group")
+ {
+ gdb_group = value.str();
+ }
+ else if (name == "regnum")
+ {
+ const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ if (regnum != LLDB_INVALID_REGNUM)
{
- reg.m_type = RegTypeTable[j].m_type;
- break;
+ reg_info.kinds[eRegisterKindGDB] = regnum;
+ reg_info.kinds[eRegisterKindLLDB] = regnum;
+ prev_reg_num = regnum;
}
}
-
- reg.m_flags.m_has_type = (reg.m_type != GdbServerRegisterInfo::eUnknown);
- }
-
- if ((attr = xmlExFindAttribute( regs[i], "group")))
- {
- reg.m_group = xmlExGetTextContent(attr);
- reg.m_flags.m_has_group = true;
- }
-
- if ((attr = xmlExFindAttribute(regs[i], "regnum")))
- {
- const std::string v = xmlExGetTextContent(attr);
- reg.m_regNum = atoi(v.c_str());
- reg.m_flags.m_has_regNum = true;
- }
-
- regList.push_back(reg);
- }
-
- //TODO: there is also a "vector" element to parse
- //TODO: there is also eflags to parse
-
- return true;
-}
-
-// build lldb gdb-remote's dynamic register info from a vector of gdb provided registers
-// input: regList = register information provided by gdbserver
-// output: regInfo = dynamic register information required by gdb-remote
-void
-BuildRegisters (const GDBServerRegisterVec & regList,
- GDBRemoteDynamicRegisterInfo & regInfo)
-{
-
- using namespace lldb_private;
-
- const uint32_t defSize = 32;
- uint32_t regNum = 0;
- uint32_t byteOffset = 0;
-
- for (uint32_t i = 0; i < regList.size(); ++i)
- {
-
- const GdbServerRegisterInfo & gdbReg = regList[i];
-
- std::string name = gdbReg.m_flags.m_has_name ? gdbReg.m_name : "unknown";
- std::string group = gdbReg.m_flags.m_has_group ? gdbReg.m_group : "general";
- uint32_t byteSize = gdbReg.m_flags.m_has_bitSize ? (gdbReg.m_bitSize/8) : defSize;
-
- if (gdbReg.m_flags.m_has_regNum)
- regNum = gdbReg.m_regNum;
-
- uint32_t regNumGcc = LLDB_INVALID_REGNUM;
- uint32_t regNumDwarf = LLDB_INVALID_REGNUM;
- uint32_t regNumGeneric = LLDB_INVALID_REGNUM;
- uint32_t regNumGdb = regNum;
- uint32_t regNumNative = regNum;
-
- if (name == "eip" || name == "pc")
- {
- regNumGeneric = LLDB_REGNUM_GENERIC_PC;
- }
- if (name == "esp" || name == "sp")
+ else if (name == "offset")
+ {
+ reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ }
+ else if (name == "altname")
+ {
+ alt_name.SetString(value);
+ }
+ else if (name == "encoding")
+ {
+ encoding_set = true;
+ reg_info.encoding = Args::StringToEncoding (value.data(), eEncodingUint);
+ }
+ else if (name == "format")
+ {
+ format_set = true;
+ Format format = eFormatInvalid;
+ if (Args::StringToFormat (value.data(), format, NULL).Success())
+ reg_info.format = format;
+ else if (value == "vector-sint8")
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value == "vector-uint8")
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value == "vector-sint16")
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value == "vector-uint16")
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value == "vector-sint32")
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value == "vector-uint32")
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value == "vector-float32")
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value == "vector-uint128")
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name == "group_id")
+ {
+ const uint32_t set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ RegisterSetMap::const_iterator pos = target_info.reg_set_map.find(set_id);
+ if (pos != target_info.reg_set_map.end())
+ set_name = pos->second.name;
+ }
+ else if (name == "gcc_regnum")
+ {
+ reg_info.kinds[eRegisterKindGCC] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name == "dwarf_regnum")
+ {
+ reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name == "generic")
+ {
+ reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister(value.data());
+ }
+ else if (name == "value_regnums")
+ {
+ SplitCommaSeparatedRegisterNumberString(value, value_regs, 0);
+ }
+ else if (name == "invalidate_regnums")
+ {
+ SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0);
+ }
+ else
+ {
+ printf("unhandled attribute %s = %s\n", name.data(), value.data());
+ }
+ return true; // Keep iterating through all attributes
+ });
+
+ if (!gdb_type.empty() && !(encoding_set || format_set))
{
- regNumGeneric = LLDB_REGNUM_GENERIC_SP;
+ if (gdb_type.find("int") == 0)
+ {
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (gdb_type == "data_ptr" || gdb_type == "code_ptr")
+ {
+ reg_info.format = eFormatAddressInfo;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (gdb_type == "i387_ext" || gdb_type == "float")
+ {
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ }
}
- if (name == "ebp")
+
+ // Only update the register set name if we didn't get a "reg_set" attribute.
+ // "set_name" will be empty if we didn't have a "reg_set" attribute.
+ if (!set_name && !gdb_group.empty())
+ set_name.SetCString(gdb_group.c_str());
+
+ reg_info.byte_offset = reg_offset;
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ if (!value_regs.empty())
{
- regNumGeneric = LLDB_REGNUM_GENERIC_FP;
+ value_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = value_regs.data();
}
- if (name == "lr")
+ if (!invalidate_regs.empty())
{
- regNumGeneric = LLDB_REGNUM_GENERIC_RA;
+ invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = invalidate_regs.data();
}
-
- RegisterInfo info =
- {
- name.c_str(),
- nullptr ,
- byteSize ,
- byteOffset ,
- lldb::Encoding::eEncodingUint,
- lldb::Format::eFormatDefault,
- { regNumGcc ,
- regNumDwarf ,
- regNumGeneric,
- regNumGdb ,
- regNumNative },
- nullptr,
- nullptr
- };
-
- ConstString regName = ConstString(gdbReg.m_name);
- ConstString regAltName = ConstString();
- ConstString regGroup = ConstString(group);
- regInfo.AddRegister(info, regName, regAltName, regGroup);
-
- // advance register info
- byteOffset += byteSize;
- regNum += 1;
- }
-
- regInfo.Finalize ();
+
+ dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+
+ return true; // Keep iterating through all "reg" elements
+ });
+ return true;
}
-
+
} // namespace {}
-void XMLCDECL
-libxml2NullErrorFunc (void *ctx, const char *msg, ...)
-{
- // do nothing currently
-}
// query the target of gdb-remote for extended target information
// return: 'true' on success
@@ -4016,13 +3800,13 @@ libxml2NullErrorFunc (void *ctx, const char *msg, ...)
bool
ProcessGDBRemote::GetGDBServerRegisterInfo ()
{
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return false;
// redirect libxml2's error handler since the default prints to stdout
- xmlGenericErrorFunc func = libxml2NullErrorFunc;
- initGenericErrorDefaultFunc( &func );
GDBRemoteCommunicationClient & comm = m_gdb_comm;
- GDBRemoteDynamicRegisterInfo & regInfo = m_register_info;
// check that we have extended feature read support
if ( !comm.GetQXferFeaturesReadSupported( ) )
@@ -4038,66 +3822,102 @@ ProcessGDBRemote::GetGDBServerRegisterInfo ()
{
return false;
}
+
- // parse the xml file in memory
- xmlDocPtr doc = xmlReadMemory(raw.c_str(), raw.size(), "noname.xml", nullptr, 0);
- if (doc == nullptr)
- return false;
-
- // extract target info from target.xml
- GdbServerTargetInfo gdbInfo;
- if (parseTargetInfo(doc, gdbInfo))
- {
- // NOTE: We could deduce triple from gdbInfo if lldb doesn't already have one set
- }
+ XMLDocument xml_document;
- // collect registers from all of the includes
- GDBServerRegisterVec regList;
- stringVec includes;
- if (parseTargetIncludes(doc, includes) > 0)
+ if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml"))
{
-
- for (uint32_t i = 0; i < includes.size(); ++i)
+ GdbServerTargetInfo target_info;
+
+ XMLNode target_node = xml_document.GetRootElement("target");
+ if (target_node)
{
-
- // request register file
- if (!comm.ReadExtFeature(ConstString("features"),
- ConstString(includes[i]),
- raw,
- lldberr))
- continue;
-
- // parse register file
- xmlDocPtr regXml = xmlReadMemory(raw.c_str(),
- raw.size( ),
- includes[i].c_str(),
- nullptr,
- 0);
- if (!regXml)
- continue;
-
- // pass registers to lldb
- parseRegisters(regXml, regList);
+ XMLNode feature_node;
+ target_node.ForEachChildElement([&target_info, this, &feature_node](const XMLNode &node) -> bool
+ {
+ llvm::StringRef name = node.GetName();
+ if (name == "architecture")
+ {
+ node.GetElementText(target_info.arch);
+ }
+ else if (name == "osabi")
+ {
+ node.GetElementText(target_info.osabi);
+ }
+ else if (name == "xi:include")
+ {
+ llvm::StringRef href = node.GetAttributeValue("href");
+ if (!href.empty())
+ target_info.includes.push_back(href.str());
+ }
+ else if (name == "feature")
+ {
+ feature_node = node;
+ }
+ else if (name == "groups")
+ {
+ node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool {
+ uint32_t set_id = UINT32_MAX;
+ RegisterSetInfo set_info;
+
+ node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+ if (name == "id")
+ set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ if (name == "name")
+ set_info.name = ConstString(value);
+ return true; // Keep iterating through all attributes
+ });
+
+ if (set_id != UINT32_MAX)
+ target_info.reg_set_map[set_id] = set_info;
+ return true; // Keep iterating through all "group" elements
+ });
+ }
+ return true; // Keep iterating through all children of the target_node
+ });
+
+ if (feature_node)
+ {
+ ParseRegisters(feature_node, target_info, this->m_register_info);
+ }
+
+ for (const auto &include : target_info.includes)
+ {
+ // request register file
+ std::string xml_data;
+ if (!comm.ReadExtFeature(ConstString("features"),
+ ConstString(include),
+ xml_data,
+ lldberr))
+ continue;
+
+ XMLDocument include_xml_document;
+ include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), include.c_str());
+ XMLNode include_feature_node = include_xml_document.GetRootElement("feature");
+ if (include_feature_node)
+ {
+ ParseRegisters(include_feature_node, target_info, this->m_register_info);
+ }
+ }
+ this->m_register_info.Finalize(GetTarget().GetArchitecture());
}
}
- // pass all of these registers to lldb
- BuildRegisters(regList, regInfo);
-
- return true;
+ return m_register_info.GetNumRegisters() > 0;
}
Error
ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
{
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS);
if (log)
log->Printf ("ProcessGDBRemote::%s", __FUNCTION__);
- // redirect libxml2's error handler since the default prints to stdout
- xmlGenericErrorFunc func = libxml2NullErrorFunc;
- initGenericErrorDefaultFunc (&func);
-
GDBRemoteCommunicationClient & comm = m_gdb_comm;
// check that we have extended feature read support
@@ -4115,79 +3935,53 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
// parse the xml file in memory
if (log)
log->Printf ("parsing: %s", raw.c_str());
- xmlDocPtr doc = xmlReadMemory (raw.c_str(), raw.size(), "noname.xml", nullptr, 0);
- if (doc == nullptr)
+ XMLDocument doc;
+
+ if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
return Error (0, ErrorType::eErrorTypeGeneric);
- xmlNodePtr elm = xmlExFindElement (doc->children, {"library-list-svr4"});
- if (!elm)
+ XMLNode root_element = doc.GetRootElement("library-list-svr4");
+ if (!root_element)
return Error();
// main link map structure
- xmlAttr * attr = xmlExFindAttribute (elm, "main-lm");
- if (attr)
+ llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm");
+ if (!main_lm.empty())
{
- std::string val = xmlExGetTextContent (attr);
- if (val.length() > 2)
- {
- uint32_t process_lm = std::stoul (val.c_str()+2, 0, 16);
- list.m_link_map = process_lm;
- }
+ list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0);
}
- // parse individual library entries
- for (xmlNode * child = elm->children; child; child=child->next)
- {
- if (!child->name)
- continue;
-
- if (strcmp ((const char*)child->name, "library") != 0)
- continue;
+ root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool {
GDBLoadedModuleInfoList::LoadedModuleInfo module;
- for (xmlAttrPtr prop = child->properties; prop; prop=prop->next)
- {
- if (strcmp ((const char*)prop->name, "name") == 0)
- module.set_name (xmlExGetTextContent (prop));
-
- // the address of the link_map struct.
- if (strcmp ((const char*)prop->name, "lm") == 0)
+ library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+
+ if (name == "name")
+ module.set_name (value.str());
+ else if (name == "lm")
{
- std::string val = xmlExGetTextContent (prop);
- if (val.length() > 2)
- {
- uint32_t module_lm = std::stoul (val.c_str()+2, 0, 16);
- module.set_link_map (module_lm);
- }
+ // the address of the link_map struct.
+ module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
}
-
- // the displacement as read from the field 'l_addr' of the link_map struct.
- if (strcmp ((const char*)prop->name, "l_addr") == 0)
+ else if (name == "l_addr")
{
- std::string val = xmlExGetTextContent (prop);
- if (val.length() > 2)
- {
- uint32_t module_base = std::stoul (val.c_str()+2, 0, 16);
- module.set_base (module_base);
- }
+ // the displacement as read from the field 'l_addr' of the link_map struct.
+ module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+
}
-
- // the memory address of the libraries PT_DYAMIC section.
- if (strcmp ((const char*)prop->name, "l_ld") == 0)
+ else if (name == "l_ld")
{
- std::string val = xmlExGetTextContent (prop);
- if (val.length() > 2)
- {
- uint32_t module_dyn = std::stoul (val.c_str()+2, 0, 16);
- module.set_dynamic (module_dyn);
- }
+ // the memory address of the libraries PT_DYAMIC section.
+ module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
}
- }
+
+ return true; // Keep iterating over all properties of "library"
+ });
if (log)
{
- std::string name ("");
+ std::string name;
lldb::addr_t lm=0, base=0, ld=0;
module.get_name (name);
@@ -4199,7 +3993,8 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
}
list.add (module);
- }
+ return true; // Keep iterating over all "library" elements in the root node
+ });
if (log)
log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size());
@@ -4207,26 +4002,6 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
return Error();
}
-#else // if defined( LIBXML2_DEFINED )
-
-Error
-ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList &)
-{
- // stub (libxml2 not present)
- Error err;
- err.SetError (0, ErrorType::eErrorTypeGeneric);
- return err;
-}
-
-bool
-ProcessGDBRemote::GetGDBServerRegisterInfo ()
-{
- // stub (libxml2 not present)
- return false;
-}
-
-#endif // if defined( LIBXML2_DEFINED )
-
lldb::ModuleSP
ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr)
{
OpenPOWER on IntegriCloud