<p dir="ltr">The same thing for me as I wrote in <a href="http://reviews.llvm.org/rL235109">http://reviews.llvm.org/rL235109</a>.</p>
<p dir="ltr">Thanks,<br>
Ilia </p>
<div class="gmail_quote">On Apr 17, 2015 12:35 AM, "Chuck Ries" <<a href="mailto:Chuck.Ries@microsoft.com">Chuck.Ries@microsoft.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">After this change I am seeing the cmake build broken on mac os.<br>
<br>
FAILED: /usr/bin/c++   -DGTEST_HAS_RTTI=0 -DHAVE_ROUND -DLIBXML2_DEFINED -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fPIC -fvisibility-inlines-hidden -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wcovered-switch-default -std=c++11 -fcolor-diagnostics -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-deprecated-register  -fno-exceptions -fno-rtti -fPIC -fPIC -g -Itools/lldb/source/Plugins/Process/gdb-remote -I/Users/chuckr/llama/llvm/tools/lldb/source/Plugins/Process/gdb-remote -I/Users/chuckr/llama/llvm/tools/lldb/include -Itools/lldb/include -Iinclude -I/Users/chuckr/llama/llvm/include -I/System/Library/Frameworks/Python.framework/Headers -I/Users/chuckr/llama/llvm/tools/lldb/../clang/include -Itools/lldb/../clang/include -I/Users/chuckr/llama/llvm/tools/lldb/source/.    -fno-exceptions -fno-rtti -MMD -MT tools/lldb/source/Plugins/Process/gdb-remote/CMakeFiles/lldbPl!<br>
 uginProcessGDBRemote.dir/ProcessGDBRemote.cpp.o -MF tools/lldb/source/Plugins/Process/gdb-remote/CMakeFiles/lldbPluginProcessGDBRemote.dir/ProcessGDBRemote.cpp.o.d -o tools/lldb/source/Plugins/Process/gdb-remote/CMakeFiles/lldbPluginProcessGDBRemote.dir/ProcessGDBRemote.cpp.o -c /Users/chuckr/llama/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp<br>
/Users/chuckr/llama/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp:31:10: fatal error: 'libxml/xmlreader.h' file not found<br>
#include <libxml/xmlreader.h><br>
         ^<br>
1 error generated.<br>
<br>
-----Original Message-----<br>
From: <a href="mailto:lldb-commits-bounces@cs.uiuc.edu">lldb-commits-bounces@cs.uiuc.edu</a> [mailto:<a href="mailto:lldb-commits-bounces@cs.uiuc.edu">lldb-commits-bounces@cs.uiuc.edu</a>] On Behalf Of Colin Riley<br>
Sent: Thursday, April 16, 2015 8:52 AM<br>
To: <a href="mailto:lldb-commits@cs.uiuc.edu">lldb-commits@cs.uiuc.edu</a><br>
Subject: [Lldb-commits] [lldb] r235109 - Adds lldb support for querying the register mapping from gdbserver remote targets using qXfer:features:read packet. Only enabled if libxml2 enabled in build.<br>
<br>
Author: domipheus<br>
Date: Thu Apr 16 10:51:33 2015<br>
New Revision: 235109<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=235109&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=235109&view=rev</a><br>
Log:<br>
Adds lldb support for querying the register mapping from gdbserver remote targets using qXfer:features:read packet. Only enabled if libxml2 enabled in build.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D8999" target="_blank">http://reviews.llvm.org/D8999</a><br>
<br>
Modified:<br>
    lldb/trunk/cmake/modules/LLDBConfig.cmake<br>
    lldb/trunk/source/Commands/CommandObjectRegister.cpp<br>
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp<br>
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h<br>
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp<br>
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h<br>
<br>
Modified: lldb/trunk/cmake/modules/LLDBConfig.cmake<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/cmake/modules/LLDBConfig.cmake?rev=235109&r1=235108&r2=235109&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/cmake/modules/LLDBConfig.cmake?rev=235109&r1=235108&r2=235109&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/cmake/modules/LLDBConfig.cmake (original)<br>
+++ lldb/trunk/cmake/modules/LLDBConfig.cmake Thu Apr 16 10:51:33 2015<br>
@@ -187,29 +187,39 @@ install(DIRECTORY include/<br>
   DESTINATION include<br>
   FILES_MATCHING<br>
   PATTERN "*.h"<br>
-  PATTERN ".svn" EXCLUDE<br>
-  )<br>
-<br>
-<br>
-# Find libraries or frameworks that may be needed -if (CMAKE_SYSTEM_NAME MATCHES "Darwin")<br>
+  PATTERN ".svn" EXCLUDE<br>
+  )<br>
+<br>
+if (NOT LIBXML2_FOUND)<br>
+  find_package(LibXml2)<br>
+endif()<br>
+<br>
+# Find libraries or frameworks that may be needed if (CMAKE_SYSTEM_NAME<br>
+MATCHES "Darwin")<br>
   find_library(CARBON_LIBRARY Carbon)<br>
   find_library(FOUNDATION_LIBRARY Foundation)<br>
   find_library(CORE_FOUNDATION_LIBRARY CoreFoundation)<br>
   find_library(CORE_SERVICES_LIBRARY CoreServices)<br>
