diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 895 |
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> ®nums, 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, ®_offset](const XMLNode ®_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, ®_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, ®_info, &prev_reg_num, ®_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) { |