Added XML to the host layer.

We know have on API we should use for all XML within LLDB in XML.h. This API will be easy back the XML parsing by different libraries in case libxml2 doesn't work on all platforms. It also allows the only place for #ifdef ...XML... to be in XML.h and XML.cpp. The API is designed so it will still compile with or without XML support and there is a static function "bool XMLDocument::XMLEnabled()" that can be called to see if XML is currently supported. All APIs will return errors, false, or nothing when XML isn't enabled.

Converted all locations that used XML over to using the host XML implementation.

Added target.xml support to debugserver. Extended the XML register format to work for LLDB by including extra attributes and elements where needed. This allows the target.xml to replace the qRegisterInfo packets and allows us to fetch all register info in a single packet.

<rdar://problem/21090173>

llvm-svn: 238224
diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index 0e9b540..f91cd19 100644
--- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -15,11 +15,12 @@
 // C++ Includes
 // Other libraries and framework includes
 // Project includes
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Core/ArchSpec.h"
 #include "lldb/Core/RegularExpression.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Core/StructuredData.h"
 #include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/StringConvert.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -36,17 +37,18 @@
 {
 }
 
-DynamicRegisterInfo::DynamicRegisterInfo(const StructuredData::Dictionary &dict, ByteOrder byte_order)
-    : m_regs()
-    , m_sets()
-    , m_set_reg_nums()
-    , m_set_names()
-    , m_value_regs_map()
-    , m_invalidate_regs_map()
-    , m_reg_data_byte_size(0)
-    , m_finalized(false)
+DynamicRegisterInfo::DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+                                         const lldb_private::ArchSpec &arch) :
+    m_regs (),
+    m_sets (),
+    m_set_reg_nums (),
+    m_set_names (),
+    m_value_regs_map (),
+    m_invalidate_regs_map (),
+    m_reg_data_byte_size (0),
+    m_finalized (false)
 {
-    SetRegisterInfo (dict, byte_order);
+    SetRegisterInfo (dict, arch);
 }
 
 DynamicRegisterInfo::~DynamicRegisterInfo ()
@@ -54,7 +56,7 @@
 }
 
 size_t
-DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, ByteOrder byte_order)
+DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const ArchSpec &arch)
 {
     assert(!m_finalized);
     StructuredData::Array *sets = nullptr;
@@ -121,6 +123,8 @@
 
         reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset, UINT32_MAX);
 
+        const ByteOrder byte_order = arch.GetByteOrder();
+        
         if (reg_info.byte_offset == UINT32_MAX)
         {
             // No offset for this register, see if the register has a value expression
@@ -384,7 +388,7 @@
         m_regs.push_back(reg_info);
         m_set_reg_nums[set].push_back(i);
     }
-    Finalize();
+    Finalize(arch);
     return m_regs.size();
 }
 
@@ -423,7 +427,7 @@
 }
 
 void
-DynamicRegisterInfo::Finalize ()
+DynamicRegisterInfo::Finalize (const ArchSpec &arch)
 {
     if (m_finalized)
         return;
@@ -518,6 +522,95 @@
         else
             m_regs[i].invalidate_regs = NULL;
     }
+    
+    // Check if we need to automatically set the generic registers in case
+    // they weren't set
+    bool generic_regs_specified = false;
+    for (const auto &reg: m_regs)
+    {
+        if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
+        {
+            generic_regs_specified = true;
+            break;
+        }
+    }
+
+    if (!generic_regs_specified)
+    {
+        switch (arch.GetMachine())
+        {
+        case llvm::Triple::aarch64:
+        case llvm::Triple::aarch64_be:
+            for (auto &reg: m_regs)
+            {
+                if (strcmp(reg.name, "pc") == 0)
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+                else if ((strcmp(reg.name, "fp") == 0) || (strcmp(reg.name, "x29") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+                else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "x30") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+                else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "x31") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+                else if (strcmp(reg.name, "cpsr") == 0)
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+            }
+            break;
+            
+        case llvm::Triple::arm:
+        case llvm::Triple::armeb:
+        case llvm::Triple::thumb:
+        case llvm::Triple::thumbeb:
+            for (auto &reg: m_regs)
+            {
+                if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+                else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "r13") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+                else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "r14") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+                else if ((strcmp(reg.name, "r7") == 0) && arch.GetTriple().getVendor() == llvm::Triple::Apple)
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+                else if ((strcmp(reg.name, "r11") == 0) && arch.GetTriple().getVendor() != llvm::Triple::Apple)
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+                else if (strcmp(reg.name, "fp") == 0)
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+                else if (strcmp(reg.name, "cpsr") == 0)
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+            }
+            break;
+            
+        case llvm::Triple::x86:
+            for (auto &reg: m_regs)
+            {
+                if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+                else if ((strcmp(reg.name, "esp") == 0) || (strcmp(reg.name, "sp") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+                else if ((strcmp(reg.name, "ebp") == 0) || (strcmp(reg.name, "fp") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+                else if ((strcmp(reg.name, "eflags") == 0) || (strcmp(reg.name, "flags") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+            }
+            break;
+
+        case llvm::Triple::x86_64:
+            for (auto &reg: m_regs)
+            {
+                if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+                else if ((strcmp(reg.name, "rsp") == 0) || (strcmp(reg.name, "sp") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+                else if ((strcmp(reg.name, "rbp") == 0) || (strcmp(reg.name, "fp") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+                else if ((strcmp(reg.name, "rflags") == 0) || (strcmp(reg.name, "flags") == 0))
+                    reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+            }
+            break;
+
+        default:
+            break;
+        }
+    }
 }
 
 size_t
diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
index 128d898..1b99e2f 100644
--- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
+++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -26,12 +26,14 @@
 public:
     DynamicRegisterInfo ();
 
-    DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, lldb::ByteOrder byte_order);
+    DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+                        const lldb_private::ArchSpec &arch);
 
     virtual 
     ~DynamicRegisterInfo ();
 
-    size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, lldb::ByteOrder byte_order);
+    size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+                           const lldb_private::ArchSpec &arch);
 
     void
     AddRegister (lldb_private::RegisterInfo &reg_info, 
@@ -40,7 +42,7 @@
                  lldb_private::ConstString &set_name);
 
     void
-    Finalize ();
+    Finalize (const lldb_private::ArchSpec &arch);
 
     size_t
     GetNumRegisters() const;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 7f194cd..a452ae9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -3929,9 +3929,12 @@
     std::stringstream output;
     StringExtractorGDBRemote chunk;
 
-    const int size   = 0xfff;
-    int       offset = 0;
-    bool      active = true;
+    uint64_t size = GetRemoteMaxPacketSize();
+    if (size == 0)
+        size = 0x1000;
+    size = size - 1; // Leave space for the 'm' or 'l' character in the response
+    int offset = 0;
+    bool active = true;
 
     // loop until all data has been read
     while ( active ) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a03c43b..0399634 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 @@
                     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 @@
     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 @@
     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 @@
                     }
                     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 @@
         }
     }
 