-  find_library(SECURITY_LIBRARY Security)<br>
-  find_library(DEBUG_SYMBOLS_LIBRARY DebugSymbols PATHS "/System/Library/PrivateFrameworks")<br>
-<br>
-  if (NOT LIBXML2_FOUND)<br>
-    find_package(LibXml2)<br>
-  endif ()<br>
-  list(APPEND system_libs xml2 ncurses panel)<br>
-  list(APPEND system_libs ${CARBON_LIBRARY} ${FOUNDATION_LIBRARY}<br>
-  ${CORE_FOUNDATION_LIBRARY} ${CORE_SERVICES_LIBRARY} ${SECURITY_LIBRARY}<br>
-  ${DEBUG_SYMBOLS_LIBRARY})<br>
-endif()<br>
-<br>
-if(LLDB_REQUIRES_EH)<br>
+  find_library(SECURITY_LIBRARY Security)<br>
+ find_library(DEBUG_SYMBOLS_LIBRARY DebugSymbols PATHS<br>
+ "/System/Library/PrivateFrameworks")<br>
+<br>
+  add_definitions( -DLIBXML2_DEFINED )<br>
+  list(APPEND system_libs xml2 ncurses panel)  list(APPEND system_libs<br>
+ ${CARBON_LIBRARY} ${FOUNDATION_LIBRARY}  ${CORE_FOUNDATION_LIBRARY}<br>
+ ${CORE_SERVICES_LIBRARY} ${SECURITY_LIBRARY}<br>
+  ${DEBUG_SYMBOLS_LIBRARY})<br>
+<br>
+else()<br>
+<br>
+  if (LIBXML2_FOUND)<br>
+    add_definitions( -DLIBXML2_DEFINED )<br>
+    list(APPEND system_libs ${LIBXML2_LIBRARIES})<br>
+    include_directories(${LIBXML2_INCLUDE_DIR})<br>
+  endif()<br>
+<br>
+endif()<br>
+<br>
+if(LLDB_REQUIRES_EH)<br>
   set(LLDB_REQUIRES_RTTI ON)<br>
 else()<br>
   if(LLVM_COMPILER_IS_GCC_COMPATIBLE)<br>
<br>
Modified: lldb/trunk/source/Commands/CommandObjectRegister.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectRegister.cpp?rev=235109&r1=235108&r2=235109&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectRegister.cpp?rev=235109&r1=235108&r2=235109&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Commands/CommandObjectRegister.cpp (original)<br>
+++ lldb/trunk/source/Commands/CommandObjectRegister.cpp Thu Apr 16<br>
+++ 10:51:33 2015<br>
@@ -144,7 +144,7 @@ public:<br>
         const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx);<br>
         if (reg_set)<br>
         {<br>
-            strm.Printf ("%s:\n", reg_set->name);<br>
+            strm.Printf ("%s:\n", (reg_set->name ? reg_set->name :<br>
+ "unknown") );<br>
             strm.IndentMore ();<br>
             const size_t num_registers = reg_set->num_registers;<br>
             for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)<br>
<br>
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=235109&r1=235108&r2=235109&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=235109&r1=235108&r2=235109&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)<br>
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationC<br>
+++ lient.cpp Thu Apr 16 10:51:33 2015<br>
@@ -79,6 +79,7 @@ GDBRemoteCommunicationClient::GDBRemoteC<br>
     m_supports_QSaveRegisterState (eLazyBoolCalculate),<br>
     m_supports_qXfer_auxv_read (eLazyBoolCalculate),<br>
     m_supports_qXfer_libraries_read (eLazyBoolCalculate),<br>
+    m_supports_qXfer_features_read (eLazyBoolCalculate),<br>
     m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate),<br>
     m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),<br>
     m_supports_jThreadExtendedInfo (eLazyBoolCalculate), @@ -214,6 +215,16 @@ GDBRemoteCommunicationClient::GetQXferAu<br>
     return (m_supports_qXfer_auxv_read == eLazyBoolYes);  }<br>
