diff options
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); |