diff options
author | Greg Clayton <gclayton@apple.com> | 2015-05-26 18:00:51 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2015-05-26 18:00:51 +0000 |
commit | d04f0edad9afe46f18b86de9199884ea1dceb220 (patch) | |
tree | b0fc46f21a8b89ad468b8fae3c98e81f29e182c3 /lldb | |
parent | bfecc06656d0f9fcdf22270b6c0aa15441d8d198 (diff) | |
download | bcm5719-llvm-d04f0edad9afe46f18b86de9199884ea1dceb220.tar.gz bcm5719-llvm-d04f0edad9afe46f18b86de9199884ea1dceb220.zip |
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
Diffstat (limited to 'lldb')
17 files changed, 1713 insertions, 718 deletions
diff --git a/lldb/include/lldb/Host/XML.h b/lldb/include/lldb/Host/XML.h new file mode 100644 index 00000000000..d0e2ea3c84c --- /dev/null +++ b/lldb/include/lldb/Host/XML.h @@ -0,0 +1,216 @@ +//===-- XML.h ---------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_XML_h_ +#define liblldb_XML_h_ + +// C Includes + +#if defined( LIBXML2_DEFINED ) +#include <libxml/xmlreader.h> +#endif + +// C++ Includes + +#include <functional> +#include <string> +#include <vector> + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "llvm/ADT/StringRef.h" +#include "lldb/Core/StreamString.h" + + +namespace lldb_private { + +#if defined( LIBXML2_DEFINED ) + typedef xmlNodePtr XMLNodeImpl; + typedef xmlDocPtr XMLDocumentImpl; +#else + typedef void * XMLNodeImpl; + typedef void * XMLDocumentImpl; +#endif + + class XMLNode; + + typedef std::vector<std::string> NamePath; + typedef std::function <bool(const XMLNode &node)> NodeCallback; + typedef std::function <bool(const llvm::StringRef &name, const llvm::StringRef &value)> AttributeCallback; + + class XMLNode + { + public: + XMLNode(); + + XMLNode(XMLNodeImpl node); + + ~XMLNode(); + + explicit operator bool() const + { + return IsValid(); + } + + void + Clear(); + + bool + IsValid() const; + + bool + IsElement () const; + + llvm::StringRef + GetName() const; + + bool + GetElementText (std::string &text) const; + + bool + NameIs (const char *name) const; + + XMLNode + GetParent() const; + + XMLNode + GetSibling() const; + + XMLNode + GetChild () const; + + llvm::StringRef + GetAttributeValue(const char *name, const char *fail_value = NULL) const; + + XMLNode + FindFirstChildElementWithName (const char *name) const; + + XMLNode + GetElementForPath (const NamePath &path); + + //---------------------------------------------------------------------- + // Iterate through all sibling nodes of any type + //---------------------------------------------------------------------- + void + ForEachSiblingNode (NodeCallback const &callback) const; + + //---------------------------------------------------------------------- + // Iterate through only the sibling nodes that are elements + //---------------------------------------------------------------------- + void + ForEachSiblingElement (NodeCallback const &callback) const; + + //---------------------------------------------------------------------- + // Iterate through only the sibling nodes that are elements and whose + // name matches \a name. + //---------------------------------------------------------------------- + void + ForEachSiblingElementWithName (const char *name, NodeCallback const &callback) const; + + void + ForEachChildNode (NodeCallback const &callback) const; + + void + ForEachChildElement (NodeCallback const &callback) const; + + void + ForEachChildElementWithName (const char *name, NodeCallback const &callback) const; + + void + ForEachAttribute (AttributeCallback const &callback) const; + + protected: + XMLNodeImpl m_node; + }; + + class XMLDocument + { + public: + + XMLDocument (); + + ~XMLDocument (); + + explicit operator bool() const + { + return IsValid(); + } + + bool + IsValid() const; + + void + Clear(); + + bool + ParseFile (const char *path); + + bool + ParseMemory (const char *xml, size_t xml_length, const char *url = "untitled.xml"); + + //---------------------------------------------------------------------- + // If \a name is NULL, just get the root element node, else only return + // a value XMLNode if the name of the root element matches \a name. + //---------------------------------------------------------------------- + XMLNode + GetRootElement(const char *required_name = nullptr); + + static void + ErrorCallback (void *ctx, const char *format, ...); + + static bool + XMLEnabled (); + + protected: + XMLDocumentImpl m_document; + StreamString m_errors; + }; + + class ApplePropertyList + { + public: + ApplePropertyList(); + + ApplePropertyList(const char *path); + + bool + ParseFile (const char *path); + + explicit operator bool() const + { + return IsValid(); + } + + bool + IsValid() const; + + XMLNode + GetValueNode (const char *key) const; + + bool + GetValueAsString (const char *key, std::string &value) const; + + protected: + + // Using a node returned from GetValueNode() extract its value as a + // string (if possible). Array and dictionary nodes will return false + // as they have no string value. Boolean nodes will return true and + // \a value will be "true" or "false" as the string value comes from + // the element name itself. All other nodes will return the text + // content of the XMLNode. + static bool + ExtractStringFromValueNode (const XMLNode &node, std::string &value); + + XMLDocument m_xml_doc; + XMLNode m_dict_node; + }; +} // namespace lldb_private + +#endif // liblldb_XML_h_ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 9c37e1798e6..8f13355fd06 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -71,15 +71,10 @@ 23059A101958B319007B8189 /* SBUnixSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0F1958B319007B8189 /* SBUnixSignals.cpp */; }; 23059A121958B3B2007B8189 /* SBUnixSignals.h in Headers */ = {isa = PBXBuildFile; fileRef = 23059A111958B37B007B8189 /* SBUnixSignals.h */; settings = {ATTRIBUTES = (Public, ); }; }; 232CB615191E00CD00EF39FC /* NativeBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */; }; - 232CB616191E00CD00EF39FC /* NativeBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */; }; 232CB617191E00CD00EF39FC /* NativeBreakpointList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */; }; - 232CB618191E00CD00EF39FC /* NativeBreakpointList.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */; }; 232CB619191E00CD00EF39FC /* NativeProcessProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */; }; - 232CB61A191E00CD00EF39FC /* NativeProcessProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */; }; 232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */; }; - 232CB61C191E00CD00EF39FC /* NativeThreadProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */; }; 232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */; }; - 232CB61E191E00CD00EF39FC /* SoftwareBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */; }; 233B007D1960C9F90090E598 /* ProcessInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B007B1960C9E60090E598 /* ProcessInfo.cpp */; }; 233B007F1960CB280090E598 /* ProcessLaunchInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B007E1960CB280090E598 /* ProcessLaunchInfo.cpp */; }; 236124A41986B4E2004EFC37 /* IOObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 236124A21986B4E2004EFC37 /* IOObject.cpp */; }; @@ -336,6 +331,10 @@ 26744EF11338317700EF765A /* GDBRemoteCommunicationClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */; }; 26744EF31338317700EF765A /* GDBRemoteCommunicationServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EEF1338317700EF765A /* GDBRemoteCommunicationServer.cpp */; }; 26780C611867C33D00234593 /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2670F8111862B44A006B332C /* libncurses.dylib */; }; + 267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267A47FA1B1411C40021A5BC /* NativeRegisterContext.cpp */; }; + 267A47FD1B1411CC0021A5BC /* NativeRegisterContextRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267A47FC1B1411CC0021A5BC /* NativeRegisterContextRegisterInfo.cpp */; }; + 267A47FF1B1411D90021A5BC /* NativeWatchpointList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267A47FE1B1411D90021A5BC /* NativeWatchpointList.cpp */; }; + 267A48011B1411E40021A5BC /* XML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267A48001B1411E40021A5BC /* XML.cpp */; }; 267C012B136880DF006E963E /* OptionGroupValueObjectDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267C012A136880DF006E963E /* OptionGroupValueObjectDisplay.cpp */; }; 267C01371368C49C006E963E /* OptionGroupOutputFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BCFC531368B3E4006DC050 /* OptionGroupOutputFile.cpp */; }; 267DFB461B06752A00000FB7 /* MICmdArgValPrintValues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267DFB441B06752A00000FB7 /* MICmdArgValPrintValues.cpp */; }; @@ -1196,15 +1195,10 @@ 23059A111958B37B007B8189 /* SBUnixSignals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBUnixSignals.h; path = include/lldb/API/SBUnixSignals.h; sourceTree = "<group>"; }; 23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-x86-register-enums.h"; path = "Utility/lldb-x86-register-enums.h"; sourceTree = "<group>"; }; 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeBreakpoint.cpp; path = source/Host/common/NativeBreakpoint.cpp; sourceTree = "<group>"; }; - 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeBreakpoint.h; path = source/Host/common/NativeBreakpoint.h; sourceTree = "<group>"; }; 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeBreakpointList.cpp; path = source/Host/common/NativeBreakpointList.cpp; sourceTree = "<group>"; }; - 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeBreakpointList.h; path = source/Host/common/NativeBreakpointList.h; sourceTree = "<group>"; }; 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = NativeProcessProtocol.cpp; path = source/Host/common/NativeProcessProtocol.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeProcessProtocol.h; path = source/Host/common/NativeProcessProtocol.h; sourceTree = "<group>"; }; 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeThreadProtocol.cpp; path = source/Host/common/NativeThreadProtocol.cpp; sourceTree = "<group>"; }; - 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeThreadProtocol.h; path = source/Host/common/NativeThreadProtocol.h; sourceTree = "<group>"; }; 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SoftwareBreakpoint.cpp; path = source/Host/common/SoftwareBreakpoint.cpp; sourceTree = "<group>"; }; - 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SoftwareBreakpoint.h; path = source/Host/common/SoftwareBreakpoint.h; sourceTree = "<group>"; }; 232CB62B19213AC200EF39FC /* NativeProcessLinux.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeProcessLinux.cpp; sourceTree = "<group>"; }; 232CB62C19213AC200EF39FC /* NativeProcessLinux.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = NativeProcessLinux.h; sourceTree = "<group>"; }; 232CB62D19213AC200EF39FC /* NativeThreadLinux.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeThreadLinux.cpp; sourceTree = "<group>"; }; @@ -1737,6 +1731,19 @@ 2675F6FF1332BE690067997B /* PlatformRemoteiOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRemoteiOS.h; sourceTree = "<group>"; }; 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractorGDBRemote.cpp; path = source/Utility/StringExtractorGDBRemote.cpp; sourceTree = "<group>"; }; 2676A094119C93C8008A98EF /* StringExtractorGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringExtractorGDBRemote.h; path = source/Utility/StringExtractorGDBRemote.h; sourceTree = "<group>"; }; + 267A47F21B14115A0021A5BC /* SoftwareBreakpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SoftwareBreakpoint.h; path = include/lldb/Host/common/SoftwareBreakpoint.h; sourceTree = "<group>"; }; + 267A47F31B14116E0021A5BC /* NativeBreakpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeBreakpoint.h; path = include/lldb/Host/common/NativeBreakpoint.h; sourceTree = "<group>"; }; + 267A47F41B1411750021A5BC /* NativeBreakpointList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeBreakpointList.h; path = include/lldb/Host/common/NativeBreakpointList.h; sourceTree = "<group>"; }; + 267A47F51B14117F0021A5BC /* NativeProcessProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeProcessProtocol.h; path = include/lldb/Host/common/NativeProcessProtocol.h; sourceTree = "<group>"; }; + 267A47F61B14118F0021A5BC /* NativeRegisterContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContext.h; path = include/lldb/Host/common/NativeRegisterContext.h; sourceTree = "<group>"; }; + 267A47F71B14119A0021A5BC /* NativeRegisterContextRegisterInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContextRegisterInfo.h; path = include/lldb/Host/common/NativeRegisterContextRegisterInfo.h; sourceTree = "<group>"; }; + 267A47F81B1411A40021A5BC /* NativeThreadProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeThreadProtocol.h; path = include/lldb/Host/common/NativeThreadProtocol.h; sourceTree = "<group>"; }; + 267A47F91B1411AC0021A5BC /* NativeWatchpointList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NativeWatchpointList.h; path = include/lldb/Host/common/NativeWatchpointList.h; sourceTree = "<group>"; }; + 267A47FA1B1411C40021A5BC /* NativeRegisterContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContext.cpp; path = source/Host/common/NativeRegisterContext.cpp; sourceTree = "<group>"; }; + 267A47FC1B1411CC0021A5BC /* NativeRegisterContextRegisterInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContextRegisterInfo.cpp; path = source/Host/common/NativeRegisterContextRegisterInfo.cpp; sourceTree = "<group>"; }; + 267A47FE1B1411D90021A5BC /* NativeWatchpointList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeWatchpointList.cpp; path = source/Host/common/NativeWatchpointList.cpp; sourceTree = "<group>"; }; + 267A48001B1411E40021A5BC /* XML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = XML.cpp; path = source/Host/common/XML.cpp; sourceTree = "<group>"; }; + 267A48031B1416080021A5BC /* XML.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = XML.h; path = include/lldb/Host/XML.h; sourceTree = "<group>"; }; 267C0128136880C7006E963E /* OptionGroupValueObjectDisplay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OptionGroupValueObjectDisplay.h; path = include/lldb/Interpreter/OptionGroupValueObjectDisplay.h; sourceTree = "<group>"; }; 267C012A136880DF006E963E /* OptionGroupValueObjectDisplay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionGroupValueObjectDisplay.cpp; path = source/Interpreter/OptionGroupValueObjectDisplay.cpp; sourceTree = "<group>"; }; 267DFB441B06752A00000FB7 /* MICmdArgValPrintValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MICmdArgValPrintValues.cpp; path = "tools/lldb-mi/MICmdArgValPrintValues.cpp"; sourceTree = SOURCE_ROOT; }; @@ -4418,14 +4425,20 @@ 3FDFE57519AFABFD009756A7 /* HostThread.h */, 236124A61986B50E004EFC37 /* IOObject.h */, 26BC7DD510F1B7D500F91463 /* Mutex.h */, + 267A47F31B14116E0021A5BC /* NativeBreakpoint.h */, 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */, - 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */, + 267A47F41B1411750021A5BC /* NativeBreakpointList.h */, 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */, - 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */, + 267A47F51B14117F0021A5BC /* NativeProcessProtocol.h */, 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */, - 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */, + 267A47F61B14118F0021A5BC /* NativeRegisterContext.h */, + 267A47FA1B1411C40021A5BC /* NativeRegisterContext.cpp */, + 267A47F71B14119A0021A5BC /* NativeRegisterContextRegisterInfo.h */, + 267A47FC1B1411CC0021A5BC /* NativeRegisterContextRegisterInfo.cpp */, + 267A47F81B1411A40021A5BC /* NativeThreadProtocol.h */, 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */, - 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */, + 267A47F91B1411AC0021A5BC /* NativeWatchpointList.h */, + 267A47FE1B1411D90021A5BC /* NativeWatchpointList.cpp */, A36FF33D17D8E98800244D40 /* OptionParser.h */, 260A39A519647A3A004B4130 /* Pipe.h */, 3F5E8AF31A40D4A500A73232 /* PipeBase.h */, @@ -4434,14 +4447,16 @@ 236124A71986B50E004EFC37 /* Socket.h */, 26D7E45B13D5E2F9007FD12B /* SocketAddress.h */, 26D7E45C13D5E30A007FD12B /* SocketAddress.cpp */, + 267A47F21B14115A0021A5BC /* SoftwareBreakpoint.h */, 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */, - 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */, 2689B0A4113EE3CD00A4AEDB /* Symbols.h */, 268DA871130095D000C9483A /* Terminal.h */, 3FDFED0D19B7D269009756A7 /* ThisThread.cpp */, 3FDFED0919B7C8C7009756A7 /* ThisThread.h */, 3FDFED2319BA6D55009756A7 /* ThreadLauncher.h */, 26B4E26E112F35F700AB3F64 /* TimeValue.h */, + 267A48031B1416080021A5BC /* XML.h */, + 267A48001B1411E40021A5BC /* XML.cpp */, ); name = Host; sourceTree = "<group>"; @@ -5435,7 +5450,6 @@ AF1F7B08189C904B0087DB9C /* AppleGetPendingItemsHandler.h in Headers */, AF77E0AA1A033D740096C0EA /* RegisterContextPOSIXCore_powerpc.h in Headers */, AF2BCA6D18C7EFDE005B4526 /* JITLoaderGDB.h in Headers */, - 232CB61E191E00CD00EF39FC /* SoftwareBreakpoint.h in Headers */, B5EFAE871AE53B1D007059F3 /* RegisterContextFreeBSD_arm.h in Headers */, 26BC17B218C7F4CB00D2196D /* ThreadElfCore.h in Headers */, AF77E0A51A033D360096C0EA /* RegisterContextPOSIX_powerpc.h in Headers */, @@ -5461,7 +5475,6 @@ 260CC63115D04377002BF2E0 /* OptionValueProperties.h in Headers */, 260CC63215D04377002BF2E0 /* OptionValueDictionary.h in Headers */, 262173A118395D3800C52091 /* SectionLoadHistory.h in Headers */, - 232CB61A191E00CD00EF39FC /* NativeProcessProtocol.h in Headers */, 260CC63315D04377002BF2E0 /* OptionValueEnumeration.h in Headers */, AF45FDE618A1F3AC0007051C /* AppleGetThreadItemInfoHandler.h in Headers */, 260A63171861008E00FECF8E /* IOHandler.h in Headers */, @@ -5515,10 +5528,7 @@ 49724D9A1AD6ED390033C538 /* RenderScriptRuntime.h in Headers */, 4C73152219B7D71700F865A4 /* Iterable.h in Headers */, 2698699D15E6CBD0002415FF /* OperatingSystemPython.h in Headers */, - 232CB618191E00CD00EF39FC /* NativeBreakpointList.h in Headers */, 260D9B2715EC369500960137 /* ModuleSpec.h in Headers */, - 232CB61C191E00CD00EF39FC /* NativeThreadProtocol.h in Headers */, - 232CB616191E00CD00EF39FC /* NativeBreakpoint.h in Headers */, 947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */, 262ED0051631FA2800879631 /* OptionGroupString.h in Headers */, 26474CA918D0CB070073DEBA /* RegisterContextFreeBSD_i386.h in Headers */, @@ -6029,6 +6039,7 @@ 2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */, 26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */, 2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */, + 267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */, 2689FFF113353DB600698AC0 /* BreakpointID.cpp in Sources */, AF77E0A91A033D740096C0EA /* RegisterContextPOSIXCore_powerpc.cpp in Sources */, 2689FFF313353DB600698AC0 /* BreakpointIDList.cpp in Sources */, @@ -6088,6 +6099,7 @@ 2689002413353DDE00698AC0 /* CommandObjectSettings.cpp in Sources */, 2689002513353DDE00698AC0 /* CommandObjectSource.cpp in Sources */, 2689002613353DDE00698AC0 /* CommandObjectSyntax.cpp in Sources */, + 267A48011B1411E40021A5BC /* XML.cpp in Sources */, 3F8169331ABB7A6D001DA9DF /* SystemLifetimeManager.cpp in Sources */, 4959511F1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp in Sources */, 26BC179918C7F2B300D2196D /* JITLoader.cpp in Sources */, @@ -6256,6 +6268,7 @@ 3FDFE56C19AF9C44009756A7 /* HostProcessPosix.cpp in Sources */, 268900B413353E5000698AC0 /* RegisterContextMacOSXFrameBackchain.cpp in Sources */, 3F8169311ABB7A6D001DA9DF /* SystemInitializer.cpp in Sources */, + 267A47FD1B1411CC0021A5BC /* NativeRegisterContextRegisterInfo.cpp in Sources */, 3FDFED2D19C257A0009756A7 /* HostProcess.cpp in Sources */, 268900B513353E5000698AC0 /* StopInfoMachException.cpp in Sources */, 268900B613353E5000698AC0 /* UnwindMacOSXFrameBackchain.cpp in Sources */, @@ -6467,6 +6480,7 @@ 26D7E45D13D5E30A007FD12B /* SocketAddress.cpp in Sources */, 94CD7D0C19A3FBCE00908B7C /* AppleObjCTypeEncodingParser.cpp in Sources */, 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */, + 267A47FF1B1411D90021A5BC /* NativeWatchpointList.cpp in Sources */, 26F4A21C13FBA31A0064B613 /* ThreadMemory.cpp in Sources */, 94EA27CE17DE91750070F505 /* LibCxxUnorderedMap.cpp in Sources */, 266DFE9713FD656E00D0C574 /* OperatingSystem.cpp in Sources */, diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index a13defa46c5..0a005af18d7 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -37,6 +37,7 @@ add_host_subdirectory(common common/ThisThread.cpp common/ThreadLauncher.cpp common/TimeValue.cpp + common/XML.cpp ) if (NOT LLDB_DISABLE_LIBEDIT) diff --git a/lldb/source/Host/common/XML.cpp b/lldb/source/Host/common/XML.cpp new file mode 100644 index 00000000000..6e84428fc6b --- /dev/null +++ b/lldb/source/Host/common/XML.cpp @@ -0,0 +1,548 @@ +//===-- XML.cpp -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/XML.h" + +using namespace lldb; +using namespace lldb_private; + + +#pragma mark -- XMLDocument + +XMLDocument::XMLDocument () : + m_document (nullptr) +{ +} + +XMLDocument::~XMLDocument () +{ + Clear(); +} + +void +XMLDocument::Clear() +{ +#if defined( LIBXML2_DEFINED ) + if (m_document) + { + xmlDocPtr doc = m_document; + m_document = nullptr; + xmlFreeDoc(doc); + } +#endif +} + +bool +XMLDocument::IsValid() const +{ + return m_document != nullptr; +} + +void +XMLDocument::ErrorCallback (void *ctx, const char *format, ...) +{ + XMLDocument *document = (XMLDocument *)ctx; + va_list args; + va_start (args, format); + document->m_errors.PrintfVarArg(format, args); + document->m_errors.EOL(); + va_end (args); +} + +bool +XMLDocument::ParseFile (const char *path) +{ +#if defined( LIBXML2_DEFINED ) + Clear(); + xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback ); + m_document = xmlParseFile(path); + xmlSetGenericErrorFunc(nullptr, nullptr); +#endif + return IsValid(); +} + +bool +XMLDocument::ParseMemory (const char *xml, size_t xml_length, const char *url) +{ +#if defined( LIBXML2_DEFINED ) + Clear(); + xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback ); + m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0); + xmlSetGenericErrorFunc(nullptr, nullptr); +#endif + return IsValid(); + +} + +XMLNode +XMLDocument::GetRootElement(const char *required_name) +{ +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + { + XMLNode root_node(xmlDocGetRootElement(m_document)); + if (required_name) + { + llvm::StringRef actual_name = root_node.GetName(); + if (actual_name == required_name) + return root_node; + } + else + { + return root_node; + } + } +#endif + return XMLNode(); +} + +bool +XMLDocument::XMLEnabled () +{ +#if defined( LIBXML2_DEFINED ) + return true; +#else + return false; +#endif +} + +#pragma mark -- XMLNode + +XMLNode::XMLNode() : + m_node(nullptr) +{ +} + +XMLNode::XMLNode(XMLNodeImpl node) : + m_node(node) +{ +} + +XMLNode::~XMLNode() +{ + +} + +void +XMLNode::Clear() +{ + m_node = nullptr; +} + +XMLNode +XMLNode::GetParent() const +{ +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + return XMLNode(m_node->parent); + else + return XMLNode(); +#else + return XMLNode(); +#endif + +} + +XMLNode +XMLNode::GetSibling() const +{ +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + return XMLNode(m_node->next); + else + return XMLNode(); +#else + return XMLNode(); +#endif + +} + +XMLNode +XMLNode::GetChild () const +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + return XMLNode(m_node->children); + else + return XMLNode(); +#else + return XMLNode(); +#endif + +} + +llvm::StringRef +XMLNode::GetAttributeValue(const char *name, const char *fail_value) const +{ + const char *attr_value = NULL; +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name); + else + attr_value = fail_value; +#else + attr_value = fail_value; +#endif + if (attr_value) + return llvm::StringRef(attr_value); + else + return llvm::StringRef(); +} + + + + +void +XMLNode::ForEachChildNode (NodeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + GetChild().ForEachSiblingNode(callback); +#endif +} + +void +XMLNode::ForEachChildElement (NodeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + XMLNode child = GetChild(); + if (child) + child.ForEachSiblingElement(callback); +#endif +} + +void +XMLNode::ForEachChildElementWithName (const char *name, NodeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + XMLNode child = GetChild(); + if (child) + child.ForEachSiblingElementWithName(name, callback); +#endif +} + +void +XMLNode::ForEachAttribute (AttributeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + for (xmlAttrPtr attr = m_node->properties; attr != nullptr; attr=attr->next) + { + // check if name matches + if (attr->name) + { + // check child is a text node + xmlNodePtr child = attr->children; + if (child->type == XML_TEXT_NODE) + { + llvm::StringRef attr_value; + if (child->content) + attr_value = llvm::StringRef((const char *)child->content); + if (callback(llvm::StringRef((const char *)attr->name), attr_value) == false) + return; + } + } + } + } +#endif +} + + +void +XMLNode::ForEachSiblingNode (NodeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + // iterate through all siblings + for (xmlNodePtr node = m_node; node; node=node->next) + { + if (callback(XMLNode(node)) == false) + return; + } + } +#endif +} + +void +XMLNode::ForEachSiblingElement (NodeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + // iterate through all siblings + for (xmlNodePtr node = m_node; node; node=node->next) + { + // we are looking for element nodes only + if (node->type != XML_ELEMENT_NODE) + continue; + + if (callback(XMLNode(node)) == false) + return; + } + } +#endif +} + +void +XMLNode::ForEachSiblingElementWithName (const char *name, NodeCallback const &callback) const +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + // iterate through all siblings + for (xmlNodePtr node = m_node; node; node=node->next) + { + // we are looking for element nodes only + if (node->type != XML_ELEMENT_NODE) + continue; + + // If name is nullptr, we take all nodes of type "t", else + // just the ones whose name matches + if (name) + { + if (strcmp((const char *)node->name, name) != 0) + continue; // Name mismatch, ignore this one + } + else + { + if (node->name) + continue; // nullptr name specified and this elemnt has a name, ignore this one + } + + if (callback(XMLNode(node)) == false) + return; + } + } +#endif +} + +llvm::StringRef +XMLNode::GetName() const +{ +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + { + if (m_node->name) + return llvm::StringRef((const char *)m_node->name); + } +#endif + return llvm::StringRef(); +} + +bool +XMLNode::GetElementText (std::string &text) const +{ + text.clear(); +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + { + bool success = false; + if (m_node->type == XML_ELEMENT_NODE) + { + // check child is a text node + for (xmlNodePtr node = m_node->children; + node != nullptr; + node = node->next) + { + if (node->type == XML_TEXT_NODE) + { + text.append((const char *)node->content); + success = true; + } + } + } + return success; + } +#endif + return false; +} + + + +bool +XMLNode::NameIs (const char *name) const +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + // In case we are looking for a nullptr name or an exact pointer match + if (m_node->name == (const xmlChar *)name) + return true; + if (m_node->name) + return strcmp((const char *)m_node->name, name) == 0; + } +#endif + return false; +} + +XMLNode +XMLNode::FindFirstChildElementWithName (const char *name) const +{ + XMLNode result_node; + +#if defined( LIBXML2_DEFINED ) + ForEachChildElementWithName(name, [&result_node, name](const XMLNode& node) -> bool { + result_node = node; + // Stop iterating, we found the node we wanted + return false; + }); +#endif + + return result_node; +} + +bool +XMLNode::IsValid() const +{ + return m_node != nullptr; +} + +bool +XMLNode::IsElement () const +{ +#if defined( LIBXML2_DEFINED ) + if (IsValid()) + return m_node->type == XML_ELEMENT_NODE; +#endif + return false; +} + + +XMLNode +XMLNode::GetElementForPath (const NamePath &path) +{ +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + if (path.empty()) + return *this; + else + { + XMLNode node = FindFirstChildElementWithName(path[0].c_str()); + const size_t n = path.size(); + for (size_t i=1; node && i<n; ++i) + node = node.FindFirstChildElementWithName(path[i].c_str()); + return node; + } + } +#endif + + return XMLNode(); +} + + +#pragma mark -- ApplePropertyList + +ApplePropertyList::ApplePropertyList() : + m_xml_doc(), + m_dict_node() +{ + +} + +ApplePropertyList::ApplePropertyList (const char *path) : + m_xml_doc(), + m_dict_node() +{ + ParseFile(path); +} + +bool +ApplePropertyList::ParseFile (const char *path) +{ + if (m_xml_doc.ParseFile(path)) + { + XMLNode plist = m_xml_doc.GetRootElement("plist"); + if (plist) + { + plist.ForEachChildElementWithName("dict", [this](const XMLNode &dict) -> bool { + this->m_dict_node = dict; + return false; // Stop iterating + }); + return (bool)m_dict_node; + } + } + return false; +} + +bool +ApplePropertyList::IsValid() const +{ + return (bool)m_dict_node; +} + +bool +ApplePropertyList::GetValueAsString (const char *key, std::string &value) const +{ + XMLNode value_node = GetValueNode (key); + if (value_node) + return ApplePropertyList::ExtractStringFromValueNode(value_node, value); + return false; +} + +XMLNode +ApplePropertyList::GetValueNode (const char *key) const +{ + XMLNode value_node; +#if defined( LIBXML2_DEFINED ) + + if (IsValid()) + { + m_dict_node.ForEachChildElementWithName("key", [key, &value_node](const XMLNode &key_node) -> bool { + std::string key_name; + if (key_node.GetElementText(key_name)) + { + if (key_name.compare(key) == 0) + { + value_node = key_node.GetSibling(); + while (value_node && !value_node.IsElement()) + value_node = value_node.GetSibling(); + return false; // Stop iterating + } + } + return true; // Keep iterating + }); + } +#endif + return value_node; +} + +bool +ApplePropertyList::ExtractStringFromValueNode (const XMLNode &node, std::string &value) +{ + value.clear(); +#if defined( LIBXML2_DEFINED ) + if (node.IsValid()) + { + llvm::StringRef element_name = node.GetName(); + if (element_name == "true" or element_name == "false") + { + // The text value _is_ the element name itself... + value = std::move(element_name.str()); + return true; + } + else if (element_name == "dict" or element_name == "array") + return false; // dictionaries and arrays have no text value, so we fail + else + return node.GetElementText(value); + } +#endif + return false; +} + diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index df847dbb9ce..95bd8402446 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -146,7 +146,7 @@ OperatingSystemPython::GetDynamicRegisterInfo () if (!dictionary) return NULL; - m_register_info_ap.reset(new DynamicRegisterInfo(*dictionary, m_process->GetTarget().GetArchitecture().GetByteOrder())); + m_register_info_ap.reset(new DynamicRegisterInfo(*dictionary, m_process->GetTarget().GetArchitecture())); assert (m_register_info_ap->GetNumRegisters() > 0); assert (m_register_info_ap->GetNumRegisterSets() > 0); } diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp index 3dce3e2ba4a..dce88bc62db 100644 --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -742,4 +742,4 @@ PlatformWindows::GetEnvironment(StringList &env) } return Host::GetEnvironment(env); -}
\ No newline at end of file +} diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 0e9b540b7cf..f91cd19b7f2 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 () : { } -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 @@ DynamicRegisterInfo::~DynamicRegisterInfo () } 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 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, Byt 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 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, Byt 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 @@ DynamicRegisterInfo::AddRegister (RegisterInfo ®_info, } void -DynamicRegisterInfo::Finalize () +DynamicRegisterInfo::Finalize (const ArchSpec &arch) { if (m_finalized) return; @@ -518,6 +522,95 @@ DynamicRegisterInfo::Finalize () 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 ®: 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 ®: 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 ®: 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 ®: 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 ®: 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 128d8987397..1b99e2f1e70 100644 --- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -26,12 +26,14 @@ class DynamicRegisterInfo 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 ®_info, @@ -40,7 +42,7 @@ public: 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 7f194cdd55b..a452ae95b07 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3929,9 +3929,12 @@ GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString ob 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 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) { diff --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp index 1e99dcf4599..15e31c1774e 100644 --- a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -9,11 +9,6 @@ #include "SymbolVendorMacOSX.h" -#if defined( LIBXML2_DEFINED ) -#include <libxml/parser.h> -#include <libxml/tree.h> -#endif // #if defined( LIBXML2_DEFINED ) - #include <string.h> #include "lldb/Core/Module.h" @@ -24,6 +19,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Symbols.h" +#include "lldb/Host/XML.h" #include "lldb/Symbol/ObjectFile.h" using namespace lldb; @@ -177,111 +173,46 @@ SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp, lldb_privat dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset); if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) { -#if defined( LIBXML2_DEFINED ) - char dsym_path[PATH_MAX]; - if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path))) + // We need a XML parser if we hope to parse a plist... + if (XMLDocument::XMLEnabled()) { - lldb_private::UUID dsym_uuid; - if (dsym_objfile_sp->GetUUID(&dsym_uuid)) + char dsym_path[PATH_MAX]; + if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path))) { - std::string uuid_str = dsym_uuid.GetAsString (); - if (!uuid_str.empty()) + lldb_private::UUID dsym_uuid; + if (dsym_objfile_sp->GetUUID(&dsym_uuid)) { - char *resources = strstr (dsym_path, "/Contents/Resources/"); - if (resources) + std::string uuid_str = dsym_uuid.GetAsString (); + if (!uuid_str.empty()) { - char dsym_uuid_plist_path[PATH_MAX]; - resources[strlen("/Contents/Resources/")] = '\0'; - snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str()); - FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false); - if (dsym_uuid_plist_spec.Exists()) + char *resources = strstr (dsym_path, "/Contents/Resources/"); + if (resources) { - xmlDoc *doc = ::xmlReadFile (dsym_uuid_plist_path, NULL, 0); - if (doc) + char dsym_uuid_plist_path[PATH_MAX]; + resources[strlen("/Contents/Resources/")] = '\0'; + snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str()); + FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false); + if (dsym_uuid_plist_spec.Exists()) { - char DBGBuildSourcePath[PATH_MAX]; - char DBGSourcePath[PATH_MAX]; - DBGBuildSourcePath[0] = '\0'; - DBGSourcePath[0] = '\0'; - for (xmlNode *node = doc->children; node; node = node ? node->next : NULL) + ApplePropertyList plist(dsym_uuid_plist_path); + if (plist) { - if (node->type == XML_ELEMENT_NODE) + std::string DBGBuildSourcePath; + std::string DBGSourcePath; + + plist.GetValueAsString("DBGBuildSourcePath", DBGBuildSourcePath); + plist.GetValueAsString("DBGSourcePath", DBGSourcePath); + if (DBGBuildSourcePath[0] && DBGSourcePath[0]) { - if (node->name && strcmp((const char*)node->name, "plist") == 0) - { - xmlNode *dict_node = node->children; - while (dict_node && dict_node->type != XML_ELEMENT_NODE) - dict_node = dict_node->next; - if (dict_node && dict_node->name && strcmp((const char *)dict_node->name, "dict") == 0) - { - for (xmlNode *key_node = dict_node->children; key_node; key_node = key_node->next) - { - if (key_node && key_node->type == XML_ELEMENT_NODE && key_node->name) - { - if (strcmp((const char *)key_node->name, "key") == 0) - { - const char *key_name = (const char *)::xmlNodeGetContent(key_node); - if (strcmp(key_name, "DBGBuildSourcePath") == 0) - { - xmlNode *value_node = key_node->next; - while (value_node && value_node->type != XML_ELEMENT_NODE) - value_node = value_node->next; - if (value_node && value_node->name) - { - if (strcmp((const char *)value_node->name, "string") == 0) - { - const char *node_content = (const char *)::xmlNodeGetContent(value_node); - if (node_content) - { - ::snprintf(DBGBuildSourcePath, sizeof(DBGBuildSourcePath), "%s", node_content); - xmlFree((void *) node_content); - } - } - key_node = value_node; - } - } - else if (strcmp(key_name, "DBGSourcePath") == 0) - { - xmlNode *value_node = key_node->next; - while (value_node && value_node->type != XML_ELEMENT_NODE) - value_node = value_node->next; - if (value_node && value_node->name) - { - if (strcmp((const char *)value_node->name, "string") == 0) - { - const char *node_content = (const char *)::xmlNodeGetContent(value_node); - if (node_content) - { - FileSpec resolved_source_path(node_content, true); - resolved_source_path.GetPath(DBGSourcePath, sizeof(DBGSourcePath)); - xmlFree ((void *) node_content); - } - } - key_node = value_node; - } - } - if (key_name != NULL) - xmlFree((void *) key_name); - } - } - } - } - } + module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true); } } - ::xmlFreeDoc (doc); - - if (DBGBuildSourcePath[0] && DBGSourcePath[0]) - { - module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true); - } } } } } } } -#endif // #if defined( LIBXML2_DEFINED ) symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp); return symbol_vendor; diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp index 875193440b2..4d773221a45 100644 --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -1482,6 +1482,12 @@ DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, stru return 0; } +uint32_t +DNBGetRegisterCPUType() +{ + return DNBArchProtocol::GetRegisterCPUType (); + +} //---------------------------------------------------------------------- // Get the register set information for a specific thread. //---------------------------------------------------------------------- diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h index 363ca042e83..e57bb08b678 100644 --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -151,6 +151,7 @@ nub_bool_t DNBWatchpointSet (nub_process_t pid, nub_addr_t a nub_bool_t DNBWatchpointClear (nub_process_t pid, nub_addr_t addr); uint32_t DNBWatchpointGetNumSupportedHWP (nub_process_t pid); +uint32_t DNBGetRegisterCPUType (); const DNBRegisterSetInfo * DNBGetRegisterSetInfo (nub_size_t *num_reg_sets); nub_bool_t DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info); diff --git a/lldb/tools/debugserver/source/DNBArch.cpp b/lldb/tools/debugserver/source/DNBArch.cpp index c3f1fdf2682..4b56cae18e1 100644 --- a/lldb/tools/debugserver/source/DNBArch.cpp +++ b/lldb/tools/debugserver/source/DNBArch.cpp @@ -57,6 +57,15 @@ DNBArchProtocol::RegisterArchPlugin (const DNBArchPluginInfo &arch_info) g_arch_plugins[arch_info.cpu_type] = arch_info; } +uint32_t +DNBArchProtocol::GetRegisterCPUType () +{ + const DNBArchPluginInfo *arch_info = GetArchInfo (); + if (arch_info) + return arch_info->cpu_type; + return 0; +} + const DNBRegisterSetInfo * DNBArchProtocol::GetRegisterSetInfo (nub_size_t *num_reg_sets) { diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h index b3cb070e55c..998ca4df55b 100644 --- a/lldb/tools/debugserver/source/DNBArch.h +++ b/lldb/tools/debugserver/source/DNBArch.h @@ -43,6 +43,9 @@ public: static DNBArchProtocol * Create (MachThread *thread); + static uint32_t + GetRegisterCPUType (); + static const DNBRegisterSetInfo * GetRegisterSetInfo (nub_size_t *num_reg_sets); diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 88ff9242fdb..25988b9294b 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -210,6 +210,7 @@ RNBRemote::CreatePacketTable () t.push_back (Packet (set_process_event, &RNBRemote::HandlePacket_QSetProcessEvent, NULL, "QSetProcessEvent:", "Set a process event, to be passed to the process, can be set before the process is started, or after.")); t.push_back (Packet (set_detach_on_error, &RNBRemote::HandlePacket_QSetDetachOnError, NULL, "QSetDetachOnError:", "Set whether debugserver will detach (1) or kill (0) from the process it is controlling if it loses connection to lldb.")); t.push_back (Packet (speed_test, &RNBRemote::HandlePacket_qSpeedTest, NULL, "qSpeedTest:", "Test the maximum speed at which packet can be sent/received.")); + t.push_back (Packet (query_transfer, &RNBRemote::HandlePacket_qXfer, NULL, "qXfer:", "Support the qXfer packet.")); } @@ -3085,7 +3086,7 @@ RNBRemote::HandlePacket_qSupported (const char *p) { uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less char buf[64]; - snprintf (buf, sizeof(buf), "PacketSize=%x", max_packet_size); + snprintf (buf, sizeof(buf), "qXfer:features:read+;PacketSize=%x", max_packet_size); return SendPacket (buf); } @@ -3979,38 +3980,94 @@ RNBRemote::HandlePacket_S (const char *p) return rnb_success; } -rnb_err_t -RNBRemote::HandlePacket_qHostInfo (const char *p) +static const char * +GetArchName (const uint32_t cputype, const uint32_t cpusubtype) { - std::ostringstream strm; + switch (cputype) + { + case CPU_TYPE_ARM: + switch (cpusubtype) + { + case 5: return "armv4"; + case 6: return "armv6"; + case 7: return "armv5t"; + case 8: return "xscale"; + case 9: return "armv7"; + case 10: return "armv7f"; + case 11: return "armv7s"; + case 12: return "armv7k"; + case 14: return "armv6m"; + case 15: return "armv7m"; + case 16: return "armv7em"; + default: return "arm"; + } + break; + case CPU_TYPE_ARM64: return "arm64"; + case CPU_TYPE_I386: return "i386"; + case CPU_TYPE_X86_64: + switch (cpusubtype) + { + default: return "x86_64"; + case 8: return "x86_64h"; + } + break; + } + return NULL; +} - uint32_t cputype, is_64_bit_capable; - size_t len = sizeof(cputype); - bool promoted_to_64 = false; - if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0) +static bool +GetHostCPUType (uint32_t &cputype, uint32_t &cpusubtype, uint32_t &is_64_bit_capable, bool &promoted_to_64) +{ + static uint32_t g_host_cputype = 0; + static uint32_t g_host_cpusubtype = 0; + static uint32_t g_is_64_bit_capable = 0; + static bool g_promoted_to_64 = false; + + if (g_host_cputype == 0) { - len = sizeof (is_64_bit_capable); - if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0) + g_promoted_to_64 = false; + size_t len = sizeof(uint32_t); + if (::sysctlbyname("hw.cputype", &g_host_cputype, &len, NULL, 0) == 0) { - if (is_64_bit_capable && ((cputype & CPU_ARCH_ABI64) == 0)) + len = sizeof (uint32_t); + if (::sysctlbyname("hw.cpu64bit_capable", &g_is_64_bit_capable, &len, NULL, 0) == 0) { - promoted_to_64 = true; - cputype |= CPU_ARCH_ABI64; + if (g_is_64_bit_capable && ((g_host_cputype & CPU_ARCH_ABI64) == 0)) + { + g_promoted_to_64 = true; + g_host_cputype |= CPU_ARCH_ABI64; + } } } - strm << "cputype:" << std::dec << cputype << ';'; + len = sizeof(uint32_t); + if (::sysctlbyname("hw.cpusubtype", &g_host_cpusubtype, &len, NULL, 0) == 0) + { + if (g_promoted_to_64 && + g_host_cputype == CPU_TYPE_X86_64 && g_host_cpusubtype == CPU_SUBTYPE_486) + g_host_cpusubtype = CPU_SUBTYPE_X86_64_ALL; + } } + + cputype = g_host_cputype; + cpusubtype = g_host_cpusubtype; + is_64_bit_capable = g_is_64_bit_capable; + promoted_to_64 = g_promoted_to_64; + return g_host_cputype != 0; +} - uint32_t cpusubtype; - len = sizeof(cpusubtype); - if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) - { - if (promoted_to_64 && - cputype == CPU_TYPE_X86_64 && - cpusubtype == CPU_SUBTYPE_486) - cpusubtype = CPU_SUBTYPE_X86_64_ALL; +rnb_err_t +RNBRemote::HandlePacket_qHostInfo (const char *p) +{ + std::ostringstream strm; + uint32_t cputype = 0; + uint32_t cpusubtype = 0; + uint32_t is_64_bit_capable = 0; + bool promoted_to_64 = false; + if (GetHostCPUType (cputype, cpusubtype, is_64_bit_capable, promoted_to_64)) + { + strm << "cputype:" << std::dec << cputype << ';'; strm << "cpusubtype:" << std::dec << cpusubtype << ';'; } @@ -4054,6 +4111,340 @@ RNBRemote::HandlePacket_qHostInfo (const char *p) return SendPacket (strm.str()); } +void +XMLElementStart (std::ostringstream &s, uint32_t indent, const char *name, bool has_attributes) +{ + if (indent) + s << INDENT_WITH_SPACES(indent); + s << '<' << name; + if (!has_attributes) + s << '>' << std::endl; +} + +void +XMLElementStartEndAttributes (std::ostringstream &s, bool empty) +{ + if (empty) + s << '/'; + s << '>' << std::endl; +} + +void +XMLElementEnd (std::ostringstream &s, uint32_t indent, const char *name) +{ + if (indent) + s << INDENT_WITH_SPACES(indent); + s << '<' << '/' << name << '>' << std::endl; +} + +void +XMLElementWithStringValue (std::ostringstream &s, uint32_t indent, const char *name, const char *value, bool close = true) +{ + if (value) + { + if (indent) + s << INDENT_WITH_SPACES(indent); + s << '<' << name << '>' << value; + if (close) + XMLElementEnd(s, 0, name); + } +} + +void +XMLElementWithUnsignedValue (std::ostringstream &s, uint32_t indent, const char *name, uint64_t value, bool close = true) +{ + if (indent) + s << INDENT_WITH_SPACES(indent); + + s << '<' << name << '>' << DECIMAL << value; + if (close) + XMLElementEnd(s, 0, name); +} + +void +XMLAttributeString (std::ostringstream &s, const char *name, const char *value, const char *default_value = NULL) +{ + if (value) + { + if (default_value && strcmp(value, default_value) == 0) + return; // No need to emit the attribute because it matches the default value + s <<' ' << name << "=\"" << value << "\""; + } +} + +void +XMLAttributeUnsignedDecimal (std::ostringstream &s, const char *name, uint64_t value) +{ + s <<' ' << name << "=\"" << DECIMAL << value << "\""; +} + +void +GenerateTargetXMLRegister (std::ostringstream &s, + const uint32_t reg_num, + nub_size_t num_reg_sets, + const DNBRegisterSetInfo *reg_set_info, + const register_map_entry_t ®) +{ + const char *default_lldb_encoding = "uint"; + const char *lldb_encoding = default_lldb_encoding; + const char *gdb_group = "general"; + const char *default_gdb_type = "int"; + const char *gdb_type = default_gdb_type; + const char *default_lldb_format = "hex"; + const char *lldb_format = default_lldb_format; + const char *lldb_set = NULL; + + switch (reg.nub_info.type) + { + case Uint: lldb_encoding = "uint"; break; + case Sint: lldb_encoding = "sint"; break; + case IEEE754: lldb_encoding = "ieee754"; if (reg.nub_info.set > 0) gdb_group = "float"; break; + case Vector: lldb_encoding = "vector"; if (reg.nub_info.set > 0) gdb_group = "vector"; break; + } + + switch (reg.nub_info.format) + { + case Binary: lldb_format = "binary"; break; + case Decimal: lldb_format = "decimal"; break; + case Hex: lldb_format = "hex"; break; + case Float: gdb_type = "float"; lldb_format = "float"; break; + case VectorOfSInt8: gdb_type = "float"; lldb_format = "vector-sint8"; break; + case VectorOfUInt8: gdb_type = "float"; lldb_format = "vector-uint8"; break; + case VectorOfSInt16: gdb_type = "float"; lldb_format = "vector-sint16"; break; + case VectorOfUInt16: gdb_type = "float"; lldb_format = "vector-uint16"; break; + case VectorOfSInt32: gdb_type = "float"; lldb_format = "vector-sint32"; break; + case VectorOfUInt32: gdb_type = "float"; lldb_format = "vector-uint32"; break; + case VectorOfFloat32: gdb_type = "float"; lldb_format = "vector-float32"; break; + case VectorOfUInt128: gdb_type = "float"; lldb_format = "vector-uint128"; break; + }; + if (reg_set_info && reg.nub_info.set < num_reg_sets) + lldb_set = reg_set_info[reg.nub_info.set].name; + + uint32_t indent = 2; + + XMLElementStart(s, indent, "reg", true); + XMLAttributeString(s, "name", reg.nub_info.name); + XMLAttributeUnsignedDecimal(s, "regnum", reg_num); + XMLAttributeUnsignedDecimal(s, "offset", reg.offset); + XMLAttributeUnsignedDecimal(s, "bitsize", reg.nub_info.size * 8); + XMLAttributeString(s, "group", gdb_group); + XMLAttributeString(s, "type", gdb_type, default_gdb_type); + XMLAttributeString (s, "altname", reg.nub_info.alt); + XMLAttributeString(s, "encoding", lldb_encoding, default_lldb_encoding); + XMLAttributeString(s, "format", lldb_format, default_lldb_format); + XMLAttributeUnsignedDecimal(s, "group_id", reg.nub_info.set); + if (reg.nub_info.reg_gcc != INVALID_NUB_REGNUM) + XMLAttributeUnsignedDecimal(s, "gcc_regnum", reg.nub_info.reg_gcc); + if (reg.nub_info.reg_dwarf != INVALID_NUB_REGNUM) + XMLAttributeUnsignedDecimal(s, "dwarf_regnum", reg.nub_info.reg_dwarf); + + const char *lldb_generic = NULL; + switch (reg.nub_info.reg_generic) + { + case GENERIC_REGNUM_FP: lldb_generic = "fp"; break; + case GENERIC_REGNUM_PC: lldb_generic = "pc"; break; + case GENERIC_REGNUM_SP: lldb_generic = "sp"; break; + case GENERIC_REGNUM_RA: lldb_generic = "ra"; break; + case GENERIC_REGNUM_FLAGS: lldb_generic = "flags"; break; + case GENERIC_REGNUM_ARG1: lldb_generic = "arg1"; break; + case GENERIC_REGNUM_ARG2: lldb_generic = "arg2"; break; + case GENERIC_REGNUM_ARG3: lldb_generic = "arg3"; break; + case GENERIC_REGNUM_ARG4: lldb_generic = "arg4"; break; + case GENERIC_REGNUM_ARG5: lldb_generic = "arg5"; break; + case GENERIC_REGNUM_ARG6: lldb_generic = "arg6"; break; + case GENERIC_REGNUM_ARG7: lldb_generic = "arg7"; break; + case GENERIC_REGNUM_ARG8: lldb_generic = "arg8"; break; + default: break; + } + XMLAttributeString(s, "generic", lldb_generic); + + + bool empty = reg.value_regnums.empty() && reg.invalidate_regnums.empty(); + if (!empty) + { + if (!reg.value_regnums.empty()) + { + std::ostringstream regnums; + bool first = true; + regnums << DECIMAL; + for (auto regnum : reg.value_regnums) + { + if (!first) + regnums << ','; + regnums << regnum; + first = false; + } + XMLAttributeString(s, "value_regnums", regnums.str().c_str()); + } + + if (!reg.invalidate_regnums.empty()) + { + std::ostringstream regnums; + bool first = true; + regnums << DECIMAL; + for (auto regnum : reg.invalidate_regnums) + { + if (!first) + regnums << ','; + regnums << regnum; + first = false; + } + XMLAttributeString(s, "invalidate_regnums", regnums.str().c_str()); + } + } + XMLElementStartEndAttributes(s, true); +} + +void +GenerateTargetXMLRegisters (std::ostringstream &s) +{ + nub_size_t num_reg_sets = 0; + const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo (&num_reg_sets); + + + uint32_t cputype = DNBGetRegisterCPUType(); + if (cputype) + { + XMLElementStart(s, 0, "feature", true); + std::ostringstream name_strm; + name_strm << "com.apple.debugserver." << GetArchName (cputype, 0); + XMLAttributeString(s, "name", name_strm.str().c_str()); + XMLElementStartEndAttributes(s, false); + for (uint32_t reg_num = 0; reg_num < g_num_reg_entries; ++reg_num) +// for (const auto ®: g_dynamic_register_map) + { + GenerateTargetXMLRegister(s, reg_num, num_reg_sets, reg_sets, g_reg_entries[reg_num]); + } + XMLElementEnd(s, 0, "feature"); + + if (num_reg_sets > 0) + { + XMLElementStart(s, 0, "groups", false); + for (uint32_t set=1; set<num_reg_sets; ++set) + { + XMLElementStart(s, 2, "group", true); + XMLAttributeUnsignedDecimal(s, "id", set); + XMLAttributeString(s, "name", reg_sets[set].name); + XMLElementStartEndAttributes(s, true); + } + XMLElementEnd(s, 0, "groups"); + } + } +} + +static const char *g_target_xml_header = R"(<?xml version="1.0"?> +<target version="1.0">)"; + +static const char *g_target_xml_footer = "</target>"; + +static std::string g_target_xml; + +void +UpdateTargetXML () +{ + std::ostringstream s; + s << g_target_xml_header << std::endl; + + // Set the architecture + //s << "<architecture>" << arch "</architecture>" << std::endl; + + // Set the OSABI + //s << "<osabi>abi-name</osabi>" + + GenerateTargetXMLRegisters(s); + + s << g_target_xml_footer << std::endl; + + // Save the XML output in case it gets retrieved in chunks + g_target_xml = s.str(); +} + +rnb_err_t +RNBRemote::HandlePacket_qXfer (const char *command) +{ + const char *p = command; + p += strlen ("qXfer:"); + const char *sep = strchr(p, ':'); + if (sep) + { + std::string object(p, sep - p); // "auxv", "backtrace", "features", etc + p = sep + 1; + sep = strchr(p, ':'); + if (sep) + { + std::string rw(p, sep - p); // "read" or "write" + p = sep + 1; + sep = strchr(p, ':'); + if (sep) + { + std::string annex(p, sep - p); // "read" or "write" + + p = sep + 1; + sep = strchr(p, ','); + if (sep) + { + std::string offset_str(p, sep - p); // read the length as a string + p = sep + 1; + std::string length_str(p); // read the offset as a string + char *end = nullptr; + const uint64_t offset = strtoul(offset_str.c_str(), &end, 16); // convert offset_str to a offset + if (*end == '\0') + { + const uint64_t length = strtoul(length_str.c_str(), &end, 16); // convert length_str to a length + if (*end == '\0') + { + if (object == "features" && + rw == "read" && + annex == "target.xml") + { + std::ostringstream xml_out; + + if (offset == 0) + { + InitializeRegisters (true); + + UpdateTargetXML(); + if (g_target_xml.empty()) + return SendPacket("E83"); + + if (length > g_target_xml.size()) + { + xml_out << 'l'; // No more data + xml_out << binary_encode_string(g_target_xml); + } + else + { + xml_out << 'm'; // More data needs to be read with a subsequent call + xml_out << binary_encode_string(std::string(g_target_xml, offset, length)); + } + } + else + { + // Retrieving target XML in chunks + if (offset < g_target_xml.size()) + { + std::string chunk(g_target_xml, offset, length); + if (chunk.size() < length) + xml_out << 'l'; // No more data + else + xml_out << 'm'; // More data needs to be read with a subsequent call + xml_out << binary_encode_string(chunk.data()); + } + } + return SendPacket(xml_out.str()); + } + // Well formed, put not supported + return HandlePacket_UNIMPLEMENTED (command); + } + } + } + } + } + } + return SendPacket ("E82"); +} + + rnb_err_t RNBRemote::HandlePacket_qGDBServerVersion (const char *p) { diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index 0d99465f507..c58c32b1b02 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -127,6 +127,7 @@ public: restore_register_state, // '_G' speed_test, // 'qSpeedTest:' set_detach_on_error, // 'QSetDetachOnError:' + query_transfer, // 'qXfer:' unknown_type } PacketEnum; @@ -234,6 +235,7 @@ public: rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p); rnb_err_t HandlePacket_WatchpointSupportInfo (const char *p); rnb_err_t HandlePacket_qSpeedTest (const char *p); + rnb_err_t HandlePacket_qXfer (const char *p); rnb_err_t HandlePacket_stop_process (const char *p); rnb_err_t HandlePacket_QSetDetachOnError (const char *p); |