<br>
+bool<br>
+GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported () {<br>
+    if (m_supports_qXfer_features_read == eLazyBoolCalculate)<br>
+    {<br>
+        GetRemoteQSupported();<br>
+    }<br>
+    return (m_supports_qXfer_features_read == eLazyBoolYes); }<br>
+<br>
 uint64_t<br>
 GDBRemoteCommunicationClient::GetRemoteMaxPacketSize()<br>
 {<br>
@@ -335,6 +346,7 @@ GDBRemoteCommunicationClient::ResetDisco<br>
     m_supports_qXfer_auxv_read = eLazyBoolCalculate;<br>
     m_supports_qXfer_libraries_read = eLazyBoolCalculate;<br>
     m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;<br>
+    m_supports_qXfer_features_read = eLazyBoolCalculate;<br>
     m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;<br>
<br>
     m_supports_qProcessInfoPID = true;<br>
@@ -373,10 +385,21 @@ GDBRemoteCommunicationClient::GetRemoteQ<br>
     m_supports_qXfer_libraries_read = eLazyBoolNo;<br>
     m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;<br>
     m_supports_augmented_libraries_svr4_read = eLazyBoolNo;<br>
+    m_supports_qXfer_features_read = eLazyBoolNo;<br>
     m_max_packet_size = UINT64_MAX;  // It's supposed to always be there, but if not, we assume no limit<br>
<br>
+    // build the qSupported packet<br>
+    std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"};<br>
+    StreamString packet;<br>
+    packet.PutCString( "qSupported" );<br>
+    for ( uint32_t i = 0; i < features.size( ); ++i )<br>
+    {<br>
+        packet.PutCString( i==0 ? ":" : ";");<br>
+        packet.PutCString( features[i].c_str( ) );<br>
+    }<br>
+<br>
     StringExtractorGDBRemote response;<br>
-    if (SendPacketAndWaitForResponse("qSupported",<br>
+    if (SendPacketAndWaitForResponse(packet.GetData(),<br>
                                      response,<br>
                                      /*send_async=*/false) == PacketResult::Success)<br>
     {<br>
@@ -392,6 +415,8 @@ GDBRemoteCommunicationClient::GetRemoteQ<br>
         }<br>
         if (::strstr (response_cstr, "qXfer:libraries:read+"))<br>
             m_supports_qXfer_libraries_read = eLazyBoolYes;<br>
+        if (::strstr (response_cstr, "qXfer:features:read+"))<br>
+            m_supports_qXfer_features_read = eLazyBoolYes;<br>
<br>
         const char *packet_size_str = ::strstr (response_cstr, "PacketSize=");<br>
         if (packet_size_str)<br>
@@ -3776,3 +3801,74 @@ GDBRemoteCommunicationClient::GetModuleI<br>
<br>
     return true;<br>
 }<br>
+<br>
+// query the target remote for extended information using the qXfer<br>
+packet // // example: object='features', annex='target.xml', out=<xml<br>
+output> // return:  'true'  on success<br>
+//          'false' on failure (err set)<br>
+bool<br>
+GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object,<br>
+                                              const lldb_private::ConstString annex,<br>
+                                              std::string & out,<br>
+                                              lldb_private::Error &<br>
+err) {<br>
+<br>
+    std::stringstream output;<br>
+    StringExtractorGDBRemote chunk;<br>
+<br>
+    const int size   = 0xfff;<br>
+    int       offset = 0;<br>
+    bool      active = true;<br>
+<br>
+    // loop until all data has been read<br>
+    while ( active ) {<br>
+<br>
+        // send query extended feature packet<br>
+        std::stringstream packet;<br>
+        packet << "qXfer:"<br>
+               << object.AsCString( ) << ":read:"<br>
+               << annex.AsCString( )  << ":"<br>
+               << std::hex << offset  << ","<br>
+               << std::hex << size;<br>
+<br>
+        GDBRemoteCommunication::PacketResult res =<br>
+            SendPacketAndWaitForResponse( packet.str().c_str(),<br>
+                                          chunk,<br>
+                                          false );<br>
+<br>
+        if ( res != GDBRemoteCommunication::PacketResult::Success ) {<br>
+            err.SetErrorString( "Error sending $qXfer packet" );<br>
+            return false;<br>
+        }<br>
+<br>
+        const std::string & str = chunk.GetStringRef( );<br>
+        if ( str.length() == 0 ) {<br>
+            // should have some data in chunk<br>
+            err.SetErrorString( "Empty response from $qXfer packet" );<br>
+            return false;<br>
+        }<br>
+<br>
+        // check packet code<br>
+        switch ( str[0] ) {<br>
+            // last chunk<br>
+        case ( 'l' ):<br>
+            active = false;<br>
+            // fall through intensional<br>
+<br>
+            // more chunks<br>
+        case ( 'm' ) :<br>
+            if ( str.length() > 1 )<br>
+                output << &str[1];<br>
+            break;<br>
+<br>
+            // unknown chunk<br>
+        default:<br>
+            err.SetErrorString( "Invalid continuation code from $qXfer packet" );<br>
+            return false;<br>
+        }<br>
+    }<br>
+<br>
+    out = output.str( );<br>
+    err.Success( );<br>
+    return true;<br>
+}<br>
<br>
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=235109&r1=235108&r2=235109&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=235109&r1=235108&r2=235109&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)<br>
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationC<br>
+++ lient.h Thu Apr 16 10:51:33 2015<br>
@@ -426,6 +426,9 @@ public:<br>
     bool<br>
     GetAugmentedLibrariesSVR4ReadSupported ();<br>