-    // 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)
-    {
-        // try to extract information from servers target.xml
-        if (GetGDBServerRegisterInfo ())
-            return;
-
-        FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();
+    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;
-        }
+    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 @@
     // 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 @@
     }
 
     // At this point, we can finalize our register info.
-    m_register_info.Finalize ();
+    m_register_info.Finalize (GetTarget().GetArchitecture());
 }
 
 Error
@@ -3595,420 +3591,208 @@
     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 RegisterSetInfo
+{
+    ConstString name;
+};
 
+typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap;
+ 
 struct GdbServerTargetInfo
 {
-    std::string m_arch;
-    std::string m_osabi;
+    std::string arch;
+    std::string osabi;
+    stringVec includes;
+    RegisterSetMap reg_set_map;
+    XMLNode feature_node;
 };
-
-// conversion table between gdb register type and enum
-struct
-{
-    const char * m_name;
-    GdbServerRegisterInfo::RegType m_type;
-}
-RegTypeTable[] =
-{
-    { "int32"   , GdbServerRegisterInfo::eInt32    },
-    { "int"     , GdbServerRegisterInfo::eInt32    },
-    { "data_ptr", GdbServerRegisterInfo::eDataPtr  },
-    { "code_ptr", GdbServerRegisterInfo::eCodePtr  },
-    { "i387_ext", GdbServerRegisterInfo::eI387Ext  }, // 80bit fpu
-    { nullptr   , GdbServerRegisterInfo::eUnknown  }  // sentinel
-};
-
-// 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)
+ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info)
 {
-    if (!doc)
+    if (!feature_node)
         return false;
-    xmlNodePtr e1 = xmlExFindElement (doc->children, {"target", "architecture"});
-    if (!e1)
-        return false;
-    out.m_arch = xmlExGetTextContent (e1);
+    
+    uint32_t prev_reg_num = 0;
+    uint32_t reg_offset = 0;
 
-    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)
-{
-
-    if (!doc)
-        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;
-
-            // 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
             {
-                if (RegTypeTable[j].m_name == v)
+                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")
+            {
+                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")))
+            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))
         {
-            reg.m_group = xmlExGetTextContent(attr);
-            reg.m_flags.m_has_group = true;
+            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 ((attr = xmlExFindAttribute(regs[i], "regnum")))
+        
+        // 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())
         {
-            const std::string v = xmlExGetTextContent(attr);
-            reg.m_regNum = atoi(v.c_str());
-            reg.m_flags.m_has_regNum = true;
+            value_regs.push_back(LLDB_INVALID_REGNUM);
+            reg_info.value_regs = value_regs.data();
         }
-
-        regList.push_back(reg);
-    }
-
-    //TODO: there is also a "vector" element to parse
-    //TODO: there is also eflags to parse
-
+        if (!invalidate_regs.empty())
+        {
+            invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+            reg_info.invalidate_regs = invalidate_regs.data();
+        }
+        
+        dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+        
+        return true; // Keep iterating through all "reg" elements
+    });
     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")
-        {
-            regNumGeneric = LLDB_REGNUM_GENERIC_SP;
-        }
-        if (name == "ebp")
-        {
-            regNumGeneric = LLDB_REGNUM_GENERIC_FP;
-        }
-        if (name == "lr")
-        {
-            regNumGeneric = LLDB_REGNUM_GENERIC_RA;
-        }
-
-        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 ();
-}
-
+    
 } // 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 @@
 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 @@
     {
         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;
+    XMLDocument xml_document;
 
-    // extract target info from target.xml
-    GdbServerTargetInfo gdbInfo;
-    if (parseTargetInfo(doc, gdbInfo))
+    if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml"))
     {
-        // NOTE: We could deduce triple from gdbInfo if lldb doesn't already have one set
-    }
-
-    // collect registers from all of the includes
-    GDBServerRegisterVec regList;
-    stringVec includes;
-    if (parseTargetIncludes(doc, includes) > 0)
-    {
-
-        for (uint32_t i = 0; i < includes.size(); ++i)
+        GdbServerTargetInfo target_info;
+        
+        XMLNode target_node = xml_document.GetRootElement("target");
+        if (target_node)
         {
+            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;
 
-            // 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);
+                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 @@
     // 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 @@
         }
 
         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 @@
     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)
 {