<br>
+    bool<br>
+    GetQXferFeaturesReadSupported ();<br>
+<br>
     LazyBool<br>
     SupportsAllocDeallocMemory () // const<br>
     {<br>
@@ -533,6 +536,12 @@ public:<br>
                    const ArchSpec& arch_spec,<br>
                    ModuleSpec &module_spec);<br>
<br>
+    bool<br>
+    ReadExtFeature (const lldb_private::ConstString object,<br>
+                    const lldb_private::ConstString annex,<br>
+                    std::string & out,<br>
+                    lldb_private::Error & err);<br>
+<br>
 protected:<br>
<br>
     PacketResult<br>
@@ -576,6 +585,7 @@ protected:<br>
     LazyBool m_supports_qXfer_auxv_read;<br>
     LazyBool m_supports_qXfer_libraries_read;<br>
     LazyBool m_supports_qXfer_libraries_svr4_read;<br>
+    LazyBool m_supports_qXfer_features_read;<br>
     LazyBool m_supports_augmented_libraries_svr4_read;<br>
     LazyBool m_supports_jThreadExtendedInfo;<br>
<br>
<br>
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=235109&r1=235108&r2=235109&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=235109&r1=235108&r2=235109&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)<br>
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp<br>
+++ Thu Apr 16 10:51:33 2015<br>
@@ -27,6 +27,9 @@<br>
 #include <mutex><br>
<br>
 // Other libraries and framework includes<br>
+#if defined( LIBXML2_DEFINED )<br>
+#include <libxml/xmlreader.h><br>
+#endif<br>
<br>
 #include "lldb/Breakpoint/Watchpoint.h"<br>
 #include "lldb/Interpreter/Args.h"<br>
@@ -571,6 +574,10 @@ ProcessGDBRemote::BuildDynamicRegisterIn<br>
<br>
     if (reg_num == 0)<br>
     {<br>
+        // try to extract information from servers target.xml<br>
+        if ( GetGDBServerInfo( ) )<br>
+            return;<br>
+<br>
         FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();<br>
<br>
         if (target_definition_fspec)<br>
@@ -3429,6 +3436,465 @@ ProcessGDBRemote::GetModuleSpec(const Fi<br>
     return true;<br>
 }<br>
<br>
+#if defined( LIBXML2_DEFINED )<br>
+namespace {<br>
+<br>
+typedef std::vector<std::string> stringVec; typedef<br>
+std::vector<xmlNodePtr> xmlNodePtrVec;<br>
+<br>
+struct GdbServerRegisterInfo {<br>
+<br>
+    struct {<br>
+        bool m_has_name     : 1;<br>
+        bool m_has_bitSize  : 1;<br>
+        bool m_has_type     : 1;<br>
+        bool m_has_group    : 1;<br>
+        bool m_has_regNum   : 1;<br>
+    }<br>
+    m_flags;<br>
+<br>
+    std::string m_name;<br>
+    std::string m_group;<br>
+    uint32_t    m_bitSize;<br>
+    uint32_t    m_regNum;<br>
+<br>
+    enum RegType {<br>
+        eUnknown   ,<br>
+        eCodePtr   ,<br>
+        eDataPtr   ,<br>
+        eInt32     ,<br>
+        eI387Ext   ,<br>
+    }<br>
+    m_type;<br>
+<br>
+    void clear(  ) {<br>
+        memset( &m_flags, 0, sizeof( m_flags ) );<br>
+    }<br>
+};<br>
+<br>
+typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec;<br>
+<br>
+struct GdbServerTargetInfo {<br>
+<br>
+    std::string m_arch;<br>
+    std::string m_osabi;<br>
+};<br>
+<br>
+// conversion table between gdb register type and enum struct {<br>
+    const char * m_name;<br>
+    GdbServerRegisterInfo::RegType m_type; } RegTypeTable[] = {<br>
+    { "int32"   , GdbServerRegisterInfo::eInt32    },<br>
+    { "int"     , GdbServerRegisterInfo::eInt32    },<br>
+    { "data_ptr", GdbServerRegisterInfo::eDataPtr  },<br>
+    { "code_ptr", GdbServerRegisterInfo::eCodePtr  },<br>
+    { "i387_ext", GdbServerRegisterInfo::eI387Ext  }, // 80bit fpu<br>
+    { nullptr } // sentinel<br>
+};<br>
+<br>
+// find the first sibling with a matching name xmlNodePtr<br>
+xmlExFindSibling (xmlNodePtr node,<br>
+                  const std::string & name) {<br>
+<br>
+    if ( !node ) return nullptr;<br>
+    // iterate through all siblings<br>
+    for ( xmlNodePtr temp = node; temp; temp=temp->next ) {<br>
+        // we are looking for elements<br>
+        if ( temp->type != XML_ELEMENT_NODE )<br>
+            continue;<br>
+        // check element name matches<br>
+        if ( !temp->name ) continue;<br>
+        if ( std::strcmp((const char*)temp->name, name.c_str() ) == 0 )<br>
+            return temp;<br>
+    }<br>
+    // no sibling found<br>
+    return nullptr;<br>
+}<br>
+<br>
+// find an element from a given element path xmlNodePtr<br>
+xmlExFindElement (xmlNodePtr node,<br>
+                  const stringVec & path) {<br>
+<br>
+    if ( !node ) return nullptr;<br>
+    xmlNodePtr temp = node;<br>
+    // iterate all elements in path<br>
+    for ( uint32_t i = 0; i < path.size( ); i++ ) {<br>
+<br>
+        // search for a sibling with this name<br>
+        temp = xmlExFindSibling( temp, path[i] );<br>
+        if ( !temp )<br>
+            return nullptr;<br>
+        // enter this node if we still need to search<br>
+        if ( (i+1) < path.size() )<br>
+            // enter the node we have found<br>
+            temp = temp->children;<br>
+    }<br>
+    // note: node may still be nullptr at this step<br>
+    return temp;<br>
+}<br>
+<br>
+// locate a specific attribute in an element xmlAttr *<br>
+xmlExFindAttribute (xmlNodePtr node,<br>
+                    const std::string & name) {<br>
+<br>
+    if ( !node )<br>
+        return nullptr;<br>
+    if ( node->type != XML_ELEMENT_NODE )<br>
+        return nullptr;<br>
+    // iterate over all attributes<br>
+    for ( xmlAttrPtr attr = node->properties; attr != nullptr; attr=attr->next ) {<br>
+        // check if name matches<br>
+        if ( !attr->name ) continue;<br>
+        if ( std::strcmp( (const char*)attr->name, name.c_str( ) ) == 0 )<br>
+            return attr;<br>
+    }<br>
+    return nullptr;<br>
+}<br>
+<br>
+// find all child elements with given name and add them to a vector //<br>
+// input:   node = xml element to search<br>
+//          name = name used when matching child elements<br>
+// output:  out  = list of matches<br>
+// return:  number of children added to 'out'<br>
+int<br>
+xmlExFindChildren (xmlNodePtr node,<br>
+                   const std::string & name,<br>
+                   xmlNodePtrVec & out) {<br>
+<br>
+    if ( !node ) return 0;<br>
+    int count = 0;<br>
+    // iterate over all children<br>
+    for ( xmlNodePtr child = node->children; child; child = child->next ) {<br>
+        // if name matches<br>
+        if ( !child->name ) continue;<br>
+        if ( std::strcmp( (const char*)child->name, name.c_str( ) ) == 0 ) {<br>
+            // add to output list<br>
+            out.push_back( child );<br>
+            ++count;<br>
+        }<br>
+    }<br>
+    return count;<br>
+}<br>
+<br>
+// get the text content from an attribute std::string<br>
+xmlExGetTextContent (xmlAttrPtr attr) {<br>
+<br>
+    if ( !attr )<br>
+        return std::string( );<br>
+    if ( attr->type != XML_ATTRIBUTE_NODE )<br>
+        return std::string( );<br>
+    // check child is a text node<br>
+    xmlNodePtr child = attr->children;<br>
+    if ( child->type != XML_TEXT_NODE )<br>
+        return std::string( );<br>
+    // access the content<br>
+    assert( child->content != nullptr );<br>
+    return std::string( (const char*) child->content ); }<br>
+<br>
+// get the text content from an node<br>
+std::string<br>
+xmlExGetTextContent (xmlNodePtr node) {<br>
+<br>
+    if ( !node )<br>
+        return std::string( );<br>
+    if ( node->type != XML_ELEMENT_NODE )<br>
+        return std::string( );<br>
+    // check child is a text node<br>
+    xmlNodePtr child = node->children;<br>
+    if ( child->type != XML_TEXT_NODE )<br>
+        return std::string( );<br>
+    // access the content<br>
+    assert( child->content != nullptr );<br>
+    return std::string( (const char*) child->content ); }<br>
+<br>
+// compile a list of xml includes from the target file<br>
+// input:   doc = target.xml<br>
+// output:  includes = list of .xml names specified in target.xml //<br>
+return:  number of .xml files specified in target.xml and added to<br>
+includes int parseTargetIncludes (xmlDocPtr doc, stringVec & includes)<br>
+{<br>
+<br>
+    if ( !doc ) return 0;<br>
+    int count = 0;<br>
+    xmlNodePtr elm = xmlExFindElement( doc->children, { "target" } );<br>
+    if (! elm ) return 0;<br>
+    xmlNodePtrVec nodes;<br>
+    xmlExFindChildren( elm, "xi:include", nodes );<br>
+    // iterate over all includes<br>
+    for ( uint32_t i = 0; i < nodes.size(); i++ ) {<br>
+        xmlAttrPtr attr = xmlExFindAttribute( nodes[i], "href" );<br>
+        if ( attr != nullptr ) {<br>
+            std::string text = xmlExGetTextContent( attr );<br>
+            includes.push_back( text );<br>
+            ++count;<br>
+        }<br>
+    }<br>
+    return count;<br>
+}<br>
+<br>
+// extract target arch information from the target.xml file<br>
+// input:   doc = target.xml document<br>
+// output:  out = remote target information // return:  'true'  on<br>
+success<br>
+//          'false' on failure<br>
+bool<br>
+parseTargetInfo (xmlDocPtr doc, GdbServerTargetInfo & out) {<br>
+<br>
+    if ( !doc ) return false;<br>
+    xmlNodePtr e1 = xmlExFindElement( doc->children, { "target", "architecture" } );<br>
+    if ( !e1 ) return false;<br>
+    out.m_arch = xmlExGetTextContent( e1 );<br>
+<br>
+    xmlNodePtr e2 = xmlExFindElement( doc->children, { "target", "osabi" } );<br>
+    if ( !e2 ) return false;<br>
+    out.m_osabi = xmlExGetTextContent( e2 );<br>
+<br>
+    return true;<br>
+}<br>
+<br>
+// extract register information from one of the xml files specified in target.xml<br>
+// input:   doc = xml document<br>
+// output:  regList = list of extracted register info // return:<br>
+'true'  on success<br>
+//          'false' on failure<br>
+bool<br>
+parseRegisters (xmlDocPtr doc, GDBServerRegisterVec & regList) {<br>
+<br>
+    if ( !doc ) return false;<br>
+    xmlNodePtr elm = xmlExFindElement( doc->children, { "feature" } );<br>
+    if ( !elm ) return false;<br>
+<br>
+    xmlAttrPtr attr = nullptr;<br>
+<br>
+    xmlNodePtrVec regs;<br>
+    xmlExFindChildren( elm, "reg", regs );<br>
+    for ( int i = 0; i < regs.size( ); i++ ) {<br>
+<br>
+        GdbServerRegisterInfo reg;<br>
+        reg.clear( );<br>
+<br>
+        if ( attr = xmlExFindAttribute( regs[i], "name" ) ) {<br>
+            reg.m_name = xmlExGetTextContent( attr ).c_str();<br>
+            reg.m_flags.m_has_name = true;<br>
+        }<br>
+<br>
+        if ( attr = xmlExFindAttribute( regs[i], "bitsize" ) ) {<br>
+            const std::string v = xmlExGetTextContent( attr );<br>
+            reg.m_bitSize = atoi( v.c_str( ) );<br>
+            reg.m_flags.m_has_bitSize = true;<br>
+        }<br>
+<br>
+        if ( attr = xmlExFindAttribute( regs[i], "type" ) ) {<br>
+            const std::string v = xmlExGetTextContent( attr );<br>
+            reg.m_type = GdbServerRegisterInfo::eUnknown;<br>
+<br>
+            // search the type table for a match<br>
+            for ( int j = 0; RegTypeTable[j].m_name !=nullptr ;++j ) {<br>
+                if (RegTypeTable[j].m_name == v) {<br>
+                    reg.m_type = RegTypeTable[j].m_type;<br>
+                    break;<br>
+                }<br>
+            }<br>
+<br>
+            reg.m_flags.m_has_type = (reg.m_type != GdbServerRegisterInfo::eUnknown);<br>
+        }<br>
+<br>
+        if ( attr = xmlExFindAttribute( regs[i], "group" ) ) {<br>
+            reg.m_group = xmlExGetTextContent( attr );<br>
+            reg.m_flags.m_has_group = true;<br>
+        }<br>
+<br>
+        if ( attr = xmlExFindAttribute( regs[i], "regnum" ) ) {<br>
+            const std::string v = xmlExGetTextContent( attr );<br>
+            reg.m_regNum = atoi( v.c_str( ) );<br>
+            reg.m_flags.m_has_regNum = true;<br>
+        }<br>
+<br>
+        regList.push_back( reg );<br>
+    }<br>
+<br>
+    //TODO: there is also a "vector" element to parse<br>
+    //TODO: there is also eflags to parse<br>
+<br>
+    return true;<br>
+}<br>
+<br>
+// build lldb gdb-remote's dynamic register info from a vector of gdb provided registers<br>
+// input:   regList = register information provided by gdbserver<br>
+// output:  regInfo = dynamic register information required by<br>
+gdb-remote void BuildRegisters (const GDBServerRegisterVec & regList,<br>
+                GDBRemoteDynamicRegisterInfo & regInfo) {<br>
+<br>
+    using namespace lldb_private;<br>
+<br>
+    const uint32_t defSize    = 32;<br>
+          uint32_t regNum     = 0;<br>
+          uint32_t byteOffset = 0;<br>
+<br>
+    for ( uint32_t i = 0; i < regList.size( ); ++i ) {<br>
+<br>
+        const GdbServerRegisterInfo & gdbReg = regList[i];<br>
+<br>
+        std::string name     = gdbReg.m_flags.m_has_name    ? gdbReg.m_name        : "unknown";<br>
+        std::string group    = gdbReg.m_flags.m_has_group   ? gdbReg.m_group       : "general";<br>
+        uint32_t    byteSize = gdbReg.m_flags.m_has_bitSize ? (gdbReg.m_bitSize/8) : defSize;<br>
+<br>
+        if ( gdbReg.m_flags.m_has_regNum )<br>
+            regNum = gdbReg.m_regNum;<br>
+<br>
+        uint32_t regNumGcc     = LLDB_INVALID_REGNUM;<br>
+        uint32_t regNumDwarf   = LLDB_INVALID_REGNUM;<br>
+        uint32_t regNumGeneric = LLDB_INVALID_REGNUM;<br>
+        uint32_t regNumGdb     = regNum;<br>
+        uint32_t regNumNative  = regNum;<br>
+<br>
+        if ( name == "eip" || name == "pc" ) {<br>
+            regNumGeneric = LLDB_REGNUM_GENERIC_PC;<br>
+        }<br>
+        if ( name == "esp" || name == "sp" ) {<br>
+            regNumGeneric = LLDB_REGNUM_GENERIC_SP;<br>
+        }<br>
+        if ( name == "ebp") {<br>
+            regNumGeneric = LLDB_REGNUM_GENERIC_FP;<br>
+        }<br>
+        if ( name == "lr" ) {<br>
+            regNumGeneric = LLDB_REGNUM_GENERIC_RA;<br>
+        }<br>
+<br>
+        RegisterInfo info = {<br>
+            name.c_str(),<br>
+            nullptr     ,<br>
+            byteSize    ,<br>
+            byteOffset  ,<br>
+            lldb::Encoding::eEncodingUint,<br>
+            lldb::Format::eFormatDefault,<br>
+            { regNumGcc    ,<br>
+              regNumDwarf  ,<br>
+              regNumGeneric,<br>
+              regNumGdb    ,<br>
+              regNumNative },<br>
+            nullptr,<br>
+            nullptr<br>
+        };<br>
+<br>
+        ConstString regName    = ConstString( gdbReg.m_name );<br>
+        ConstString regAltName = ConstString( );<br>
+        ConstString regGroup   = ConstString( group );<br>
+        regInfo.AddRegister( info, regName, regAltName, regGroup );<br>
+<br>
+        // advance register info<br>
+        byteOffset += byteSize;<br>
+        regNum     += 1;<br>
+    }<br>
+<br>
+    regInfo.Finalize ();<br>
+}<br>
+<br>
+} // namespace {}<br>
+<br>
+void XMLCDECL<br>
+libxml2NullErrorFunc (void *ctx, const char *msg, ...) {<br>
+    // do nothing currently<br>
+}<br>
+<br>
+// query the target of gdb-remote for extended target information //<br>
+return:  'true'  on success<br>
+//          'false' on failure<br>
+bool<br>
+ProcessGDBRemote::GetGDBServerInfo ()<br>
+{<br>
+<br>
+    // redirect libxml2's error handler since the default prints to stdout<br>
+    xmlGenericErrorFunc func = libxml2NullErrorFunc;<br>
+    initGenericErrorDefaultFunc( &func );<br>
+<br>
+    GDBRemoteCommunicationClient & comm = m_gdb_comm;<br>
+    GDBRemoteDynamicRegisterInfo & regInfo = m_register_info;<br>
+<br>
+    // check that we have extended feature read support<br>
+    if ( !comm.GetQXferFeaturesReadSupported( ) )<br>
+        return false;<br>
+<br>
+    // request the target xml file<br>
+    std::string raw;<br>
+    lldb_private::Error lldberr;<br>
+    if (! comm.ReadExtFeature( ConstString( "features" ),<br>
+                               ConstString( "target.xml" ),<br>
+                               raw,<br>
+                               lldberr ) ) {<br>
+        return false;<br>
+    }<br>
+<br>
+    // parse the xml file in memory<br>
+    xmlDocPtr doc = xmlReadMemory( raw.c_str( ), raw.size( ), "noname.xml", nullptr, 0 );<br>
+    if ( doc == nullptr )<br>
+        return false;<br>
+<br>
+    // extract target info from target.xml<br>
+    GdbServerTargetInfo gdbInfo;<br>
+    if ( parseTargetInfo( doc, gdbInfo ) ) {<br>
+        // NOTE: We could deduce triple from gdbInfo if lldb doesn't already have one set<br>
+    }<br>
+<br>
+    // collect registers from all of the includes<br>
+    GDBServerRegisterVec regList;<br>
+    stringVec includes;<br>
+    if ( parseTargetIncludes( doc, includes ) > 0 ) {<br>
+<br>
+        for ( uint32_t i = 0; i < includes.size( ); ++i ) {<br>
+<br>
+            // request register file<br>
+            if ( !comm.ReadExtFeature( ConstString( "features" ),<br>
+                                       ConstString( includes[i] ),<br>
+                                       raw,<br>
+                                       lldberr ) )<br>
+                continue;<br>
+<br>
+            // parse register file<br>
+            xmlDocPtr regXml = xmlReadMemory( raw.c_str(),<br>
+                                              raw.size( ),<br>
+                                              includes[i].c_str(),<br>
+                                              nullptr,<br>
+                                              0 );<br>
+            if ( !regXml )<br>
+                continue;<br>
+<br>
+            // pass registers to lldb<br>
+            parseRegisters( regXml, regList );<br>
+        }<br>
+    }<br>
+<br>
+    // pass all of these registers to lldb<br>
+    BuildRegisters( regList, regInfo );<br>
+<br>
+    return true;<br>
+}<br>
+<br>
+#else // if defined( LIBXML2_DEFINED )<br>
+<br>
+using namespace lldb_private::process_gdb_remote;<br>
+<br>
+bool<br>
+ProcessGDBRemote::GetGDBServerInfo ()<br>
+{<br>
+    // stub (libxml2 not present)<br>
+    return false;<br>
+}<br>
+<br>
+#endif // if defined( LIBXML2_DEFINED )<br>
+<br>
+<br>
 class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed  {<br>
 private:<br>
<br>
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=235109&r1=235108&r2=235109&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=235109&r1=235108&r2=235109&view=diff</a><br>
==============================================================================<br>
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)<br>
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Thu<br>
+++ Apr 16 10:51:33 2015<br>
@@ -241,6 +241,10 @@ public:<br>
                   const ArchSpec& arch,<br>
                   ModuleSpec &module_spec) override;<br>
<br>
+    // query remote gdbserver for information<br>
+    bool<br>
+    GetGDBServerInfo ( );<br>
+<br>
 protected:<br>
     friend class ThreadGDBRemote;<br>
     friend class GDBRemoteCommunicationClient;<br>
<br>
<br>
_______________________________________________<br>
lldb-commits mailing list<br>
<a href="mailto:lldb-commits@cs.uiuc.edu">lldb-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits</a><br>
<br>
_______________________________________________<br>
lldb-commits mailing list<br>
<a href="mailto:lldb-commits@cs.uiuc.edu">lldb-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits</a><br>
</blockquote></div>