diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h index f2846710c614..448e9593492b 100644 --- a/lldb/include/lldb/API/SBProcess.h +++ b/lldb/include/lldb/API/SBProcess.h @@ -279,6 +279,9 @@ public: lldb::SBError UnloadImage (uint32_t image_token); + lldb::SBError + SendEventData (const char *data); + //------------------------------------------------------------------ /// Return the number of different thread-origin extended backtraces /// this process can support. diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 230dffc68251..bcb9fc5d7830 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -110,6 +110,12 @@ public: bool AddSuppressFileAction (int fd, bool read, bool write); + void + SetLaunchEventData (const char *data); + + const char * + GetLaunchEventData () const; + protected: friend class SBTarget; diff --git a/lldb/include/lldb/Core/ArchSpec.h b/lldb/include/lldb/Core/ArchSpec.h index 1ccb385783a0..4593bf4116af 100644 --- a/lldb/include/lldb/Core/ArchSpec.h +++ b/lldb/include/lldb/Core/ArchSpec.h @@ -50,6 +50,7 @@ public: eCore_arm_armv7m, eCore_arm_armv7em, eCore_arm_xscale, + eCore_thumb, eCore_thumbv4t, eCore_thumbv5, @@ -57,11 +58,12 @@ public: eCore_thumbv6, eCore_thumbv6m, eCore_thumbv7, - eCore_thumbv7f, eCore_thumbv7s, eCore_thumbv7k, + eCore_thumbv7f, eCore_thumbv7m, eCore_thumbv7em, + eCore_arm_arm64, eCore_mips64, diff --git a/lldb/include/lldb/Core/RegisterValue.h b/lldb/include/lldb/Core/RegisterValue.h index cf29cea46d36..1b1a71a11c5a 100644 --- a/lldb/include/lldb/Core/RegisterValue.h +++ b/lldb/include/lldb/Core/RegisterValue.h @@ -374,6 +374,12 @@ namespace lldb_private { uint32_t GetByteSize () const; + static uint32_t + GetMaxByteSize () + { + return kMaxRegisterByteSize; + } + void Clear(); diff --git a/lldb/include/lldb/Expression/ExpressionSourceCode.h b/lldb/include/lldb/Expression/ExpressionSourceCode.h index be1014ae3047..2dd09378fcd2 100644 --- a/lldb/include/lldb/Expression/ExpressionSourceCode.h +++ b/lldb/include/lldb/Expression/ExpressionSourceCode.h @@ -17,6 +17,8 @@ namespace lldb_private { +class ExecutionContext; + class ExpressionSourceCode { public: @@ -53,7 +55,8 @@ public: bool GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, - bool static_method) const; + bool static_method, + ExecutionContext &exe_ctx) const; private: ExpressionSourceCode (const char *name, diff --git a/lldb/include/lldb/Symbol/ClangASTType.h b/lldb/include/lldb/Symbol/ClangASTType.h index 19b5d6ec6727..ad980ce50c84 100644 --- a/lldb/include/lldb/Symbol/ClangASTType.h +++ b/lldb/include/lldb/Symbol/ClangASTType.h @@ -155,6 +155,9 @@ public: bool IsFunctionType (bool *is_variadic_ptr = NULL) const; + uint32_t + IsHomogeneousAggregate (ClangASTType* base_type_ptr) const; + size_t GetNumberOfFunctionArguments () const; diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index b40a02ef9eef..55775b501efe 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -856,6 +856,18 @@ public: } + void + SetLaunchEventData (const char *data) + { + m_event_data.assign (data); + } + + const char * + GetLaunchEventData () const + { + return m_event_data.c_str(); + } + protected: std::string m_working_dir; std::string m_plugin_name; @@ -867,6 +879,7 @@ protected: Host::MonitorChildProcessCallback m_monitor_callback; void *m_monitor_callback_baton; bool m_monitor_signals; + std::string m_event_data; // A string passed to the plugin launch, having no meaning to the upper levels of lldb. lldb::ListenerSP m_hijack_listener_sp; }; @@ -3638,8 +3651,17 @@ public: else return m_public_run_lock; } - + +public: + virtual Error + SendEventData(const char *data) + { + Error return_error ("Sending an event is not supported for this process."); + return return_error; + } + protected: + //------------------------------------------------------------------ // NextEventAction provides a way to register an action on the next // event that is delivered to this process. There is currently only diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile index 88e4329033b2..fd06e483775a 100644 --- a/lldb/lib/Makefile +++ b/lldb/lib/Makefile @@ -32,12 +32,14 @@ USEDLIBS = lldbAPI.a \ lldbInitAndLog.a \ lldbInterpreter.a \ lldbPluginABIMacOSX_arm.a \ + lldbPluginABIMacOSX_arm64.a \ lldbPluginABIMacOSX_i386.a \ lldbPluginABISysV_x86_64.a \ lldbPluginDisassemblerLLVM.a \ lldbPluginDynamicLoaderStatic.a \ lldbPluginDynamicLoaderPOSIX.a \ lldbPluginEmulateInstructionARM.a \ + lldbPluginEmulateInstructionARM64.a \ lldbPluginLanguageRuntimeCPlusPlusItaniumABI.a \ lldbPluginLanguageRuntimeObjCAppleObjCRuntime.a \ lldbPluginObjectContainerBSDArchive.a \ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 10482147f0e2..73efbcd25aad 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -140,6 +140,8 @@ 26474CD518D0CB710073DEBA /* RegisterInfos_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 26474CD218D0CB710073DEBA /* RegisterInfos_x86_64.h */; }; 26491E3B15E1DB8600CBFFC2 /* OptionValueRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 26491E3A15E1DB8600CBFFC2 /* OptionValueRegex.h */; }; 26491E3E15E1DB9F00CBFFC2 /* OptionValueRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26491E3D15E1DB9F00CBFFC2 /* OptionValueRegex.cpp */; }; + 264A12FC1372522000875C42 /* EmulateInstructionARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264A12FA1372522000875C42 /* EmulateInstructionARM64.cpp */; }; + 264A1300137252C700875C42 /* ARM64_DWARF_Registers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264A12FE137252C700875C42 /* ARM64_DWARF_Registers.cpp */; }; 264A97BF133918BC0017F0BE /* PlatformRemoteGDBServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264A97BD133918BC0017F0BE /* PlatformRemoteGDBServer.cpp */; }; 264D8D5013661BD7003A368F /* UnwindAssembly.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D8D4F13661BD7003A368F /* UnwindAssembly.cpp */; }; 265205A813D3E3F700132FE2 /* RegisterContextKDP_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 265205A213D3E3F700132FE2 /* RegisterContextKDP_arm.cpp */; }; @@ -519,6 +521,7 @@ 26DAED6015D327A200E15819 /* OptionValuePathMappings.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DAED5F15D327A200E15819 /* OptionValuePathMappings.h */; }; 26DAED6315D327C200E15819 /* OptionValuePathMappings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DAED6215D327C200E15819 /* OptionValuePathMappings.cpp */; }; 26DB3E161379E7AD0080DC73 /* ABIMacOSX_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DB3E071379E7AD0080DC73 /* ABIMacOSX_arm.cpp */; }; + 26DB3E191379E7AD0080DC73 /* ABIMacOSX_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DB3E0B1379E7AD0080DC73 /* ABIMacOSX_arm64.cpp */; }; 26DB3E1C1379E7AD0080DC73 /* ABIMacOSX_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DB3E0F1379E7AD0080DC73 /* ABIMacOSX_i386.cpp */; }; 26DB3E1F1379E7AD0080DC73 /* ABISysV_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DB3E131379E7AD0080DC73 /* ABISysV_x86_64.cpp */; }; 26DC6A1D1337FECA00FF7998 /* lldb-platform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DC6A1C1337FECA00FF7998 /* lldb-platform.cpp */; }; @@ -661,6 +664,8 @@ AF061F88182C97ED00B6A19C /* RegisterContextHistory.h in Headers */ = {isa = PBXBuildFile; fileRef = AF061F86182C97ED00B6A19C /* RegisterContextHistory.h */; }; AF061F8B182C980000B6A19C /* HistoryThread.h in Headers */ = {isa = PBXBuildFile; fileRef = AF061F89182C980000B6A19C /* HistoryThread.h */; }; AF061F8C182C980000B6A19C /* HistoryUnwind.h in Headers */ = {isa = PBXBuildFile; fileRef = AF061F8A182C980000B6A19C /* HistoryUnwind.h */; }; + AF0F6E501739A76D009180FE /* RegisterContextKDP_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF0F6E4E1739A76D009180FE /* RegisterContextKDP_arm64.cpp */; }; + AF0F6E511739A76D009180FE /* RegisterContextKDP_arm64.h in Headers */ = {isa = PBXBuildFile; fileRef = AF0F6E4F1739A76D009180FE /* RegisterContextKDP_arm64.h */; }; AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF0C112718580CD800C4C45B /* QueueItem.cpp */; }; AF0E22F018A09FB20009B7D1 /* AppleGetItemInfoHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF0E22EE18A09FB20009B7D1 /* AppleGetItemInfoHandler.cpp */; }; AF0E22F118A09FB20009B7D1 /* AppleGetItemInfoHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AF0E22EF18A09FB20009B7D1 /* AppleGetItemInfoHandler.h */; }; @@ -685,6 +690,8 @@ AF45FDE618A1F3AC0007051C /* AppleGetThreadItemInfoHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AF45FDE418A1F3AC0007051C /* AppleGetThreadItemInfoHandler.h */; }; AF81DEFA1828A23F0042CF19 /* SystemRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF81DEF91828A23F0042CF19 /* SystemRuntime.cpp */; }; AF90106515AB7D3600FF120D /* lldb.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = AF90106315AB7C5700FF120D /* lldb.1 */; }; + AF9107EE168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9107EC168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp */; }; + AF9107EF168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9107EC168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp */; }; AF9B8F33182DB52900DA866F /* SystemRuntimeMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9B8F31182DB52900DA866F /* SystemRuntimeMacOSX.cpp */; }; AF9B8F34182DB52900DA866F /* SystemRuntimeMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = AF9B8F32182DB52900DA866F /* SystemRuntimeMacOSX.h */; }; AFF87C87150FF669000E1742 /* com.apple.debugserver.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = AFF87C86150FF669000E1742 /* com.apple.debugserver.plist */; }; @@ -1099,6 +1106,10 @@ 26474CD218D0CB710073DEBA /* RegisterInfos_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterInfos_x86_64.h; path = Utility/RegisterInfos_x86_64.h; sourceTree = ""; }; 26491E3A15E1DB8600CBFFC2 /* OptionValueRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionValueRegex.h; path = include/lldb/Interpreter/OptionValueRegex.h; sourceTree = ""; }; 26491E3D15E1DB9F00CBFFC2 /* OptionValueRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionValueRegex.cpp; path = source/Interpreter/OptionValueRegex.cpp; sourceTree = ""; }; + 264A12FA1372522000875C42 /* EmulateInstructionARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmulateInstructionARM64.cpp; sourceTree = ""; }; + 264A12FB1372522000875C42 /* EmulateInstructionARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmulateInstructionARM64.h; sourceTree = ""; }; + 264A12FE137252C700875C42 /* ARM64_DWARF_Registers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ARM64_DWARF_Registers.cpp; path = source/Utility/ARM64_DWARF_Registers.cpp; sourceTree = ""; }; + 264A12FF137252C700875C42 /* ARM64_DWARF_Registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARM64_DWARF_Registers.h; path = source/Utility/ARM64_DWARF_Registers.h; sourceTree = ""; }; 264A43BB1320B3B4005B4096 /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Platform.h; path = include/lldb/Target/Platform.h; sourceTree = ""; }; 264A43BD1320BCEB005B4096 /* Platform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Platform.cpp; path = source/Target/Platform.cpp; sourceTree = ""; }; 264A97BD133918BC0017F0BE /* PlatformRemoteGDBServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformRemoteGDBServer.cpp; path = "gdb-server/PlatformRemoteGDBServer.cpp"; sourceTree = ""; }; @@ -1143,7 +1154,7 @@ 2670F8111862B44A006B332C /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = /usr/lib/libncurses.dylib; sourceTree = ""; }; 2671A0CD134825F6003A87BB /* ConnectionMachPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConnectionMachPort.h; path = include/lldb/Core/ConnectionMachPort.h; sourceTree = ""; }; 2671A0CF13482601003A87BB /* ConnectionMachPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConnectionMachPort.cpp; path = source/Core/ConnectionMachPort.cpp; sourceTree = ""; }; - 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = ""; }; 2672D8471189055500FF4019 /* CommandObjectFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFrame.h; path = source/Commands/CommandObjectFrame.h; sourceTree = ""; }; 26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteCommunicationClient.cpp; sourceTree = ""; }; 26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationClient.h; sourceTree = ""; }; @@ -1359,7 +1370,7 @@ 26BC7D7E10F1B77400F91463 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timer.h; path = include/lldb/Core/Timer.h; sourceTree = ""; }; 26BC7D8010F1B77400F91463 /* UserID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserID.h; path = include/lldb/Core/UserID.h; sourceTree = ""; }; 26BC7D8110F1B77400F91463 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Value.h; path = include/lldb/Core/Value.h; sourceTree = ""; }; - 26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = ""; }; 26BC7D8310F1B77400F91463 /* ValueObjectChild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectChild.h; path = include/lldb/Core/ValueObjectChild.h; sourceTree = ""; }; 26BC7D8410F1B77400F91463 /* ValueObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectList.h; path = include/lldb/Core/ValueObjectList.h; sourceTree = ""; }; 26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectVariable.h; path = include/lldb/Core/ValueObjectVariable.h; sourceTree = ""; }; @@ -1457,7 +1468,7 @@ 26BC7E9610F1B85900F91463 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Timer.cpp; path = source/Core/Timer.cpp; sourceTree = ""; }; 26BC7E9810F1B85900F91463 /* UserID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserID.cpp; path = source/Core/UserID.cpp; sourceTree = ""; }; 26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = ""; }; - 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = ""; }; 26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectChild.cpp; path = source/Core/ValueObjectChild.cpp; sourceTree = ""; }; 26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = ""; }; 26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = ""; }; @@ -1560,6 +1571,8 @@ 26DAFD9711529BC7005A394E /* ExecutionContextScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionContextScope.h; path = include/lldb/Target/ExecutionContextScope.h; sourceTree = ""; }; 26DB3E071379E7AD0080DC73 /* ABIMacOSX_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABIMacOSX_arm.cpp; sourceTree = ""; }; 26DB3E081379E7AD0080DC73 /* ABIMacOSX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABIMacOSX_arm.h; sourceTree = ""; }; + 26DB3E0B1379E7AD0080DC73 /* ABIMacOSX_arm64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABIMacOSX_arm64.cpp; sourceTree = ""; }; + 26DB3E0C1379E7AD0080DC73 /* ABIMacOSX_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABIMacOSX_arm64.h; sourceTree = ""; }; 26DB3E0F1379E7AD0080DC73 /* ABIMacOSX_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABIMacOSX_i386.cpp; sourceTree = ""; }; 26DB3E101379E7AD0080DC73 /* ABIMacOSX_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABIMacOSX_i386.h; sourceTree = ""; }; 26DB3E131379E7AD0080DC73 /* ABISysV_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABISysV_x86_64.cpp; sourceTree = ""; }; @@ -1903,6 +1916,8 @@ AF061F86182C97ED00B6A19C /* RegisterContextHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextHistory.h; path = Utility/RegisterContextHistory.h; sourceTree = ""; }; AF061F89182C980000B6A19C /* HistoryThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryThread.h; path = Utility/HistoryThread.h; sourceTree = ""; }; AF061F8A182C980000B6A19C /* HistoryUnwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryUnwind.h; path = Utility/HistoryUnwind.h; sourceTree = ""; }; + AF0F6E4E1739A76D009180FE /* RegisterContextKDP_arm64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextKDP_arm64.cpp; sourceTree = ""; }; + AF0F6E4F1739A76D009180FE /* RegisterContextKDP_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextKDP_arm64.h; sourceTree = ""; }; AF0C112718580CD800C4C45B /* QueueItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QueueItem.cpp; path = source/Target/QueueItem.cpp; sourceTree = ""; }; AF0E22EE18A09FB20009B7D1 /* AppleGetItemInfoHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleGetItemInfoHandler.cpp; sourceTree = ""; }; AF0E22EF18A09FB20009B7D1 /* AppleGetItemInfoHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleGetItemInfoHandler.h; sourceTree = ""; }; @@ -1933,6 +1948,9 @@ AF68D3301255A110002FF25B /* UnwindLLDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindLLDB.h; path = Utility/UnwindLLDB.h; sourceTree = ""; }; AF81DEF91828A23F0042CF19 /* SystemRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SystemRuntime.cpp; path = source/Target/SystemRuntime.cpp; sourceTree = ""; }; AF90106315AB7C5700FF120D /* lldb.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = lldb.1; path = docs/lldb.1; sourceTree = ""; }; + AF9107E91685709A00DBCD3C /* ARM64_GCC_Registers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARM64_GCC_Registers.h; path = source/Utility/ARM64_GCC_Registers.h; sourceTree = ""; }; + AF9107EC168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextDarwin_arm64.cpp; path = Utility/RegisterContextDarwin_arm64.cpp; sourceTree = ""; }; + AF9107ED168570D200DBCD3C /* RegisterContextDarwin_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextDarwin_arm64.h; path = Utility/RegisterContextDarwin_arm64.h; sourceTree = ""; }; AF94005711C03F6500085DB9 /* SymbolVendor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolVendor.cpp; path = source/Symbol/SymbolVendor.cpp; sourceTree = ""; }; AF9B8F31182DB52900DA866F /* SystemRuntimeMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemRuntimeMacOSX.cpp; sourceTree = ""; }; AF9B8F32182DB52900DA866F /* SystemRuntimeMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemRuntimeMacOSX.h; sourceTree = ""; }; @@ -2524,6 +2542,8 @@ 2642FBA713D003B400ED6808 /* MacOSX-Kernel */ = { isa = PBXGroup; children = ( + AF0F6E4E1739A76D009180FE /* RegisterContextKDP_arm64.cpp */, + AF0F6E4F1739A76D009180FE /* RegisterContextKDP_arm64.h */, 2642FBA813D003B400ED6808 /* CommunicationKDP.cpp */, 2642FBA913D003B400ED6808 /* CommunicationKDP.h */, 2642FBAA13D003B400ED6808 /* ProcessKDP.cpp */, @@ -2542,6 +2562,15 @@ path = "MacOSX-Kernel"; sourceTree = ""; }; + 264A12F91372522000875C42 /* ARM64 */ = { + isa = PBXGroup; + children = ( + 264A12FA1372522000875C42 /* EmulateInstructionARM64.cpp */, + 264A12FB1372522000875C42 /* EmulateInstructionARM64.h */, + ); + path = ARM64; + sourceTree = ""; + }; 264A97BC133918A30017F0BE /* GDB Server */ = { isa = PBXGroup; children = ( @@ -2642,9 +2671,12 @@ 2682F168115ED9C800CCFF99 /* Utility */ = { isa = PBXGroup; children = ( + AF9107E91685709A00DBCD3C /* ARM64_GCC_Registers.h */, 26CF992414428766001E4138 /* AnsiTerminal.h */, 26F996A7119B79C300412154 /* ARM_DWARF_Registers.h */, 26ECA04213665FED008D1F18 /* ARM_DWARF_Registers.cpp */, + 264A12FF137252C700875C42 /* ARM64_DWARF_Registers.h */, + 264A12FE137252C700875C42 /* ARM64_DWARF_Registers.cpp */, 26F996A8119B79C300412154 /* ARM_GCC_Registers.h */, 264723A511FA076E00DE380C /* CleanUp.h */, 26D1804416CEE12500EDFB5B /* KQueue.h */, @@ -2770,6 +2802,8 @@ 26474C9F18D0CAEC0073DEBA /* RegisterContext_x86.h */, 26957D9213D381C900670048 /* RegisterContextDarwin_arm.cpp */, 26957D9313D381C900670048 /* RegisterContextDarwin_arm.h */, + AF9107EC168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp */, + AF9107ED168570D200DBCD3C /* RegisterContextDarwin_arm64.h */, 26957D9413D381C900670048 /* RegisterContextDarwin_i386.cpp */, 26957D9513D381C900670048 /* RegisterContextDarwin_i386.h */, 26957D9613D381C900670048 /* RegisterContextDarwin_x86_64.cpp */, @@ -3527,6 +3561,7 @@ isa = PBXGroup; children = ( 26D9FDCB12F785270003F2EE /* ARM */, + 264A12F91372522000875C42 /* ARM64 */, ); path = Instruction; sourceTree = ""; @@ -3546,6 +3581,7 @@ isa = PBXGroup; children = ( 26DB3E061379E7AD0080DC73 /* MacOSX-arm */, + 26DB3E0A1379E7AD0080DC73 /* MacOSX-arm64 */, 26DB3E0E1379E7AD0080DC73 /* MacOSX-i386 */, 26DB3E121379E7AD0080DC73 /* SysV-x86_64 */, ); @@ -3561,6 +3597,15 @@ path = "MacOSX-arm"; sourceTree = ""; }; + 26DB3E0A1379E7AD0080DC73 /* MacOSX-arm64 */ = { + isa = PBXGroup; + children = ( + 26DB3E0B1379E7AD0080DC73 /* ABIMacOSX_arm64.cpp */, + 26DB3E0C1379E7AD0080DC73 /* ABIMacOSX_arm64.h */, + ); + path = "MacOSX-arm64"; + sourceTree = ""; + }; 26DB3E0E1379E7AD0080DC73 /* MacOSX-i386 */ = { isa = PBXGroup; children = ( @@ -4004,6 +4049,7 @@ AF061F8C182C980000B6A19C /* HistoryUnwind.h in Headers */, 260CC63815D04377002BF2E0 /* OptionValueString.h in Headers */, 260CC63915D04377002BF2E0 /* OptionValueUInt64.h in Headers */, + AF0F6E511739A76D009180FE /* RegisterContextKDP_arm64.h in Headers */, 260CC63A15D04377002BF2E0 /* OptionValueUUID.h in Headers */, 260A248E15D06C50009981B0 /* OptionValues.h in Headers */, AF061F88182C97ED00B6A19C /* RegisterContextHistory.h in Headers */, @@ -4415,6 +4461,7 @@ 9475C18E14E5F834001BFC6D /* SBTypeNameSpecifier.cpp in Sources */, 9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */, 4CE4F675162C973F00F75CB3 /* SBExpressionOptions.cpp in Sources */, + AF9107EE168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4740,7 +4787,10 @@ 260E07C8136FAB9200CF21D3 /* OptionGroupFile.cpp in Sources */, 2686536C1370ACB200D186A3 /* OptionGroupBoolean.cpp in Sources */, 268653701370AE7200D186A3 /* OptionGroupUInt64.cpp in Sources */, + 264A12FC1372522000875C42 /* EmulateInstructionARM64.cpp in Sources */, + 264A1300137252C700875C42 /* ARM64_DWARF_Registers.cpp in Sources */, 26DB3E161379E7AD0080DC73 /* ABIMacOSX_arm.cpp in Sources */, + 26DB3E191379E7AD0080DC73 /* ABIMacOSX_arm64.cpp in Sources */, 26DB3E1C1379E7AD0080DC73 /* ABIMacOSX_i386.cpp in Sources */, 26DB3E1F1379E7AD0080DC73 /* ABISysV_x86_64.cpp in Sources */, 26D1803E16CEBFD300EDFB5B /* KQueue.cpp in Sources */, @@ -4796,6 +4846,7 @@ 26B7564E14F89356008D9CB3 /* PlatformiOSSimulator.cpp in Sources */, 26FFC19914FC072100087D58 /* AuxVector.cpp in Sources */, 26FFC19B14FC072100087D58 /* DYLDRendezvous.cpp in Sources */, + AF0F6E501739A76D009180FE /* RegisterContextKDP_arm64.cpp in Sources */, 26FFC19D14FC072100087D58 /* DynamicLoaderPOSIXDYLD.cpp in Sources */, 2694E99D14FC0BB30076DE67 /* PlatformFreeBSD.cpp in Sources */, 2694E9A414FC0BBD0076DE67 /* PlatformLinux.cpp in Sources */, @@ -4834,6 +4885,7 @@ 947A1D641616476B0017C8D1 /* CommandObjectPlugin.cpp in Sources */, 262ED0081631FA3A00879631 /* OptionGroupString.cpp in Sources */, 94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */, + AF9107EF168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp in Sources */, 94CB255B16B069770059775D /* CXXFormatterFunctions.cpp in Sources */, 94CB255C16B069770059775D /* DataVisualization.cpp in Sources */, 94CD705016F8DF1C00CF1E42 /* LibCxxList.cpp in Sources */, @@ -4978,7 +5030,10 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(NATIVE_ARCH)"; - "ARCHS[sdk=iphoneos*]" = armv7; + "ARCHS[sdk=iphoneos*]" = ( + arm64, + armv7, + ); "ARCHS[sdk=macosx*]" = ( x86_64, i386, @@ -5007,6 +5062,7 @@ NO_XPC_SERVICES, ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -5033,6 +5089,7 @@ "-flimit-debug-info", "-Wparentheses", ); + SDKROOT = ""; STRIP_INSTALLED_PRODUCT = NO; STRIP_STYLE = debugging; WARNING_CFLAGS = "-Wreorder"; @@ -5044,7 +5101,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(NATIVE_ARCH)"; - "ARCHS[sdk=iphoneos*]" = armv7; + "ARCHS[sdk=iphoneos*]" = arm64; "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -5054,7 +5111,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEBUG_INFORMATION_FORMAT = dwarf; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = ( __STDC_CONSTANT_MACROS, @@ -5069,6 +5126,7 @@ NO_XPC_SERVICES, ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -5095,6 +5153,7 @@ "-flimit-debug-info", "-Wparentheses", ); + SDKROOT = ""; STRIP_INSTALLED_PRODUCT = NO; STRIP_STYLE = debugging; WARNING_CFLAGS = "-Wreorder"; @@ -5434,7 +5493,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(NATIVE_ARCH)"; - "ARCHS[sdk=iphoneos*]" = armv7; + "ARCHS[sdk=iphoneos*]" = arm64; "ARCHS[sdk=macosx*]" = ( x86_64, i386, @@ -5462,6 +5521,7 @@ NO_XPC_SERVICES, ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -5489,6 +5549,7 @@ "-flimit-debug-info", "-Wparentheses", ); + SDKROOT = ""; STRIP_INSTALLED_PRODUCT = NO; STRIP_STYLE = debugging; WARNING_CFLAGS = "-Wreorder"; @@ -5522,6 +5583,7 @@ __TEXT, __info_plist, "$(PROJECT_DIR)/tools/driver/lldb-Info.plist", + "-Wl,-rpath,@loader_path/../../Library/PrivateFrameworks/", "-Wl,-rpath,@loader_path/../../../SharedFrameworks", "-Wl,-rpath,@loader_path/../../System/Library/PrivateFrameworks", "-Wl,-rpath,@loader_path/../../Library/PrivateFrameworks", @@ -6015,8 +6077,6 @@ "-lxml2", "-framework", Foundation, - "-framework", - UIKit, ); PRODUCT_NAME = "lldb-platform"; SKIP_INSTALL = YES; @@ -6085,8 +6145,6 @@ "-lxml2", "-framework", Foundation, - "-framework", - UIKit, ); PRODUCT_NAME = "lldb-platform"; SKIP_INSTALL = YES; @@ -6155,8 +6213,6 @@ "-lxml2", "-framework", Foundation, - "-framework", - UIKit, ); PRODUCT_NAME = "lldb-platform"; SKIP_INSTALL = YES; @@ -6227,7 +6283,10 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(NATIVE_ARCH)"; - "ARCHS[sdk=iphoneos*]" = armv7; + "ARCHS[sdk=iphoneos*]" = ( + armv7, + arm64, + ); "ARCHS[sdk=macosx*]" = ( x86_64, i386, @@ -6256,6 +6315,7 @@ NO_XPC_SERVICES, ); GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + "GCC_WARN_64_TO_32_BIT_CONVERSION[arch=*64]" = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; @@ -6282,6 +6342,7 @@ "-flimit-debug-info", "-Wparentheses", ); + SDKROOT = ""; STRIP_INSTALLED_PRODUCT = NO; STRIP_STYLE = debugging; WARNING_CFLAGS = "-Wreorder"; diff --git a/lldb/scripts/Python/interface/SBProcess.i b/lldb/scripts/Python/interface/SBProcess.i index 7abbf919af25..d023b2472ccc 100644 --- a/lldb/scripts/Python/interface/SBProcess.i +++ b/lldb/scripts/Python/interface/SBProcess.i @@ -362,6 +362,9 @@ public: lldb::SBError UnloadImage (uint32_t image_token); + + lldb::SBError + SendEventData (const char *event_data); %feature("autodoc", " Return the number of different thread-origin extended backtraces diff --git a/lldb/scripts/Python/interface/SBTarget.i b/lldb/scripts/Python/interface/SBTarget.i index d26b3faacee2..87d5c5b13b0c 100644 --- a/lldb/scripts/Python/interface/SBTarget.i +++ b/lldb/scripts/Python/interface/SBTarget.i @@ -94,6 +94,13 @@ public: bool AddSuppressFileAction (int fd, bool read, bool write); + + void + SetLaunchEventData (const char *data); + + const char * + GetLaunchEventData () const; + }; class SBAttachInfo diff --git a/lldb/scripts/build-llvm.pl b/lldb/scripts/build-llvm.pl index 4f9a2bfd1a1c..1c7492470e45 100644 --- a/lldb/scripts/build-llvm.pl +++ b/lldb/scripts/build-llvm.pl @@ -75,6 +75,12 @@ our @archive_files = ( "$llvm_configuration/lib/libLLVMARMDesc.a", "$llvm_configuration/lib/libLLVMARMDisassembler.a", "$llvm_configuration/lib/libLLVMARMInfo.a", + "$llvm_configuration/lib/libLLVMARM64AsmParser.a", + "$llvm_configuration/lib/libLLVMARM64AsmPrinter.a", + "$llvm_configuration/lib/libLLVMARM64CodeGen.a", + "$llvm_configuration/lib/libLLVMARM64Desc.a", + "$llvm_configuration/lib/libLLVMARM64Disassembler.a", + "$llvm_configuration/lib/libLLVMARM64Info.a", "$llvm_configuration/lib/libLLVMAsmParser.a", "$llvm_configuration/lib/libLLVMAsmPrinter.a", "$llvm_configuration/lib/libLLVMBitReader.a", @@ -328,7 +334,7 @@ sub build_llvm { # Build llvm and clang print "Configuring clang ($arch) in '$llvm_dstroot_arch'...\n"; - my $lldb_configuration_options = "--enable-targets=x86_64,arm $common_configure_options $llvm_config_href->{configure_options}"; + my $lldb_configuration_options = "--enable-targets=x86_64,arm,arm64 $common_configure_options $llvm_config_href->{configure_options}"; # We're configuring llvm/clang with --enable-cxx11 and --enable-libcpp but llvm/configure doesn't # pick up the right C++ standard library. If we have a MACOSX_DEPLOYMENT_TARGET of 10.7 or 10.8 diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp index 47a6ee48cf3c..52de0cd4fe38 100644 --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -1306,6 +1306,32 @@ SBProcess::UnloadImage (uint32_t image_token) return sb_error; } +lldb::SBError +SBProcess::SendEventData (const char *event_data) +{ + lldb::SBError sb_error; + ProcessSP process_sp(GetSP()); + if (process_sp) + { + Process::StopLocker stop_locker; + if (stop_locker.TryLock(&process_sp->GetRunLock())) + { + Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); + sb_error.SetError (process_sp->SendEventData (event_data)); + } + else + { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + log->Printf ("SBProcess(%p)::SendEventData() => error: process is running", process_sp.get()); + sb_error.SetErrorString("process is running"); + } + } + else + sb_error.SetErrorString("invalid process"); + return sb_error; +} + uint32_t SBProcess::GetNumExtendedBacktraceTypes () { diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 224349c0bce6..9f006f51312d 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -268,6 +268,17 @@ SBLaunchInfo::AddSuppressFileAction (int fd, bool read, bool write) return m_opaque_sp->AppendSuppressFileAction(fd, read, write); } +void +SBLaunchInfo::SetLaunchEventData (const char *data) +{ + m_opaque_sp->SetLaunchEventData (data); +} + +const char * +SBLaunchInfo::GetLaunchEventData () const +{ + return m_opaque_sp->GetLaunchEventData (); +} SBAttachInfo::SBAttachInfo () : m_opaque_sp (new ProcessAttachInfo()) diff --git a/lldb/source/CMakeLists.txt b/lldb/source/CMakeLists.txt index 2ab37c9707b1..4e697eeba81a 100644 --- a/lldb/source/CMakeLists.txt +++ b/lldb/source/CMakeLists.txt @@ -74,9 +74,11 @@ set( LLDB_USED_LIBS lldbPluginAppleObjCRuntime lldbPluginCXXItaniumABI lldbPluginABIMacOSX_arm + lldbPluginABIMacOSX_arm64 lldbPluginABIMacOSX_i386 lldbPluginABISysV_x86_64 lldbPluginInstructionARM + lldbPluginInstructionARM64 lldbPluginObjectFilePECOFF lldbPluginOSPython ) diff --git a/lldb/source/Core/ArchSpec.cpp b/lldb/source/Core/ArchSpec.cpp index 4cf278948036..b1303462572d 100644 --- a/lldb/source/Core/ArchSpec.cpp +++ b/lldb/source/Core/ArchSpec.cpp @@ -76,6 +76,7 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] = { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7k , "thumbv7k" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7m , "thumbv7m" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7em , "thumbv7em" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::arm64 , ArchSpec::eCore_arm_arm64 , "arm64" }, { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" }, @@ -179,6 +180,10 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = { ArchSpec::eCore_arm_armv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 1 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 13 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumb , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, @@ -729,6 +734,7 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su switch (core_def->machine) { + case llvm::Triple::arm64: case llvm::Triple::arm: case llvm::Triple::thumb: m_triple.setOS (llvm::Triple::IOS); diff --git a/lldb/source/Core/Error.cpp b/lldb/source/Core/Error.cpp index 7aabe5b386d4..bbcf39d74389 100644 --- a/lldb/source/Core/Error.cpp +++ b/lldb/source/Core/Error.cpp @@ -21,7 +21,7 @@ #include #include -#if defined (__arm__) && defined (__APPLE__) +#if (defined (__arm__) || defined (__arm64__)) && defined (__APPLE__) #include #endif diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 0cc1bc8b777d..a6ffbd2b76aa 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -404,6 +404,7 @@ Module::GetClangASTContext () && object_arch.GetTriple().getOS() == llvm::Triple::UnknownOS) { if (object_arch.GetTriple().getArch() == llvm::Triple::arm || + object_arch.GetTriple().getArch() == llvm::Triple::arm64 || object_arch.GetTriple().getArch() == llvm::Triple::thumb) { object_arch.GetTriple().setOS(llvm::Triple::IOS); diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index 44f1e535ec7c..bde24691142d 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -156,11 +156,15 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_compiler->getTargetOpts().Features.push_back("+sse2"); } - if (m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) + // Any arm32 iOS environment, but not on arm64 + if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos + && m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) + { m_compiler->getTargetOpts().ABI = "apcs-gnu"; - + } + m_compiler->createDiagnostics(); - + // Create the target instance. m_compiler->setTarget(TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), &m_compiler->getTargetOpts())); diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 4eefddda41ae..e29995674df0 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -465,7 +465,7 @@ ClangUserExpression::Parse (Stream &error_stream, else lang_type = lldb::eLanguageTypeC; - if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method)) + if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method, exe_ctx)) { error_stream.PutCString ("error: couldn't construct expression body"); return false; diff --git a/lldb/source/Expression/ExpressionSourceCode.cpp b/lldb/source/Expression/ExpressionSourceCode.cpp index aef3b9e301e5..c79a2d795ce4 100644 --- a/lldb/source/Expression/ExpressionSourceCode.cpp +++ b/lldb/source/Expression/ExpressionSourceCode.cpp @@ -10,6 +10,9 @@ #include "lldb/Expression/ExpressionSourceCode.h" #include "lldb/Core/StreamString.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Target.h" using namespace lldb_private; @@ -25,7 +28,6 @@ ExpressionSourceCode::g_expression_prefix = R"( #define nil (__null) #define YES ((BOOL)1) #define NO ((BOOL)0) -typedef signed char BOOL; typedef signed __INT8_TYPE__ int8_t; typedef unsigned __INT8_TYPE__ uint8_t; typedef signed __INT16_TYPE__ int16_t; @@ -42,8 +44,29 @@ typedef unsigned short unichar; )"; -bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method) const +bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const { + const char *target_specific_defines = "typedef signed char BOOL;\n"; + static ConstString g_platform_ios_simulator ("PlatformiOSSimulator"); + + if (Target *target = exe_ctx.GetTargetPtr()) + { + if (target->GetArchitecture().GetMachine() == llvm::Triple::arm64) + { + target_specific_defines = "typedef bool BOOL;\n"; + } + if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) + { + if (lldb::PlatformSP platform_sp = target->GetPlatform()) + { + if (platform_sp->GetPluginName() == g_platform_ios_simulator) + { + target_specific_defines = "typedef bool BOOL;\n"; + } + } + } + } + if (m_wrap) { switch (wrapping_language) @@ -64,6 +87,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi break; case lldb::eLanguageTypeC: wrap_stream.Printf("%s \n" + "%s \n" "%s \n" "void \n" "%s(void *$__lldb_arg) \n" @@ -71,12 +95,14 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi " %s; \n" "} \n", g_expression_prefix, + target_specific_defines, m_prefix.c_str(), m_name.c_str(), m_body.c_str()); break; case lldb::eLanguageTypeC_plus_plus: wrap_stream.Printf("%s \n" + "%s \n" "%s \n" "void \n" "$__lldb_class::%s(void *$__lldb_arg) %s\n" @@ -84,6 +110,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi " %s; \n" "} \n", g_expression_prefix, + target_specific_defines, m_prefix.c_str(), m_name.c_str(), (const_object ? "const" : ""), @@ -93,6 +120,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi if (static_method) { wrap_stream.Printf("%s \n" + "%s \n" "%s \n" "@interface $__lldb_objc_class ($__lldb_category) \n" "+(void)%s:(void *)$__lldb_arg; \n" @@ -104,6 +132,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi "} \n" "@end \n", g_expression_prefix, + target_specific_defines, m_prefix.c_str(), m_name.c_str(), m_name.c_str(), @@ -112,6 +141,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi else { wrap_stream.Printf("%s \n" + "%s \n" "%s \n" "@interface $__lldb_objc_class ($__lldb_category) \n" "-(void)%s:(void *)$__lldb_arg; \n" @@ -123,6 +153,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi "} \n" "@end \n", g_expression_prefix, + target_specific_defines, m_prefix.c_str(), m_name.c_str(), m_name.c_str(), diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index e5a0f339e9d6..197be193e6bf 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -1067,7 +1067,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) if (framework_pos) { framework_pos += strlen("LLDB.framework"); -#if defined (__arm__) +#if defined (__arm__) || defined (__arm64__) // Shallow bundle *framework_pos = '\0'; #else @@ -1075,7 +1075,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path)); #endif } -#endif +#endif // #if defined (__APPLE__) FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); g_lldb_support_exe_dir.SetCString(resolved_path); } diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm index ef3ecfb0a9ca..b9d2419dcdfd 100644 --- a/lldb/source/Host/macosx/Host.mm +++ b/lldb/source/Host/macosx/Host.mm @@ -57,12 +57,13 @@ #include "cfcpp/CFCReleaser.h" #include "cfcpp/CFCString.h" + #include #include #include -#if !defined(__arm__) +#if !defined(__arm__) && !defined(__arm64__) #include #endif @@ -231,7 +232,7 @@ Host::ResolveExecutableInBundle (FileSpec &file) lldb::pid_t Host::LaunchApplication (const FileSpec &app_file_spec) { -#if defined (__arm__) +#if defined (__arm__) || defined(__arm64__) return LLDB_INVALID_PROCESS_ID; #else char app_path[PATH_MAX]; @@ -324,7 +325,7 @@ WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds) } return false; } -#if !defined(__arm__) +#if !defined(__arm__) && !defined(__arm64__) //static lldb::pid_t //LaunchInNewTerminalWithCommandFile @@ -731,7 +732,7 @@ Host::SetCrashDescription (const char *cstr) bool Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no) { -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) return false; #else // We attach this to an 'odoc' event to specify a particular selection @@ -1081,7 +1082,7 @@ GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info) mib[mib_len] = process_info.GetProcessID(); mib_len++; - + cpu_type_t cpu, sub = 0; size_t len = sizeof(cpu); if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0) @@ -1090,12 +1091,35 @@ GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info) { case CPU_TYPE_I386: sub = CPU_SUBTYPE_I386_ALL; break; case CPU_TYPE_X86_64: sub = CPU_SUBTYPE_X86_64_ALL; break; + +#if defined (CPU_TYPE_ARM64) && defined (CPU_SUBTYPE_ARM64_ALL) + case CPU_TYPE_ARM64: sub = CPU_SUBTYPE_ARM64_ALL; break; +#endif + case CPU_TYPE_ARM: { + // Note that we fetched the cpu type from the PROCESS but we can't get a cpusubtype of the + // process -- we can only get the host's cpu subtype. uint32_t cpusubtype = 0; len = sizeof(cpusubtype); if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) sub = cpusubtype; + + bool host_cpu_is_64bit; + uint32_t is64bit_capable; + size_t is64bit_capable_len = sizeof (is64bit_capable); + if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0) + host_cpu_is_64bit = true; + else + host_cpu_is_64bit = false; + + // if the host is an armv8 device, its cpusubtype will be in CPU_SUBTYPE_ARM64 numbering + // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value instead. + + if (host_cpu_is_64bit) + { + sub = CPU_SUBTYPE_ARM_V7; + } } break; @@ -1591,7 +1615,7 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)) { -#if !defined(__arm__) +#if !defined(__arm__) && !defined(__arm64__) return LaunchInNewTerminalWithAppleScript (exe_path, launch_info); #else error.SetErrorString ("launching a processs in a new terminal is not supported on iOS devices"); diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp index 935c9ffc945a..f7f74f34c1de 100644 --- a/lldb/source/Host/macosx/Symbols.cpp +++ b/lldb/source/Host/macosx/Symbols.cpp @@ -41,7 +41,7 @@ using namespace lldb; using namespace lldb_private; using namespace llvm::MachO; -#if !defined (__arm__) // No DebugSymbols on the iOS devices +#if !defined (__arm__) && !defined (__arm64__) // No DebugSymbols on the iOS devices extern "C" { CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url); @@ -293,7 +293,7 @@ LocateMacOSXFilesUsingDebugSymbols if (out_dsym_fspec) out_dsym_fspec->Clear(); -#if !defined (__arm__) // No DebugSymbols on the iOS devices +#if !defined (__arm__) && !defined (__arm64__) // No DebugSymbols on the iOS devices const UUID *uuid = module_spec.GetUUIDPtr(); const ArchSpec *arch = module_spec.GetArchitecturePtr(); diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 832ccbb06f37..18f108bb58ae 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -324,7 +324,7 @@ CommandInterpreter::Initialize () if (cmd_obj_sp) { alias_arguments_vector_sp.reset (new OptionArgVector); -#if defined (__arm__) +#if defined (__arm__) || defined (__arm64__) ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp); #else ProcessAliasOptionsArgs (cmd_obj_sp, "--shell=" LLDB_DEFAULT_SHELL " --", alias_arguments_vector_sp); diff --git a/lldb/source/Plugins/ABI/CMakeLists.txt b/lldb/source/Plugins/ABI/CMakeLists.txt index 5d4fb5ce3377..4ce15a11292a 100644 --- a/lldb/source/Plugins/ABI/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(SysV-x86_64) add_subdirectory(MacOSX-i386) add_subdirectory(MacOSX-arm) +add_subdirectory(MacOSX-arm64) diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp new file mode 100644 index 000000000000..1b6c7ef55ae7 --- /dev/null +++ b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -0,0 +1,1102 @@ +//===-- ABIMacOSX_arm64.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABIMacOSX_arm64.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + + +#include "llvm/ADT/Triple.h" + +#include "Utility/ARM64_DWARF_Registers.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +static const char *pluginDesc = "Mac OS X ABI for arm64 targets"; +static const char *pluginShort = "abi.macosx-arm64"; + + +static RegisterInfo g_register_infos[] = +{ + // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE + // ========== ======= == === ============= =================== =================== ====================== =========================== ======================= ====================== + { "x0", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x1", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x2", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x3", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x4", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x5", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x6", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x7", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x8", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x9", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x10", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x11", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x12", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x13", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x14", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x15", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x16", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x17", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x18", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x19", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x20", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x21", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x22", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x23", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x24", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x25", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x26", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x27", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "x28", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "fp", "x29", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "lr", "x30", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "sp", "x31", 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "pc", NULL, 8, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "cpsr", "psr", 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "v0", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v1", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v2", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v3", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v4", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v5", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v6", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v7", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v8", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v9", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v10", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v11", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v12", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v13", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v14", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v15", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v16", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v17", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v18", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v19", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v20", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v21", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v22", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v23", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v24", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v25", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v26", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v27", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v28", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v29", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v30", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "v31", NULL, 16, 0, eEncodingVector , eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "fpsr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "fpcr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "s0", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s1", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s2", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s3", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s4", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s5", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s6", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s7", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s8", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s9", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s10", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s11", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s12", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s13", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s14", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s15", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s16", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s17", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s18", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s19", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s20", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s21", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s22", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s23", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s24", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s25", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s26", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s27", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s28", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s29", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s30", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "s31", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + + { "d0", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d1", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d2", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d3", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d4", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d5", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d6", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d7", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d8", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d9", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d10", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d11", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d12", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d13", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d14", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d15", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d16", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d17", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d18", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d19", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d20", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d21", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d22", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d23", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d24", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d25", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d26", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d27", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d28", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d29", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d30", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }, + { "d31", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } +}; + +static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo); +static bool g_register_info_names_constified = false; + +const lldb_private::RegisterInfo * +ABIMacOSX_arm64::GetRegisterInfoArray (uint32_t &count) +{ + // Make the C-string names and alt_names for the register infos into const + // C-string values by having the ConstString unique the names in the global + // constant C-string pool. + if (!g_register_info_names_constified) + { + g_register_info_names_constified = true; + for (uint32_t i=0; i args) const +{ + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + StreamString s; + s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, + thread.GetID(), + (uint64_t)sp, + (uint64_t)func_addr, + (uint64_t)return_addr); + + for (int i = 0; i < args.size(); ++i) + s.Printf (", arg%d = 0x%" PRIx64, i + 1, args[i]); + s.PutCString (")"); + log->PutCString(s.GetString().c_str()); + } + + const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); + const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); + + // x0 - x7 contain first 8 simple args + if (args.size() > 8) // TODO handle more than 6 arguments + return false; + + for (int i = 0; i < args.size(); ++i) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); + if (log) + log->Printf("About to write arg%d (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) + return false; + } + + // Set "lr" to the return address + if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (ra_reg_num), return_addr)) + return false; + + // Set "sp" to the requested value + if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (sp_reg_num), sp)) + return false; + + // Set "pc" to the address requested + if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoAtIndex (pc_reg_num), func_addr)) + return false; + + return true; +} + + +bool +ABIMacOSX_arm64::GetArgumentValues (Thread &thread, ValueList &values) const +{ + uint32_t num_values = values.GetSize(); + + ExecutionContext exe_ctx (thread.shared_from_this()); + + // Extract the register context so we can read arguments from registers + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + + if (!reg_ctx) + return false; + + addr_t sp = 0; + + for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) + { + // We currently only support extracting values with Clang QualTypes. + // Do we care about others? + Value *value = values.GetValueAtIndex(value_idx); + + if (!value) + return false; + + ClangASTType value_type = value->GetClangType(); + if (value_type) + { + bool is_signed = false; + size_t bit_width = 0; + if (value_type.IsIntegerType (is_signed)) + { + bit_width = value_type.GetBitSize(); + } + else if (value_type.IsPointerOrReferenceType ()) + { + bit_width = value_type.GetBitSize(); + } + else + { + // We only handle integer, pointer and reference types currently... + return false; + } + + if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) + { + if (value_idx < 8) + { + // Arguments 1-6 are in x0-x5... + const RegisterInfo *reg_info = NULL; + // Search by generic ID first, then fall back to by name + uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx); + if (arg_reg_num != LLDB_INVALID_REGNUM) + { + reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num); + } + else + { + switch (value_idx) + { + case 0: reg_info = reg_ctx->GetRegisterInfoByName("x0"); break; + case 1: reg_info = reg_ctx->GetRegisterInfoByName("x1"); break; + case 2: reg_info = reg_ctx->GetRegisterInfoByName("x2"); break; + case 3: reg_info = reg_ctx->GetRegisterInfoByName("x3"); break; + case 4: reg_info = reg_ctx->GetRegisterInfoByName("x4"); break; + case 5: reg_info = reg_ctx->GetRegisterInfoByName("x5"); break; + case 6: reg_info = reg_ctx->GetRegisterInfoByName("x6"); break; + case 7: reg_info = reg_ctx->GetRegisterInfoByName("x7"); break; + } + } + + if (reg_info) + { + RegisterValue reg_value; + + if (reg_ctx->ReadRegister(reg_info, reg_value)) + { + if (is_signed) + reg_value.SignExtend(bit_width); + if (!reg_value.GetScalarValue(value->GetScalar())) + return false; + continue; + } + } + return false; + } + else + { + if (sp == 0) + { + // Read the stack pointer if we already haven't read it + sp = reg_ctx->GetSP(0); + if (sp == 0) + return false; + } + + // Arguments 5 on up are on the stack + const uint32_t arg_byte_size = (bit_width + (8-1)) / 8; + Error error; + if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(sp, arg_byte_size, is_signed, value->GetScalar(), error)) + return false; + + sp += arg_byte_size; + // Align up to the next 8 byte boundary if needed + if (sp % 8) + { + sp >>= 3; + sp += 1; + sp <<= 3; + } + } + } + } + } + return true; +} + +Error +ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) +{ + Error error; + if (!new_value_sp) + { + error.SetErrorString("Empty value object for return value."); + return error; + } + + ClangASTType return_value_type = new_value_sp->GetClangType(); + if (!return_value_type) + { + error.SetErrorString ("Null clang type for return value."); + return error; + } + + Thread *thread = frame_sp->GetThread().get(); + + RegisterContext *reg_ctx = thread->GetRegisterContext().get(); + + if (reg_ctx) + { + DataExtractor data; + Error data_error; + const uint64_t byte_size = new_value_sp->GetData(data, data_error); + if (data_error.Fail()) + { + error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); + return error; + } + + const uint32_t type_flags = return_value_type.GetTypeInfo (NULL); + if (type_flags & ClangASTType::eTypeIsScalar || + type_flags & ClangASTType::eTypeIsPointer) + { + if (type_flags & ClangASTType::eTypeIsInteger || + type_flags & ClangASTType::eTypeIsPointer ) + { + // Extract the register context so we can read arguments from registers + lldb::offset_t offset = 0; + if (byte_size <= 16) + { + const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0); + if (byte_size <= 8) + { + uint64_t raw_value = data.GetMaxU64(&offset, byte_size); + + if (!reg_ctx->WriteRegisterFromUnsigned (x0_info, raw_value)) + error.SetErrorString ("failed to write register x0"); + } + else + { + uint64_t raw_value = data.GetMaxU64(&offset, 8); + + if (reg_ctx->WriteRegisterFromUnsigned (x0_info, raw_value)) + { + const RegisterInfo *x1_info = reg_ctx->GetRegisterInfoByName("x1", 0); + raw_value = data.GetMaxU64(&offset, byte_size - offset); + + if (!reg_ctx->WriteRegisterFromUnsigned (x1_info, raw_value)) + error.SetErrorString ("failed to write register x1"); + } + } + } + else + { + error.SetErrorString("We don't support returning longer than 128 bit integer values at present."); + } + } + else if (type_flags & ClangASTType::eTypeIsFloat) + { + if (type_flags & ClangASTType::eTypeIsComplex) + { + // Don't handle complex yet. + error.SetErrorString ("returning complex float values are not supported"); + } + else + { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) + { + if (byte_size <= 16) + { + if (byte_size <= RegisterValue::GetMaxByteSize()) + { + RegisterValue reg_value; + error = reg_value.SetValueFromData (v0_info, data, 0, true); + if (error.Success()) + { + if (!reg_ctx->WriteRegister (v0_info, reg_value)) + error.SetErrorString ("failed to write register v0"); + } + } + else + { + error.SetErrorStringWithFormat ("returning float values with a byte size of %" PRIu64 " are not supported", byte_size); + } + } + else + { + error.SetErrorString("returning float values longer than 128 bits are not supported"); + } + } + else + { + error.SetErrorString("v0 register is not available on this target"); + } + } + } + } + else if (type_flags & ClangASTType::eTypeIsVector) + { + if (byte_size > 0) + { + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) + { + if (byte_size <= v0_info->byte_size) + { + RegisterValue reg_value; + error = reg_value.SetValueFromData (v0_info, data, 0, true); + if (error.Success()) + { + if (!reg_ctx->WriteRegister (v0_info, reg_value)) + error.SetErrorString ("failed to write register v0"); + } + } + } + } + } + } + else + { + error.SetErrorString("no registers are available"); + } + + return error; +} + +bool +ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t lr_reg_num = arm64_dwarf::lr; + uint32_t sp_reg_num = arm64_dwarf::sp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + + // Our previous Call Frame Address is the stack pointer + row->SetCFARegister (sp_reg_num); + + // Our previous PC is in the LR + row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); + + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("arm64 at-func-entry default"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + + return true; +} + +bool +ABIMacOSX_arm64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + uint32_t fp_reg_num = arm64_dwarf::fp; + uint32_t pc_reg_num = arm64_dwarf::pc; + + UnwindPlan::RowSP row(new UnwindPlan::Row); + const int32_t ptr_size = 8; + + row->SetCFARegister (fp_reg_num); + row->SetCFAOffset (2 * ptr_size); + row->SetOffset (0); + + row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); + row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); + + unwind_plan.AppendRow (row); + unwind_plan.SetSourceName ("arm64-apple-darwin default unwind plan"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + return true; +} + +// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says +// registers x19 through x28 and sp are callee preserved. +// v8-v15 are non-volatile (and specifically only the lower 8 bytes of these regs), +// the rest of the fp/SIMD registers are volatile. + +// We treat x29 as callee preserved also, else the unwinder won't try to +// retrieve fp saves. + +bool +ABIMacOSX_arm64::RegisterIsVolatile (const RegisterInfo *reg_info) +{ + if (reg_info) + { + const char *name = reg_info->name; + + // Sometimes we'll be called with the "alternate" name for these registers; + // recognize them as non-volatile. + + if (name[0] == 'p' && name[1] == 'c') // pc + return false; + if (name[0] == 'f' && name[1] == 'p') // fp + return false; + if (name[0] == 's' && name[1] == 'p') // sp + return false; + if (name[0] == 'l' && name[1] == 'r') // lr + return false; + + if (name[0] == 'x') + { + // Volatile registers: x0-x18, x30 (lr) + // Return false for the non-volatile gpr regs, true for everything else + switch (name[1]) + { + case '1': + switch (name[2]) + { + case '9': + return false; // x19 is non-volatile + default: + return true; + } + break; + case '2': + switch (name[2]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + return false; // x20 - 28 are non-volatile + case '9': + return false; // x29 aka fp treat as non-volatile on Darwin + default: + return true; + } + case '3': // x30 aka lr treat as non-volatile + if (name[2] == '0') + return false; + default: + return true; + } + } + else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') + { + // Volatile registers: v0-7, v16-v31 + // Return false for non-volatile fp/SIMD regs, true for everything else + switch (name[1]) + { + case '8': + case '9': + return false; // v8-v9 are non-volatile + case '1': + switch (name[2]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + return false; // v10-v15 are non-volatile + default: + return true; + } + default: + return true; + } + } + } + return true; +} + +static bool +LoadValueFromConsecutiveGPRRegisters (ExecutionContext &exe_ctx, + RegisterContext *reg_ctx, + const ClangASTType &value_type, + bool is_return_value, // false => parameter, true => return value + uint32_t &NGRN, // NGRN (see ABI documentation) + uint32_t &NSRN, // NSRN (see ABI documentation) + DataExtractor &data) +{ + const size_t byte_size = value_type.GetByteSize(); + + if (byte_size == 0) + return false; + + std::unique_ptr heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + Error error; + + ClangASTType base_type; + const uint32_t homogeneous_count = value_type.IsHomogeneousAggregate (&base_type); + if (homogeneous_count > 0 && homogeneous_count <= 8) + { + printf ("ClangASTContext::IsHomogeneousAggregate() => %u\n", homogeneous_count); + // Make sure we have enough registers + if (NSRN < 8 && (8-NSRN) >= homogeneous_count) + { + if (!base_type) + return false; + const size_t base_byte_size = base_type.GetByteSize(); + printf ("ClangASTContext::IsHomogeneousAggregate() => base_byte_size = %" PRIu64 "\n", (uint64_t) base_byte_size); + uint32_t data_offset = 0; + + for (uint32_t i=0; iGetRegisterInfoByName(v_name, 0); + if (reg_info == NULL) + return false; + + if (base_byte_size > reg_info->byte_size) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + // Make sure we have enough room in "heap_data_ap" + if ((data_offset + base_byte_size) <= heap_data_ap->GetByteSize()) + { + const size_t bytes_copied = reg_value.GetAsMemoryData (reg_info, + heap_data_ap->GetBytes()+data_offset, + base_byte_size, + byte_order, + error); + if (bytes_copied != base_byte_size) + return false; + data_offset += bytes_copied; + ++NSRN; + } + else + return false; + } + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP (heap_data_ap.release())); + return true; + } + } + + const size_t max_reg_byte_size = 16; + if (byte_size <= max_reg_byte_size) + { + size_t bytes_left = byte_size; + uint32_t data_offset = 0; + while (data_offset < byte_size) + { + if (NGRN >= 8) + return false; + + uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_info == NULL) + return false; + + RegisterValue reg_value; + + if (!reg_ctx->ReadRegister(reg_info, reg_value)) + return false; + + const size_t curr_byte_size = std::min(8,bytes_left); + const size_t bytes_copied = reg_value.GetAsMemoryData (reg_info, heap_data_ap->GetBytes()+data_offset, curr_byte_size, byte_order, error); + if (bytes_copied == 0) + return false; + if (bytes_copied >= bytes_left) + break; + data_offset += bytes_copied; + bytes_left -= bytes_copied; + ++NGRN; + } + } + else + { + const RegisterInfo *reg_info = NULL; + if (is_return_value) + { + // We are assumging we are decoding this immediately after returning + // from a function call and that the address of the structure is in x8 + reg_info = reg_ctx->GetRegisterInfoByName("x8", 0); + } + else + { + // We are assuming we are stopped at the first instruction in a function + // and that the ABI is being respected so all paramters appear where they + // should be (functions with no external linkage can legally violate the ABI). + if (NGRN >= 8) + return false; + + uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_info == NULL) + return false; + ++NGRN; + } + + if (reg_info == NULL) + return false; + + const lldb::addr_t value_addr = reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS); + + if (value_addr == LLDB_INVALID_ADDRESS) + return false; + + if (exe_ctx.GetProcessRef().ReadMemory (value_addr, + heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), + error) != heap_data_ap->GetByteSize()) + { + return false; + } + } + + data.SetByteOrder(byte_order); + data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize()); + data.SetData(DataBufferSP (heap_data_ap.release())); + return true; +} + +ValueObjectSP +ABIMacOSX_arm64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const +{ + ValueObjectSP return_valobj_sp; + Value value; + + ExecutionContext exe_ctx (thread.shared_from_this()); + if (exe_ctx.GetTargetPtr() == NULL || exe_ctx.GetProcessPtr() == NULL) + return return_valobj_sp; + + //value.SetContext (Value::eContextTypeClangType, return_clang_type); + value.SetClangType(return_clang_type); + + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return return_valobj_sp; + + const size_t byte_size = return_clang_type.GetByteSize(); + + const uint32_t type_flags = return_clang_type.GetTypeInfo (NULL); + if (type_flags & ClangASTType::eTypeIsScalar || + type_flags & ClangASTType::eTypeIsPointer) + { + value.SetValueType(Value::eValueTypeScalar); + + bool success = false; + if (type_flags & ClangASTType::eTypeIsInteger || + type_flags & ClangASTType::eTypeIsPointer ) + { + // Extract the register context so we can read arguments from registers + if (byte_size <= 8) + { + const RegisterInfo *x0_reg_info = reg_ctx->GetRegisterInfoByName("x0", 0); + if (x0_reg_info) + { + uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info, 0); + const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0; + switch (byte_size) + { + default: + break; + case 16: // uint128_t + // In register x0 and x1 + { + const RegisterInfo *x1_reg_info = reg_ctx->GetRegisterInfoByName("x1", 0); + + if (x1_reg_info) + { + if (byte_size <= x0_reg_info->byte_size + x1_reg_info->byte_size) + { + std::unique_ptr heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue x0_reg_value; + RegisterValue x1_reg_value; + if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) && + reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) + { + Error error; + if (x0_reg_value.GetAsMemoryData (x0_reg_info, heap_data_ap->GetBytes()+0, 8, byte_order, error) && + x1_reg_value.GetAsMemoryData (x1_reg_info, heap_data_ap->GetBytes()+8, 8, byte_order, error)) + { + DataExtractor data (DataBufferSP (heap_data_ap.release()), + byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + return return_valobj_sp; + } + } + } + } + } + break; + case sizeof(uint64_t): + if (is_signed) + value.GetScalar() = (int64_t)(raw_value); + else + value.GetScalar() = (uint64_t)(raw_value); + success = true; + break; + + case sizeof(uint32_t): + if (is_signed) + value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); + else + value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); + success = true; + break; + + case sizeof(uint16_t): + if (is_signed) + value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); + else + value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); + success = true; + break; + + case sizeof(uint8_t): + if (is_signed) + value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); + else + value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); + success = true; + break; + } + } + } + } + else if (type_flags & ClangASTType::eTypeIsFloat) + { + if (type_flags & ClangASTType::eTypeIsComplex) + { + // Don't handle complex yet. + } + else + { + if (byte_size <= sizeof(long double)) + { + const RegisterInfo *v0_reg_info = reg_ctx->GetRegisterInfoByName("v0", 0); + RegisterValue v0_value; + if (reg_ctx->ReadRegister (v0_reg_info, v0_value)) + { + DataExtractor data; + if (v0_value.GetData(data)) + { + lldb::offset_t offset = 0; + if (byte_size == sizeof(float)) + { + value.GetScalar() = data.GetFloat(&offset); + success = true; + } + else if (byte_size == sizeof(double)) + { + value.GetScalar() = data.GetDouble(&offset); + success = true; + } + else if (byte_size == sizeof(long double)) + { + value.GetScalar() = data.GetLongDouble(&offset); + success = true; + } + } + } + } + } + } + + if (success) + return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), + value, + ConstString("")); + + } + else if (type_flags & ClangASTType::eTypeIsVector) + { + if (byte_size > 0) + { + + const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); + + if (v0_info) + { + if (byte_size <= v0_info->byte_size) + { + std::unique_ptr heap_data_ap (new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(v0_info, reg_value)) + { + Error error; + if (reg_value.GetAsMemoryData (v0_info, + heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), + byte_order, + error)) + { + DataExtractor data (DataBufferSP (heap_data_ap.release()), + byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + } + } + } + } + } + } + else if (type_flags & ClangASTType::eTypeIsStructUnion || + type_flags & ClangASTType::eTypeIsClass) + { + DataExtractor data; + + uint32_t NGRN = 0; // Search ABI docs for NGRN + uint32_t NSRN = 0; // Search ABI docs for NSRN + const bool is_return_value = true; + if (LoadValueFromConsecutiveGPRRegisters (exe_ctx, reg_ctx, return_clang_type, is_return_value, NGRN, NSRN, data)) + { + return_valobj_sp = ValueObjectConstResult::Create (&thread, + return_clang_type, + ConstString(""), + data); + } + } + return return_valobj_sp; +} + +void +ABIMacOSX_arm64::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + pluginDesc, + CreateInstance); +} + +void +ABIMacOSX_arm64::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +ConstString +ABIMacOSX_arm64::GetPluginNameStatic() +{ + static ConstString g_plugin_name("ABIMacOSX_arm64"); + return g_plugin_name; +} + +const char * +ABIMacOSX_arm64::GetShortPluginName() +{ + return pluginShort; +} + +uint32_t +ABIMacOSX_arm64::GetPluginVersion() +{ + return 1; +} + diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h new file mode 100644 index 000000000000..0753b23ce2a2 --- /dev/null +++ b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h @@ -0,0 +1,145 @@ +//===-- ABIMacOSX_arm64.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_ABIMacOSX_arm64_h_ +#define liblldb_ABIMacOSX_arm64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Target/ABI.h" + +class ABIMacOSX_arm64 : + public lldb_private::ABI +{ +public: + ~ABIMacOSX_arm64() { } + + virtual size_t + GetRedZoneSize () const; + + virtual bool + PrepareTrivialCall (lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const; + + virtual bool + GetArgumentValues (lldb_private::Thread &thread, + lldb_private::ValueList &values) const; + + virtual bool + CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan); + + virtual bool + RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info); + + + virtual bool + StackUsesFrames () + { + // MacOSX uses frame pointers. + return true; + } + + // The arm64 ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + + virtual bool + CallFrameAddressIsValid (lldb::addr_t cfa) + { + // Make sure the stack call frame addresses are are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + virtual bool + CodeAddressIsValid (lldb::addr_t pc) + { + if (pc & (4ull - 1ull)) + return false; // Not 4 byte aligned + + // Anything else if fair game.. + return true; + } + + virtual bool + FunctionCallsChangeCFA () + { + return false; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray (uint32_t &count); + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb::ABISP + CreateInstance (const lldb_private::ArchSpec &arch); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + static lldb_private::ConstString + GetPluginNameStatic(); + + virtual lldb_private::ConstString + GetPluginName() + { + return GetPluginNameStatic(); + } + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual lldb_private::Error + SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value); + +protected: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl (lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type) const; + +private: + ABIMacOSX_arm64() : + lldb_private::ABI() + { + // Call CreateInstance instead. + } +}; + +#endif // liblldb_ABI_h_ diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt b/lldb/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt new file mode 100644 index 000000000000..35dc034a547a --- /dev/null +++ b/lldb/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginABIMacOSX_arm64 + ABIMacOSX_arm64.cpp + ) diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/Makefile b/lldb/source/Plugins/ABI/MacOSX-arm64/Makefile new file mode 100644 index 000000000000..7fc6909e43cc --- /dev/null +++ b/lldb/source/Plugins/ABI/MacOSX-arm64/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/ABI/MacOSX-arm64/Makefile ------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginABIMacOSX_arm64 +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index 5c279c91613c..d9f06a4bc460 100644 --- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -735,7 +735,7 @@ void DisassemblerLLVMC::Initialize() { PluginManager::RegisterPlugin (GetPluginNameStatic(), - "Disassembler that uses LLVM MC to disassemble i386, x86_64 and ARM.", + "Disassembler that uses LLVM MC to disassemble i386, x86_64, ARM, and ARM64.", CreateInstance); llvm::InitializeAllTargetInfos(); diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index 30ba80c0ba34..f475dbd773db 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -328,7 +328,7 @@ DynamicLoaderMacOSXDYLD::LocateDYLD() { return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x7fff5fc00000ull); } - else if (exe_arch.GetMachine() == llvm::Triple::arm || exe_arch.GetMachine() == llvm::Triple::thumb) + else if (exe_arch.GetMachine() == llvm::Triple::arm || exe_arch.GetMachine() == llvm::Triple::thumb || exe_arch.GetMachine() == llvm::Triple::arm64) { return ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x2fe00000); } diff --git a/lldb/source/Plugins/Instruction/ARM64/CMakeLists.txt b/lldb/source/Plugins/Instruction/ARM64/CMakeLists.txt new file mode 100644 index 000000000000..03031bf5dc89 --- /dev/null +++ b/lldb/source/Plugins/Instruction/ARM64/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginInstructionARM64 + EmulateInstructionARM64.cpp + ) diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp new file mode 100644 index 000000000000..9cc1cc5ec1ff --- /dev/null +++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -0,0 +1,722 @@ +//===-- EmulateInstructionARM64.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "EmulateInstructionARM64.h" + +#include + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/UnwindPlan.h" + +#include "Plugins/Process/Utility/ARMDefines.h" +#include "Plugins/Process/Utility/ARMUtils.h" +#include "Utility/ARM64_DWARF_Registers.h" + +#include "llvm/Support/MathExtras.h" // for SignExtend32 template function + // and CountTrailingZeros_32 function + +#include "Plugins/Process/Utility/InstructionUtils.h" + +using namespace lldb; +using namespace lldb_private; + +#define No_VFP 0 +#define VFPv1 (1u << 1) +#define VFPv2 (1u << 2) +#define VFPv3 (1u << 3) +#define AdvancedSIMD (1u << 4) + +#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD) +#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD) +#define VFPv2v3 (VFPv2 | VFPv3) + +#define UInt(x) ((uint64_t)x) +#define SInt(x) ((int64_t)x) +#define bit bool +#define boolean bool +#define integer int64_t + +static inline bool +IsZero(uint64_t x) +{ + return x == 0; +} + +static inline uint64_t +NOT(uint64_t x) +{ + return ~x; +} + + +static inline int64_t +SignExtend64(uint64_t x, uint32_t msbit) +{ + return int64_t(x << (64 - msbit)) >> (64 - msbit); +} + + +// LSL_C() +// ======= +static inline uint64_t +LSL_C (uint64_t x, integer shift, bool &carry_out) +{ + assert (shift >= 0); + uint64_t result = x << shift; + carry_out = ((1ull << (64-1)) >> (shift - 1)) != 0; + return result; +} + +// LSL() +// ===== + +static inline uint64_t +LSL(uint64_t x, integer shift) +{ + if (shift == 0) + return x; + return x << shift; +} + +// AddWithCarry() +// =============== +static inline uint64_t +AddWithCarry (uint32_t N, uint64_t x, uint64_t y, bit carry_in, EmulateInstructionARM64::ProcState &proc_state) +{ + uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in); + int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in); + uint64_t result = unsigned_sum; + if (N < 64) + result = Bits64 (result, N-1, 0); + proc_state.N = Bit64(result, N-1); + proc_state.Z = IsZero(result); + proc_state.C = UInt(result) == unsigned_sum; + proc_state.V = SInt(result) == signed_sum; + return result; +} + +// ConstrainUnpredictable() +// ======================== + +EmulateInstructionARM64::ConstraintType +ConstrainUnpredictable (EmulateInstructionARM64::Unpredictable which) +{ + EmulateInstructionARM64::ConstraintType result = EmulateInstructionARM64::Constraint_UNKNOWN; + switch (which) + { + case EmulateInstructionARM64::Unpredictable_WBOVERLAP: + case EmulateInstructionARM64::Unpredictable_LDPOVERLAP: + // TODO: don't know what to really do here? Pseudo code says: + // set result to one of above Constraint behaviours or UNDEFINED + break; + } + return result; +} + + + +//---------------------------------------------------------------------- +// +// EmulateInstructionARM implementation +// +//---------------------------------------------------------------------- + +void +EmulateInstructionARM64::Initialize () +{ + PluginManager::RegisterPlugin (GetPluginNameStatic (), + GetPluginDescriptionStatic (), + CreateInstance); +} + +void +EmulateInstructionARM64::Terminate () +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +ConstString +EmulateInstructionARM64::GetPluginNameStatic () +{ + ConstString g_plugin_name ("lldb.emulate-instruction.arm64"); + return g_plugin_name; +} + +lldb_private::ConstString +EmulateInstructionARM64::GetPluginName() +{ + static ConstString g_plugin_name ("EmulateInstructionARM64"); + return g_plugin_name; +} + +const char * +EmulateInstructionARM64::GetPluginDescriptionStatic () +{ + return "Emulate instructions for the ARM64 architecture."; +} + +EmulateInstruction * +EmulateInstructionARM64::CreateInstance (const ArchSpec &arch, InstructionType inst_type) +{ + if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(inst_type)) + { + if (arch.GetTriple().getArch() == llvm::Triple::arm64) + { + std::auto_ptr emulate_insn_ap (new EmulateInstructionARM64 (arch)); + if (emulate_insn_ap.get()) + return emulate_insn_ap.release(); + } + } + + return NULL; +} + +bool +EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch) +{ + if (arch.GetTriple().getArch () == llvm::Triple::arm) + return true; + else if (arch.GetTriple().getArch () == llvm::Triple::thumb) + return true; + + return false; +} + +bool +EmulateInstructionARM64::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo ®_info) +{ + if (reg_kind == eRegisterKindGeneric) + { + switch (reg_num) + { + case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::pc; break; + case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::sp; break; + case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::fp; break; + case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = arm64_dwarf::lr; break; + case LLDB_REGNUM_GENERIC_FLAGS: + // There is no DWARF register number for the CPSR right now... + reg_info.name = "cpsr"; + reg_info.alt_name = NULL; + reg_info.byte_size = 4; + reg_info.byte_offset = 0; + reg_info.encoding = eEncodingUint; + reg_info.format = eFormatHex; + for (uint32_t i=0; i, , # {, }" }, + { 0xff000000, 0xf1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS , , # {, }" }, + { 0xff000000, 0x91000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD , , # {, }" }, + { 0xff000000, 0xb1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS , , # {, }" }, + + + { 0xff000000, 0x51000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB , , # {, }" }, + { 0xff000000, 0x71000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS , , # {, }" }, + { 0xff000000, 0x11000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD , , # {, }" }, + { 0xff000000, 0x31000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS , , # {, }" }, + + { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP , , [{, #}]" }, + { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP , , [{, #}]" }, + { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP , , [{, #}]" }, + { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP
, , [{, #}]" }, + { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP , , [{, #}]" }, + + { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP , , [, #]!" }, + { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP , , [, #]!" }, + { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP , , [, #]!" }, + { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP
, , [, #]!" }, + { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP , , [, #]!" }, + + }; + static const size_t k_num_arm_opcodes = sizeof(g_opcodes)/sizeof(EmulateInstructionARM64::Opcode); + + for (size_t i=0; iname); + const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; + m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions; + + bool success = false; +// if (m_opcode_cpsr == 0 || m_ignore_conditions == false) +// { +// m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, // use eRegisterKindDWARF is we ever get a cpsr DWARF register number +// LLDB_REGNUM_GENERIC_FLAGS, // use arm64_dwarf::cpsr if we ever get one +// 0, +// &success); +// } + + // Only return false if we are unable to read the CPSR if we care about conditions + if (success == false && m_ignore_conditions == false) + return false; + + uint32_t orig_pc_value = 0; + if (auto_advance_pc) + { + orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success); + if (!success) + return false; + } + + // Call the Emulate... function. + success = (this->*opcode_data->callback) (opcode); + if (!success) + return false; + + if (auto_advance_pc) + { + uint32_t new_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::pc, 0, &success); + if (!success) + return false; + + if (auto_advance_pc && (new_pc_value == orig_pc_value)) + { + EmulateInstruction::Context context; + context.type = eContextAdvancePC; + context.SetNoArgs(); + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::pc, orig_pc_value + 4)) + return false; + } + } + return true; +} + +bool +EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) +{ + unwind_plan.Clear(); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + UnwindPlan::RowSP row(new UnwindPlan::Row); + const bool can_replace = false; + + // Our previous Call Frame Address is the stack pointer + row->SetCFARegister (arm64_dwarf::sp); + + // Our previous PC is in the LR + row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace); + + unwind_plan.AppendRow (row); + + // All other registers are the same. + + unwind_plan.SetSourceName ("EmulateInstructionARM64"); + return true; +} + + + +bool +EmulateInstructionARM64::Emulate_addsub_imm (const uint32_t opcode) +{ + // integer d = UInt(Rd); + // integer n = UInt(Rn); + // integer datasize = if sf == 1 then 64 else 32; + // boolean sub_op = (op == 1); + // boolean setflags = (S == 1); + // bits(datasize) imm; + // + // case shift of + // when '00' imm = ZeroExtend(imm12, datasize); + // when '01' imm = ZeroExtend(imm12 : Zeros(12), datasize); + // when '1x' UNDEFINED; + // + // + // bits(datasize) result; + // bits(datasize) operand1 = if n == 31 then SP[] else X[n]; + // bits(datasize) operand2 = imm; + // bits(4) nzcv; + // bit carry_in; + // + // if sub_op then + // operand2 = NOT(operand2); + // carry_in = 1; + // else + // carry_in = 0; + // + // (result, nzcv) = AddWithCarry(operand1, operand2, carry_in); + // + // if setflags then + // PSTATE.NZCV = nzcv; + // + // if d == 31 && !setflags then + // SP[] = result; + // else + // X[d] = result; + + const uint32_t sf = Bit32(opcode, 31); + const uint32_t op = Bit32(opcode, 30); + const uint32_t S = Bit32(opcode, 29); + const uint32_t shift = Bits32(opcode, 23, 22); + const uint32_t imm12 = Bits32(opcode, 21, 10); + const uint32_t Rn = Bits32(opcode, 9, 5); + const uint32_t Rd = Bits32(opcode, 4, 0); + + bool success = false; + + const uint32_t d = UInt(Rd); + const uint32_t n = UInt(Rn); + const uint32_t datasize = (sf == 1) ? 64 : 32; + boolean sub_op = op == 1; + boolean setflags = S == 1; + uint64_t imm; + + switch (shift) + { + case 0: imm = imm12; break; + case 1: imm = imm12 << 12; break; + default: return false; // UNDEFINED; + } + uint64_t result; + uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success); + uint64_t operand2 = imm; + bit carry_in; + + if (sub_op) + { + operand2 = NOT(operand2); + carry_in = 1; + imm = -imm; // For the Register plug offset context below + } + else + { + carry_in = 0; + } + + ProcState proc_state; + + result = AddWithCarry (datasize, operand1, operand2, carry_in, proc_state); + + if (setflags) + { + m_emulated_pstate.N = proc_state.N; + m_emulated_pstate.Z = proc_state.Z; + m_emulated_pstate.C = proc_state.C; + m_emulated_pstate.V = proc_state.V; + } + + Context context; + RegisterInfo reg_info_Rn; + if (arm64_dwarf::GetRegisterInfo (n, reg_info_Rn)) + context.SetRegisterPlusOffset (reg_info_Rn, imm); + + if ((n == arm64_dwarf::sp || n == arm64_dwarf::fp) && + d == arm64_dwarf::sp && + !setflags) + { + context.type = EmulateInstruction::eContextAdjustStackPointer; + } + else if (d == arm64_dwarf::fp && + n == arm64_dwarf::sp && + !setflags) + { + context.type = EmulateInstruction::eContextSetFramePointer; + } + else + { + context.type = EmulateInstruction::eContextImmediate; + } + WriteRegisterUnsigned (context, eRegisterKindDWARF, arm64_dwarf::x0 + d, result); + + return false; +} + +bool +EmulateInstructionARM64::Emulate_ldstpair_off (const uint32_t opcode) +{ + return Emulate_ldstpair (opcode, AddrMode_OFF); +} + + +bool +EmulateInstructionARM64::Emulate_ldstpair_pre (const uint32_t opcode) +{ + return Emulate_ldstpair (opcode, AddrMode_PRE); +} + +bool +EmulateInstructionARM64::Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode) +{ + uint32_t opc = Bits32(opcode, 31, 30); + uint32_t V = Bit32(opcode, 26); + uint32_t L = Bit32(opcode, 22); + uint32_t imm7 = Bits32(opcode, 21, 15); + uint32_t Rt2 = Bits32(opcode, 14, 10); + uint32_t Rn = Bits32(opcode, 9, 5); + uint32_t Rt = Bits32(opcode, 4, 0); + + integer n = UInt(Rn); + integer t = UInt(Rt); + integer t2 = UInt(Rt2); + uint64_t idx; + + MemOp memop = L == 1 ? MemOp_LOAD : MemOp_STORE; + boolean vector = (V == 1); + //AccType acctype = AccType_NORMAL; + boolean is_signed = false; + boolean wback = a_mode != AddrMode_OFF; + boolean wb_unknown = false; + boolean rt_unknown = false; + integer scale; + integer size; + + if (opc == 3) + return false; // UNDEFINED + + if (vector) + { + scale = 2 + UInt(opc); + } + else + { + scale = (opc & 2) ? 3 : 2; + is_signed = (opc & 1) != 0; + if (is_signed && memop == MemOp_STORE) + return false; // UNDEFINED + } + + if (!vector && wback && ((t == n) || (t2 == n))) + { + switch (ConstrainUnpredictable(Unpredictable_WBOVERLAP)) + { + case Constraint_UNKNOWN: + wb_unknown = true; // writeback is UNKNOWN + break; + + case Constraint_SUPPRESSWB: + wback = false; // writeback is suppressed + break; + + case Constraint_NOP: + memop = MemOp_NOP; // do nothing + wback = false; + break; + + case Constraint_NONE: + break; + } + } + + if (memop == MemOp_LOAD && t == t2) + { + switch (ConstrainUnpredictable(Unpredictable_LDPOVERLAP)) + { + case Constraint_UNKNOWN: + rt_unknown = true; // result is UNKNOWN + break; + + case Constraint_NOP: + memop = MemOp_NOP; // do nothing + wback = false; + break; + + default: + break; + } + } + + idx = LSL(llvm::SignExtend64<7>(imm7), scale); + size = 1 << scale; + uint64_t datasize = size * 8; + uint64_t address; + uint64_t wb_address; + + RegisterValue data_Rt; + RegisterValue data_Rt2; + + // if (vector) + // CheckFPEnabled(false); + + RegisterInfo reg_info_base; + RegisterInfo reg_info_Rt; + RegisterInfo reg_info_Rt2; + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + n, reg_info_base)) + return false; + + if (vector) + { + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt)) + return false; + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::v0 + n, reg_info_Rt2)) + return false; + } + else + { + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t, reg_info_Rt)) + return false; + if (!GetRegisterInfo (eRegisterKindDWARF, arm64_dwarf::x0 + t2, reg_info_Rt2)) + return false; + } + + bool success = false; + if (n == 31) + { + //CheckSPAlignment(); + address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::sp, 0, &success); + } + else + address = ReadRegisterUnsigned (eRegisterKindDWARF, arm64_dwarf::x0 + n, 0, &success); + + wb_address = address + idx; + if (a_mode != AddrMode_POST) + address = wb_address; + + Context context_t; + Context context_t2; + + if (n == 31 || n == 29) // if this store is based off of the sp or fp register + { + context_t.type = eContextPushRegisterOnStack; + context_t2.type = eContextPushRegisterOnStack; + } + else + { + context_t.type = eContextRegisterPlusOffset; + context_t2.type = eContextRegisterPlusOffset; + } + context_t.SetRegisterToRegisterPlusOffset (reg_info_Rt, reg_info_base, 0); + context_t2.SetRegisterToRegisterPlusOffset (reg_info_Rt2, reg_info_base, size); + uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; + Error error; + + switch (memop) + { + case MemOp_STORE: + { + if (!ReadRegister (®_info_Rt, data_Rt)) + return false; + + if (data_Rt.GetAsMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt.byte_size)) + return false; + + if (!ReadRegister (®_info_Rt2, data_Rt2)) + return false; + + if (data_Rt2.GetAsMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!WriteMemory(context_t2, address + size, buffer, reg_info_Rt2.byte_size)) + return false; + } + break; + + case MemOp_LOAD: + { + if (rt_unknown) + memset (buffer, 'U', reg_info_Rt.byte_size); + else + { + if (!ReadMemory (context_t, address, buffer, reg_info_Rt.byte_size)) + return false; + } + + if (data_Rt.SetFromMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!vector && is_signed && !data_Rt.SignExtend (datasize)) + return false; + + if (!WriteRegister (context_t, ®_info_Rt, data_Rt)) + return false; + + if (!rt_unknown) + { + if (!ReadMemory (context_t2, address + size, buffer, reg_info_Rt2.byte_size)) + return false; + } + + if (data_Rt2.SetFromMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0) + return false; + + if (!vector && is_signed && !data_Rt2.SignExtend (datasize)) + return false; + + if (!WriteRegister (context_t2, ®_info_Rt2, data_Rt2)) + return false; + } + break; + + default: + break; + } + + if (wback) + { + if (wb_unknown) + wb_address = LLDB_INVALID_ADDRESS; + Context context; + context.SetImmediateSigned (idx); + if (n == 31) + context.type = eContextAdjustStackPointer; + else + context.type = eContextAdjustBaseRegister; + WriteRegisterUnsigned (context, ®_info_base, wb_address); + } + return true; +} diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h new file mode 100644 index 000000000000..333e0a9dba57 --- /dev/null +++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h @@ -0,0 +1,300 @@ +//===-- EmulateInstructionARM64.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef EmulateInstructionARM64_h_ +#define EmulateInstructionARM64_h_ + +#include "lldb/Core/EmulateInstruction.h" +#include "lldb/Core/Error.h" +#include "lldb/Interpreter/OptionValue.h" +#include "Plugins/Process/Utility/ARMDefines.h" + +class EmulateInstructionARM64 : public lldb_private::EmulateInstruction +{ +public: + static void + Initialize (); + + static void + Terminate (); + + static lldb_private::ConstString + GetPluginNameStatic (); + + static const char * + GetPluginDescriptionStatic (); + + static lldb_private::EmulateInstruction * + CreateInstance (const lldb_private::ArchSpec &arch, + lldb_private::InstructionType inst_type); + + static bool + SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type) + { + switch (inst_type) + { + case lldb_private::eInstructionTypeAny: + case lldb_private::eInstructionTypePrologueEpilogue: + return true; + + case lldb_private::eInstructionTypePCModifying: + case lldb_private::eInstructionTypeAll: + return false; + + default: + break; + } + return false; + } + + virtual lldb_private::ConstString + GetPluginName(); + + virtual lldb_private::ConstString + GetShortPluginName() + { + return GetPluginNameStatic(); + } + + virtual uint32_t + GetPluginVersion() + { + return 1; + } + + bool + SetTargetTriple (const lldb_private::ArchSpec &arch); + + EmulateInstructionARM64 (const lldb_private::ArchSpec &arch) : + EmulateInstruction (arch), + m_opcode_pstate (), + m_emulated_pstate (), + m_ignore_conditions (false) + { + } + + virtual bool + SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type) + { + return SupportsEmulatingInstructionsOfTypeStatic (inst_type); + } + + virtual bool + ReadInstruction (); + + virtual bool + EvaluateInstruction (uint32_t evaluate_options); + + virtual bool + TestEmulation (lldb_private::Stream *out_stream, + lldb_private::ArchSpec &arch, + lldb_private::OptionValueDictionary *test_data) + { + return false; + } + + virtual bool + GetRegisterInfo (uint32_t reg_kind, + uint32_t reg_num, + lldb_private::RegisterInfo ®_info); + + virtual bool + CreateFunctionEntryUnwind (lldb_private::UnwindPlan &unwind_plan); + + + typedef enum + { + AddrMode_OFF, + AddrMode_PRE, + AddrMode_POST + } AddrMode; + + typedef enum + { + BranchType_CALL, + BranchType_ERET, + BranchType_DRET, + BranchType_RET, + BranchType_JMP + } BranchType; + + typedef enum + { + CountOp_CLZ, + CountOp_CLS, + CountOp_CNT + } CountOp; + + typedef enum + { + RevOp_RBIT, + RevOp_REV16, + RevOp_REV32, + RevOp_REV64 + } RevOp; + + typedef enum + { + BitwiseOp_NOT, + BitwiseOp_RBIT + } BitwiseOp; + + + typedef enum + { + EL0 = 0, + EL1 = 1, + EL2 = 2, + EL3 = 3 + } ExceptionLevel; + + typedef enum + { + ExtendType_SXTB, + ExtendType_SXTH, + ExtendType_SXTW, + ExtendType_SXTX, + ExtendType_UXTB, + ExtendType_UXTH, + ExtendType_UXTW, + ExtendType_UXTX + } ExtendType; + + typedef enum + { + ExtractType_LEFT, + ExtractType_RIGHT + } ExtractType; + + typedef enum + { + LogicalOp_AND, + LogicalOp_EOR, + LogicalOp_ORR + } LogicalOp; + + typedef enum + { + MemOp_LOAD, + MemOp_STORE, + MemOp_PREFETCH, + MemOp_NOP + } MemOp; + + typedef enum + { + MoveWideOp_N, + MoveWideOp_Z, + MoveWideOp_K + } MoveWideOp; + + typedef enum { + ShiftType_LSL, + ShiftType_LSR, + ShiftType_ASR, + ShiftType_ROR + } ShiftType; + + typedef enum + { + SP0 = 0, + SPx = 1 + } StackPointerSelection; + + typedef enum + { + Unpredictable_WBOVERLAP, + Unpredictable_LDPOVERLAP + } Unpredictable; + + typedef enum + { + Constraint_NONE, + Constraint_UNKNOWN, + Constraint_SUPPRESSWB, + Constraint_NOP + } ConstraintType; + + typedef enum + { + AccType_NORMAL, + AccType_UNPRIV, + AccType_STREAM, + AccType_ALIGNED, + AccType_ORDERED + } AccType; + + typedef struct + { + uint32_t + N:1, + V:1, + C:1, + Z:1, // condition code flags – can also be accessed as PSTATE.[N,Z,C,V] + Q:1, // AArch32 only – CSPR.Q bit + IT:8, // AArch32 only – CPSR.IT bits + J:1, // AArch32 only – CSPR.J bit + T:1, // AArch32 only – CPSR.T bit + SS:1, // Single step process state bit + IL:1, // Illegal state bit + D:1, + A:1, + I:1, + F:1, // Interrupt masks – can also be accessed as PSTATE.[D,A,I,F] + E:1, // AArch32 only – CSPR.E bit + M:5, // AArch32 only – mode encodings + RW:1, // Current register width – 0 is AArch64, 1 is AArch32 + EL:2, // Current exception level (see ExceptionLevel enum) + SP:1; // AArch64 only - Stack Pointer selection (see StackPointerSelection enum) + } ProcState; + +protected: + + typedef struct + { + uint32_t mask; + uint32_t value; + uint32_t vfp_variants; + bool (EmulateInstructionARM64::*callback) (const uint32_t opcode); + const char *name; + } Opcode; + + static Opcode* + GetOpcodeForInstruction (const uint32_t opcode); + + bool + Emulate_addsub_imm (const uint32_t opcode); + +// bool +// Emulate_STP_Q_ldstpair_off (const uint32_t opcode); +// +// bool +// Emulate_STP_S_ldstpair_off (const uint32_t opcode); +// +// bool +// Emulate_STP_32_ldstpair_off (const uint32_t opcode); +// +// bool +// Emulate_STP_D_ldstpair_off (const uint32_t opcode); +// + bool + Emulate_ldstpair_off (const uint32_t opcode); + + bool + Emulate_ldstpair_pre (const uint32_t opcode); + + bool + Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode); + + ProcState m_opcode_pstate; + ProcState m_emulated_pstate; // This can get updated by the opcode. + bool m_ignore_conditions; +}; + +#endif // EmulateInstructionARM64_h_ diff --git a/lldb/source/Plugins/Instruction/ARM64/Makefile b/lldb/source/Plugins/Instruction/ARM64/Makefile new file mode 100644 index 000000000000..b07a6020dd33 --- /dev/null +++ b/lldb/source/Plugins/Instruction/ARM64/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Instruction/ARM/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginEmulateInstructionARM64 +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/Instruction/CMakeLists.txt b/lldb/source/Plugins/Instruction/CMakeLists.txt index 3eef5f4922ed..21fd82a7ab3f 100644 --- a/lldb/source/Plugins/Instruction/CMakeLists.txt +++ b/lldb/source/Plugins/Instruction/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(ARM) +add_subdirectory(ARM64) diff --git a/lldb/source/Plugins/Makefile b/lldb/source/Plugins/Makefile index 7b39dd536275..eb15cf979932 100644 --- a/lldb/source/Plugins/Makefile +++ b/lldb/source/Plugins/Makefile @@ -12,10 +12,12 @@ LLDB_LEVEL := ../.. include $(LLDB_LEVEL)/../../Makefile.config -DIRS := ABI/MacOSX-arm ABI/MacOSX-i386 ABI/SysV-x86_64 Disassembler/llvm \ +DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64 ABI/MacOSX-i386 ABI/SysV-x86_64 \ + Disassembler/llvm \ ObjectContainer/BSD-Archive ObjectFile/ELF ObjectFile/PECOFF \ ObjectFile/JIT SymbolFile/DWARF SymbolFile/Symtab Process/Utility \ - DynamicLoader/Static Platform Process/gdb-remote Instruction/ARM \ + DynamicLoader/Static Platform Process/gdb-remote \ + Instruction/ARM Instruction/ARM64 \ UnwindAssembly/InstEmulation UnwindAssembly/x86 \ LanguageRuntime/CPlusPlus/ItaniumABI \ LanguageRuntime/ObjC/AppleObjCRuntime \ diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index a4bfc5caec53..814df8897a44 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -37,10 +37,11 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" +#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__)) // GetLLDBSharedCacheUUID() needs to call dlsym() #include #endif @@ -398,6 +399,129 @@ protected: } }; +class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 +{ +public: + RegisterContextDarwin_arm64_Mach (lldb_private::Thread &thread, const DataExtractor &data) : + RegisterContextDarwin_arm64 (thread, 0) + { + SetRegisterDataFrom_LC_THREAD (data); + } + + virtual void + InvalidateAllRegisters () + { + // Do nothing... registers are always valid... + } + + void + SetRegisterDataFrom_LC_THREAD (const DataExtractor &data) + { + lldb::offset_t offset = 0; + SetError (GPRRegSet, Read, -1); + SetError (FPURegSet, Read, -1); + SetError (EXCRegSet, Read, -1); + bool done = false; + while (!done) + { + int flavor = data.GetU32 (&offset); + uint32_t count = data.GetU32 (&offset); + lldb::offset_t next_thread_state = offset + (count * 4); + switch (flavor) + { + case GPRRegSet: + // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1 32-bit register) + if (count >= (33 * 2) + 1) + { + for (uint32_t i=0; i<33; ++i) + gpr.x[i] = data.GetU64(&offset); + gpr.cpsr = data.GetU32(&offset); + SetError (GPRRegSet, Read, 0); + } + offset = next_thread_state; + break; + case FPURegSet: + { + uint8_t *fpu_reg_buf = (uint8_t*) &fpu.v[0]; + const int fpu_reg_buf_size = sizeof (fpu); + if (fpu_reg_buf_size == count + && data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size) + { + SetError (FPURegSet, Read, 0); + } + else + { + done = true; + } + } + offset = next_thread_state; + break; + case EXCRegSet: + if (count == 4) + { + exc.far = data.GetU64(&offset); + exc.esr = data.GetU32(&offset); + exc.exception = data.GetU32(&offset); + SetError (EXCRegSet, Read, 0); + } + offset = next_thread_state; + break; + default: + done = true; + break; + } + } + } +protected: + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) + { + return -1; + } + + virtual int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) + { + return -1; + } + + virtual int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) + { + return -1; + } + + virtual int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) + { + return -1; + } + + virtual int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) + { + return 0; + } + + virtual int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) + { + return 0; + } + + virtual int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) + { + return 0; + } + + virtual int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) + { + return -1; + } +}; + static uint32_t MachHeaderSizeFromMagic(uint32_t magic) { @@ -1772,8 +1896,8 @@ ObjectFileMachO::ParseSymtab () bool data_was_read = false; -#if defined (__APPLE__) && defined (__arm__) - if (m_header.flags & 0x80000000u) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__)) + if (m_header.flags & 0x80000000u && process->GetAddressByteSize() == sizeof (void*)) { // This mach-o memory file is in the dyld shared cache. If this // program is not remote and this is iOS, then this process will @@ -2031,7 +2155,7 @@ ObjectFileMachO::ParseSymtab () } } -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__)) // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been optimized by moving LOCAL // symbols out of the memory mapped portion of the DSC. The symbol information has all been retained, @@ -4152,6 +4276,14 @@ ObjectFileMachO::GetEntryPointAddress () done = true; } break; + case llvm::MachO::CPU_TYPE_ARM64: + if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h + { + offset += 256; // This is the offset of pc in the GPR thread state data structure. + start_address = m_data.GetU64(&offset); + done = true; + } + break; case llvm::MachO::CPU_TYPE_I386: if (flavor == 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h { @@ -4304,6 +4436,10 @@ ObjectFileMachO::GetThreadContextAtIndex (uint32_t idx, lldb_private::Thread &th switch (m_header.cputype) { + case llvm::MachO::CPU_TYPE_ARM64: + reg_ctx_sp.reset (new RegisterContextDarwin_arm64_Mach (thread, data)); + break; + case llvm::MachO::CPU_TYPE_ARM: reg_ctx_sp.reset (new RegisterContextDarwin_arm_Mach (thread, data)); break; @@ -4544,7 +4680,7 @@ UUID ObjectFileMachO::GetLLDBSharedCacheUUID () { UUID uuid; -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__)) uint8_t *(*dyld_get_all_image_infos)(void); dyld_get_all_image_infos = (uint8_t*(*)()) dlsym (RTLD_DEFAULT, "_dyld_get_all_image_infos"); if (dyld_get_all_image_infos) @@ -4555,7 +4691,16 @@ ObjectFileMachO::GetLLDBSharedCacheUUID () uint32_t *version = (uint32_t*) dyld_all_image_infos_address; // version if (*version >= 13) { - uuid_t *sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID + uuid_t *sharedCacheUUID_address = 0; + int wordsize = sizeof (uint8_t *); + if (wordsize == 8) + { + sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 160); // sharedCacheUUID + } + else + { + sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID + } uuid.SetBytes (sharedCacheUUID_address); } } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index f98fe9d01987..8d05eb609212 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -530,6 +530,17 @@ PlatformDarwin::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite } break; + case llvm::Triple::arm64: + { + // TODO: fix this with actual darwin breakpoint opcode for arm64. + // right now debugging uses the Z packets with GDB remote so this + // is not needed, but the size needs to be correct... + static const uint8_t g_arm64_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 }; + trap_opcode = g_arm64_breakpoint_opcode; + trap_opcode_size = sizeof(g_arm64_breakpoint_opcode); + } + break; + case llvm::Triple::thumb: bp_is_thumb = true; // Fall through... case llvm::Triple::arm: @@ -939,20 +950,51 @@ bool PlatformDarwin::ARMGetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) { ArchSpec system_arch (GetSystemArchitecture()); + const ArchSpec::Core system_core = system_arch.GetCore(); switch (system_core) { default: switch (idx) { - case 0: arch.SetTriple ("armv7-apple-ios"); return true; - case 1: arch.SetTriple ("armv7f-apple-ios"); return true; - case 2: arch.SetTriple ("armv7k-apple-ios"); return true; - case 3: arch.SetTriple ("armv7s-apple-ios"); return true; - case 4: arch.SetTriple ("armv7m-apple-ios"); return true; - case 5: arch.SetTriple ("armv7em-apple-ios"); return true; - case 6: arch.SetTriple ("armv6-apple-ios"); return true; + case 0: arch.SetTriple ("arm64-apple-ios"); return true; + case 1: arch.SetTriple ("armv7-apple-ios"); return true; + case 2: arch.SetTriple ("armv7f-apple-ios"); return true; + case 3: arch.SetTriple ("armv7k-apple-ios"); return true; + case 4: arch.SetTriple ("armv7s-apple-ios"); return true; + case 5: arch.SetTriple ("armv7m-apple-ios"); return true; + case 6: arch.SetTriple ("armv7em-apple-ios"); return true; case 7: arch.SetTriple ("armv6m-apple-ios"); return true; + case 8: arch.SetTriple ("armv6-apple-ios"); return true; + case 9: arch.SetTriple ("armv5-apple-ios"); return true; + case 10: arch.SetTriple ("armv4-apple-ios"); return true; + case 11: arch.SetTriple ("arm-apple-ios"); return true; + case 12: arch.SetTriple ("thumbv7-apple-ios"); return true; + case 13: arch.SetTriple ("thumbv7f-apple-ios"); return true; + case 14: arch.SetTriple ("thumbv7k-apple-ios"); return true; + case 15: arch.SetTriple ("thumbv7s-apple-ios"); return true; + case 16: arch.SetTriple ("thumbv7m-apple-ios"); return true; + case 17: arch.SetTriple ("thumbv7em-apple-ios"); return true; + case 18: arch.SetTriple ("thumbv6m-apple-ios"); return true; + case 19: arch.SetTriple ("thumbv6-apple-ios"); return true; + case 20: arch.SetTriple ("thumbv5-apple-ios"); return true; + case 21: arch.SetTriple ("thumbv4t-apple-ios"); return true; + case 22: arch.SetTriple ("thumb-apple-ios"); return true; + default: break; + } + break; + + case ArchSpec::eCore_arm_arm64: + switch (idx) + { + case 0: arch.SetTriple ("arm64-apple-ios"); return true; + case 1: arch.SetTriple ("armv7s-apple-ios"); return true; + case 2: arch.SetTriple ("armv7f-apple-ios"); return true; + case 3: arch.SetTriple ("armv7m-apple-ios"); return true; + case 4: arch.SetTriple ("armv7em-apple-ios"); return true; + case 5: arch.SetTriple ("armv7-apple-ios"); return true; + case 6: arch.SetTriple ("armv6m-apple-ios"); return true; + case 7: arch.SetTriple ("armv6-apple-ios"); return true; case 8: arch.SetTriple ("armv5-apple-ios"); return true; case 9: arch.SetTriple ("armv4-apple-ios"); return true; case 10: arch.SetTriple ("arm-apple-ios"); return true; @@ -962,8 +1004,8 @@ PlatformDarwin::ARMGetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch case 14: arch.SetTriple ("thumbv7s-apple-ios"); return true; case 15: arch.SetTriple ("thumbv7m-apple-ios"); return true; case 16: arch.SetTriple ("thumbv7em-apple-ios"); return true; - case 17: arch.SetTriple ("thumbv6-apple-ios"); return true; - case 18: arch.SetTriple ("thumbv6m-apple-ios"); return true; + case 17: arch.SetTriple ("thumbv6m-apple-ios"); return true; + case 18: arch.SetTriple ("thumbv6-apple-ios"); return true; case 19: arch.SetTriple ("thumbv5-apple-ios"); return true; case 20: arch.SetTriple ("thumbv4t-apple-ios"); return true; case 21: arch.SetTriple ("thumb-apple-ios"); return true; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 67ff026081e9..820f18e124cc 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -133,6 +133,7 @@ PlatformDarwinKernel::CreateInstance (bool force, const ArchSpec *arch) is_ios_debug_session = eLazyBoolNo; break; case llvm::Triple::arm: + case llvm::Triple::arm64: case llvm::Triple::thumb: is_ios_debug_session = eLazyBoolYes; break; @@ -649,7 +650,7 @@ PlatformDarwinKernel::ExamineKextForMatchingUUID (const FileSpec &kext_bundle_pa bool PlatformDarwinKernel::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) { -#if defined (__arm__) +#if defined (__arm__) || defined (__arm64__) return ARMGetSupportedArchitectureAtIndex (idx, arch); #else return x86GetSupportedArchitectureAtIndex (idx, arch); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index fe84e5f0a2ee..7acde1804a8e 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -312,7 +312,7 @@ PlatformMacOSX::GetFileWithUUID (const lldb_private::FileSpec &platform_file, bool PlatformMacOSX::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) { -#if defined (__arm__) +#if defined (__arm__) || defined (__arm64__) return ARMGetSupportedArchitectureAtIndex (idx, arch); #else return x86GetSupportedArchitectureAtIndex (idx, arch); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp index 7b5ab9aec41b..545ac073c977 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp @@ -92,6 +92,7 @@ PlatformRemoteiOS::CreateInstance (bool force, const ArchSpec *arch) switch (arch->GetMachine()) { case llvm::Triple::arm: + case llvm::Triple::arm64: case llvm::Triple::thumb: { const llvm::Triple &triple = arch->GetTriple(); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp index ac0a96cfbdbb..0a809503d1e2 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp @@ -68,7 +68,7 @@ PlatformiOSSimulator::CreateInstance (bool force, const ArchSpec *arch) { switch (arch->GetMachine()) { - // Currently simulator is i386 only... + case llvm::Triple::x86_64: case llvm::Triple::x86: { const llvm::Triple &triple = arch->GetTriple(); @@ -407,9 +407,21 @@ PlatformiOSSimulator::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &a { if (idx == 0) { - // All iOS simulator binaries are currently i386 - arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); + arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture); return arch.IsValid(); } + else if (idx == 1) + { + ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture)); + ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64)); + if (platform_arch.IsExactMatch(platform_arch64)) + { + // This macosx platform supports both 32 and 64 bit. Since we already + // returned the 64 bit arch for idx == 0, return the 32 bit arch + // for idx == 1 + arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32); + return arch.IsValid(); + } + } return false; } diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt b/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt index 4203a87cfd87..b0172037b04c 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginProcessMacOSXKernel ProcessKDP.cpp ProcessKDPLog.cpp RegisterContextKDP_arm.cpp + RegisterContextKDP_arm64.cpp RegisterContextKDP_i386.cpp RegisterContextKDP_x86_64.cpp ThreadKDP.cpp diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp new file mode 100644 index 000000000000..ed62f1982d3c --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp @@ -0,0 +1,161 @@ +//===-- RegisterContextKDP_arm64.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextKDP_arm64.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_arm64::RegisterContextKDP_arm64 (ThreadKDP &thread, uint32_t concrete_frame_idx) : + RegisterContextDarwin_arm64 (thread, concrete_frame_idx), + m_kdp_thread (thread) +{ +} + +RegisterContextKDP_arm64::~RegisterContextKDP_arm64() +{ +} + +int +RegisterContextKDP_arm64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + +int +RegisterContextKDP_arm64::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) +{ + ProcessSP process_sp (CalculateProcess()); + if (process_sp) + { + Error error; + if (static_cast(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) + { + if (error.Success()) + return 0; + } + } + return -1; +} + + diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h new file mode 100644 index 000000000000..8780b7be4a9a --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h @@ -0,0 +1,61 @@ +//===-- RegisterContextKDP_arm64.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_RegisterContextKDP_arm64_h_ +#define liblldb_RegisterContextKDP_arm64_h_ + +// C Includes + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" + +class ThreadKDP; + +class RegisterContextKDP_arm64 : public RegisterContextDarwin_arm64 +{ +public: + + RegisterContextKDP_arm64 (ThreadKDP &thread, + uint32_t concrete_frame_idx); + + virtual + ~RegisterContextKDP_arm64(); + +protected: + + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); + + int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); + + int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); + + int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg); + + int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); + + int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); + + int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); + + int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg); + + ThreadKDP &m_kdp_thread; +}; + +#endif // liblldb_RegisterContextKDP_arm64_h_ diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp index bb7e8a317a0f..562ba8b0a16c 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -26,6 +26,7 @@ #include "ProcessKDP.h" #include "ProcessKDPLog.h" #include "RegisterContextKDP_arm.h" +#include "RegisterContextKDP_arm64.h" #include "RegisterContextKDP_i386.h" #include "RegisterContextKDP_x86_64.h" #include "Plugins/Process/Utility/StopInfoMachException.h" @@ -127,6 +128,9 @@ ThreadKDP::CreateRegisterContextForFrame (StackFrame *frame) case llvm::MachO::CPU_TYPE_ARM: reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx)); break; + case llvm::MachO::CPU_TYPE_ARM64: + reg_ctx_sp.reset (new RegisterContextKDP_arm64 (*this, concrete_frame_idx)); + break; case llvm::MachO::CPU_TYPE_I386: reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx)); break; diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt index 6cd8e6459009..e1a64ecfdc8b 100644 --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessUtility HistoryUnwind.cpp InferiorCallPOSIX.cpp RegisterContextDarwin_arm.cpp + RegisterContextDarwin_arm64.cpp RegisterContextDarwin_i386.cpp RegisterContextDarwin_x86_64.cpp RegisterContextDummy.cpp diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp new file mode 100644 index 000000000000..b42f35b927b1 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -0,0 +1,1235 @@ +//===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined(__APPLE__) + +#include "RegisterContextDarwin_arm64.h" + +// C Includes +#include +#include +#include + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "Plugins/Process/Utility/InstructionUtils.h" + +// Support building against older versions of LLVM, this macro was added +// recently. +#ifndef LLVM_EXTENSION +#define LLVM_EXTENSION +#endif + +// Project includes +#include "ARM64_GCC_Registers.h" +#include "ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +enum +{ + gpr_x0 = 0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_x29 = 29, gpr_fp = gpr_x29, + gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30, + gpr_x31 = 31, gpr_sp = gpr_x31, + gpr_pc = 32, + gpr_cpsr, + + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + + fpu_fpsr, + fpu_fpcr, + + exc_far, + exc_esr, + exc_exception, + + dbg_bvr0, + dbg_bvr1, + dbg_bvr2, + dbg_bvr3, + dbg_bvr4, + dbg_bvr5, + dbg_bvr6, + dbg_bvr7, + dbg_bvr8, + dbg_bvr9, + dbg_bvr10, + dbg_bvr11, + dbg_bvr12, + dbg_bvr13, + dbg_bvr14, + dbg_bvr15, + + dbg_bcr0, + dbg_bcr1, + dbg_bcr2, + dbg_bcr3, + dbg_bcr4, + dbg_bcr5, + dbg_bcr6, + dbg_bcr7, + dbg_bcr8, + dbg_bcr9, + dbg_bcr10, + dbg_bcr11, + dbg_bcr12, + dbg_bcr13, + dbg_bcr14, + dbg_bcr15, + + dbg_wvr0, + dbg_wvr1, + dbg_wvr2, + dbg_wvr3, + dbg_wvr4, + dbg_wvr5, + dbg_wvr6, + dbg_wvr7, + dbg_wvr8, + dbg_wvr9, + dbg_wvr10, + dbg_wvr11, + dbg_wvr12, + dbg_wvr13, + dbg_wvr14, + dbg_wvr15, + + dbg_wcr0, + dbg_wcr1, + dbg_wcr2, + dbg_wcr3, + dbg_wcr4, + dbg_wcr5, + dbg_wcr6, + dbg_wcr7, + dbg_wcr8, + dbg_wcr9, + dbg_wcr10, + dbg_wcr11, + dbg_wcr12, + dbg_wcr13, + dbg_wcr14, + dbg_wcr15, + + k_num_registers +}; + + +RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) : + RegisterContext(thread, concrete_frame_idx), + gpr(), + fpu(), + exc() +{ + uint32_t i; + for (i=0; ireg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) + +static RegisterInfo g_register_infos[] = { +// General purpose registers +// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS +// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== +{ "x0", NULL, 8, GPR_OFFSET(0), eEncodingUint, eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_INVALID_REGNUM, arm64_gcc::x0, gpr_x0 }, NULL, NULL}, +{ "x1", NULL, 8, GPR_OFFSET(1), eEncodingUint, eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_INVALID_REGNUM, arm64_gcc::x1, gpr_x1 }, NULL, NULL}, +{ "x2", NULL, 8, GPR_OFFSET(2), eEncodingUint, eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_INVALID_REGNUM, arm64_gcc::x2, gpr_x2 }, NULL, NULL}, +{ "x3", NULL, 8, GPR_OFFSET(3), eEncodingUint, eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_INVALID_REGNUM, arm64_gcc::x3, gpr_x3 }, NULL, NULL}, +{ "x4", NULL, 8, GPR_OFFSET(4), eEncodingUint, eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_INVALID_REGNUM, arm64_gcc::x4, gpr_x4 }, NULL, NULL}, +{ "x5", NULL, 8, GPR_OFFSET(5), eEncodingUint, eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_INVALID_REGNUM, arm64_gcc::x5, gpr_x5 }, NULL, NULL}, +{ "x6", NULL, 8, GPR_OFFSET(6), eEncodingUint, eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_INVALID_REGNUM, arm64_gcc::x6, gpr_x6 }, NULL, NULL}, +{ "x7", NULL, 8, GPR_OFFSET(7), eEncodingUint, eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_INVALID_REGNUM, arm64_gcc::x7, gpr_x7 }, NULL, NULL}, +{ "x8", NULL, 8, GPR_OFFSET(8), eEncodingUint, eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL}, +{ "x9", NULL, 8, GPR_OFFSET(9), eEncodingUint, eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL}, +{ "x10", NULL, 8, GPR_OFFSET(10), eEncodingUint, eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL}, +{ "x11", NULL, 8, GPR_OFFSET(11), eEncodingUint, eFormatHex, { arm64_gcc::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, arm64_gcc::x11, gpr_x11 }, NULL, NULL}, +{ "x12", NULL, 8, GPR_OFFSET(12), eEncodingUint, eFormatHex, { arm64_gcc::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, arm64_gcc::x12, gpr_x12 }, NULL, NULL}, +{ "x13", NULL, 8, GPR_OFFSET(13), eEncodingUint, eFormatHex, { arm64_gcc::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, arm64_gcc::x13, gpr_x13 }, NULL, NULL}, +{ "x14", NULL, 8, GPR_OFFSET(14), eEncodingUint, eFormatHex, { arm64_gcc::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, arm64_gcc::x14, gpr_x14 }, NULL, NULL}, +{ "x15", NULL, 8, GPR_OFFSET(15), eEncodingUint, eFormatHex, { arm64_gcc::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, arm64_gcc::x15, gpr_x15 }, NULL, NULL}, +{ "x16", NULL, 8, GPR_OFFSET(16), eEncodingUint, eFormatHex, { arm64_gcc::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, arm64_gcc::x16, gpr_x16 }, NULL, NULL}, +{ "x17", NULL, 8, GPR_OFFSET(17), eEncodingUint, eFormatHex, { arm64_gcc::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, arm64_gcc::x17, gpr_x17 }, NULL, NULL}, +{ "x18", NULL, 8, GPR_OFFSET(18), eEncodingUint, eFormatHex, { arm64_gcc::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, arm64_gcc::x18, gpr_x18 }, NULL, NULL}, +{ "x19", NULL, 8, GPR_OFFSET(19), eEncodingUint, eFormatHex, { arm64_gcc::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, arm64_gcc::x19, gpr_x19 }, NULL, NULL}, +{ "x20", NULL, 8, GPR_OFFSET(20), eEncodingUint, eFormatHex, { arm64_gcc::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, arm64_gcc::x20, gpr_x20 }, NULL, NULL}, +{ "x21", NULL, 8, GPR_OFFSET(21), eEncodingUint, eFormatHex, { arm64_gcc::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, arm64_gcc::x21, gpr_x21 }, NULL, NULL}, +{ "x22", NULL, 8, GPR_OFFSET(22), eEncodingUint, eFormatHex, { arm64_gcc::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, arm64_gcc::x22, gpr_x22 }, NULL, NULL}, +{ "x23", NULL, 8, GPR_OFFSET(23), eEncodingUint, eFormatHex, { arm64_gcc::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, arm64_gcc::x23, gpr_x23 }, NULL, NULL}, +{ "x24", NULL, 8, GPR_OFFSET(24), eEncodingUint, eFormatHex, { arm64_gcc::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, arm64_gcc::x24, gpr_x24 }, NULL, NULL}, +{ "x25", NULL, 8, GPR_OFFSET(25), eEncodingUint, eFormatHex, { arm64_gcc::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, arm64_gcc::x25, gpr_x25 }, NULL, NULL}, +{ "x26", NULL, 8, GPR_OFFSET(26), eEncodingUint, eFormatHex, { arm64_gcc::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, arm64_gcc::x26, gpr_x26 }, NULL, NULL}, +{ "x27", NULL, 8, GPR_OFFSET(27), eEncodingUint, eFormatHex, { arm64_gcc::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, arm64_gcc::x27, gpr_x27 }, NULL, NULL}, +{ "x28", NULL, 8, GPR_OFFSET(28), eEncodingUint, eFormatHex, { arm64_gcc::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, arm64_gcc::x28, gpr_x28 }, NULL, NULL}, + +{ "fp", "x29", 8, GPR_OFFSET(29), eEncodingUint, eFormatHex, { arm64_gcc::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, arm64_gcc::fp, gpr_fp }, NULL, NULL}, +{ "lr", "x30", 8, GPR_OFFSET(30), eEncodingUint, eFormatHex, { arm64_gcc::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, arm64_gcc::lr, gpr_lr }, NULL, NULL}, +{ "sp", "x31", 8, GPR_OFFSET(31), eEncodingUint, eFormatHex, { arm64_gcc::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, arm64_gcc::sp, gpr_sp }, NULL, NULL}, +{ "pc", NULL, 8, GPR_OFFSET(32), eEncodingUint, eFormatHex, { arm64_gcc::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, arm64_gcc::pc, gpr_pc }, NULL, NULL}, + +{ "cpsr", NULL, 4, GPR_OFFSET_NAME(cpsr), eEncodingUint, eFormatHex, { arm64_gcc::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, arm64_gcc::cpsr, gpr_cpsr }, NULL, NULL}, + +{ "v0", NULL, 16, FPU_OFFSET(0), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, arm64_gcc::v0, fpu_v0 }, NULL, NULL}, +{ "v1", NULL, 16, FPU_OFFSET(1), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, arm64_gcc::v1, fpu_v1 }, NULL, NULL}, +{ "v2", NULL, 16, FPU_OFFSET(2), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, arm64_gcc::v2, fpu_v2 }, NULL, NULL}, +{ "v3", NULL, 16, FPU_OFFSET(3), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, arm64_gcc::v3, fpu_v3 }, NULL, NULL}, +{ "v4", NULL, 16, FPU_OFFSET(4), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, arm64_gcc::v4, fpu_v4 }, NULL, NULL}, +{ "v5", NULL, 16, FPU_OFFSET(5), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, arm64_gcc::v5, fpu_v5 }, NULL, NULL}, +{ "v6", NULL, 16, FPU_OFFSET(6), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, arm64_gcc::v6, fpu_v6 }, NULL, NULL}, +{ "v7", NULL, 16, FPU_OFFSET(7), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, arm64_gcc::v7, fpu_v7 }, NULL, NULL}, +{ "v8", NULL, 16, FPU_OFFSET(8), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, arm64_gcc::v8, fpu_v8 }, NULL, NULL}, +{ "v9", NULL, 16, FPU_OFFSET(9), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, arm64_gcc::v9, fpu_v9 }, NULL, NULL}, +{ "v10", NULL, 16, FPU_OFFSET(10), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, arm64_gcc::v10, fpu_v10 }, NULL, NULL}, +{ "v11", NULL, 16, FPU_OFFSET(11), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, arm64_gcc::v11, fpu_v11 }, NULL, NULL}, +{ "v12", NULL, 16, FPU_OFFSET(12), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, arm64_gcc::v12, fpu_v12 }, NULL, NULL}, +{ "v13", NULL, 16, FPU_OFFSET(13), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, arm64_gcc::v13, fpu_v13 }, NULL, NULL}, +{ "v14", NULL, 16, FPU_OFFSET(14), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, arm64_gcc::v14, fpu_v14 }, NULL, NULL}, +{ "v15", NULL, 16, FPU_OFFSET(15), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, arm64_gcc::v15, fpu_v15 }, NULL, NULL}, +{ "v16", NULL, 16, FPU_OFFSET(16), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, arm64_gcc::v16, fpu_v16 }, NULL, NULL}, +{ "v17", NULL, 16, FPU_OFFSET(17), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, arm64_gcc::v17, fpu_v17 }, NULL, NULL}, +{ "v18", NULL, 16, FPU_OFFSET(18), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, arm64_gcc::v18, fpu_v18 }, NULL, NULL}, +{ "v19", NULL, 16, FPU_OFFSET(19), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, arm64_gcc::v19, fpu_v19 }, NULL, NULL}, +{ "v20", NULL, 16, FPU_OFFSET(20), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, arm64_gcc::v20, fpu_v20 }, NULL, NULL}, +{ "v21", NULL, 16, FPU_OFFSET(21), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, arm64_gcc::v21, fpu_v21 }, NULL, NULL}, +{ "v22", NULL, 16, FPU_OFFSET(22), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, arm64_gcc::v22, fpu_v22 }, NULL, NULL}, +{ "v23", NULL, 16, FPU_OFFSET(23), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, arm64_gcc::v23, fpu_v23 }, NULL, NULL}, +{ "v24", NULL, 16, FPU_OFFSET(24), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, arm64_gcc::v24, fpu_v24 }, NULL, NULL}, +{ "v25", NULL, 16, FPU_OFFSET(25), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, arm64_gcc::v25, fpu_v25 }, NULL, NULL}, +{ "v26", NULL, 16, FPU_OFFSET(26), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, arm64_gcc::v26, fpu_v26 }, NULL, NULL}, +{ "v27", NULL, 16, FPU_OFFSET(27), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, arm64_gcc::v27, fpu_v27 }, NULL, NULL}, +{ "v28", NULL, 16, FPU_OFFSET(28), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, arm64_gcc::v28, fpu_v28 }, NULL, NULL}, +{ "v29", NULL, 16, FPU_OFFSET(29), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, arm64_gcc::v29, fpu_v29 }, NULL, NULL}, +{ "v30", NULL, 16, FPU_OFFSET(30), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, arm64_gcc::v30, fpu_v30 }, NULL, NULL}, +{ "v31", NULL, 16, FPU_OFFSET(31), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, arm64_gcc::v31, fpu_v31 }, NULL, NULL}, + +{ "fpsr", NULL, 4, FPU_OFFSET_NAME(fpsr), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, NULL, NULL}, +{ "fpcr", NULL, 4, FPU_OFFSET_NAME(fpcr), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, NULL, NULL}, + +{ "far", NULL, 8, EXC_OFFSET_NAME(far), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL}, +{ "esr", NULL, 4, EXC_OFFSET_NAME(esr), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, NULL, NULL}, +{ "exception",NULL, 4, EXC_OFFSET_NAME(exception), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, + +{ DEFINE_DBG (bvr, 0) }, +{ DEFINE_DBG (bvr, 1) }, +{ DEFINE_DBG (bvr, 2) }, +{ DEFINE_DBG (bvr, 3) }, +{ DEFINE_DBG (bvr, 4) }, +{ DEFINE_DBG (bvr, 5) }, +{ DEFINE_DBG (bvr, 6) }, +{ DEFINE_DBG (bvr, 7) }, +{ DEFINE_DBG (bvr, 8) }, +{ DEFINE_DBG (bvr, 9) }, +{ DEFINE_DBG (bvr, 10) }, +{ DEFINE_DBG (bvr, 11) }, +{ DEFINE_DBG (bvr, 12) }, +{ DEFINE_DBG (bvr, 13) }, +{ DEFINE_DBG (bvr, 14) }, +{ DEFINE_DBG (bvr, 15) }, + +{ DEFINE_DBG (bcr, 0) }, +{ DEFINE_DBG (bcr, 1) }, +{ DEFINE_DBG (bcr, 2) }, +{ DEFINE_DBG (bcr, 3) }, +{ DEFINE_DBG (bcr, 4) }, +{ DEFINE_DBG (bcr, 5) }, +{ DEFINE_DBG (bcr, 6) }, +{ DEFINE_DBG (bcr, 7) }, +{ DEFINE_DBG (bcr, 8) }, +{ DEFINE_DBG (bcr, 9) }, +{ DEFINE_DBG (bcr, 10) }, +{ DEFINE_DBG (bcr, 11) }, +{ DEFINE_DBG (bcr, 12) }, +{ DEFINE_DBG (bcr, 13) }, +{ DEFINE_DBG (bcr, 14) }, +{ DEFINE_DBG (bcr, 15) }, + +{ DEFINE_DBG (wvr, 0) }, +{ DEFINE_DBG (wvr, 1) }, +{ DEFINE_DBG (wvr, 2) }, +{ DEFINE_DBG (wvr, 3) }, +{ DEFINE_DBG (wvr, 4) }, +{ DEFINE_DBG (wvr, 5) }, +{ DEFINE_DBG (wvr, 6) }, +{ DEFINE_DBG (wvr, 7) }, +{ DEFINE_DBG (wvr, 8) }, +{ DEFINE_DBG (wvr, 9) }, +{ DEFINE_DBG (wvr, 10) }, +{ DEFINE_DBG (wvr, 11) }, +{ DEFINE_DBG (wvr, 12) }, +{ DEFINE_DBG (wvr, 13) }, +{ DEFINE_DBG (wvr, 14) }, +{ DEFINE_DBG (wvr, 15) }, + +{ DEFINE_DBG (wcr, 0) }, +{ DEFINE_DBG (wcr, 1) }, +{ DEFINE_DBG (wcr, 2) }, +{ DEFINE_DBG (wcr, 3) }, +{ DEFINE_DBG (wcr, 4) }, +{ DEFINE_DBG (wcr, 5) }, +{ DEFINE_DBG (wcr, 6) }, +{ DEFINE_DBG (wcr, 7) }, +{ DEFINE_DBG (wcr, 8) }, +{ DEFINE_DBG (wcr, 9) }, +{ DEFINE_DBG (wcr, 10) }, +{ DEFINE_DBG (wcr, 11) }, +{ DEFINE_DBG (wcr, 12) }, +{ DEFINE_DBG (wcr, 13) }, +{ DEFINE_DBG (wcr, 14) }, +{ DEFINE_DBG (wcr, 15) } +}; + +// General purpose registers +static uint32_t +g_gpr_regnums[] = +{ + gpr_x0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_fp, + gpr_lr, + gpr_sp, + gpr_pc, + gpr_cpsr +}; + +// Floating point registers +static uint32_t +g_fpu_regnums[] = +{ + fpu_v0, + fpu_v1, + fpu_v2, + fpu_v3, + fpu_v4, + fpu_v5, + fpu_v6, + fpu_v7, + fpu_v8, + fpu_v9, + fpu_v10, + fpu_v11, + fpu_v12, + fpu_v13, + fpu_v14, + fpu_v15, + fpu_v16, + fpu_v17, + fpu_v18, + fpu_v19, + fpu_v20, + fpu_v21, + fpu_v22, + fpu_v23, + fpu_v24, + fpu_v25, + fpu_v26, + fpu_v27, + fpu_v28, + fpu_v29, + fpu_v30, + fpu_v31, + fpu_fpsr, + fpu_fpcr +}; + +// Exception registers + +static uint32_t +g_exc_regnums[] = +{ + exc_far, + exc_esr, + exc_exception +}; + +static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); + +void +RegisterContextDarwin_arm64::InvalidateAllRegisters () +{ + InvalidateAllRegisterStates(); +} + + +size_t +RegisterContextDarwin_arm64::GetRegisterCount () +{ + assert(k_num_register_infos == k_num_registers); + return k_num_registers; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfoAtIndex (size_t reg) +{ + assert(k_num_register_infos == k_num_registers); + if (reg < k_num_registers) + return &g_register_infos[reg]; + return NULL; +} + +size_t +RegisterContextDarwin_arm64::GetRegisterInfosCount () +{ + return k_num_register_infos; +} + +const RegisterInfo * +RegisterContextDarwin_arm64::GetRegisterInfos () +{ + return g_register_infos; +} + + +// Number of registers in each register set +const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t); +const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t); +const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t); + +//---------------------------------------------------------------------- +// Register set definitions. The first definitions at register set index +// of zero is for all registers, followed by other registers sets. The +// register information for the all register set need not be filled in. +//---------------------------------------------------------------------- +static const RegisterSet g_reg_sets[] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, }, + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }, + { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums } +}; + +const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet); + + +size_t +RegisterContextDarwin_arm64::GetRegisterSetCount () +{ + return k_num_regsets; +} + +const RegisterSet * +RegisterContextDarwin_arm64::GetRegisterSet (size_t reg_set) +{ + if (reg_set < k_num_regsets) + return &g_reg_sets[reg_set]; + return NULL; +} + + +//---------------------------------------------------------------------- +// Register information defintions for arm64 +//---------------------------------------------------------------------- +int +RegisterContextDarwin_arm64::GetSetForNativeRegNum (int reg) +{ + if (reg < fpu_v0) + return GPRRegSet; + else if (reg < exc_far) + return FPURegSet; + else if (reg < k_num_registers) + return EXCRegSet; + return -1; +} + +int +RegisterContextDarwin_arm64::ReadGPR (bool force) +{ + int set = GPRRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr)); + } + return GetError(GPRRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadFPU (bool force) +{ + int set = FPURegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu)); + } + return GetError(FPURegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadEXC (bool force) +{ + int set = EXCRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadEXC(GetThreadID(), set, exc)); + } + return GetError(EXCRegSet, Read); +} + +int +RegisterContextDarwin_arm64::ReadDBG (bool force) +{ + int set = DBGRegSet; + if (force || !RegisterSetIsCached(set)) + { + SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg)); + } + return GetError(DBGRegSet, Read); +} + +int +RegisterContextDarwin_arm64::WriteGPR () +{ + int set = GPRRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr)); + SetError (set, Read, -1); + return GetError(GPRRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteFPU () +{ + int set = FPURegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu)); + SetError (set, Read, -1); + return GetError(FPURegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteEXC () +{ + int set = EXCRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc)); + SetError (set, Read, -1); + return GetError(EXCRegSet, Write); +} + +int +RegisterContextDarwin_arm64::WriteDBG () +{ + int set = DBGRegSet; + if (!RegisterSetIsCached(set)) + { + SetError (set, Write, -1); + return KERN_INVALID_ARGUMENT; + } + SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg)); + SetError (set, Read, -1); + return GetError(DBGRegSet, Write); +} + + +int +RegisterContextDarwin_arm64::ReadRegisterSet (uint32_t set, bool force) +{ + switch (set) + { + case GPRRegSet: return ReadGPR(force); + case FPURegSet: return ReadFPU(force); + case EXCRegSet: return ReadEXC(force); + case DBGRegSet: return ReadDBG(force); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +int +RegisterContextDarwin_arm64::WriteRegisterSet (uint32_t set) +{ + // Make sure we have a valid context to set. + if (RegisterSetIsCached(set)) + { + switch (set) + { + case GPRRegSet: return WriteGPR(); + case FPURegSet: return WriteFPU(); + case EXCRegSet: return WriteEXC(); + case DBGRegSet: return WriteDBG(); + default: break; + } + } + return KERN_INVALID_ARGUMENT; +} + +void +RegisterContextDarwin_arm64::LogDBGRegisters (Log *log, const DBG& dbg) +{ + if (log) + { + for (uint32_t i=0; i<16; i++) + log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }", + i, i, dbg.bvr[i], dbg.bcr[i], + i, i, dbg.wvr[i], dbg.wcr[i]); + } +} + + +bool +RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + value.SetUInt64 (gpr.x[reg - gpr_x0]); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder()); + break; + + case fpu_fpsr: + value.SetUInt32 (fpu.fpsr); + break; + + case fpu_fpcr: + value.SetUInt32 (fpu.fpcr); + break; + + case exc_exception: + value.SetUInt32 (exc.exception); + break; + case exc_esr: + value.SetUInt32 (exc.esr); + break; + case exc_far: + value.SetUInt64 (exc.far); + break; + + default: + value.SetValueToInvalid(); + return false; + + } + return true; +} + + +bool +RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info, + const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = GetSetForNativeRegNum (reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != KERN_SUCCESS) + return false; + + switch (reg) + { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_fp: + case gpr_sp: + case gpr_lr: + case gpr_pc: + case gpr_cpsr: + gpr.x[reg - gpr_x0] = value.GetAsUInt64(); + break; + + case fpu_v0: + case fpu_v1: + case fpu_v2: + case fpu_v3: + case fpu_v4: + case fpu_v5: + case fpu_v6: + case fpu_v7: + case fpu_v8: + case fpu_v9: + case fpu_v10: + case fpu_v11: + case fpu_v12: + case fpu_v13: + case fpu_v14: + case fpu_v15: + case fpu_v16: + case fpu_v17: + case fpu_v18: + case fpu_v19: + case fpu_v20: + case fpu_v21: + case fpu_v22: + case fpu_v23: + case fpu_v24: + case fpu_v25: + case fpu_v26: + case fpu_v27: + case fpu_v28: + case fpu_v29: + case fpu_v30: + case fpu_v31: + ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize()); + break; + + case fpu_fpsr: + fpu.fpsr = value.GetAsUInt32(); + break; + + case fpu_fpcr: + fpu.fpcr = value.GetAsUInt32(); + break; + + case exc_exception: + exc.exception = value.GetAsUInt32(); + break; + case exc_esr: + exc.esr = value.GetAsUInt32(); + break; + case exc_far: + exc.far = value.GetAsUInt64(); + break; + + default: + return false; + + } + return WriteRegisterSet(set) == KERN_SUCCESS; +} + +bool +RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && + ReadGPR (false) == KERN_SUCCESS && + ReadFPU (false) == KERN_SUCCESS && + ReadEXC (false) == KERN_SUCCESS) + { + uint8_t *dst = data_sp->GetBytes(); + ::memcpy (dst, &gpr, sizeof(gpr)); + dst += sizeof(gpr); + + ::memcpy (dst, &fpu, sizeof(fpu)); + dst += sizeof(gpr); + + ::memcpy (dst, &exc, sizeof(exc)); + return true; + } + return false; +} + +bool +RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + const uint8_t *src = data_sp->GetBytes(); + ::memcpy (&gpr, src, sizeof(gpr)); + src += sizeof(gpr); + + ::memcpy (&fpu, src, sizeof(fpu)); + src += sizeof(gpr); + + ::memcpy (&exc, src, sizeof(exc)); + uint32_t success_count = 0; + if (WriteGPR() == KERN_SUCCESS) + ++success_count; + if (WriteFPU() == KERN_SUCCESS) + ++success_count; + if (WriteEXC() == KERN_SUCCESS) + ++success_count; + return success_count == 3; + } + return false; +} + +uint32_t +RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg) +{ + if (kind == eRegisterKindGeneric) + { + switch (reg) + { + case LLDB_REGNUM_GENERIC_PC: return gpr_pc; + case LLDB_REGNUM_GENERIC_SP: return gpr_sp; + case LLDB_REGNUM_GENERIC_FP: return gpr_fp; + case LLDB_REGNUM_GENERIC_RA: return gpr_lr; + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr; + default: + break; + } + } + else if (kind == eRegisterKindDWARF) + { + switch (reg) + { + case arm64_dwarf::x0: return gpr_x0; + case arm64_dwarf::x1: return gpr_x1; + case arm64_dwarf::x2: return gpr_x2; + case arm64_dwarf::x3: return gpr_x3; + case arm64_dwarf::x4: return gpr_x4; + case arm64_dwarf::x5: return gpr_x5; + case arm64_dwarf::x6: return gpr_x6; + case arm64_dwarf::x7: return gpr_x7; + case arm64_dwarf::x8: return gpr_x8; + case arm64_dwarf::x9: return gpr_x9; + case arm64_dwarf::x10: return gpr_x10; + case arm64_dwarf::x11: return gpr_x11; + case arm64_dwarf::x12: return gpr_x12; + case arm64_dwarf::x13: return gpr_x13; + case arm64_dwarf::x14: return gpr_x14; + case arm64_dwarf::x15: return gpr_x15; + case arm64_dwarf::x16: return gpr_x16; + case arm64_dwarf::x17: return gpr_x17; + case arm64_dwarf::x18: return gpr_x18; + case arm64_dwarf::x19: return gpr_x19; + case arm64_dwarf::x20: return gpr_x20; + case arm64_dwarf::x21: return gpr_x21; + case arm64_dwarf::x22: return gpr_x22; + case arm64_dwarf::x23: return gpr_x23; + case arm64_dwarf::x24: return gpr_x24; + case arm64_dwarf::x25: return gpr_x25; + case arm64_dwarf::x26: return gpr_x26; + case arm64_dwarf::x27: return gpr_x27; + case arm64_dwarf::x28: return gpr_x28; + + case arm64_dwarf::fp: return gpr_fp; + case arm64_dwarf::sp: return gpr_sp; + case arm64_dwarf::lr: return gpr_lr; + case arm64_dwarf::pc: return gpr_pc; + case arm64_dwarf::cpsr: return gpr_cpsr; + + case arm64_dwarf::v0: return fpu_v0; + case arm64_dwarf::v1: return fpu_v1; + case arm64_dwarf::v2: return fpu_v2; + case arm64_dwarf::v3: return fpu_v3; + case arm64_dwarf::v4: return fpu_v4; + case arm64_dwarf::v5: return fpu_v5; + case arm64_dwarf::v6: return fpu_v6; + case arm64_dwarf::v7: return fpu_v7; + case arm64_dwarf::v8: return fpu_v8; + case arm64_dwarf::v9: return fpu_v9; + case arm64_dwarf::v10: return fpu_v10; + case arm64_dwarf::v11: return fpu_v11; + case arm64_dwarf::v12: return fpu_v12; + case arm64_dwarf::v13: return fpu_v13; + case arm64_dwarf::v14: return fpu_v14; + case arm64_dwarf::v15: return fpu_v15; + case arm64_dwarf::v16: return fpu_v16; + case arm64_dwarf::v17: return fpu_v17; + case arm64_dwarf::v18: return fpu_v18; + case arm64_dwarf::v19: return fpu_v19; + case arm64_dwarf::v20: return fpu_v20; + case arm64_dwarf::v21: return fpu_v21; + case arm64_dwarf::v22: return fpu_v22; + case arm64_dwarf::v23: return fpu_v23; + case arm64_dwarf::v24: return fpu_v24; + case arm64_dwarf::v25: return fpu_v25; + case arm64_dwarf::v26: return fpu_v26; + case arm64_dwarf::v27: return fpu_v27; + case arm64_dwarf::v28: return fpu_v28; + case arm64_dwarf::v29: return fpu_v29; + case arm64_dwarf::v30: return fpu_v30; + case arm64_dwarf::v31: return fpu_v31; + + default: + break; + } + } + else if (kind == eRegisterKindGCC) + { + switch (reg) + { + case arm64_gcc::x0: return gpr_x0; + case arm64_gcc::x1: return gpr_x1; + case arm64_gcc::x2: return gpr_x2; + case arm64_gcc::x3: return gpr_x3; + case arm64_gcc::x4: return gpr_x4; + case arm64_gcc::x5: return gpr_x5; + case arm64_gcc::x6: return gpr_x6; + case arm64_gcc::x7: return gpr_x7; + case arm64_gcc::x8: return gpr_x8; + case arm64_gcc::x9: return gpr_x9; + case arm64_gcc::x10: return gpr_x10; + case arm64_gcc::x11: return gpr_x11; + case arm64_gcc::x12: return gpr_x12; + case arm64_gcc::x13: return gpr_x13; + case arm64_gcc::x14: return gpr_x14; + case arm64_gcc::x15: return gpr_x15; + case arm64_gcc::x16: return gpr_x16; + case arm64_gcc::x17: return gpr_x17; + case arm64_gcc::x18: return gpr_x18; + case arm64_gcc::x19: return gpr_x19; + case arm64_gcc::x20: return gpr_x20; + case arm64_gcc::x21: return gpr_x21; + case arm64_gcc::x22: return gpr_x22; + case arm64_gcc::x23: return gpr_x23; + case arm64_gcc::x24: return gpr_x24; + case arm64_gcc::x25: return gpr_x25; + case arm64_gcc::x26: return gpr_x26; + case arm64_gcc::x27: return gpr_x27; + case arm64_gcc::x28: return gpr_x28; + case arm64_gcc::fp: return gpr_fp; + case arm64_gcc::sp: return gpr_sp; + case arm64_gcc::lr: return gpr_lr; + case arm64_gcc::pc: return gpr_pc; + case arm64_gcc::cpsr: return gpr_cpsr; + } + } + else if (kind == eRegisterKindLLDB) + { + return reg; + } + return LLDB_INVALID_REGNUM; +} + + +uint32_t +RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints () +{ +#if defined (__arm64__) + // autodetect how many watchpoints are supported dynamically... + static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; + if (g_num_supported_hw_watchpoints == UINT32_MAX) + { + size_t len; + uint32_t n = 0; + len = sizeof (n); + if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) + { + g_num_supported_hw_watchpoints = n; + } + } + return g_num_supported_hw_watchpoints; +#else + // TODO: figure out remote case here! + return 2; +#endif +} + + +uint32_t +RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) +{ +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write); + + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + // Can't watch zero bytes + if (size == 0) + return LLDB_INVALID_INDEX32; + + // We must watch for either read or write + if (read == false && write == false) + return LLDB_INVALID_INDEX32; + + // Can't watch more than 4 bytes per WVR/WCR pair + if (size > 4) + return LLDB_INVALID_INDEX32; + + // We can only watch up to four bytes that follow a 4 byte aligned address + // per watchpoint register pair. Since we have at most so we can only watch + // until the next 4 byte boundary and we need to make sure we can properly + // encode this. + uint32_t addr_word_offset = addr % 4; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); + + uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); + if (byte_mask > 0xfu) + return LLDB_INVALID_INDEX32; + + // Read the debug state + int kret = ReadDBG (false); + + if (kret == KERN_SUCCESS) + { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i=0; iPrintf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return i; + } + else + { +// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); + } + } + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index) +{ + int kret = ReadDBG (false); + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (kret == KERN_SUCCESS) + { + if (hw_index < num_hw_points) + { + dbg.wcr[hw_index] = 0; +// if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", +// hw_index, +// hw_index, +// dbg.wvr[hw_index], +// hw_index, +// dbg.wcr[hw_index]); + + kret = WriteDBG(); + + if (kret == KERN_SUCCESS) + return true; + } + } + return false; +} + +#endif diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h new file mode 100644 index 000000000000..44479c81058c --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h @@ -0,0 +1,296 @@ +//===-- RegisterContextDarwin_arm64.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_RegisterContextDarwin_arm64_h_ +#define liblldb_RegisterContextDarwin_arm64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" + +// Break only in privileged or user mode +#define S_RSVD ((uint32_t)(0u << 1)) +#define S_PRIV ((uint32_t)(1u << 1)) +#define S_USER ((uint32_t)(2u << 1)) +#define S_PRIV_USER ((S_PRIV) | (S_USER)) + +#define WCR_ENABLE ((uint32_t)(1u)) + +// Watchpoint load/store +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) + +class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext +{ +public: + + RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx); + + virtual + ~RegisterContextDarwin_arm64(); + + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb_private::RegisterSet * + GetRegisterSet (size_t set); + + virtual bool + ReadRegister (const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue ®_value); + + virtual bool + WriteRegister (const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue ®_value); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + + virtual uint32_t + NumSupportedHardwareWatchpoints (); + + virtual uint32_t + SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); + + virtual bool + ClearHardwareWatchpoint (uint32_t hw_index); + + // mirrors arm_thread_state64_t + struct GPR + { + uint64_t x[29]; // x0-x28 + uint64_t fp; // x29 + uint64_t lr; // x30 + uint64_t sp; // x31 + uint64_t pc; // pc + uint32_t cpsr; // cpsr + }; + + + struct VReg + { + uint8_t bytes[16]; + }; + + // mirrors arm_neon_state64_t + struct FPU + { + VReg v[32]; + uint32_t fpsr; + uint32_t fpcr; + }; + + // mirrors arm_exception_state64_t + struct EXC + { + uint64_t far; // Virtual Fault Address + uint32_t esr; // Exception syndrome + uint32_t exception; // number of arm exception token + }; + + // mirrors arm_debug_state64_t + struct DBG + { + uint64_t bvr[16]; + uint64_t bcr[16]; + uint64_t wvr[16]; + uint64_t wcr[16]; + uint64_t mdscr_el1; + }; + + static void + LogDBGRegisters (lldb_private::Log *log, const DBG& dbg); + +protected: + + enum + { + GPRRegSet = 6, // ARM_THREAD_STATE64 + FPURegSet = 17, // ARM_NEON_STATE64 + EXCRegSet = 7, // ARM_EXCEPTION_STATE64 + DBGRegSet = 15 // ARM_DEBUG_STATE64 + }; + + enum + { + GPRWordCount = sizeof(GPR)/sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT + FPUWordCount = sizeof(FPU)/sizeof(uint32_t), // ARM_NEON_STATE64_COUNT + EXCWordCount = sizeof(EXC)/sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT + DBGWordCount = sizeof(DBG)/sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT + }; + + enum + { + Read = 0, + Write = 1, + kNumErrors = 2 + }; + + GPR gpr; + FPU fpu; + EXC exc; + DBG dbg; + int gpr_errs[2]; // Read/Write errors + int fpu_errs[2]; // Read/Write errors + int exc_errs[2]; // Read/Write errors + int dbg_errs[2]; // Read/Write errors + + void + InvalidateAllRegisterStates() + { + SetError (GPRRegSet, Read, -1); + SetError (FPURegSet, Read, -1); + SetError (EXCRegSet, Read, -1); + } + + int + GetError (int flavor, uint32_t err_idx) const + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case GPRRegSet: return gpr_errs[err_idx]; + case FPURegSet: return fpu_errs[err_idx]; + case EXCRegSet: return exc_errs[err_idx]; + case DBGRegSet: return dbg_errs[err_idx]; + default: break; + } + } + return -1; + } + + bool + SetError (int flavor, uint32_t err_idx, int err) + { + if (err_idx < kNumErrors) + { + switch (flavor) + { + case GPRRegSet: + gpr_errs[err_idx] = err; + return true; + + case FPURegSet: + fpu_errs[err_idx] = err; + return true; + + case EXCRegSet: + exc_errs[err_idx] = err; + return true; + + case DBGRegSet: + exc_errs[err_idx] = err; + return true; + + default: break; + } + } + return false; + } + + bool + RegisterSetIsCached (int set) const + { + return GetError(set, Read) == 0; + } + + int + ReadGPR (bool force); + + int + ReadFPU (bool force); + + int + ReadEXC (bool force); + + int + ReadDBG (bool force); + + int + WriteGPR (); + + int + WriteFPU (); + + int + WriteEXC (); + + int + WriteDBG (); + + + // Subclasses override these to do the actual reading. + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) + { + return -1; + } + + virtual int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0; + + virtual int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0; + + virtual int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0; + + virtual int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0; + + virtual int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0; + + virtual int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0; + + virtual int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0; + + int + ReadRegisterSet (uint32_t set, bool force); + + int + WriteRegisterSet (uint32_t set); + + static uint32_t + GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num); + + static int + GetSetForNativeRegNum (int reg_num); + + static size_t + GetRegisterInfosCount (); + + static const lldb_private::RegisterInfo * + GetRegisterInfos (); +}; + +#endif // liblldb_RegisterContextDarwin_arm64_h_ diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 5b6d9fe9f3bb..131aa452e3e3 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -149,7 +149,7 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info, // TOOD: need a better way to detect when "long double" types are // the same bytes size as "double" -#if !defined(__arm__) && !defined(_MSC_VER) && !defined(__mips__) +#if !defined(__arm__) && !defined(__arm64__) && !defined(_MSC_VER) && !defined(__mips__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 8aa21c61856d..d1862398086e 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -439,6 +439,37 @@ StopInfoMachException::CreateStopReasonWithMachException } break; + case llvm::Triple::arm64: + { + if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT + { + // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 is set + return StopInfo::CreateStopReasonToTrace(thread); + } + if (exc_code == 0x102) // EXC_ARM_DA_DEBUG + { + // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled + // data break address from our watchpoint list. + lldb::WatchpointSP wp_sp; + if (target) + wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); + if (wp_sp && wp_sp->IsEnabled()) + { + // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data. + // Set the hardware index if that's the case. + if (exc_data_count >= 3) + wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code); + return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + } + // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS + if (thread.GetTemporaryResumeState() == eStateStepping) + return StopInfo::CreateStopReasonToTrace(thread); + } + // It looks like exc_sub_code has the 4 bytes of the instruction that triggered the + // exception, i.e. our breakpoint opcode + is_actual_breakpoint = exc_code == 1; + } + default: break; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index e27186ff86c3..f436799a86a1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -27,6 +27,7 @@ #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Target.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -57,6 +58,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_vCont_S (eLazyBoolCalculate), m_qHostInfo_is_valid (eLazyBoolCalculate), m_qProcessInfo_is_valid (eLazyBoolCalculate), + m_qGDBServerVersion_is_valid (eLazyBoolCalculate), m_supports_alloc_dealloc_memory (eLazyBoolCalculate), m_supports_memory_region_info (eLazyBoolCalculate), m_supports_watchpoint_support_info (eLazyBoolCalculate), @@ -65,6 +67,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_avoid_g_packets (eLazyBoolCalculate), m_supports_QSaveRegisterState (eLazyBoolCalculate), m_supports_qXfer_auxv_read (eLazyBoolCalculate), m_supports_qXfer_libraries_read (eLazyBoolCalculate), @@ -100,6 +103,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_os_build (), m_os_kernel (), m_hostname (), + m_gdb_server_name(), + m_gdb_server_version(UINT32_MAX), m_default_packet_timeout (0), m_max_packet_size (0) { @@ -301,10 +306,12 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; + m_qGDBServerVersion_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; + m_avoid_g_packets = eLazyBoolCalculate; m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; @@ -322,8 +329,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; + m_host_arch.Clear(); m_process_arch.Clear(); + m_os_version_major = UINT32_MAX; + m_os_version_minor = UINT32_MAX; + m_os_version_update = UINT32_MAX; + m_os_build.clear(); + m_os_kernel.clear(); + m_hostname.clear(); + m_gdb_server_name.clear(); + m_gdb_server_version = UINT32_MAX; + m_default_packet_timeout = 0; m_max_packet_size = 0; } @@ -1314,6 +1331,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) return -1; } +int +GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) +{ + if (data && *data != '\0') + { + StreamString packet; + packet.Printf("QSetProcessEvent:%s", data); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) + { + if (response.IsOKResponse()) + { + if (was_supported) + *was_supported = true; + return 0; + } + else if (response.IsUnsupportedResponse()) + { + if (was_supported) + *was_supported = false; + return -1; + } + else + { + uint8_t error = response.GetError(); + if (was_supported) + *was_supported = true; + if (error) + return error; + } + } + } + return -1; +} + bool GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, uint32_t &minor, @@ -1394,6 +1446,69 @@ GDBRemoteCommunicationClient::GetProcessArchitecture () return m_process_arch; } +bool +GDBRemoteCommunicationClient::GetGDBServerVersion() +{ + if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) + { + m_gdb_server_name.clear(); + m_gdb_server_version = 0; + m_qGDBServerVersion_is_valid = eLazyBoolNo; + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) + { + if (response.IsNormalResponse()) + { + std::string name; + std::string value; + bool success = false; + while (response.GetNameColonValue(name, value)) + { + if (name.compare("name") == 0) + { + success = true; + m_gdb_server_name.swap(value); + } + else if (name.compare("version") == 0) + { + size_t dot_pos = value.find('.'); + if (dot_pos != std::string::npos) + value[dot_pos] = '\0'; + const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0); + if (version != UINT32_MAX) + { + success = true; + m_gdb_server_version = version; + } + } + } + if (success) + m_qGDBServerVersion_is_valid = eLazyBoolYes; + } + } + } + return m_qGDBServerVersion_is_valid == eLazyBoolYes; +} + +const char * +GDBRemoteCommunicationClient::GetGDBServerProgramName() +{ + if (GetGDBServerVersion()) + { + if (!m_gdb_server_name.empty()) + return m_gdb_server_name.c_str(); + } + return NULL; +} + +uint32_t +GDBRemoteCommunicationClient::GetGDBServerProgramVersion() +{ + if (GetGDBServerVersion()) + return m_gdb_server_version; + return 0; +} bool GDBRemoteCommunicationClient::GetHostInfo (bool force) @@ -1558,6 +1673,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::arm64: case llvm::Triple::arm: case llvm::Triple::thumb: os_name = "ios"; @@ -1598,6 +1714,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { switch (m_host_arch.GetMachine()) { + case llvm::Triple::arm64: case llvm::Triple::arm: case llvm::Triple::thumb: host_triple.setOS(llvm::Triple::IOS); @@ -3228,6 +3345,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s return false; } +bool +GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) +{ + // Some targets have issues with g/G packets and we need to avoid using them + if (m_avoid_g_packets == eLazyBoolCalculate) + { + if (process) + { + m_avoid_g_packets = eLazyBoolNo; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS + && arch.GetTriple().getArch() == llvm::Triple::arm64) + { + m_avoid_g_packets = eLazyBoolYes; + uint32_t gdb_server_version = GetGDBServerProgramVersion(); + if (gdb_server_version != 0) + { + const char *gdb_server_name = GetGDBServerProgramName(); + if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) + { + if (gdb_server_version >= 310) + m_avoid_g_packets = eLazyBoolNo; + } + } + } + } + } + return m_avoid_g_packets == eLazyBoolYes; +} + bool GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 4e404b6ab44a..8de845fa5fee 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -159,6 +159,10 @@ public: int SendLaunchArchPacket (const char *arch); + + int + SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL); + //------------------------------------------------------------------ /// Sends a "vAttach:PID" where PID is in hex. /// @@ -494,7 +498,16 @@ public: bool RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + + const char * + GetGDBServerProgramName(); + uint32_t + GetGDBServerProgramVersion(); + + bool + AvoidGPackets(ProcessGDBRemote *process); + protected: PacketResult @@ -505,6 +518,9 @@ protected: bool GetCurrentProcessInfo (); + bool + GetGDBServerVersion(); + //------------------------------------------------------------------ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these //------------------------------------------------------------------ @@ -519,6 +535,7 @@ protected: lldb_private::LazyBool m_supports_vCont_S; lldb_private::LazyBool m_qHostInfo_is_valid; lldb_private::LazyBool m_qProcessInfo_is_valid; + lldb_private::LazyBool m_qGDBServerVersion_is_valid; lldb_private::LazyBool m_supports_alloc_dealloc_memory; lldb_private::LazyBool m_supports_memory_region_info; lldb_private::LazyBool m_supports_watchpoint_support_info; @@ -527,6 +544,7 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_avoid_g_packets; lldb_private::LazyBool m_supports_QSaveRegisterState; lldb_private::LazyBool m_supports_qXfer_auxv_read; lldb_private::LazyBool m_supports_qXfer_libraries_read; @@ -574,6 +592,8 @@ protected: std::string m_os_build; std::string m_os_kernel; std::string m_hostname; + std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported + uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported uint32_t m_default_packet_timeout; uint64_t m_max_packet_size; // as returned by qSupported diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 5542f7915a1d..2fadf3359f56 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -447,22 +447,21 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } #if defined(__APPLE__) -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) // For iOS devices, we are connected through a USB Mux so we never pretend // to actually have a hostname as far as the remote lldb that is connecting // to this lldb-platform is concerned response.PutCString ("hostname:"); response.PutCStringAsRawHex8("127.0.0.1"); response.PutChar(';'); -#else // #if defined(__arm__) +#else // #if defined(__arm__) || defined(__arm64__) if (Host::GetHostname (s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - -#endif // #if defined(__arm__) +#endif // #if defined(__arm__) || defined(__arm64__) #else // #if defined(__APPLE__) if (Host::GetHostname (s)) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 73b9b3e8267e..9e5b0d79e101 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -21,6 +21,7 @@ #include "lldb/Interpreter/PythonDataObjects.h" #endif #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -502,6 +503,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) StringExtractorGDBRemote response; + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) { @@ -519,29 +522,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsErrorResponse()) - return false; - - std::string &response_str = response.GetStringRef(); - if (isxdigit(response_str[0])) + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { - response_str.insert(0, 1, 'G'); - if (thread_suffix_supported) + if (response.IsErrorResponse()) + return false; + + std::string &response_str = response.GetStringRef(); + if (isxdigit(response_str[0])) { - char thread_id_cstr[64]; - ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - response_str.append (thread_id_cstr); + response_str.insert(0, 1, 'G'); + if (thread_suffix_supported) + { + char thread_id_cstr[64]; + ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + response_str.append (thread_id_cstr); + } + data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); + return true; } - data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); - return true; } } + else + { + // For the use_g_packet == false case, we're going to read each register + // individually and store them as binary data in a buffer instead of as ascii + // characters. + const RegisterInfo *reg_info; + + // data_sp will take ownership of this DataBufferHeap pointer soon. + DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); + + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + ReadRegisterBytes (reg_info, m_reg_data); + // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer + } + memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); + + data_sp = reg_ctx; + return true; + } } } else { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { @@ -575,6 +611,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; + StringExtractorGDBRemote response; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) @@ -588,63 +626,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data // as well. const char *G_packet = (const char *)data_sp->GetBytes(); size_t G_packet_len = data_sp->GetByteSize(); - if (gdb_comm.SendPacketAndWaitForResponse (G_packet, - G_packet_len, - response, - false) == GDBRemoteCommunication::PacketResult::Success) + if (use_g_packet + && gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - return true; - else if (response.IsErrorResponse()) + // The data_sp contains the entire G response packet including the + // G, and if the thread suffix is supported, it has the thread suffix + // as well. + const char *G_packet = (const char *)data_sp->GetBytes(); + size_t G_packet_len = data_sp->GetByteSize(); + if (gdb_comm.SendPacketAndWaitForResponse (G_packet, + G_packet_len, + response, + false) == GDBRemoteCommunication::PacketResult::Success) { - uint32_t num_restored = 0; - // We need to manually go through all of the registers and - // restore them manually - - response.GetStringRef().assign (G_packet, G_packet_len); - response.SetFilePos(1); // Skip the leading 'G' - DataBufferHeap buffer (m_reg_data.GetByteSize(), 0); - DataExtractor restore_data (buffer.GetBytes(), - buffer.GetByteSize(), - m_reg_data.GetByteOrder(), - m_reg_data.GetAddressByteSize()); - - const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), - restore_data.GetByteSize(), - '\xcc'); - - if (bytes_extracted < restore_data.GetByteSize()) - restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); - - //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data) - const RegisterInfo *reg_info; - // We have to march the offset of each register along in the - // buffer to make sure we get the right offset. - uint32_t reg_byte_offset = 0; - for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size) + if (response.IsOKResponse()) + return true; + else if (response.IsErrorResponse()) { - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + uint32_t num_restored = 0; + // We need to manually go through all of the registers and + // restore them manually + + response.GetStringRef().assign (G_packet, G_packet_len); + response.SetFilePos(1); // Skip the leading 'G' - // Skip composite registers. - if (reg_info->value_regs) - continue; + // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix therad specifier. + // This means buffer will be a little more than 2x larger than necessary but we resize + // it down once we've extracted all hex ascii chars from the packet. + DataBufferHeap buffer (G_packet_len, 0); + DataExtractor restore_data (buffer.GetBytes(), + buffer.GetByteSize(), + m_reg_data.GetByteOrder(), + m_reg_data.GetAddressByteSize()); + + const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(), + restore_data.GetByteSize(), + '\xcc'); + + if (bytes_extracted < restore_data.GetByteSize()) + restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); + + const RegisterInfo *reg_info; - // Only write down the registers that need to be written - // if we are going to be doing registers individually. - bool write_reg = true; - const uint32_t reg_byte_size = reg_info->byte_size; + // The g packet contents may either include the slice registers (registers defined in + // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers + // should NOT be in the g packet, but some implementations may incorrectly include them. + // + // If the slice registers are included in the packet, we must step over the slice registers + // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. + // If the slice registers are not included, then using the byte_offset values into the + // data buffer is the best way to find individual register values. - const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size); - if (restore_src) + int size_including_slice_registers = 0; + int size_not_including_slice_registers = 0; + int size_by_highest_offset = 0; + + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) { - if (GetRegisterIsValid(reg)) + size_including_slice_registers += reg_info->byte_size; + if (reg_info->value_regs == NULL) + size_not_including_slice_registers += reg_info->byte_size; + if (reg_info->byte_offset >= size_by_highest_offset) + size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; + } + + bool use_byte_offset_into_buffer; + if (size_by_highest_offset == restore_data.GetByteSize()) + { + // The size of the packet agrees with the highest offset: + size in the register file + use_byte_offset_into_buffer = true; + } + else if (size_not_including_slice_registers == restore_data.GetByteSize()) + { + // The size of the packet is the same as concenating all of the registers sequentially, + // skipping the slice registers + use_byte_offset_into_buffer = true; + } + else if (size_including_slice_registers == restore_data.GetByteSize()) + { + // The slice registers are present in the packet (when they shouldn't be). + // Don't try to use the RegisterInfo byte_offset into the restore_data, it will + // point to the wrong place. + use_byte_offset_into_buffer = false; + } + else { + // None of our expected sizes match the actual g packet data we're looking at. + // The most conservative approach here is to use the running total byte offset. + use_byte_offset_into_buffer = false; + } + + // In case our register definitions don't include the correct offsets, + // keep track of the size of each reg & compute offset based on that. + uint32_t running_byte_offset = 0; + for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) + { + // Skip composite aka slice registers (e.g. eax is a slice of rax). + if (reg_info->value_regs) + continue; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + uint32_t register_offset; + if (use_byte_offset_into_buffer) { - const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size); - if (current_src) - write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + register_offset = reg_info->byte_offset; + } + else + { + register_offset = running_byte_offset; } - if (write_reg) + // Only write down the registers that need to be written + // if we are going to be doing registers individually. + bool write_reg = true; + const uint32_t reg_byte_size = reg_info->byte_size; + + const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); + if (restore_src) { StreamString packet; packet.Printf ("P%x=", reg); @@ -662,15 +763,89 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data response, false) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsOKResponse()) - ++num_restored; + const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); + if (current_src) + write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; + } + + if (write_reg) + { + StreamString packet; + packet.Printf ("P%x=", reg); + packet.PutBytesAsRawHex8 (restore_src, + reg_byte_size, + lldb::endian::InlHostByteOrder(), + lldb::endian::InlHostByteOrder()); + + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; + } } } } + return num_restored > 0; } - return num_restored > 0; } } + else + { + // For the use_g_packet == false case, we're going to write each register + // individually. The data buffer is binary data in this case, instead of + // ascii characters. + + bool arm64_debugserver = false; + if (m_thread.GetProcess().get()) + { + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + if (arch.IsValid() + && arch.GetMachine() == llvm::Triple::arm64 + && arch.GetTriple().getVendor() == llvm::Triple::Apple + && arch.GetTriple().getOS() == llvm::Triple::IOS) + { + arm64_debugserver = true; + } + } + uint32_t num_restored = 0; + const RegisterInfo *reg_info; + for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) + { + if (reg_info->value_regs) // skip registers that are slices of real registers + continue; + // Skip the fpsr and fpcr floating point status/control register writing to + // work around a bug in an older version of debugserver that would lead to + // register context corruption when writing fpsr/fpcr. + if (arm64_debugserver && + (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) + { + continue; + } + StreamString packet; + packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]); + packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); + if (thread_suffix_supported) + packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); + + SetRegisterIsValid(reg_info, false); + if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), + packet.GetString().size(), + response, + false) == GDBRemoteCommunication::PacketResult::Success) + { + if (response.IsOKResponse()) + ++num_restored; + } + } + return num_restored > 0; + } } } else diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 1bee5806e5f8..48db3b0ffaec 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -800,6 +800,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName()); + const char * launch_event_data = launch_info.GetLaunchEventData(); + if (launch_event_data != NULL && *launch_event_data != '\0') + m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); + if (working_dir && working_dir[0]) { m_gdb_comm.SetWorkingDir (working_dir); @@ -2608,7 +2612,7 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); debugserver_launch_info.SetUserID(process_info.GetUserID()); -#if defined (__APPLE__) && defined (__arm__) +#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__)) // On iOS, still do a local connection using a random port const char *hostname = "127.0.0.1"; uint16_t port = get_random_port (); @@ -2924,13 +2928,33 @@ ProcessGDBRemote::AsyncThread (void *arg) break; case eStateExited: + { process->SetLastStopPacket (response); process->ClearThreadIDList(); response.SetFilePos(1); - process->SetExitStatus(response.GetHexU8(), NULL); + + int exit_status = response.GetHexU8(); + const char *desc_cstr = NULL; + StringExtractor extractor; + std::string desc_string; + if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') + { + std::string desc_token; + while (response.GetNameColonValue (desc_token, desc_string)) + { + if (desc_token == "description") + { + extractor.GetStringRef().swap(desc_string); + extractor.SetFilePos(0); + extractor.GetHexByteString (desc_string); + desc_cstr = desc_string.c_str(); + } + } + } + process->SetExitStatus(exit_status, desc_cstr); done = true; break; - + } case eStateInvalid: process->SetExitStatus(-1, "lost connection"); break; @@ -3066,6 +3090,25 @@ ProcessGDBRemote::GetDynamicLoader () return m_dyld_ap.get(); } +Error +ProcessGDBRemote::SendEventData(const char *data) +{ + int return_value; + bool was_supported; + + Error error; + + return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); + if (return_value != 0) + { + if (!was_supported) + error.SetErrorString("Sending events is not supported for this process."); + else + error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); + } + return error; +} + const DataBufferSP ProcessGDBRemote::GetAuxvData() { @@ -3079,7 +3122,6 @@ ProcessGDBRemote::GetAuxvData() return buf; } - class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { private: diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 1d4a23509e65..4f5cca576598 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -221,13 +221,15 @@ public: return m_gdb_comm; } + virtual lldb_private::Error + SendEventData(const char *data); + //---------------------------------------------------------------------- // Override SetExitStatus so we can disconnect from the remote GDB server //---------------------------------------------------------------------- virtual bool SetExitStatus (int exit_status, const char *cstr); - protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; diff --git a/lldb/source/Symbol/ClangASTType.cpp b/lldb/source/Symbol/ClangASTType.cpp index fdb92f2ba3b3..aff032f4cf2e 100644 --- a/lldb/source/Symbol/ClangASTType.cpp +++ b/lldb/source/Symbol/ClangASTType.cpp @@ -406,6 +406,102 @@ ClangASTType::IsFunctionType (bool *is_variadic_ptr) const return false; } +// Used to detect "Homogeneous Floating-point Aggregates" +uint32_t +ClangASTType::IsHomogeneousAggregate (ClangASTType* base_type_ptr) const +{ + if (!IsValid()) + return 0; + + QualType qual_type(GetCanonicalQualType()); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + if (GetCompleteType ()) + { + const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + if (cxx_record_decl->getNumBases() || + cxx_record_decl->isDynamicClass()) + return 0; + } + const RecordType *record_type = cast(qual_type.getTypePtr()); + if (record_type) + { + const RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) + { + // We are looking for a structure that contains only floating point types + RecordDecl::field_iterator field_pos, field_end = record_decl->field_end(); + uint32_t num_fields = 0; + bool is_hva = false; + bool is_hfa = false; + QualType base_qual_type; + for (field_pos = record_decl->field_begin(); field_pos != field_end; ++field_pos) + { + QualType field_qual_type = field_pos->getType(); + if (field_qual_type->isFloatingType()) + { + if (field_qual_type->isComplexType()) + return 0; + else + { + if (num_fields == 0) + base_qual_type = field_qual_type; + else + { + if (is_hva) + return 0; + is_hfa = true; + if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr()) + return 0; + } + } + } + else if (field_qual_type->isVectorType() || field_qual_type->isExtVectorType()) + { + const VectorType *array = cast(field_qual_type.getTypePtr()); + if (array && array->getNumElements() <= 4) + { + if (num_fields == 0) + base_qual_type = array->getElementType(); + else + { + if (is_hfa) + return 0; + is_hva = true; + if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr()) + return 0; + } + } + else + return 0; + } + else + return 0; + ++num_fields; + } + if (base_type_ptr) + *base_type_ptr = ClangASTType (m_ast, base_qual_type); + return num_fields; + } + } + } + break; + + case clang::Type::Typedef: + return ClangASTType(m_ast, cast(qual_type)->getDecl()->getUnderlyingType()).IsHomogeneousAggregate (base_type_ptr); + + case clang::Type::Elaborated: + return ClangASTType(m_ast, cast(qual_type)->getNamedType()).IsHomogeneousAggregate (base_type_ptr); + default: + break; + } + return 0; +} + size_t ClangASTType::GetNumberOfFunctionArguments () const { @@ -6545,3 +6641,4 @@ lldb_private::operator != (const lldb_private::ClangASTType &lhs, const lldb_pri } + diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 15768b087a28..1d7da985fbac 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -2082,6 +2082,7 @@ Thread::GetUnwinder () case llvm::Triple::x86_64: case llvm::Triple::x86: case llvm::Triple::arm: + case llvm::Triple::arm64: case llvm::Triple::thumb: case llvm::Triple::mips64: case llvm::Triple::hexagon: diff --git a/lldb/source/Utility/ARM64_DWARF_Registers.cpp b/lldb/source/Utility/ARM64_DWARF_Registers.cpp new file mode 100644 index 000000000000..760ee052a4cf --- /dev/null +++ b/lldb/source/Utility/ARM64_DWARF_Registers.cpp @@ -0,0 +1,146 @@ +//===-- ARM64_DWARF_Registers.c ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARM64_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; +using namespace arm64_dwarf; + +const char * +arm64_dwarf::GetRegisterName (unsigned reg_num, bool altnernate_name) +{ + if (altnernate_name) + { + switch (reg_num) + { + case fp: return "x29"; + case lr: return "x30"; + case sp: return "x31"; + default: + break; + } + return NULL; + } + + switch (reg_num) + { + case x0: return "x0"; + case x1: return "x1"; + case x2: return "x2"; + case x3: return "x3"; + case x4: return "x4"; + case x5: return "x5"; + case x6: return "x6"; + case x7: return "x7"; + case x8: return "x8"; + case x9: return "x9"; + case x10: return "x10"; + case x11: return "x11"; + case x12: return "x12"; + case x13: return "x13"; + case x14: return "x14"; + case x15: return "x15"; + case x16: return "x16"; + case x17: return "x17"; + case x18: return "x18"; + case x19: return "x19"; + case x20: return "x20"; + case x21: return "x21"; + case x22: return "x22"; + case x23: return "x23"; + case x24: return "x24"; + case x25: return "x25"; + case x26: return "x26"; + case x27: return "x27"; + case x28: return "x28"; + case fp: return "fp"; + case lr: return "lr"; + case sp: return "sp"; + case pc: return "pc"; + case cpsr: return "cpsr"; + case v0: return "v0"; + case v1: return "v1"; + case v2: return "v2"; + case v3: return "v3"; + case v4: return "v4"; + case v5: return "v5"; + case v6: return "v6"; + case v7: return "v7"; + case v8: return "v8"; + case v9: return "v9"; + case v10: return "v10"; + case v11: return "v11"; + case v12: return "v12"; + case v13: return "v13"; + case v14: return "v14"; + case v15: return "v15"; + case v16: return "v16"; + case v17: return "v17"; + case v18: return "v18"; + case v19: return "v19"; + case v20: return "v20"; + case v21: return "v21"; + case v22: return "v22"; + case v23: return "v23"; + case v24: return "v24"; + case v25: return "v25"; + case v26: return "v26"; + case v27: return "v27"; + case v28: return "v28"; + case v29: return "v29"; + case v30: return "v30"; + case v31: return "v31"; + } + return 0; +} + +bool +arm64_dwarf::GetRegisterInfo (unsigned reg_num, RegisterInfo ®_info) +{ + ::memset (®_info, 0, sizeof(RegisterInfo)); + ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds)); + + if (reg_num >= x0 && reg_num <= pc) + { + reg_info.byte_size = 8; + reg_info.format = eFormatHex; + reg_info.encoding = eEncodingUint; + } + else if (reg_num >= v0 && reg_num <= v31) + { + reg_info.byte_size = 16; + reg_info.format = eFormatVectorOfFloat32; + reg_info.encoding = eEncodingVector; + } + else if (reg_num == cpsr) + { + reg_info.byte_size = 4; + reg_info.format = eFormatHex; + reg_info.encoding = eEncodingUint; + } + else + { + return false; + } + + reg_info.name = arm64_dwarf::GetRegisterName (reg_num, false); + reg_info.alt_name = arm64_dwarf::GetRegisterName (reg_num, true); + reg_info.kinds[eRegisterKindDWARF] = reg_num; + + switch (reg_num) + { + case fp: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break; + case lr: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break; + case sp: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break; + case pc: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break; + default: break; + } + return true; +} diff --git a/lldb/source/Utility/ARM64_DWARF_Registers.h b/lldb/source/Utility/ARM64_DWARF_Registers.h new file mode 100644 index 000000000000..832f25d45b5d --- /dev/null +++ b/lldb/source/Utility/ARM64_DWARF_Registers.h @@ -0,0 +1,102 @@ +//===-- ARM64_DWARF_Registers.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_ARM64_DWARF_Registers_h_ +#define utility_ARM64_DWARF_Registers_h_ + +#include "lldb/lldb-private.h" + +namespace arm64_dwarf { + +enum +{ + x0 = 0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29 = 29, fp = x29, + x30 = 30, lr = x30, + x31 = 31, sp = x31, + pc = 32, + cpsr = 33, + // 34-63 reserved + + // V0-V31 (128 bit vector registers) + v0 = 64, + v1, + v2, + v3, + v4, + v5, + v6, + v7, + v8, + v9, + v10, + v11, + v12, + v13, + v14, + v15, + v16, + v17, + v18, + v19, + v20, + v21, + v22, + v23, + v24, + v25, + v26, + v27, + v28, + v29, + v30, + v31 + + // 96-127 reserved +}; + +const char * +GetRegisterName (unsigned reg_num, bool altnernate_name); + +bool +GetRegisterInfo (unsigned reg_num, + lldb_private::RegisterInfo ®_info); + +} // namespace arm64_dwarf + +#endif // utility_ARM64_DWARF_Registers_h_ + diff --git a/lldb/source/Utility/ARM64_GCC_Registers.h b/lldb/source/Utility/ARM64_GCC_Registers.h new file mode 100644 index 000000000000..960b5e046f96 --- /dev/null +++ b/lldb/source/Utility/ARM64_GCC_Registers.h @@ -0,0 +1,92 @@ +//===-- ARM64_gdb_Registers.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_ARM64_gdb_Registers_h_ +#define utility_ARM64_gdb_Registers_h_ + +namespace arm64_gcc { + +enum +{ + x0 = 0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + fp, // aka x29 + lr, // aka x30 + sp, // aka x31 aka wzr + pc, // value is 32 + cpsr +}; + +enum +{ + v0 = 64, + v1, + v2, + v3, + v4, + v5, + v6, + v7, + v8, + v9, + v10, + v11, + v12, + v13, + v14, + v15, + v16, + v17, + v18, + v19, + v20, + v21, + v22, + v23, + v24, + v25, + v26, + v27, + v28, + v29, + v30, + v31 // 95 +}; + +}; + +#endif // utility_ARM64_gdb_Registers_h_ + diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index 19dcde5930b4..167a9d4ad392 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1) add_lldb_library(lldbUtility ARM_DWARF_Registers.cpp + ARM64_DWARF_Registers.cpp KQueue.cpp PseudoTerminal.cpp Range.cpp diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index 4afd74e7f54c..30f446d5bb51 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -27,10 +27,13 @@ #include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h" #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" +#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h" #include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h" #include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" #include "Plugins/Instruction/ARM/EmulateInstructionARM.h" +#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h" +#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h" #include "Plugins/JITLoader/GDB/JITLoaderGDB.h" #include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h" #include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h" @@ -103,6 +106,7 @@ lldb_private::Initialize () ABIMacOSX_i386::Initialize(); ABIMacOSX_arm::Initialize(); + ABIMacOSX_arm64::Initialize(); ABISysV_x86_64::Initialize(); DisassemblerLLVMC::Initialize(); ObjectContainerBSDArchive::Initialize(); @@ -113,6 +117,7 @@ lldb_private::Initialize () UnwindAssemblyInstEmulation::Initialize(); UnwindAssembly_x86::Initialize(); EmulateInstructionARM::Initialize (); + EmulateInstructionARM64::Initialize (); ObjectFilePECOFF::Initialize (); DynamicLoaderPOSIXDYLD::Initialize (); PlatformFreeBSD::Initialize(); @@ -188,6 +193,7 @@ lldb_private::Terminate () PluginManager::Terminate(); ABIMacOSX_i386::Terminate(); ABIMacOSX_arm::Terminate(); + ABIMacOSX_arm64::Terminate(); ABISysV_x86_64::Terminate(); DisassemblerLLVMC::Terminate(); ObjectContainerBSDArchive::Terminate(); @@ -198,6 +204,7 @@ lldb_private::Terminate () UnwindAssembly_x86::Terminate(); UnwindAssemblyInstEmulation::Terminate(); EmulateInstructionARM::Terminate (); + EmulateInstructionARM64::Terminate (); ObjectFilePECOFF::Terminate (); DynamicLoaderPOSIXDYLD::Terminate (); PlatformFreeBSD::Terminate(); diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m b/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m index eb3f4a2a6207..6c6cbd461657 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m @@ -10,7 +10,7 @@ #import #if defined(__APPLE__) -#if defined(__arm__) +#if defined(__arm__) || defined(__arm64__) #define IOS #endif #endif diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj index fbe621b5486e..ce63f89d696b 100644 --- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj +++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; 2660D9CE1192280900958FBD /* StringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2660D9CC1192280900958FBD /* StringExtractor.cpp */; }; + 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; @@ -18,12 +19,12 @@ 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; 26CE05B0115C36340022F371 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; - 26CE05B1115C36350022F371 /* MachProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.cpp */; }; + 26CE05B1115C36350022F371 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; 26CE05B2115C36360022F371 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; 26CE05B3115C36370022F371 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; 26CE05B4115C36380022F371 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; 26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; - 26CE05B6115C36390022F371 /* MachTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */; }; + 26CE05B6115C36390022F371 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; @@ -56,6 +57,8 @@ 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; 2660D9CC1192280900958FBD /* StringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractor.cpp; path = ../../source/Utility/StringExtractor.cpp; sourceTree = SOURCE_ROOT; }; 2660D9CD1192280900958FBD /* StringExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringExtractor.h; path = ../../source/Utility/StringExtractor.h; sourceTree = SOURCE_ROOT; }; + 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplARM64.cpp; sourceTree = ""; }; + 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplARM64.h; sourceTree = ""; }; 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = ""; }; 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = ""; }; 2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = ""; }; @@ -77,7 +80,7 @@ 26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = ""; }; 26ACA3340D3E956300A2120B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 26B67DE00EE9BC30006C8BC0 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = ""; }; - 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachTask.cpp; sourceTree = ""; }; + 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MachTask.mm; sourceTree = ""; }; 26C636AD0C71303A0024798E /* dbgnub-config.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = "dbgnub-config.pl"; sourceTree = ""; }; 26C637D60C71334A0024798E /* DNB.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNB.cpp; sourceTree = ""; }; 26C637D70C71334A0024798E /* DNB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNB.h; sourceTree = ""; }; @@ -99,7 +102,7 @@ 26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = ""; }; 26C637EE0C71334A0024798E /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = ""; }; 26C637EF0C71334A0024798E /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = ""; }; - 26C637F00C71334A0024798E /* MachProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachProcess.cpp; sourceTree = ""; }; + 26C637F00C71334A0024798E /* MachProcess.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = MachProcess.mm; sourceTree = ""; }; 26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = ""; }; 26C637F20C71334A0024798E /* MachThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThread.cpp; sourceTree = ""; }; 26C637F30C71334A0024798E /* MachThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachThread.h; sourceTree = ""; }; @@ -167,6 +170,15 @@ name = Products; sourceTree = ""; }; + 266B5ECE1460A68200E43F0A /* arm64 */ = { + isa = PBXGroup; + children = ( + 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */, + 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */, + ); + path = arm64; + sourceTree = ""; + }; 2675D41C0CCEB6CF000F49AF /* arm */ = { isa = PBXGroup; children = ( @@ -269,6 +281,7 @@ 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */, 26C637E70C71334A0024798E /* CFUtils.h */, 2675D41C0CCEB6CF000F49AF /* arm */, + 266B5ECE1460A68200E43F0A /* arm64 */, 26C637E90C71334A0024798E /* i386 */, 26C637FA0C71334A0024798E /* ppc */, 26CF99A11142EB7400011AAB /* x86_64 */, @@ -278,7 +291,7 @@ 26C637EF0C71334A0024798E /* MachException.h */, 26C637EE0C71334A0024798E /* MachException.cpp */, 26C637F10C71334A0024798E /* MachProcess.h */, - 26C637F00C71334A0024798E /* MachProcess.cpp */, + 26C637F00C71334A0024798E /* MachProcess.mm */, 26C637F30C71334A0024798E /* MachThread.h */, 26C637F20C71334A0024798E /* MachThread.cpp */, 26C637F50C71334A0024798E /* MachThreadList.h */, @@ -288,7 +301,7 @@ 26C637F90C71334A0024798E /* MachVMRegion.h */, 26C637F80C71334A0024798E /* MachVMRegion.cpp */, 26B67DE00EE9BC30006C8BC0 /* MachTask.h */, - 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */, + 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */, 9457ECF61419864100DFE7D8 /* stack_logging.h */, ); path = MacOSX; @@ -437,12 +450,12 @@ 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */, 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */, 26CE05B0115C36340022F371 /* MachException.cpp in Sources */, - 26CE05B1115C36350022F371 /* MachProcess.cpp in Sources */, + 26CE05B1115C36350022F371 /* MachProcess.mm in Sources */, 26CE05B2115C36360022F371 /* MachThread.cpp in Sources */, 26CE05B3115C36370022F371 /* MachThreadList.cpp in Sources */, 26CE05B4115C36380022F371 /* MachVMMemory.cpp in Sources */, 26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */, - 26CE05B6115C36390022F371 /* MachTask.cpp in Sources */, + 26CE05B6115C36390022F371 /* MachTask.mm in Sources */, 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */, 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */, 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */, @@ -462,6 +475,7 @@ 2660D9CE1192280900958FBD /* StringExtractor.cpp in Sources */, 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */, 4971AE7213D10F4F00649E37 /* HasAVX.s in Sources */, + 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -472,8 +486,8 @@ isa = XCBuildConfiguration; buildSettings = { "ARCHS[sdk=iphoneos*]" = ( + arm64, armv7, - armv7s, ); "ARCHS[sdk=macosx*]" = ( x86_64, @@ -533,10 +547,7 @@ 262419A11198A93E00067686 /* BuildAndIntegration */ = { isa = XCBuildConfiguration; buildSettings = { - "ARCHS[sdk=iphoneos*]" = ( - armv7, - armv7s, - ); + "ARCHS[sdk=iphoneos*]" = arm64; "ARCHS[sdk=macosx*]" = ( x86_64, i386, @@ -588,7 +599,7 @@ "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DWITH_LOCKDOWN", - "-DWITH_SPRINGBOARD", + "-DWITH_BKS", "-DOS_OBJECT_USE_OBJC=0", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; @@ -601,6 +612,10 @@ "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "-framework", SpringBoardServices, + "-framework", + BackBoardServices, + "-framework", + Foundation, "-llockdown", ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; @@ -640,7 +655,7 @@ "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DWITH_LOCKDOWN", - "-DWITH_SPRINGBOARD", + "-DWITH_BKS", "-DOS_OBJECT_USE_OBJC=0", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; @@ -653,6 +668,10 @@ "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "-framework", SpringBoardServices, + "-framework", + BackBoardServices, + "-framework", + Foundation, "-llockdown", ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; @@ -692,7 +711,7 @@ "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DWITH_LOCKDOWN", - "-DWITH_SPRINGBOARD", + "-DWITH_BKS", "-DOS_OBJECT_USE_OBJC=0", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; @@ -705,7 +724,11 @@ "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "-framework", SpringBoardServices, + "-framework", + BackBoardServices, "-llockdown", + "-framework", + Foundation, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -721,8 +744,8 @@ isa = XCBuildConfiguration; buildSettings = { "ARCHS[sdk=iphoneos*]" = ( + arm64, armv7, - armv7s, ); "ARCHS[sdk=macosx*]" = ( x86_64, @@ -776,7 +799,7 @@ "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DWITH_LOCKDOWN", - "-DWITH_SPRINGBOARD", + "-DWITH_BKS", "-DOS_OBJECT_USE_OBJC=0", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; @@ -789,7 +812,11 @@ "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "-framework", SpringBoardServices, + "-framework", + BackBoardServices, "-llockdown", + "-framework", + Foundation, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp index cd23a401e21b..0fb08e2c4fd2 100644 --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -26,6 +26,16 @@ #include #include +#define TRY_KQUEUE 1 + +#ifdef TRY_KQUEUE + #include + #include + #ifdef NOTE_EXIT_DETAIL + #define USE_KQUEUE + #endif +#endif + #include "MacOSX/MachProcess.h" #include "MacOSX/MachTask.h" #include "CFString.h" @@ -123,6 +133,95 @@ GetProcessSP (nub_process_t pid, MachProcessSP& procSP) return false; } +#ifdef USE_KQUEUE +void * +kqueue_thread (void *arg) +{ + int kq_id = (int) (intptr_t) arg; + + struct kevent death_event; + while (1) + { + int n_events = kevent (kq_id, NULL, 0, &death_event, 1, NULL); + if (n_events == -1) + { + if (errno == EINTR) + continue; + else + { + DNBLogError ("kqueue failed with error: (%d): %s", errno, strerror(errno)); + return NULL; + } + } + else if (death_event.flags & EV_ERROR) + { + int error_no = death_event.data; + const char *error_str = strerror(death_event.data); + if (error_str == NULL) + error_str = "Unknown error"; + DNBLogError ("Failed to initialize kqueue event: (%d): %s", error_no, error_str ); + return NULL; + } + else + { + int status; + pid_t child_pid = waitpid ((pid_t) death_event.ident, &status, 0); + if (death_event.data & NOTE_EXIT_MEMORY) + { + if (death_event.data & NOTE_VM_PRESSURE) + DNBProcessSetExitInfo (child_pid, "Terminated due to Memory Pressure"); + else if (death_event.data & NOTE_VM_ERROR) + DNBProcessSetExitInfo (child_pid, "Terminated due to Memory Error"); + else + DNBProcessSetExitInfo (child_pid, "Terminated due to unknown Memory condition"); + } + else if (death_event.data & NOTE_EXIT_DECRYPTFAIL) + DNBProcessSetExitInfo (child_pid, "Terminated due to decrypt failure"); + else if (death_event.data & NOTE_EXIT_CSERROR) + DNBProcessSetExitInfo (child_pid, "Terminated due to code signing error"); + + DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): setting exit status for pid = %i to %i", child_pid, status); + DNBProcessSetExitStatus (child_pid, status); + return NULL; + } + } +} + +static bool +spawn_kqueue_thread (pid_t pid) +{ + pthread_t thread; + int kq_id; + + kq_id = kqueue(); + if (kq_id == -1) + { + DNBLogError ("Could not get kqueue for pid = %i.", pid); + return false; + } + + struct kevent reg_event; + + EV_SET(®_event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT|NOTE_EXIT_DETAIL, 0, NULL); + // Register the event: + int result = kevent (kq_id, ®_event, 1, NULL, 0, NULL); + if (result != 0) + { + DNBLogError ("Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, result); + return false; + } + + int ret = ::pthread_create (&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id); + + // pthread_create returns 0 if successful + if (ret == 0) + { + ::pthread_detach (thread); + return true; + } + return false; +} +#endif // #if USE_KQUEUE static void * waitpid_thread (void *arg) @@ -161,10 +260,15 @@ waitpid_thread (void *arg) DNBProcessSetExitStatus (pid, -1); return NULL; } - static bool spawn_waitpid_thread (pid_t pid) { +#ifdef USE_KQUEUE + bool success = spawn_kqueue_thread (pid); + if (success) + return true; +#endif + pthread_t thread; int ret = ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid); // pthread_create returns 0 if successful @@ -187,6 +291,7 @@ DNBProcessLaunch (const char *path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, + const char *event_data, char *err_str, size_t err_len) { @@ -229,7 +334,8 @@ DNBProcessLaunch (const char *path, stderr_path, no_stdio, launch_flavor, - disable_aslr, + disable_aslr, + event_data, launch_err); if (err_str) { @@ -681,6 +787,19 @@ DNBProcessSignal (nub_process_t pid, int signal) return false; } +nub_bool_t +DNBProcessSendEvent (nub_process_t pid, const char *event) +{ + MachProcessSP procSP; + if (GetProcessSP (pid, procSP)) + { + // FIXME: Do something with the error... + DNBError send_error; + return procSP->SendEvent (event, send_error); + } + return false; +} + nub_bool_t DNBProcessIsAlive (nub_process_t pid) @@ -733,6 +852,28 @@ DNBProcessSetExitStatus (nub_process_t pid, int status) return false; } +const char * +DNBProcessGetExitInfo (nub_process_t pid) +{ + MachProcessSP procSP; + if (GetProcessSP (pid, procSP)) + { + return procSP->GetExitInfo(); + } + return NULL; +} + +nub_bool_t +DNBProcessSetExitInfo (nub_process_t pid, const char *info) +{ + MachProcessSP procSP; + if (GetProcessSP (pid, procSP)) + { + procSP->SetExitInfo(info); + return true; + } + return false; +} const char * DNBThreadGetName (nub_process_t pid, nub_thread_t tid) @@ -2054,8 +2195,9 @@ DNBInitialize() #if defined (__i386__) || defined (__x86_64__) DNBArchImplI386::Initialize(); DNBArchImplX86_64::Initialize(); -#elif defined (__arm__) +#elif defined (__arm__) || defined (__arm64__) DNBArchMachARM::Initialize(); + DNBArchMachARM64::Initialize(); #endif } @@ -2073,6 +2215,8 @@ DNBSetArchitecture (const char *arch) return DNBArchProtocol::SetArchitecture (CPU_TYPE_I386); else if ((strcasecmp (arch, "x86_64") == 0) || (strcasecmp (arch, "x86_64h") == 0)) return DNBArchProtocol::SetArchitecture (CPU_TYPE_X86_64); + else if (strstr (arch, "arm64") == arch || strstr (arch, "armv8") == arch) + return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM64); else if (strstr (arch, "arm") == arch) return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM); } diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h index c70ede989d57..8a215cf452d3 100644 --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -18,6 +18,12 @@ #include #include +#define DNB_EXPORT __attribute__((visibility("default"))) + +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 ((cpu_type_t) 12 | 0x01000000) +#endif + typedef bool (*DNBShouldCancelCallback) (void *); void DNBInitialize (); @@ -37,7 +43,8 @@ nub_process_t DNBProcessLaunch (const char *path, const char *stderr_path, bool no_stdio, nub_launch_flavor_t launch_flavor, - int disable_aslr, + int disable_aslr, + const char *event_data, char *err_str, size_t err_len); @@ -52,43 +59,46 @@ nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavo // explicit thread action can be made by making a thread action with a tid of // INVALID_NUB_THREAD. If there is no default action, those threads will // remain stopped. -nub_bool_t DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions); -nub_bool_t DNBProcessHalt (nub_process_t pid); -nub_bool_t DNBProcessDetach (nub_process_t pid); -nub_bool_t DNBProcessSignal (nub_process_t pid, int signal); -nub_bool_t DNBProcessKill (nub_process_t pid); -nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf); -nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf); -nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions); -nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr); -int DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info); -std::string DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType); -nub_bool_t DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type); +nub_bool_t DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) DNB_EXPORT; +nub_bool_t DNBProcessHalt (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessDetach (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSignal (nub_process_t pid, int signal) DNB_EXPORT; +nub_bool_t DNBProcessKill (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSendEvent (nub_process_t pid, const char *event) DNB_EXPORT; +nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT; +nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT; +nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT; +nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; +int DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) DNB_EXPORT; +std::string DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType) DNB_EXPORT; +nub_bool_t DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) DNB_EXPORT; //---------------------------------------------------------------------- // Process status //---------------------------------------------------------------------- -nub_bool_t DNBProcessIsAlive (nub_process_t pid); -nub_state_t DNBProcessGetState (nub_process_t pid); -nub_bool_t DNBProcessGetExitStatus (nub_process_t pid, int *status); -nub_bool_t DNBProcessSetExitStatus (nub_process_t pid, int status); -nub_size_t DNBProcessGetNumThreads (nub_process_t pid); -nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid); -nub_thread_t DNBProcessGetCurrentThreadMachPort (nub_process_t pid); -nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid); -nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx); -nub_bool_t DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid); -nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid); -nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid); -nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos); -nub_bool_t DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton); -nub_bool_t DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton); -nub_addr_t DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib); -nub_size_t DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size); -nub_size_t DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size); -nub_size_t DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size); -nub_size_t DNBProcessGetStopCount (nub_process_t pid); -uint32_t DNBProcessGetCPUType (nub_process_t pid); +nub_bool_t DNBProcessIsAlive (nub_process_t pid) DNB_EXPORT; +nub_state_t DNBProcessGetState (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessGetExitStatus (nub_process_t pid, int *status) DNB_EXPORT; +nub_bool_t DNBProcessSetExitStatus (nub_process_t pid, int status) DNB_EXPORT; +const char * DNBProcessGetExitInfo (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSetExitInfo (nub_process_t pid, const char *info) DNB_EXPORT; +nub_size_t DNBProcessGetNumThreads (nub_process_t pid) DNB_EXPORT; +nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid) DNB_EXPORT; +nub_thread_t DNBProcessGetCurrentThreadMachPort (nub_process_t pid) DNB_EXPORT; +nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; +nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx) DNB_EXPORT; +nub_bool_t DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; +nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid) DNB_EXPORT; +nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT; +nub_bool_t DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) DNB_EXPORT; +nub_bool_t DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) DNB_EXPORT; +nub_addr_t DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib) DNB_EXPORT; +nub_size_t DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; +nub_size_t DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; +nub_size_t DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; +nub_size_t DNBProcessGetStopCount (nub_process_t pid) DNB_EXPORT; +uint32_t DNBProcessGetCPUType (nub_process_t pid) DNB_EXPORT; //---------------------------------------------------------------------- // Process executable and arguments diff --git a/lldb/tools/debugserver/source/DNBArch.cpp b/lldb/tools/debugserver/source/DNBArch.cpp index f56c6a3181ef..c3f1fdf2682a 100644 --- a/lldb/tools/debugserver/source/DNBArch.cpp +++ b/lldb/tools/debugserver/source/DNBArch.cpp @@ -21,18 +21,7 @@ typedef std::map CPUPluginInfoMap; -//#if defined (__i386__) -//static uint32_t g_current_cpu_type = CPU_TYPE_I386; -//#elif defined (__x86_64__) -//static uint32_t g_current_cpu_type = CPU_TYPE_X86_64; -#if defined (__i386__) || defined (__x86_64__) static uint32_t g_current_cpu_type = 0; -#elif defined (__arm__) -static uint32_t g_current_cpu_type = CPU_TYPE_ARM; -#else -static uint32_t g_current_cpu_type = 0; -#endif - CPUPluginInfoMap g_arch_plugins; diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h index e4f6bd2fada4..54300374c78c 100644 --- a/lldb/tools/debugserver/source/DNBArch.h +++ b/lldb/tools/debugserver/source/DNBArch.h @@ -118,6 +118,7 @@ protected: #include "MacOSX/arm/DNBArchImpl.h" +#include "MacOSX/arm64/DNBArchImplARM64.h" #include "MacOSX/i386/DNBArchImplI386.h" #include "MacOSX/x86_64/DNBArchImplX86_64.h" #include "MacOSX/ppc/DNBArchImpl.h" diff --git a/lldb/tools/debugserver/source/DNBDefs.h b/lldb/tools/debugserver/source/DNBDefs.h index b08885874a28..70df4ba5ea69 100644 --- a/lldb/tools/debugserver/source/DNBDefs.h +++ b/lldb/tools/debugserver/source/DNBDefs.h @@ -23,7 +23,7 @@ //---------------------------------------------------------------------- // Define nub_addr_t and the invalid address value from the architecture //---------------------------------------------------------------------- -#if defined (__x86_64__) || defined (__ppc64__) +#if defined (__x86_64__) || defined (__ppc64__) || defined (__arm64__) //---------------------------------------------------------------------- // 64 bit address architectures @@ -90,11 +90,15 @@ typedef enum typedef enum { eLaunchFlavorDefault = 0, - eLaunchFlavorPosixSpawn, - eLaunchFlavorForkExec, + eLaunchFlavorPosixSpawn = 1, + eLaunchFlavorForkExec = 2, #ifdef WITH_SPRINGBOARD - eLaunchFlavorSpringBoard, + eLaunchFlavorSpringBoard = 3, #endif +#ifdef WITH_BKS + eLaunchFlavorBKS = 4 +#endif + } nub_launch_flavor_t; #define NUB_STATE_IS_RUNNING(s) ((s) == eStateAttaching ||\ diff --git a/lldb/tools/debugserver/source/DNBError.cpp b/lldb/tools/debugserver/source/DNBError.cpp index 84727e77fa20..b4f399010898 100644 --- a/lldb/tools/debugserver/source/DNBError.cpp +++ b/lldb/tools/debugserver/source/DNBError.cpp @@ -47,6 +47,16 @@ DNBError::AsString() const m_str.clear(); } break; +#endif +#ifdef WITH_BKS + case BackBoard: + { + // You have to call ObjC routines to get the error string from BackBoardServices. + // Not sure I want to make DNBError.cpp an .mm file. For now just make sure you + // pre-populate the error string when you make the DNBError of type BackBoard. + m_str.assign("Should have set Backboard error when making the error string."); + } + break; #endif default: break; diff --git a/lldb/tools/debugserver/source/DNBError.h b/lldb/tools/debugserver/source/DNBError.h index 78b2c8b50f38..3f8fa2f1db81 100644 --- a/lldb/tools/debugserver/source/DNBError.h +++ b/lldb/tools/debugserver/source/DNBError.h @@ -26,10 +26,13 @@ public: typedef enum { Generic = 0, - MachKernel, - POSIX + MachKernel = 1, + POSIX = 2 #ifdef WITH_SPRINGBOARD - , SpringBoard + , SpringBoard = 3 +#endif +#ifdef WITH_BKS + , BackBoard = 4 #endif } FlavorType; diff --git a/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt b/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt index 8e2ec1c66e48..24342c84f87a 100644 --- a/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt +++ b/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_NO_RTTI 1) +#add_subdirectory(arm64) #add_subdirectory(arm) add_subdirectory(i386) #add_subdirectory(ppc) @@ -31,8 +32,8 @@ add_lldb_executable(debugserver CFData.cpp CFString.cpp MachException.cpp - MachProcess.cpp - MachTask.cpp + MachProcess.mm + MachTask.mm MachThread.cpp MachThreadList.cpp MachVMMemory.cpp diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.h b/lldb/tools/debugserver/source/MacOSX/MachException.h index 08d22cd28e6e..74041e0c4bd4 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachException.h +++ b/lldb/tools/debugserver/source/MacOSX/MachException.h @@ -82,7 +82,7 @@ public: } bool IsBreakpoint() const { - return (exc_type == EXC_BREAKPOINT) || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1); + return (exc_type == EXC_BREAKPOINT || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1)); } void Dump() const; void DumpStopReason() const; diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h index 5fa5dbdcfc76..c98700c0fc59 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -55,7 +55,8 @@ public: const char *stderr_path, bool no_stdio, nub_launch_flavor_t launch_flavor, - int disable_aslr, + int disable_aslr, + const char *event_data, DNBError &err); static uint32_t GetCPUTypeForLocalProcess (pid_t pid); @@ -76,8 +77,14 @@ public: static const void * PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str); static void CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str); static nub_process_t CheckForProcess (const void *attach_token); +#ifdef WITH_BKS + pid_t BKSLaunchForDebug (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, const char *event_data, DNBError &launch_err); + pid_t BKSForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, const char *event_data, DNBError &launch_err); + bool BKSSendEvent (const char *event, DNBError &error); + static void BKSCleanupAfterAttach (const void *attach_token, DNBError &err_str); +#endif #ifdef WITH_SPRINGBOARD - pid_t SBLaunchForDebug (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, DNBError &launch_err); + pid_t SBLaunchForDebug (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, DNBError &launch_err); static pid_t SBForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], bool no_stdio, MachProcess* process, DNBError &launch_err); #endif nub_addr_t LookupSymbol (const char *name, const char *shlib); @@ -94,6 +101,7 @@ public: bool Resume (const DNBThreadResumeActions& thread_actions); bool Signal (int signal, const struct timespec *timeout_abstime = NULL); + bool SendEvent (const char *event, DNBError &send_err); bool Kill (const struct timespec *timeout_abstime = NULL); bool Detach (); nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf); @@ -213,6 +221,15 @@ public: m_exit_status = status; SetState(eStateExited); } + const char * GetExitInfo () + { + return m_exit_info.c_str(); + } + + void SetExitInfo (const char *info) + { + m_exit_info.assign(info); + } uint32_t StopCount() const { return m_stop_count; } void SetChildFileDescriptors (int stdin_fileno, int stdout_fileno, int stderr_fileno) @@ -248,6 +265,7 @@ public: } bool ProcessUsingSpringBoard() const { return (m_flags & eMachProcessFlagsUsingSBS) != 0; } + bool ProcessUsingBackBoard() const { return (m_flags & eMachProcessFlagsUsingBKS) != 0; } DNBProfileDataScanType GetProfileScanType () { return m_profile_scan_type; } @@ -256,7 +274,8 @@ private: { eMachProcessFlagsNone = 0, eMachProcessFlagsAttached = (1 << 0), - eMachProcessFlagsUsingSBS = (1 << 1) + eMachProcessFlagsUsingSBS = (1 << 1), + eMachProcessFlagsUsingBKS = (1 << 2) }; void Clear (bool detaching = false); void ReplyToAllExceptions (); @@ -273,6 +292,7 @@ private: std::string m_path; // A path to the executable if we have one std::vector m_args; // The arguments with which the process was lauched int m_exit_status; // The exit status for the process + std::string m_exit_info; // Any extra info that we may have about the exit MachTask m_task; // The mach task for this process uint32_t m_flags; // Process specific flags (see eMachProcessFlags enums) uint32_t m_stop_count; // A count of many times have we stopped @@ -304,6 +324,7 @@ private: DNBCallbackCopyExecutableImageInfos m_image_infos_callback; void * m_image_infos_baton; + std::string m_bundle_id; // If we are a SB or BKS process, this will be our bundle ID. bool m_did_exec; }; diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm similarity index 76% rename from lldb/tools/debugserver/source/MacOSX/MachProcess.cpp rename to lldb/tools/debugserver/source/MacOSX/MachProcess.mm index c077f9be0025..ca7a5b5dab5d 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -39,7 +39,7 @@ #include "CFData.h" #include "CFString.h" -static CFStringRef CopyBundleIDForPath (const char *app_buncle_path, DNBError &err_str); +static CFStringRef CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str); #ifdef WITH_SPRINGBOARD @@ -54,8 +54,44 @@ IsSBProcess (nub_process_t pid) return appIdsForPID.get() != NULL; } -#endif +#endif // WITH_SPRINGBOARD +#ifdef WITH_BKS +#import +extern "C" +{ +#import +#import +#import +} + +static bool +IsBKSProcess (nub_process_t pid) +{ + BKSApplicationStateMonitor *state_monitor = [[BKSApplicationStateMonitor alloc] init]; + BKSApplicationState app_state = [state_monitor mostElevatedApplicationStateForPID: pid]; + return app_state != BKSApplicationStateUnknown; +} + +static void +SetBKSError (BKSOpenApplicationErrorCode error_code, DNBError &error) +{ + error.SetError (error_code, DNBError::BackBoard); + NSString *err_nsstr = ::BKSOpenApplicationErrorCodeToString(error_code); + const char *err_str = NULL; + if (err_nsstr == NULL) + err_str = "unknown BKS error"; + else + { + err_str = [err_nsstr UTF8String]; + if (err_str == NULL) + err_str = "unknown BKS error"; + } + error.SetErrorString(err_str); +} + +static const int BKS_OPEN_APPLICATION_TIMEOUT_ERROR = 111; +#endif // WITH_BKS #if 0 #define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__) #else @@ -456,6 +492,18 @@ MachProcess::Signal (int signal, const struct timespec *timeout_abstime) } +bool +MachProcess::SendEvent (const char *event, DNBError &send_err) +{ + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SendEvent (event = %s) to pid: %d", event, m_pid); + if (m_pid == INVALID_NUB_PROCESS) + return false; +#if WITH_BKS + return BKSSendEvent (event, send_err); +#endif + return true; +} + nub_state_t MachProcess::DoSIGSTOP (bool clear_bps_and_wps, bool allow_running, uint32_t *thread_idx_ptr) { @@ -1475,8 +1523,11 @@ MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len) SetState(eStateAttaching); m_pid = pid; - // Let ourselves know we are going to be using SBS if the correct flag bit is set... -#ifdef WITH_SPRINGBOARD + // Let ourselves know we are going to be using SBS or BKS if the correct flag bit is set... +#if defined (WITH_BKS) + if (IsBKSProcess (pid)) + m_flags |= eMachProcessFlagsUsingBKS; +#elif defined (WITH_SPRINGBOARD) if (IsSBProcess(pid)) m_flags |= eMachProcessFlagsUsingSBS; #endif @@ -1523,9 +1574,9 @@ MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len) // cleanup seems good. const void * -MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str) +MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &attach_err) { -#ifdef WITH_SPRINGBOARD +#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) // Tell SpringBoard to halt the next launch of this application on startup. if (!waitfor) @@ -1535,50 +1586,142 @@ MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flav const bool is_app = app_ext != NULL && (app_ext[4] == '\0' || app_ext[4] == '/'); if (!is_app) { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, we can't tell springboard to wait for launch...", path); + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, " + "we can't tell springboard to wait for launch...", + path); return NULL; } - if (launch_flavor != eLaunchFlavorSpringBoard - && launch_flavor != eLaunchFlavorDefault) +#if defined (WITH_BKS) + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = eLaunchFlavorBKS; + if (launch_flavor != eLaunchFlavorBKS) return NULL; +#elif defined (WITH_SPRINGBOARD) + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = eLaunchFlavorSpringBoard; + if (launch_flavor != eLaunchFlavorSpringBoard) + return NULL; +#endif std::string app_bundle_path(path, app_ext + strlen(".app")); - CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path.c_str (), err_str); + CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path.c_str (), attach_err); std::string bundleIDStr; CFString::UTF8(bundleIDCFStr, bundleIDStr); - DNBLogThreadedIf(LOG_PROCESS, "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", app_bundle_path.c_str (), bundleIDStr.c_str()); + DNBLogThreadedIf(LOG_PROCESS, + "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", + app_bundle_path.c_str (), + bundleIDStr.c_str()); if (bundleIDCFStr == NULL) { return NULL; } - SBSApplicationLaunchError sbs_error = 0; - - const char *stdout_err = "/dev/null"; - CFString stdio_path; - stdio_path.SetFileSystemRepresentation (stdout_err); - - DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", bundleIDStr.c_str(), stdout_err, stdout_err); - sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr, - (CFURLRef)NULL, // openURL - NULL, // launch_argv.get(), - NULL, // launch_envp.get(), // CFDictionaryRef environment - stdio_path.get(), - stdio_path.get(), - SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger); - - if (sbs_error != SBSApplicationLaunchErrorSuccess) +#if defined (WITH_BKS) + if (launch_flavor == eLaunchFlavorBKS) { - err_str.SetError(sbs_error, DNBError::SpringBoard); - return NULL; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSString *stdio_path = nil; + NSFileManager *file_manager = [NSFileManager defaultManager]; + const char *null_path = "/dev/null"; + stdio_path = [file_manager stringWithFileSystemRepresentation: null_path length: strlen(null_path)]; + + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + + DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: @\"%s\",options include stdio path: \"%s\", " + "BKSDebugOptionKeyDebugOnNextLaunch & BKSDebugOptionKeyWaitForDebugger )", + bundleIDStr.c_str(), + null_path); + + [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardOutPath]; + [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardErrorPath]; + [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyWaitForDebugger]; + [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyDebugOnNextLaunch]; + + [options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions]; + + BKSSystemService *system_service = [[BKSSystemService alloc] init]; + + mach_port_t client_port = [system_service createClientPort]; + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block BKSOpenApplicationErrorCode attach_error_code = BKSOpenApplicationErrorCodeNone; + + NSString *bundleIDNSStr = (NSString *) bundleIDCFStr; + + [system_service openApplication: bundleIDNSStr + options: options + clientPort: client_port + withResult: ^(NSError *error) + { + // The system service will cleanup the client port we created for us. + if (error) + attach_error_code = (BKSOpenApplicationErrorCode)[error code]; + + [system_service release]; + dispatch_semaphore_signal(semaphore); + } + ]; + + const uint32_t timeout_secs = 9; + + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); + + long success = dispatch_semaphore_wait(semaphore, timeout) == 0; + + if (!success) + { + DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); + attach_err.SetErrorString("debugserver timed out waiting for openApplication to complete."); + attach_err.SetError (BKS_OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); + } + else if (attach_error_code != BKSOpenApplicationErrorCodeNone) + { + SetBKSError (attach_error_code, attach_err); + DNBLogError("unable to launch the application with CFBundleIdentifier '%s' bks_error = %u", + bundleIDStr.c_str(), + attach_error_code); + } + dispatch_release(semaphore); + [pool drain]; } +#elif defined (WITH_SPRINGBOARD) + if (launch_flavor == eLaunchFlavorSpringBoard) + { + SBSApplicationLaunchError sbs_error = 0; + + const char *stdout_err = "/dev/null"; + CFString stdio_path; + stdio_path.SetFileSystemRepresentation (stdout_err); + + DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", " + "SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", + bundleIDStr.c_str(), + stdout_err, + stdout_err); + + sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr, + (CFURLRef)NULL, // openURL + NULL, // launch_argv.get(), + NULL, // launch_envp.get(), // CFDictionaryRef environment + stdio_path.get(), + stdio_path.get(), + SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger); + + if (sbs_error != SBSApplicationLaunchErrorSuccess) + { + attach_err.SetError(sbs_error, DNBError::SpringBoard); + return NULL; + } + } +#endif // WITH_SPRINGBOARD DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch."); return bundleIDCFStr; -# else +# else // defined (WITH_SPRINGBOARD) || defined (WITH_BKS) return NULL; #endif } @@ -1593,7 +1736,16 @@ MachProcess::CheckForProcess (const void *attach_token) if (attach_token == NULL) return INVALID_NUB_PROCESS; -#ifdef WITH_SPRINGBOARD +#if defined (WITH_BKS) + NSString *bundleIDNSStr = (NSString *) attach_token; + BKSSystemService *systemService = [[BKSSystemService alloc] init]; + pid_t pid = [systemService pidForApplication: bundleIDNSStr]; + [systemService release]; + if (pid == 0) + return INVALID_NUB_PROCESS; + else + return pid; +#elif defined (WITH_SPRINGBOARD) CFStringRef bundleIDCFStr = (CFStringRef) attach_token; Boolean got_it; nub_process_t attach_pid; @@ -1602,8 +1754,9 @@ MachProcess::CheckForProcess (const void *attach_token) return attach_pid; else return INVALID_NUB_PROCESS; -#endif +#else return INVALID_NUB_PROCESS; +#endif } // Call this to clean up after you have either attached or given up on the attach. @@ -1614,10 +1767,18 @@ MachProcess::CheckForProcess (const void *attach_token) void MachProcess::CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str) { -#ifdef WITH_SPRINGBOARD if (attach_token == NULL) return; +#if defined (WITH_BKS) + + if (!success) + { + BKSCleanupAfterAttach (attach_token, err_str); + } + CFRelease((CFStringRef) attach_token); + +#elif defined (WITH_SPRINGBOARD) // Tell SpringBoard to cancel the debug on next launch of this application // if we failed to attach if (!success) @@ -1657,6 +1818,7 @@ MachProcess::LaunchForDebug bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, + const char *event_data, DNBError &launch_err ) { @@ -1673,7 +1835,23 @@ MachProcess::LaunchForDebug case eLaunchFlavorForkExec: m_pid = MachProcess::ForkChildForPTraceDebugging (path, argv, envp, this, launch_err); break; - +#ifdef WITH_BKS + case eLaunchFlavorBKS: + { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) + { + std::string app_bundle_path(path, app_ext + strlen(".app")); + if (BKSLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. + else + break; // We tried a BKS launch, but didn't succeed lets get out + } + } + // In case the executable name has a ".app" fragment which confuses our debugserver, + // let's do an intentional fallthrough here... + launch_flavor = eLaunchFlavorPosixSpawn; +#endif #ifdef WITH_SPRINGBOARD case eLaunchFlavorSpringBoard: @@ -1696,7 +1874,7 @@ MachProcess::LaunchForDebug if (app_ext) { std::string app_bundle_path(path, app_ext + strlen(".app")); - if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, launch_err) != 0) + if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, launch_err) != 0) return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. else break; // We tried a springboard launch, but didn't succeed lets get out @@ -2063,10 +2241,47 @@ MachProcess::ForkChildForPTraceDebugging return pid; } +#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) +// This returns a CFRetained pointer to the Bundle ID for app_bundle_path, +// or NULL if there was some problem getting the bundle id. +static CFStringRef +CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str) +{ + CFBundle bundle(app_bundle_path); + CFStringRef bundleIDCFStr = bundle.GetIdentifier(); + std::string bundleID; + if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL) + { + struct stat app_bundle_stat; + char err_msg[PATH_MAX]; + + if (::stat (app_bundle_path, &app_bundle_stat) < 0) + { + err_str.SetError(errno, DNBError::POSIX); + snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path); + err_str.SetErrorString(err_msg); + DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg); + } + else + { + err_str.SetError(-1, DNBError::Generic); + snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path); + err_str.SetErrorString(err_msg); + DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path); + } + return NULL; + } + + DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str()); + CFRetain (bundleIDCFStr); + + return bundleIDCFStr; +} +#endif // #if defined 9WITH_SPRINGBOARD) || defined (WITH_BKS) #ifdef WITH_SPRINGBOARD pid_t -MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, DNBError &launch_err) +MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, DNBError &launch_err) { // Clear out and clean up from any current state Clear(); @@ -2115,42 +2330,6 @@ MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const #include -// This returns a CFRetained pointer to the Bundle ID for app_bundle_path, -// or NULL if there was some problem getting the bundle id. -static CFStringRef -CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str) -{ - CFBundle bundle(app_bundle_path); - CFStringRef bundleIDCFStr = bundle.GetIdentifier(); - std::string bundleID; - if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL) - { - struct stat app_bundle_stat; - char err_msg[PATH_MAX]; - - if (::stat (app_bundle_path, &app_bundle_stat) < 0) - { - err_str.SetError(errno, DNBError::POSIX); - snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path); - err_str.SetErrorString(err_msg); - DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg); - } - else - { - err_str.SetError(-1, DNBError::Generic); - snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path); - err_str.SetErrorString(err_msg); - DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path); - } - return NULL; - } - - DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str()); - CFRetain (bundleIDCFStr); - - return bundleIDCFStr; -} - pid_t MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, MachProcess* process, DNBError &launch_err) { @@ -2244,10 +2423,13 @@ MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char co CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err); if (bundleIDCFStr == NULL) return INVALID_NUB_PROCESS; - + + // This is just for logging: std::string bundleID; CFString::UTF8(bundleIDCFStr, bundleID); + DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__); + // Find SpringBoard SBSApplicationLaunchError sbs_error = 0; sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr, @@ -2306,4 +2488,419 @@ MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char co #endif // #ifdef WITH_SPRINGBOARD +#ifdef WITH_BKS + +// This function runs the BKSSystemService method openApplication:options:clientPort:withResult, +// messaging the app passed in bundleIDNSStr. +// The function should be run inside of an NSAutoReleasePool. +// +// It will use the "options" dictionary passed in, and fill the error passed in if there is an error. +// If return_pid is not NULL, we'll fetch the pid that was made for the bundleID. +// If bundleIDNSStr is NULL, then the system application will be messaged. + +static bool +CallBKSSystemServiceOpenApplication (NSString *bundleIDNSStr, NSDictionary *options, DNBError &error, pid_t *return_pid) +{ + // Now make our systemService: + BKSSystemService *system_service = [[BKSSystemService alloc] init]; + + if (bundleIDNSStr == nil) + { + bundleIDNSStr = [system_service systemApplicationBundleIdentifier]; + if (bundleIDNSStr == nil) + { + // Okay, no system app... + error.SetErrorString("No system application to message."); + return false; + } + } + + mach_port_t client_port = [system_service createClientPort]; + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block BKSOpenApplicationErrorCode open_app_error = BKSOpenApplicationErrorCodeNone; + bool wants_pid = (return_pid != NULL); + __block pid_t pid_in_block; + + const char *cstr = [bundleIDNSStr UTF8String]; + if (!cstr) + cstr = ""; + + DNBLog ("About to launch process for bundle ID: %s", cstr); + [system_service openApplication: bundleIDNSStr + options: options + clientPort: client_port + withResult: ^(NSError *bks_error) + { + // The system service will cleanup the client port we created for us. + if (bks_error) + open_app_error = (BKSOpenApplicationErrorCode)[bks_error code]; + + if (open_app_error == BKSOpenApplicationErrorCodeNone) + { + if (wants_pid) + { + pid_in_block = [system_service pidForApplication: bundleIDNSStr]; + DNBLog("In completion handler, got pid for bundle id, pid: %d.", pid_in_block); + DNBLogThreadedIf(LOG_PROCESS, "In completion handler, got pid for bundle id, pid: %d.", pid_in_block); + } + else + DNBLogThreadedIf (LOG_PROCESS, "In completion handler: success."); + } + else + { + const char *error_str = [[bks_error localizedDescription] UTF8String]; + DNBLogThreadedIf(LOG_PROCESS, "In completion handler for send event, got error \"%s\"(%d).", + error_str ? error_str : "", + open_app_error); + // REMOVE ME + DNBLogError ("In completion handler for send event, got error \"%s\"(%d).", + error_str ? error_str : "", + open_app_error); + } + + [system_service release]; + dispatch_semaphore_signal(semaphore); + } + + ]; + + const uint32_t timeout_secs = 9; + + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); + + long success = dispatch_semaphore_wait(semaphore, timeout) == 0; + + dispatch_release(semaphore); + + if (!success) + { + DNBLogError("timed out trying to send openApplication to %s.", cstr); + error.SetError (BKS_OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); + error.SetErrorString ("timed out trying to launch app"); + } + else if (open_app_error != BKSOpenApplicationErrorCodeNone) + { + SetBKSError (open_app_error, error); + DNBLogError("unable to launch the application with CFBundleIdentifier '%s' bks_error = %u", cstr, open_app_error); + success = false; + } + else if (wants_pid) + { + *return_pid = pid_in_block; + DNBLogThreadedIf (LOG_PROCESS, "Out of completion handler, pid from block %d and passing out: %d", pid_in_block, *return_pid); + } + + + return success; +} + +void +MachProcess::BKSCleanupAfterAttach (const void *attach_token, DNBError &err_str) +{ + bool success; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use toll-free bridging here: + NSString *bundleIDNSStr = (NSString *) attach_token; + + // Okay, now let's assemble all these goodies into the BackBoardServices options mega-dictionary: + + // First we have the debug sub-dictionary: + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyCancelDebugOnNextLaunch]; + + // That will go in the overall dictionary: + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + [options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions]; + + success = CallBKSSystemServiceOpenApplication(bundleIDNSStr, options, err_str, NULL); + + if (!success) + { + DNBLogError ("error trying to cancel debug on next launch for %s: %s", [bundleIDNSStr UTF8String], err_str.AsString()); + } + + [pool drain]; +} + +bool +AddEventDataToOptions (NSMutableDictionary *options, const char *event_data, DNBError &option_error) +{ + if (strcmp (event_data, "BackgroundContentFetching") == 0) + { + DNBLog("Setting ActivateForEvent key in options dictionary."); + NSDictionary *event_details = [NSDictionary dictionary]; + NSDictionary *event_dictionary = [NSDictionary dictionaryWithObject:event_details forKey:BKSActivateForEventOptionTypeBackgroundContentFetching]; + [options setObject: event_dictionary forKey: BKSOpenApplicationOptionKeyActivateForEvent]; + return true; + } + else + { + DNBLogError ("Unrecognized event type: %s. Ignoring.", event_data); + option_error.SetErrorString("Unrecognized event data."); + return false; + } + +} + +pid_t +MachProcess::BKSLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, const char *event_data, DNBError &launch_err) +{ + // Clear out and clean up from any current state + Clear(); + + DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); + + // Fork a child process for debugging + SetState(eStateLaunching); + m_pid = BKSForkChildForPTraceDebugging(path, argv, envp, no_stdio, disable_aslr, event_data, launch_err); + if (m_pid != 0) + { + m_flags |= eMachProcessFlagsUsingBKS; + m_path = path; + size_t i; + char const *arg; + for (i=0; (arg = argv[i]) != NULL; i++) + m_args.push_back(arg); + m_task.StartExceptionThread(launch_err); + + if (launch_err.Fail()) + { + if (launch_err.AsString() == NULL) + launch_err.SetErrorString("unable to start the exception thread"); + DNBLog ("Could not get inferior's Mach exception port, sending ptrace PT_KILL and exiting."); + ::ptrace (PT_KILL, m_pid, 0, 0); + m_pid = INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; + } + + StartSTDIOThread(); + SetState (eStateAttaching); + int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0); + if (err == 0) + { + m_flags |= eMachProcessFlagsAttached; + DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); + } + else + { + SetState (eStateExited); + DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); + } + } + return m_pid; +} + +pid_t +MachProcess::BKSForkChildForPTraceDebugging (const char *app_bundle_path, + char const *argv[], + char const *envp[], + bool no_stdio, + bool disable_aslr, + const char *event_data, + DNBError &launch_err) +{ + if (argv[0] == NULL) + return INVALID_NUB_PROCESS; + + DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, this); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + size_t argc = 0; + // Count the number of arguments + while (argv[argc] != NULL) + argc++; + + // Enumerate the arguments + size_t first_launch_arg_idx = 1; + + NSMutableArray *launch_argv = nil; + + if (argv[first_launch_arg_idx]) + { + size_t launch_argc = argc > 0 ? argc - 1 : 0; + launch_argv = [NSMutableArray arrayWithCapacity: launch_argc]; + size_t i; + char const *arg; + NSString *launch_arg; + for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++) + { + launch_arg = [NSString stringWithUTF8String: arg]; + // FIXME: Should we silently eat an argument that we can't convert into a UTF8 string? + if (launch_arg != nil) + [launch_argv addObject: launch_arg]; + else + break; + } + } + + NSMutableDictionary *launch_envp = nil; + if (envp[0]) + { + launch_envp = [[NSMutableDictionary alloc] init]; + const char *value; + int name_len; + NSString *name_string, *value_string; + + for (int i = 0; envp[i] != NULL; i++) + { + value = strstr (envp[i], "="); + + // If the name field is empty or there's no =, skip it. Somebody's messing with us. + if (value == NULL || value == envp[i]) + continue; + + name_len = value - envp[i]; + + // Now move value over the "=" + value++; + name_string = [[NSString alloc] initWithBytes: envp[i] length: name_len encoding: NSUTF8StringEncoding]; + value_string = [NSString stringWithUTF8String: value]; + [launch_envp setObject: value_string forKey: name_string]; + } + } + + NSString *stdio_path = nil; + NSFileManager *file_manager = [NSFileManager defaultManager]; + + PseudoTerminal pty; + if (!no_stdio) + { + PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY); + if (pty_err == PseudoTerminal::success) + { + const char* slave_name = pty.SlaveName(); + DNBLogThreadedIf(LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name); + if (slave_name && slave_name[0]) + { + ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO); + stdio_path = [file_manager stringWithFileSystemRepresentation: slave_name length: strlen(slave_name)]; + } + } + } + + if (stdio_path == nil) + { + const char *null_path = "/dev/null"; + stdio_path = [file_manager stringWithFileSystemRepresentation: null_path length: strlen(null_path)]; + } + + CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err); + if (bundleIDCFStr == NULL) + { + [pool drain]; + return INVALID_NUB_PROCESS; + } + + // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use toll-free bridging here: + NSString *bundleIDNSStr = (NSString *) bundleIDCFStr; + + // Okay, now let's assemble all these goodies into the BackBoardServices options mega-dictionary: + + // First we have the debug sub-dictionary: + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + if (launch_argv != nil) + [debug_options setObject: launch_argv forKey: BKSDebugOptionKeyArguments]; + if (launch_envp != nil) + [debug_options setObject: launch_envp forKey: BKSDebugOptionKeyEnvironment]; + + [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardOutPath]; + [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardErrorPath]; + [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyWaitForDebugger]; + if (disable_aslr) + [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyDisableASLR]; + + // That will go in the overall dictionary: + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + [options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions]; + + // For now we only support one kind of event: the "fetch" event, which is indicated by the fact that its data + // is an empty dictionary. + if (event_data != NULL && *event_data != '\0') + { + if (!AddEventDataToOptions(options, event_data, launch_err)) + { + [pool drain]; + return INVALID_NUB_PROCESS; + } + } + + // And there are some other options at the top level in this dictionary: + [options setObject: [NSNumber numberWithBool: YES] forKey: BKSOpenApplicationOptionKeyUnlockDevice]; + + pid_t return_pid = INVALID_NUB_PROCESS; + bool success = CallBKSSystemServiceOpenApplication(bundleIDNSStr, options, launch_err, &return_pid); + + if (success) + { + int master_fd = pty.ReleaseMasterFD(); + SetChildFileDescriptors(master_fd, master_fd, master_fd); + CFString::UTF8(bundleIDCFStr, m_bundle_id); + } + + [pool drain]; + + return return_pid; +} + +bool +MachProcess::BKSSendEvent (const char *event_data, DNBError &send_err) +{ + bool return_value = true; + + if (event_data == NULL || *event_data == '\0') + { + DNBLogError ("SendEvent called with NULL event data."); + send_err.SetErrorString("SendEvent called with empty event data"); + return false; + } + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if (strcmp (event_data, "BackgroundApplication") == 0) + { + // This is an event I cooked up. What you actually do is foreground the system app, so: + return_value = CallBKSSystemServiceOpenApplication(nil, nil, send_err, NULL); + if (!return_value) + { + DNBLogError ("Failed to background application, error: %s.", send_err.AsString()); + } + } + else + { + if (m_bundle_id.empty()) + { + // See if we can figure out the bundle ID for this PID: + + DNBLogError ("Tried to send event \"%s\" to a process that has no bundle ID.", event_data); + return false; + } + + NSString *bundleIDNSStr = [NSString stringWithUTF8String:m_bundle_id.c_str()]; + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + + if (!AddEventDataToOptions(options, event_data, send_err)) + { + [pool drain]; + return false; + } + + + return_value = CallBKSSystemServiceOpenApplication(bundleIDNSStr, options, send_err, NULL); + + if (!return_value) + { + DNBLogError ("Failed to send event: %s, error: %s.", event_data, send_err.AsString()); + } + } + + [pool drain]; + return return_value; +} +#endif // WITH_BKS diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.cpp b/lldb/tools/debugserver/source/MacOSX/MachTask.mm similarity index 97% rename from lldb/tools/debugserver/source/MacOSX/MachTask.cpp rename to lldb/tools/debugserver/source/MacOSX/MachTask.mm index 30fc22c7dfd8..8b3a4f076e1d 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachTask.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm @@ -45,6 +45,15 @@ #endif +#ifdef WITH_BKS +extern "C" +{ + #import + #import + #import +} +#endif + //---------------------------------------------------------------------- // MachTask constructor //---------------------------------------------------------------------- @@ -693,7 +702,7 @@ MachTask::ExceptionThread (void *arg) task_t task = mach_task->TaskPort(); mach_msg_timeout_t periodic_timeout = 0; -#ifdef WITH_SPRINGBOARD +#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) mach_msg_timeout_t watchdog_elapsed = 0; mach_msg_timeout_t watchdog_timeout = 60 * 1000; pid_t pid = mach_proc->ProcessID(); @@ -723,7 +732,17 @@ MachTask::ExceptionThread (void *arg) if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout) periodic_timeout = watchdog_timeout; } -#endif // #ifdef WITH_SPRINGBOARD +#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) + +#ifdef WITH_BKS + CFReleaser watchdog; + if (mach_proc->ProcessUsingBackBoard()) + { + pid_t pid = mach_proc->ProcessID(); + CFAllocatorRef alloc = kCFAllocatorDefault; + watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid)); + } +#endif // #ifdef WITH_BKS while (mach_task->ExceptionPortIsValid()) { @@ -804,7 +823,7 @@ MachTask::ExceptionThread (void *arg) continue; } -#ifdef WITH_SPRINGBOARD +#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) if (watchdog.get()) { watchdog_elapsed += periodic_timeout; @@ -832,7 +851,7 @@ MachTask::ExceptionThread (void *arg) } } -#ifdef WITH_SPRINGBOARD +#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) if (watchdog.get()) { // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel when we @@ -842,7 +861,7 @@ MachTask::ExceptionThread (void *arg) DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get()); ::SBSWatchdogAssertionRelease (watchdog.get()); } -#endif // #ifdef WITH_SPRINGBOARD +#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s (%p): thread exiting...", __FUNCTION__, arg); return NULL; diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp index adad95f2f7c2..634d2576332d 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp @@ -271,7 +271,6 @@ MachThreadList::UpdateThreadList(MachProcess *process, bool update, MachThreadLi DNBLogThreadedIf (LOG_THREAD, "MachThreadList::UpdateThreadList (pid = %4.4x, update = %u) process stop count = %u", process->ProcessID(), update, process->StopCount()); PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); -#if defined (__i386__) || defined (__x86_64__) if (process->StopCount() == 0) { int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process->ProcessID() }; @@ -283,12 +282,18 @@ MachThreadList::UpdateThreadList(MachProcess *process, bool update, MachThreadLi if (processInfo.kp_proc.p_flag & P_LP64) is_64_bit = true; } +#if defined (__i386__) || defined (__x86_64__) if (is_64_bit) DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); else DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); - } +#elif defined (__arm__) || defined (__arm64__) + if (is_64_bit) + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); + else + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); #endif + } if (m_threads.empty() || update) { diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp index f11906afd63c..fc4108d94ea1 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp @@ -311,11 +311,18 @@ static bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type) mach_vm_address_t base = 0, size = 0; switch(type) { +#if defined (CPU_TYPE_ARM64) && defined (SHARED_REGION_BASE_ARM64) + case CPU_TYPE_ARM64: + base = SHARED_REGION_BASE_ARM64; + size = SHARED_REGION_SIZE_ARM64; + break; +#endif + case CPU_TYPE_ARM: base = SHARED_REGION_BASE_ARM; size = SHARED_REGION_SIZE_ARM; break; - + case CPU_TYPE_X86_64: base = SHARED_REGION_BASE_X86_64; size = SHARED_REGION_SIZE_X86_64; diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp index e9781717d949..dc149666f0cf 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#if defined (__arm__) +#if defined (__arm__) || defined (__arm64__) #include "MacOSX/arm/DNBArchImpl.h" #include "MacOSX/MachProcess.h" @@ -23,6 +23,7 @@ #include "ARM_GCC_Registers.h" #include "ARM_DWARF_Registers.h" +#include #include // BCR address match type @@ -65,6 +66,13 @@ static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 }; static const uint8_t g_thumb_breakpoint_opcode[] = { 0xFE, 0xDE }; +// A watchpoint may need to be implemented using two watchpoint registers. +// e.g. watching an 8-byte region when the device can only watch 4-bytes. +// +// This stores the lo->hi mappings. It's safe to initialize to all 0's +// since hi > lo and therefore LoHi[i] cannot be 0. +static uint32_t LoHi[16] = { 0 }; + // ARM constants used during decoding #define REG_RD 0 #define LDM_REGLIST 1 @@ -278,9 +286,15 @@ DNBArchMachARM::GetDBGState(bool force) return KERN_SUCCESS; // Read the registers from our thread +#if defined (ARM_DEBUG_STATE32) && defined (__arm64__) + mach_msg_type_number_t count = ARM_DEBUG_STATE32_COUNT; + kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE32, (thread_state_t)&m_state.dbg, &count); +#else mach_msg_type_number_t count = ARM_DEBUG_STATE_COUNT; kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, &count); +#endif m_state.SetError(set, Read, kret); + return kret; } @@ -318,6 +332,15 @@ kern_return_t DNBArchMachARM::SetDBGState(bool also_set_on_task) { int set = e_regSetDBG; +#if defined (ARM_DEBUG_STATE32) && defined (__arm64__) + kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_DEBUG_STATE32, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE32_COUNT); + if (also_set_on_task) + { + kern_return_t task_kret = ::task_set_state (m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE32, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE32_COUNT); + if (task_kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::SetDBGState failed to set debug control register state: 0x%8.8x.", kret); + } +#else kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE_COUNT); if (also_set_on_task) { @@ -325,6 +348,7 @@ DNBArchMachARM::SetDBGState(bool also_set_on_task) if (task_kret != KERN_SUCCESS) DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::SetDBGState failed to set debug control register state: 0x%8.8x.", kret); } +#endif m_state.SetError(set, Write, kret); // Set the current write error for this register set m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently @@ -362,7 +386,7 @@ DNBArchMachARM::ThreadWillResume() return; } - DisableHardwareWatchpoint0(m_watchpoint_hw_index, true, false); + DisableHardwareWatchpoint(m_watchpoint_hw_index, false); DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() DisableHardwareWatchpoint(%d) called", m_watchpoint_hw_index); @@ -399,7 +423,7 @@ DNBArchMachARM::ThreadDidStop() { if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) { - EnableHardwareWatchpoint0(m_watchpoint_hw_index, true, false); + ReenableHardwareWatchpoint(m_watchpoint_hw_index); m_watchpoint_resume_single_step_enabled = false; m_watchpoint_did_occur = false; m_watchpoint_hw_index = -1; @@ -443,18 +467,24 @@ DNBArchMachARM::NotifyException(MachException::Data& exc) case EXC_BREAKPOINT: if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) { - // exc_code = EXC_ARM_DA_DEBUG - // - // Check whether this corresponds to a watchpoint hit event. - // If yes, retrieve the exc_sub_code as the data break address. - if (!HasWatchpointOccurred()) - break; - // The data break address is passed as exc_data[1]. nub_addr_t addr = exc.exc_data[1]; // Find the hardware index with the side effect of possibly massaging the // addr to return the starting address as seen from the debugger side. uint32_t hw_index = GetHardwareWatchpointHit(addr); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException watchpoint %d was hit on address 0x%llx", hw_index, (uint64_t) addr); + const int num_watchpoints = NumSupportedHardwareWatchpoints (); + for (int i = 0; i < num_watchpoints; i++) + { + if (LoHi[i] != 0 + && LoHi[i] == hw_index + && LoHi[i] != i + && GetWatchpointAddressByIndex (i) != INVALID_NUB_ADDRESS) + { + addr = GetWatchpointAddressByIndex (i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException It is a linked watchpoint; rewritten to index %d addr 0x%llx", LoHi[i], (uint64_t) addr); + } + } if (hw_index != INVALID_NUB_HW_INDEX) { m_watchpoint_did_occur = true; @@ -492,7 +522,6 @@ DNBArchMachARM::StepNotComplete () return false; } - // Set the single step bit in the processor status register. kern_return_t DNBArchMachARM::EnableHardwareSingleStep (bool enable) @@ -516,6 +545,22 @@ DNBArchMachARM::EnableHardwareSingleStep (bool enable) return err.Error(); } +// The use of __arm64__ here is not ideal. If debugserver is running on +// an armv8 device, regardless of whether it was built for arch arm or arch arm64, +// it needs to use the MDSCR_EL1 SS bit to single instruction step. + +#if defined (__arm64__) + if (enable) + { + DNBLogThreadedIf(LOG_STEP, "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 |= 1; // Set bit 0 (single step, SS) in the MDSCR_EL1. + } + else + { + DNBLogThreadedIf(LOG_STEP, "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 &= ~(1ULL); // Clear bit 0 (single step, SS) in the MDSCR_EL1. + } +#else const uint32_t i = 0; if (enable) { @@ -577,6 +622,7 @@ DNBArchMachARM::EnableHardwareSingleStep (bool enable) // Just restore the state we had before we did single stepping m_state.dbg = m_dbg_save; } +#endif return SetDBGState(false); } @@ -677,6 +723,7 @@ DNBArchMachARM::NumSupportedHardwareBreakpoints() } else { +#if !defined (__arm64__) // Read the DBGDIDR to get the number of available hardware breakpoints // However, in some of our current armv7 processors, hardware // breakpoints/watchpoints were not properly connected. So detect those @@ -708,6 +755,7 @@ DNBArchMachARM::NumSupportedHardwareBreakpoints() g_num_supported_hw_breakpoints = numBRPs; } } +#endif } } return g_num_supported_hw_breakpoints; @@ -736,6 +784,7 @@ DNBArchMachARM::NumSupportedHardwareWatchpoints() } else { +#if !defined (__arm64__) // Read the DBGDIDR to get the number of available hardware breakpoints // However, in some of our current armv7 processors, hardware // breakpoints/watchpoints were not properly connected. So detect those @@ -766,6 +815,7 @@ DNBArchMachARM::NumSupportedHardwareWatchpoints() g_num_supported_hw_watchpoints = numWRPs; } } +#endif } } return g_num_supported_hw_watchpoints; @@ -873,9 +923,16 @@ DNBArchMachARM::DisableHardwareBreakpoint (uint32_t hw_index) return false; } -// This stores the lo->hi mappings. It's safe to initialize to all 0's -// since hi > lo and therefore LoHi[i] cannot be 0. -static uint32_t LoHi[16] = { 0 }; +// ARM v7 watchpoints may be either word-size or double-word-size. +// It's implementation defined which they can handle. It looks like on an +// armv8 device, armv7 processes can watch dwords. But on a genuine armv7 +// device I tried, only word watchpoints are supported. + +#if defined (__arm64__) +#define WATCHPOINTS_ARE_DWORD 1 +#else +#undef WATCHPOINTS_ARE_DWORD +#endif uint32_t DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) @@ -893,16 +950,55 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool if (read == false && write == false) return INVALID_NUB_HW_INDEX; - // Divide-and-conquer for size == 8. - if (size == 8) + // Otherwise, can't watch more than 8 bytes per WVR/WCR pair + if (size > 8) + return INVALID_NUB_HW_INDEX; + + // Treat arm watchpoints as having an 8-byte alignment requirement. You can put a watchpoint on a 4-byte + // offset address but you can only watch 4 bytes with that watchpoint. + + // arm watchpoints on an 8-byte (double word) aligned addr can watch any bytes in that + // 8-byte long region of memory. They can watch the 1st byte, the 2nd byte, 3rd byte, etc, or any + // combination therein by setting the bits in the BAS [12:5] (Byte Address Select) field of + // the DBGWCRn_EL1 reg for the watchpoint. + + // If the MASK [28:24] bits in the DBGWCRn_EL1 allow a single watchpoint to monitor a larger region + // of memory (16 bytes, 32 bytes, or 2GB) but the Byte Address Select bitfield then selects a larger + // range of bytes, instead of individual bytes. See the ARMv8 Debug Architecture manual for details. + // This implementation does not currently use the MASK bits; the largest single region watched by a single + // watchpoint right now is 8-bytes. + +#if defined (WATCHPOINTS_ARE_DWORD) + nub_addr_t aligned_wp_address = addr & ~0x7; + uint32_t addr_dword_offset = addr & 0x7; + const int max_watchpoint_size = 8; +#else + nub_addr_t aligned_wp_address = addr & ~0x3; + uint32_t addr_dword_offset = addr & 0x3; + const int max_watchpoint_size = 4; +#endif + + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint aligned_wp_address is 0x%llx and addr_dword_offset is 0x%x", (uint64_t)aligned_wp_address, addr_dword_offset); + + // Do we need to split up this logical watchpoint into two hardware watchpoint + // registers? + // e.g. a watchpoint of length 4 on address 6. We need do this with + // one watchpoint on address 0 with bytes 6 & 7 being monitored + // one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored + + if (addr_dword_offset + size > max_watchpoint_size) { - uint32_t lo = EnableHardwareWatchpoint(addr, 4, read, write, also_set_on_task); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu) needs two hardware watchpoints slots to monitor", (uint64_t)addr, size); + int low_watchpoint_size = max_watchpoint_size - addr_dword_offset; + int high_watchpoint_size = addr_dword_offset + size - max_watchpoint_size; + + uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read, write, also_set_on_task); if (lo == INVALID_NUB_HW_INDEX) return INVALID_NUB_HW_INDEX; - uint32_t hi = EnableHardwareWatchpoint(addr+4, 4, read, write, also_set_on_task); + uint32_t hi = EnableHardwareWatchpoint (aligned_wp_address + max_watchpoint_size, high_watchpoint_size, read, write, also_set_on_task); if (hi == INVALID_NUB_HW_INDEX) { - DisableHardwareWatchpoint(lo, also_set_on_task); + DisableHardwareWatchpoint (lo, also_set_on_task); return INVALID_NUB_HW_INDEX; } // Tag this lo->hi mapping in our database. @@ -910,36 +1006,16 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool return lo; } - // Otherwise, can't watch more than 4 bytes per WVR/WCR pair - if (size > 4) - return INVALID_NUB_HW_INDEX; + // At this point + // 1 aligned_wp_address is the requested address rounded down to 8-byte alignment + // 2 addr_dword_offset is the offset into that double word (8-byte) region that we are watching + // 3 size is the number of bytes within that 8-byte region that we are watching - // We can only watch up to four bytes that follow a 4 byte aligned address - // per watchpoint register pair. Since we can only watch until the next 4 - // byte boundary, we need to make sure we can properly encode this. - - // addr_word_offset = addr % 4, i.e, is in set([0, 1, 2, 3]) - // - // +---+---+---+---+ - // | 0 | 1 | 2 | 3 | - // +---+---+---+---+ - // ^ - // | - // word address (4-byte aligned) = addr & 0xFFFFFFFC => goes into WVR - // - // examples: - // 1. addr_word_offset = 1, size = 1 to watch a uint_8 => byte_mask = (0b0001 << 1) = 0b0010 - // 2. addr_word_offset = 2, size = 2 to watch a uint_16 => byte_mask = (0b0011 << 2) = 0b1100 - // - // where byte_mask goes into WCR[8:5] - - uint32_t addr_word_offset = addr % 4; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); - - uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); - if (byte_mask > 0xfu) - return INVALID_NUB_HW_INDEX; + // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the above. + // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, etc, up to 0b11111111 for 8. + // then we shift those bits left by the offset into this dword that we are interested in. + // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of 0b11110000. + uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset; // Read the debug state kern_return_t kret = GetDBGState(true); @@ -960,10 +1036,14 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool { //DumpDBGState(m_state.dbg); - // Make the byte_mask into a valid Byte Address Select mask - uint32_t byte_address_select = byte_mask << 5; + // Clear any previous LoHi joined-watchpoint that may have been in use + LoHi[i] = 0; + + // shift our Byte Address Select bits up to the correct bit range for the DBGWCRn_EL1 + byte_address_select = byte_address_select << 5; + // Make sure bits 1:0 are clear in our address - m_state.dbg.__wvr[i] = addr & ~((nub_addr_t)3); // DVA (Data Virtual Address) + m_state.dbg.__wvr[i] = aligned_wp_address; // DVA (Data Virtual Address) m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow the DVA that we will watch S_USER | // Stop only in user mode (read ? WCR_LOAD : 0) | // Stop on read access? @@ -972,6 +1052,8 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() adding watchpoint on address 0x%llx with control register value 0x%x", (uint64_t) m_state.dbg.__wvr[i], (uint32_t) m_state.dbg.__wcr[i]); + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. + kret = SetDBGState(also_set_on_task); //DumpDBGState(m_state.dbg); @@ -989,29 +1071,42 @@ DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool } bool -DNBArchMachARM::EnableHardwareWatchpoint0 (uint32_t hw_index, bool Delegate, bool also_set_on_task) +DNBArchMachARM::ReenableHardwareWatchpoint (uint32_t hw_index) +{ + // If this logical watchpoint # is actually implemented using + // two hardware watchpoint registers, re-enable both of them. + + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) + { + return ReenableHardwareWatchpoint_helper (hw_index) && ReenableHardwareWatchpoint_helper (LoHi[hw_index]); + } + else + { + return ReenableHardwareWatchpoint_helper (hw_index); + } +} + +bool +DNBArchMachARM::ReenableHardwareWatchpoint_helper (uint32_t hw_index) { kern_return_t kret = GetDBGState(false); if (kret != KERN_SUCCESS) return false; - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); if (hw_index >= num_hw_points) return false; - if (Delegate && LoHi[hw_index]) { - // Enable lo and hi watchpoint hardware indexes. - return EnableHardwareWatchpoint0(hw_index, false, also_set_on_task) && - EnableHardwareWatchpoint0(LoHi[hw_index], false, also_set_on_task); - } + m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; + m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; - m_state.dbg.__wcr[hw_index] |= (nub_addr_t)WCR_ENABLE; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", hw_index, hw_index, - m_state.dbg.__wvr[hw_index], + (uint64_t) m_state.dbg.__wvr[hw_index], hw_index, - m_state.dbg.__wcr[hw_index]); + (uint64_t) m_state.dbg.__wcr[hw_index]); + + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. kret = SetDBGState(false); @@ -1021,10 +1116,18 @@ DNBArchMachARM::EnableHardwareWatchpoint0 (uint32_t hw_index, bool Delegate, boo bool DNBArchMachARM::DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) { - return DisableHardwareWatchpoint0(hw_index, true, also_set_on_task); + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) + { + return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task) && DisableHardwareWatchpoint_helper (LoHi[hw_index], also_set_on_task); + } + else + { + return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task); + } } + bool -DNBArchMachARM::DisableHardwareWatchpoint0 (uint32_t hw_index, bool Delegate, bool also_set_on_task) +DNBArchMachARM::DisableHardwareWatchpoint_helper (uint32_t hw_index, bool also_set_on_task) { kern_return_t kret = GetDBGState(false); if (kret != KERN_SUCCESS) @@ -1034,19 +1137,17 @@ DNBArchMachARM::DisableHardwareWatchpoint0 (uint32_t hw_index, bool Delegate, bo if (hw_index >= num_hw_points) return false; - if (Delegate && LoHi[hw_index]) { - // Disable lo and hi watchpoint hardware indexes. - return DisableHardwareWatchpoint0(hw_index, false, also_set_on_task) && - DisableHardwareWatchpoint0(LoHi[hw_index], false, also_set_on_task); - } + m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; + m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; - m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)WCR_ENABLE); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::DisableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", + m_state.dbg.__wvr[hw_index] = 0; + m_state.dbg.__wcr[hw_index] = 0; + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::DisableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", hw_index, hw_index, - m_state.dbg.__wvr[hw_index], + (uint64_t) m_state.dbg.__wvr[hw_index], hw_index, - m_state.dbg.__wcr[hw_index]); + (uint64_t) m_state.dbg.__wcr[hw_index]); kret = SetDBGState(also_set_on_task); @@ -1079,7 +1180,11 @@ DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr) DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr); // This is the watchpoint value to match against, i.e., word address. +#if defined (WATCHPOINTS_ARE_DWORD) + nub_addr_t wp_val = addr & ~((nub_addr_t)7); +#else nub_addr_t wp_val = addr & ~((nub_addr_t)3); +#endif if (kret == KERN_SUCCESS) { DBG &debug_state = m_state.dbg; @@ -1091,7 +1196,11 @@ DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr) "DNBArchMachARM::GetHardwareWatchpointHit() slot: %u (addr = 0x%llx).", i, (uint64_t)wp_addr); if (wp_val == wp_addr) { +#if defined (WATCHPOINTS_ARE_DWORD) + uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); +#else uint32_t byte_mask = bits(debug_state.__wcr[i], 8, 5); +#endif // Sanity check the byte_mask, first. if (LowestBitSet(byte_mask) < 0) @@ -1106,36 +1215,18 @@ DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr) return INVALID_NUB_HW_INDEX; } -// ThreadWillResume() calls this to clear bits[5:2] (Method of entry bits) of -// the Debug Status and Control Register (DSCR). -// -// b0010 = a watchpoint occurred -// b0000 is the reset value -void -DNBArchMachARM::ClearWatchpointOccurred() +nub_addr_t +DNBArchMachARM::GetWatchpointAddressByIndex (uint32_t hw_index) { - uint32_t register_DBGDSCR; - asm("mrc p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR)); - if (bits(register_DBGDSCR, 5, 2) == WATCHPOINT_OCCURRED) - { - uint32_t mask = ~(0xF << 2); - register_DBGDSCR &= mask; - asm("mcr p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR)); - } - return; -} - -// NotifyException() calls this to double check that a watchpoint has occurred -// by inspecting the bits[5:2] field of the Debug Status and Control Register -// (DSCR). -// -// b0010 = a watchpoint occurred -bool -DNBArchMachARM::HasWatchpointOccurred() -{ - uint32_t register_DBGDSCR; - asm("mrc p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR)); - return (bits(register_DBGDSCR, 5, 2) == WATCHPOINT_OCCURRED); + kern_return_t kret = GetDBGState(true); + if (kret != KERN_SUCCESS) + return INVALID_NUB_ADDRESS; + const uint32_t num = NumSupportedHardwareWatchpoints(); + if (hw_index >= num) + return INVALID_NUB_ADDRESS; + if (IsWatchpointEnabled (m_state.dbg, hw_index)) + return GetWatchAddress (m_state.dbg, hw_index); + return INVALID_NUB_ADDRESS; } bool diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h index 8cda8025395f..4d4609184e82 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h @@ -14,7 +14,7 @@ #ifndef __DebugNubArchMachARM_h__ #define __DebugNubArchMachARM_h__ -#if defined (__arm__) +#if defined (__arm__) || defined (__arm64__) #include "DNBArch.h" @@ -30,6 +30,7 @@ public: DNBArchMachARM(MachThread *thread) : m_thread(thread), m_state(), + m_disabled_watchpoints(), m_hw_single_chained_step_addr(INVALID_NUB_ADDRESS), m_last_decode_pc(INVALID_NUB_ADDRESS), m_watchpoint_hw_index(-1), @@ -37,6 +38,7 @@ public: m_watchpoint_resume_single_step_enabled(false), m_saved_register_states() { + m_disabled_watchpoints.resize (16); memset(&m_dbg_save, 0, sizeof(m_dbg_save)); #if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) ThumbStaticsInit(&m_last_decode_thumb); @@ -76,15 +78,22 @@ public: virtual uint32_t NumSupportedHardwareBreakpoints(); virtual uint32_t NumSupportedHardwareWatchpoints(); virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size); - virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); virtual bool DisableHardwareBreakpoint (uint32_t hw_break_index); + + virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); - virtual bool EnableHardwareWatchpoint0 (uint32_t hw_break_index, bool Delegate, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint0 (uint32_t hw_break_index, bool Delegate, bool also_set_on_task); + virtual bool DisableHardwareWatchpoint_helper (uint32_t hw_break_index, bool also_set_on_task); + virtual bool ReenableHardwareWatchpoint (uint32_t hw_break_index); + virtual bool ReenableHardwareWatchpoint_helper (uint32_t hw_break_index); + virtual bool StepNotComplete (); virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); +#if defined (ARM_DEBUG_STATE32) && defined (__arm64__) + typedef arm_debug_state32_t DBG; +#else typedef arm_debug_state_t DBG; +#endif protected: @@ -106,7 +115,11 @@ protected: e_regSetGPR = ARM_THREAD_STATE, e_regSetVFP = ARM_VFP_STATE, e_regSetEXC = ARM_EXCEPTION_STATE, +#if defined (ARM_DEBUG_STATE32) && defined (__arm64__) + e_regSetDBG = ARM_DEBUG_STATE32, +#else e_regSetDBG = ARM_DEBUG_STATE, +#endif kNumRegisterSets } RegisterSet; @@ -232,16 +245,26 @@ protected: kern_return_t SetEXCState (); kern_return_t SetDBGState (bool also_set_on_task); - // Helper functions for watchpoint implementaions. - static void ClearWatchpointOccurred(); - static bool HasWatchpointOccurred(); - static bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); - static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); + nub_addr_t GetWatchpointAddressByIndex (uint32_t hw_index); + nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + + class disabled_watchpoint { + public: + disabled_watchpoint () { addr = 0; control = 0; } + nub_addr_t addr; + uint32_t control; + }; protected: MachThread * m_thread; State m_state; DBG m_dbg_save; + + // armv8 doesn't keep the disabled watchpoint values in the debug register context like armv7; + // we need to save them aside when we disable them temporarily. + std::vector m_disabled_watchpoints; + nub_addr_t m_hw_single_chained_step_addr; nub_addr_t m_last_decode_pc; diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp new file mode 100644 index 000000000000..909fac69f318 --- /dev/null +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -0,0 +1,2093 @@ +//===-- DNBArchMachARM64.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 6/25/07. +// +//===----------------------------------------------------------------------===// + +#if defined (__arm__) || defined (__arm64__) + +#include "MacOSX/arm64/DNBArchImplARM64.h" + +#if defined (ARM_THREAD_STATE64_COUNT) + +#include "MacOSX/MachProcess.h" +#include "MacOSX/MachThread.h" +#include "DNBBreakpoint.h" +#include "DNBLog.h" +#include "DNBRegisterInfo.h" +#include "DNB.h" + +#include +#include + +// Break only in privileged or user mode +// (PAC bits in the DBGWVRn_EL1 watchpoint control register) +#define S_USER ((uint32_t)(2u << 1)) + +#define BCR_ENABLE ((uint32_t)(1u)) +#define WCR_ENABLE ((uint32_t)(1u)) + +// Watchpoint load/store +// (LSC bits in the DBGWVRn_EL1 watchpoint control register) +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) + +// Enable breakpoint, watchpoint, and vector catch debug exceptions. +// (MDE bit in the MDSCR_EL1 register. Equivalent to the MDBGen bit in DBGDSCRext in Aarch32) +#define MDE_ENABLE ((uint32_t)(1u << 15)) + +// Single instruction step +// (SS bit in the MDSCR_EL1 register) +#define SS_ENABLE ((uint32_t)(1u)) + +static const uint8_t g_arm64_breakpoint_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; // "brk #0", 0xd4200000 in BE byte order +static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 }; // this armv7 insn also works in arm64 + +// If we need to set one logical watchpoint by using +// two hardware watchpoint registers, the watchpoint +// will be split into a "high" and "low" watchpoint. +// Record both of them in the LoHi array. + +// It's safe to initialize to all 0's since +// hi > lo and therefore LoHi[i] cannot be 0. +static uint32_t LoHi[16] = { 0 }; + + +void +DNBArchMachARM64::Initialize() +{ + DNBArchPluginInfo arch_plugin_info = + { + CPU_TYPE_ARM64, + DNBArchMachARM64::Create, + DNBArchMachARM64::GetRegisterSetInfo, + DNBArchMachARM64::SoftwareBreakpointOpcode + }; + + // Register this arch plug-in with the main protocol class + DNBArchProtocol::RegisterArchPlugin (arch_plugin_info); +} + + +DNBArchProtocol * +DNBArchMachARM64::Create (MachThread *thread) +{ + DNBArchMachARM64 *obj = new DNBArchMachARM64 (thread); + + return obj; +} + +const uint8_t * const +DNBArchMachARM64::SoftwareBreakpointOpcode (nub_size_t byte_size) +{ + return g_arm_breakpoint_opcode; +} + +uint32_t +DNBArchMachARM64::GetCPUType() +{ + return CPU_TYPE_ARM64; +} + +uint64_t +DNBArchMachARM64::GetPC(uint64_t failValue) +{ + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__pc; + return failValue; +} + +kern_return_t +DNBArchMachARM64::SetPC(uint64_t value) +{ + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) + { + m_state.context.gpr.__pc = value; + err = SetGPRState(); + } + return err == KERN_SUCCESS; +} + +uint64_t +DNBArchMachARM64::GetSP(uint64_t failValue) +{ + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__sp; + return failValue; +} + +kern_return_t +DNBArchMachARM64::GetGPRState(bool force) +{ + int set = e_regSetGPR; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetGPRCount; + kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, &count); + if (DNBLogEnabledForAny (LOG_THREAD)) + { + uint64_t *x = &m_state.context.gpr.__x[0]; + DNBLogThreaded("thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs" + "\n x0=%16.16llx" + "\n x1=%16.16llx" + "\n x2=%16.16llx" + "\n x3=%16.16llx" + "\n x4=%16.16llx" + "\n x5=%16.16llx" + "\n x6=%16.16llx" + "\n x7=%16.16llx" + "\n x8=%16.16llx" + "\n x9=%16.16llx" + "\n x10=%16.16llx" + "\n x11=%16.16llx" + "\n x12=%16.16llx" + "\n x13=%16.16llx" + "\n x14=%16.16llx" + "\n x15=%16.16llx" + "\n x16=%16.16llx" + "\n x17=%16.16llx" + "\n x18=%16.16llx" + "\n x19=%16.16llx" + "\n x20=%16.16llx" + "\n x21=%16.16llx" + "\n x22=%16.16llx" + "\n x23=%16.16llx" + "\n x24=%16.16llx" + "\n x25=%16.16llx" + "\n x26=%16.16llx" + "\n x27=%16.16llx" + "\n x28=%16.16llx" + "\n fp=%16.16llx" + "\n lr=%16.16llx" + "\n sp=%16.16llx" + "\n pc=%16.16llx" + "\n cpsr=%8.8x", + m_thread->MachPortNumber(), + e_regSetGPR, + e_regSetGPRCount, + kret, + count, + x[0], + x[1], + x[2], + x[3], + x[4], + x[5], + x[6], + x[7], + x[8], + x[9], + x[0], + x[11], + x[12], + x[13], + x[14], + x[15], + x[16], + x[17], + x[18], + x[19], + x[20], + x[21], + x[22], + x[23], + x[24], + x[25], + x[26], + x[27], + x[28], + m_state.context.gpr.__fp, + m_state.context.gpr.__lr, + m_state.context.gpr.__sp, + m_state.context.gpr.__pc, + m_state.context.gpr.__cpsr); + } + m_state.SetError(set, Read, kret); + return kret; +} + +kern_return_t +DNBArchMachARM64::GetVFPState(bool force) +{ + int set = e_regSetVFP; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetVFPCount; + kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE64, (thread_state_t)&m_state.context.vfp, &count); + if (DNBLogEnabledForAny (LOG_THREAD)) + { +#if defined (__arm64__) + DNBLogThreaded("thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" + "\n q0 = 0x%16.16llx%16.16llx" + "\n q1 = 0x%16.16llx%16.16llx" + "\n q2 = 0x%16.16llx%16.16llx" + "\n q3 = 0x%16.16llx%16.16llx" + "\n q4 = 0x%16.16llx%16.16llx" + "\n q5 = 0x%16.16llx%16.16llx" + "\n q6 = 0x%16.16llx%16.16llx" + "\n q7 = 0x%16.16llx%16.16llx" + "\n q8 = 0x%16.16llx%16.16llx" + "\n q9 = 0x%16.16llx%16.16llx" + "\n q10 = 0x%16.16llx%16.16llx" + "\n q11 = 0x%16.16llx%16.16llx" + "\n q12 = 0x%16.16llx%16.16llx" + "\n q13 = 0x%16.16llx%16.16llx" + "\n q14 = 0x%16.16llx%16.16llx" + "\n q15 = 0x%16.16llx%16.16llx" + "\n q16 = 0x%16.16llx%16.16llx" + "\n q17 = 0x%16.16llx%16.16llx" + "\n q18 = 0x%16.16llx%16.16llx" + "\n q19 = 0x%16.16llx%16.16llx" + "\n q20 = 0x%16.16llx%16.16llx" + "\n q21 = 0x%16.16llx%16.16llx" + "\n q22 = 0x%16.16llx%16.16llx" + "\n q23 = 0x%16.16llx%16.16llx" + "\n q24 = 0x%16.16llx%16.16llx" + "\n q25 = 0x%16.16llx%16.16llx" + "\n q26 = 0x%16.16llx%16.16llx" + "\n q27 = 0x%16.16llx%16.16llx" + "\n q28 = 0x%16.16llx%16.16llx" + "\n q29 = 0x%16.16llx%16.16llx" + "\n q30 = 0x%16.16llx%16.16llx" + "\n q31 = 0x%16.16llx%16.16llx" + "\n fpsr = 0x%8.8x" + "\n fpcr = 0x%8.8x\n\n", + m_thread->MachPortNumber(), + e_regSetVFP, + e_regSetVFPCount, + kret, + count, + ((uint64_t *)&m_state.context.vfp.__v[0])[0] , ((uint64_t *)&m_state.context.vfp.__v[0])[1], + ((uint64_t *)&m_state.context.vfp.__v[1])[0] , ((uint64_t *)&m_state.context.vfp.__v[1])[1], + ((uint64_t *)&m_state.context.vfp.__v[2])[0] , ((uint64_t *)&m_state.context.vfp.__v[2])[1], + ((uint64_t *)&m_state.context.vfp.__v[3])[0] , ((uint64_t *)&m_state.context.vfp.__v[3])[1], + ((uint64_t *)&m_state.context.vfp.__v[4])[0] , ((uint64_t *)&m_state.context.vfp.__v[4])[1], + ((uint64_t *)&m_state.context.vfp.__v[5])[0] , ((uint64_t *)&m_state.context.vfp.__v[5])[1], + ((uint64_t *)&m_state.context.vfp.__v[6])[0] , ((uint64_t *)&m_state.context.vfp.__v[6])[1], + ((uint64_t *)&m_state.context.vfp.__v[7])[0] , ((uint64_t *)&m_state.context.vfp.__v[7])[1], + ((uint64_t *)&m_state.context.vfp.__v[8])[0] , ((uint64_t *)&m_state.context.vfp.__v[8])[1], + ((uint64_t *)&m_state.context.vfp.__v[9])[0] , ((uint64_t *)&m_state.context.vfp.__v[9])[1], + ((uint64_t *)&m_state.context.vfp.__v[10])[0], ((uint64_t *)&m_state.context.vfp.__v[10])[1], + ((uint64_t *)&m_state.context.vfp.__v[11])[0], ((uint64_t *)&m_state.context.vfp.__v[11])[1], + ((uint64_t *)&m_state.context.vfp.__v[12])[0], ((uint64_t *)&m_state.context.vfp.__v[12])[1], + ((uint64_t *)&m_state.context.vfp.__v[13])[0], ((uint64_t *)&m_state.context.vfp.__v[13])[1], + ((uint64_t *)&m_state.context.vfp.__v[14])[0], ((uint64_t *)&m_state.context.vfp.__v[14])[1], + ((uint64_t *)&m_state.context.vfp.__v[15])[0], ((uint64_t *)&m_state.context.vfp.__v[15])[1], + ((uint64_t *)&m_state.context.vfp.__v[16])[0], ((uint64_t *)&m_state.context.vfp.__v[16])[1], + ((uint64_t *)&m_state.context.vfp.__v[17])[0], ((uint64_t *)&m_state.context.vfp.__v[17])[1], + ((uint64_t *)&m_state.context.vfp.__v[18])[0], ((uint64_t *)&m_state.context.vfp.__v[18])[1], + ((uint64_t *)&m_state.context.vfp.__v[19])[0], ((uint64_t *)&m_state.context.vfp.__v[19])[1], + ((uint64_t *)&m_state.context.vfp.__v[20])[0], ((uint64_t *)&m_state.context.vfp.__v[20])[1], + ((uint64_t *)&m_state.context.vfp.__v[21])[0], ((uint64_t *)&m_state.context.vfp.__v[21])[1], + ((uint64_t *)&m_state.context.vfp.__v[22])[0], ((uint64_t *)&m_state.context.vfp.__v[22])[1], + ((uint64_t *)&m_state.context.vfp.__v[23])[0], ((uint64_t *)&m_state.context.vfp.__v[23])[1], + ((uint64_t *)&m_state.context.vfp.__v[24])[0], ((uint64_t *)&m_state.context.vfp.__v[24])[1], + ((uint64_t *)&m_state.context.vfp.__v[25])[0], ((uint64_t *)&m_state.context.vfp.__v[25])[1], + ((uint64_t *)&m_state.context.vfp.__v[26])[0], ((uint64_t *)&m_state.context.vfp.__v[26])[1], + ((uint64_t *)&m_state.context.vfp.__v[27])[0], ((uint64_t *)&m_state.context.vfp.__v[27])[1], + ((uint64_t *)&m_state.context.vfp.__v[28])[0], ((uint64_t *)&m_state.context.vfp.__v[28])[1], + ((uint64_t *)&m_state.context.vfp.__v[29])[0], ((uint64_t *)&m_state.context.vfp.__v[29])[1], + ((uint64_t *)&m_state.context.vfp.__v[30])[0], ((uint64_t *)&m_state.context.vfp.__v[30])[1], + ((uint64_t *)&m_state.context.vfp.__v[31])[0], ((uint64_t *)&m_state.context.vfp.__v[31])[1], + m_state.context.vfp.__fpsr, + m_state.context.vfp.__fpcr); +#endif + } + m_state.SetError(set, Read, kret); + return kret; +} + +kern_return_t +DNBArchMachARM64::GetEXCState(bool force) +{ + int set = e_regSetEXC; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetEXCCount; + kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, (thread_state_t)&m_state.context.exc, &count); + m_state.SetError(set, Read, kret); + return kret; +} + +static void +DumpDBGState(const arm_debug_state_t& dbg) +{ + uint32_t i = 0; + for (i=0; i<16; i++) + DNBLogThreadedIf(LOG_STEP, "BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }", + i, i, dbg.__bvr[i], dbg.__bcr[i], + i, i, dbg.__wvr[i], dbg.__wcr[i]); +} + +kern_return_t +DNBArchMachARM64::GetDBGState(bool force) +{ + int set = e_regSetDBG; + + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetDBGCount; + kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64, (thread_state_t)&m_state.dbg, &count); + m_state.SetError(set, Read, kret); + + return kret; +} + +kern_return_t +DNBArchMachARM64::SetGPRState() +{ + int set = e_regSetGPR; + kern_return_t kret = ::thread_set_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, e_regSetGPRCount); + m_state.SetError(set, Write, kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently + return kret; // Return the error code +} + +kern_return_t +DNBArchMachARM64::SetVFPState() +{ + int set = e_regSetVFP; + kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_NEON_STATE64, (thread_state_t)&m_state.context.vfp, e_regSetVFPCount); + m_state.SetError(set, Write, kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently + return kret; // Return the error code +} + +kern_return_t +DNBArchMachARM64::SetEXCState() +{ + int set = e_regSetEXC; + kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, (thread_state_t)&m_state.context.exc, e_regSetEXCCount); + m_state.SetError(set, Write, kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently + return kret; // Return the error code +} + +kern_return_t +DNBArchMachARM64::SetDBGState(bool also_set_on_task) +{ + int set = e_regSetDBG; + kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_DEBUG_STATE64, (thread_state_t)&m_state.dbg, e_regSetDBGCount); + if (also_set_on_task) + { + kern_return_t task_kret = task_set_state (m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE64, (thread_state_t)&m_state.dbg, e_regSetDBGCount); + if (task_kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::SetDBGState failed to set debug control register state: 0x%8.8x.", task_kret); + } + m_state.SetError(set, Write, kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently + + return kret; // Return the error code +} + +void +DNBArchMachARM64::ThreadWillResume() +{ + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) + { + EnableHardwareSingleStep(true); + } + + // Disable the triggered watchpoint temporarily before we resume. + // Plus, we try to enable hardware single step to execute past the instruction which triggered our watchpoint. + if (m_watchpoint_did_occur) + { + if (m_watchpoint_hw_index >= 0) + { + kern_return_t kret = GetDBGState(false); + if (kret == KERN_SUCCESS && !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) { + // The watchpoint might have been disabled by the user. We don't need to do anything at all + // to enable hardware single stepping. + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + return; + } + + DisableHardwareWatchpoint(m_watchpoint_hw_index, false); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() DisableHardwareWatchpoint(%d) called", + m_watchpoint_hw_index); + + // Enable hardware single step to move past the watchpoint-triggering instruction. + m_watchpoint_resume_single_step_enabled = (EnableHardwareSingleStep(true) == KERN_SUCCESS); + + // If we are not able to enable single step to move past the watchpoint-triggering instruction, + // at least we should reset the two watchpoint member variables so that the next time around + // this callback function is invoked, the enclosing logical branch is skipped. + if (!m_watchpoint_resume_single_step_enabled) { + // Reset the two watchpoint member variables. + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() failed to enable single step"); + } + else + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() succeeded to enable single step"); + } + } +} + +bool +DNBArchMachARM64::NotifyException(MachException::Data& exc) +{ + + switch (exc.exc_type) + { + default: + break; + case EXC_BREAKPOINT: + if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) + { + // The data break address is passed as exc_data[1]. + nub_addr_t addr = exc.exc_data[1]; + // Find the hardware index with the side effect of possibly massaging the + // addr to return the starting address as seen from the debugger side. + uint32_t hw_index = GetHardwareWatchpointHit(addr); + + // One logical watchpoint was split into two watchpoint locations because + // it was too big. If the watchpoint exception is indicating the 2nd half + // of the two-parter, find the address of the 1st half and report that -- + // that's what lldb is going to expect to see. + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException watchpoint %d was hit on address 0x%llx", hw_index, (uint64_t) addr); + const int num_watchpoints = NumSupportedHardwareWatchpoints (); + for (int i = 0; i < num_watchpoints; i++) + { + if (LoHi[i] != 0 + && LoHi[i] == hw_index + && LoHi[i] != i + && GetWatchpointAddressByIndex (i) != INVALID_NUB_ADDRESS) + { + addr = GetWatchpointAddressByIndex (i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException It is a linked watchpoint; rewritten to index %d addr 0x%llx", LoHi[i], (uint64_t) addr); + } + } + + if (hw_index != INVALID_NUB_HW_INDEX) + { + m_watchpoint_did_occur = true; + m_watchpoint_hw_index = hw_index; + exc.exc_data[1] = addr; + // Piggyback the hw_index in the exc.data. + exc.exc_data.push_back(hw_index); + } + + return true; + } + break; + } + return false; +} + +bool +DNBArchMachARM64::ThreadDidStop() +{ + bool success = true; + + m_state.InvalidateAllRegisterStates(); + + if (m_watchpoint_resume_single_step_enabled) + { + // Great! We now disable the hardware single step as well as re-enable the hardware watchpoint. + // See also ThreadWillResume(). + if (EnableHardwareSingleStep(false) == KERN_SUCCESS) + { + if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) + { + ReenableHardwareWatchpoint(m_watchpoint_hw_index); + m_watchpoint_resume_single_step_enabled = false; + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + } + else + { + DNBLogError("internal error detected: m_watchpoint_resume_step_enabled is true but (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) does not hold!"); + } + } + else + { + DNBLogError("internal error detected: m_watchpoint_resume_step_enabled is true but unable to disable single step!"); + } + } + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) + { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) + { + // This was the primary thread, we need to clear the trace + // bit if so. + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } + else + { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time + } + } + return success; +} + +// Set the single step bit in the processor status register. +kern_return_t +DNBArchMachARM64::EnableHardwareSingleStep (bool enable) +{ + DNBError err; + DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); + + err = GetGPRState(false); + + if (err.Fail()) + { + err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); + return err.Error(); + } + + err = GetDBGState(false); + + if (err.Fail()) + { + err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); + return err.Error(); + } + + if (enable) + { + DNBLogThreadedIf(LOG_STEP, "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 |= SS_ENABLE; + } + else + { + DNBLogThreadedIf(LOG_STEP, "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 &= ~(SS_ENABLE); + } + + return SetDBGState(false); +} + +// return 1 if bit "BIT" is set in "value" +static inline uint32_t bit(uint32_t value, uint32_t bit) +{ + return (value >> bit) & 1u; +} + +// return the bitfield "value[msbit:lsbit]". +static inline uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) +{ + assert(msbit >= lsbit); + uint64_t shift_left = sizeof(value) * 8 - 1 - msbit; + value <<= shift_left; // shift anything above the msbit off of the unsigned edge + value >>= shift_left + lsbit; // shift it back again down to the lsbit (including undoing any shift from above) + return value; // return our result +} + +uint32_t +DNBArchMachARM64::NumSupportedHardwareWatchpoints() +{ + // Set the init value to something that will let us know that we need to + // autodetect how many watchpoints are supported dynamically... + static uint32_t g_num_supported_hw_watchpoints = UINT_MAX; + if (g_num_supported_hw_watchpoints == UINT_MAX) + { + // Set this to zero in case we can't tell if there are any HW breakpoints + g_num_supported_hw_watchpoints = 0; + + + size_t len; + uint32_t n = 0; + len = sizeof (n); + if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) + { + g_num_supported_hw_watchpoints = n; + DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n); + } + else + { + // For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in EL0 so it can't + // access that reg. The kernel should have filled in the sysctls based on it though. +#if defined (__arm__) + uint32_t register_DBGDIDR; + + asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR)); + uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); + // Zero is reserved for the WRP count, so don't increment it if it is zero + if (numWRPs > 0) + numWRPs++; + g_num_supported_hw_watchpoints = numWRPs; + DNBLogThreadedIf(LOG_THREAD, "Number of supported hw watchpoints via asm(): %d", g_num_supported_hw_watchpoints); +#endif + } + } + return g_num_supported_hw_watchpoints; +} + +uint32_t +DNBArchMachARM64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) +{ + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu, read = %u, write = %u)", (uint64_t)addr, size, read, write); + + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + // Can't watch zero bytes + if (size == 0) + return INVALID_NUB_HW_INDEX; + + // We must watch for either read or write + if (read == false && write == false) + return INVALID_NUB_HW_INDEX; + + // Otherwise, can't watch more than 8 bytes per WVR/WCR pair + if (size > 8) + return INVALID_NUB_HW_INDEX; + + // arm64 watchpoints really have an 8-byte alignment requirement. You can put a watchpoint on a 4-byte + // offset address but you can only watch 4 bytes with that watchpoint. + + // arm64 watchpoints on an 8-byte (double word) aligned addr can watch any bytes in that + // 8-byte long region of memory. They can watch the 1st byte, the 2nd byte, 3rd byte, etc, or any + // combination therein by setting the bits in the BAS [12:5] (Byte Address Select) field of + // the DBGWCRn_EL1 reg for the watchpoint. + + // If the MASK [28:24] bits in the DBGWCRn_EL1 allow a single watchpoint to monitor a larger region + // of memory (16 bytes, 32 bytes, or 2GB) but the Byte Address Select bitfield then selects a larger + // range of bytes, instead of individual bytes. See the ARMv8 Debug Architecture manual for details. + // This implementation does not currently use the MASK bits; the largest single region watched by a single + // watchpoint right now is 8-bytes. + + nub_addr_t aligned_wp_address = addr & ~0x7; + uint32_t addr_dword_offset = addr & 0x7; + + // Do we need to split up this logical watchpoint into two hardware watchpoint + // registers? + // e.g. a watchpoint of length 4 on address 6. We need do this with + // one watchpoint on address 0 with bytes 6 & 7 being monitored + // one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored + + if (addr_dword_offset + size > 8) + { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu) needs two hardware watchpoints slots to monitor", (uint64_t)addr, size); + int low_watchpoint_size = 8 - addr_dword_offset; + int high_watchpoint_size = addr_dword_offset + size - 8; + + uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read, write, also_set_on_task); + if (lo == INVALID_NUB_HW_INDEX) + return INVALID_NUB_HW_INDEX; + uint32_t hi = EnableHardwareWatchpoint (aligned_wp_address + 8, high_watchpoint_size, read, write, also_set_on_task); + if (hi == INVALID_NUB_HW_INDEX) + { + DisableHardwareWatchpoint (lo, also_set_on_task); + return INVALID_NUB_HW_INDEX; + } + // Tag this lo->hi mapping in our database. + LoHi[lo] = hi; + return lo; + } + + // At this point + // 1 aligned_wp_address is the requested address rounded down to 8-byte alignment + // 2 addr_dword_offset is the offset into that double word (8-byte) region that we are watching + // 3 size is the number of bytes within that 8-byte region that we are watching + + // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the above. + // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, etc, up to 0b11111111 for 8. + // then we shift those bits left by the offset into this dword that we are interested in. + // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of 0b11110000. + uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset; + + // Read the debug state + kern_return_t kret = GetDBGState(false); + + if (kret == KERN_SUCCESS) + { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i=0; i 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return i; + } + else + { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); + } + } + return INVALID_NUB_HW_INDEX; +} + +bool +DNBArchMachARM64::ReenableHardwareWatchpoint (uint32_t hw_index) +{ + // If this logical watchpoint # is actually implemented using + // two hardware watchpoint registers, re-enable both of them. + + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) + { + return ReenableHardwareWatchpoint_helper (hw_index) && ReenableHardwareWatchpoint_helper (LoHi[hw_index]); + } + else + { + return ReenableHardwareWatchpoint_helper (hw_index); + } +} + +bool +DNBArchMachARM64::ReenableHardwareWatchpoint_helper (uint32_t hw_index) +{ + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (hw_index >= num_hw_points) + return false; + + m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; + m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; + + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", + hw_index, + hw_index, + (uint64_t) m_state.dbg.__wvr[hw_index], + hw_index, + (uint64_t) m_state.dbg.__wcr[hw_index]); + + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. + + kret = SetDBGState(false); + + return (kret == KERN_SUCCESS); +} + +bool +DNBArchMachARM64::DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) +{ + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) + { + return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task) && DisableHardwareWatchpoint_helper (LoHi[hw_index], also_set_on_task); + } + else + { + return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task); + } +} + +bool +DNBArchMachARM64::DisableHardwareWatchpoint_helper (uint32_t hw_index, bool also_set_on_task) +{ + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (hw_index >= num_hw_points) + return false; + + m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; + m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; + + m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)WCR_ENABLE); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::DisableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", + hw_index, + hw_index, + (uint64_t) m_state.dbg.__wvr[hw_index], + hw_index, + (uint64_t) m_state.dbg.__wcr[hw_index]); + + kret = SetDBGState(also_set_on_task); + + return (kret == KERN_SUCCESS); +} + +// This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control register. +// Returns -1 if the trailing bit patterns are not one of: +// { 0b???????1, 0b??????10, 0b?????100, 0b????1000, 0b???10000, 0b??100000, 0b?1000000, 0b10000000 }. +static inline +int32_t +LowestBitSet(uint32_t val) +{ + for (unsigned i = 0; i < 8; ++i) { + if (bit(val, i)) + return i; + } + return -1; +} + +// Iterate through the debug registers; return the index of the first watchpoint whose address matches. +// As a side effect, the starting address as understood by the debugger is returned which could be +// different from 'addr' passed as an in/out argument. +uint32_t +DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) +{ + // Read the debug state + kern_return_t kret = GetDBGState(true); + //DumpDBGState(m_state.dbg); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", kret); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr); + + // This is the watchpoint value to match against, i.e., word address. + nub_addr_t wp_val = addr & ~((nub_addr_t)3); + if (kret == KERN_SUCCESS) + { + DBG &debug_state = m_state.dbg; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) + { + nub_addr_t wp_addr = GetWatchAddress(debug_state, i); + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::GetHardwareWatchpointHit() slot: %u (addr = 0x%llx).", + i, (uint64_t)wp_addr); + if (wp_val == wp_addr) { + uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); + + // Sanity check the byte_mask, first. + if (LowestBitSet(byte_mask) < 0) + continue; + + // Check that the watchpoint is enabled. + if (!IsWatchpointEnabled(debug_state, i)) + continue; + + // Compute the starting address (from the point of view of the debugger). + addr = wp_addr + LowestBitSet(byte_mask); + return i; + } + } + } + return INVALID_NUB_HW_INDEX; +} + +nub_addr_t +DNBArchMachARM64::GetWatchpointAddressByIndex (uint32_t hw_index) +{ + kern_return_t kret = GetDBGState(true); + if (kret != KERN_SUCCESS) + return INVALID_NUB_ADDRESS; + const uint32_t num = NumSupportedHardwareWatchpoints(); + if (hw_index >= num) + return INVALID_NUB_ADDRESS; + if (IsWatchpointEnabled (m_state.dbg, hw_index)) + return GetWatchAddress (m_state.dbg, hw_index); + return INVALID_NUB_ADDRESS; +} + +bool +DNBArchMachARM64::IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index) +{ + // Watchpoint Control Registers, bitfield definitions + // ... + // Bits Value Description + // [0] 0 Watchpoint disabled + // 1 Watchpoint enabled. + return (debug_state.__wcr[hw_index] & 1u); +} + +nub_addr_t +DNBArchMachARM64::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) +{ + // Watchpoint Value Registers, bitfield definitions + // Bits Description + // [31:2] Watchpoint value (word address, i.e., 4-byte aligned) + // [1:0] RAZ/SBZP + return bits(debug_state.__wvr[hw_index], 63, 0); +} + +//---------------------------------------------------------------------- +// Register information defintions for 64 bit ARMv8. +//---------------------------------------------------------------------- +enum gpr_regnums +{ + gpr_x0 = 0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_fp, gpr_x29 = gpr_fp, + gpr_lr, gpr_x30 = gpr_lr, + gpr_sp, gpr_x31 = gpr_sp, + gpr_pc, + gpr_cpsr, + gpr_w0, + gpr_w1, + gpr_w2, + gpr_w3, + gpr_w4, + gpr_w5, + gpr_w6, + gpr_w7, + gpr_w8, + gpr_w9, + gpr_w10, + gpr_w11, + gpr_w12, + gpr_w13, + gpr_w14, + gpr_w15, + gpr_w16, + gpr_w17, + gpr_w18, + gpr_w19, + gpr_w20, + gpr_w21, + gpr_w22, + gpr_w23, + gpr_w24, + gpr_w25, + gpr_w26, + gpr_w27, + gpr_w28 + +}; + +enum +{ + vfp_v0 = 0, + vfp_v1, + vfp_v2, + vfp_v3, + vfp_v4, + vfp_v5, + vfp_v6, + vfp_v7, + vfp_v8, + vfp_v9, + vfp_v10, + vfp_v11, + vfp_v12, + vfp_v13, + vfp_v14, + vfp_v15, + vfp_v16, + vfp_v17, + vfp_v18, + vfp_v19, + vfp_v20, + vfp_v21, + vfp_v22, + vfp_v23, + vfp_v24, + vfp_v25, + vfp_v26, + vfp_v27, + vfp_v28, + vfp_v29, + vfp_v30, + vfp_v31, + vfp_fpsr, + vfp_fpcr, + + // lower 32 bits of the corresponding vfp_v reg. + vfp_s0, + vfp_s1, + vfp_s2, + vfp_s3, + vfp_s4, + vfp_s5, + vfp_s6, + vfp_s7, + vfp_s8, + vfp_s9, + vfp_s10, + vfp_s11, + vfp_s12, + vfp_s13, + vfp_s14, + vfp_s15, + vfp_s16, + vfp_s17, + vfp_s18, + vfp_s19, + vfp_s20, + vfp_s21, + vfp_s22, + vfp_s23, + vfp_s24, + vfp_s25, + vfp_s26, + vfp_s27, + vfp_s28, + vfp_s29, + vfp_s30, + vfp_s31, + + // lower 64 bits of the corresponding vfp_v reg. + vfp_d0, + vfp_d1, + vfp_d2, + vfp_d3, + vfp_d4, + vfp_d5, + vfp_d6, + vfp_d7, + vfp_d8, + vfp_d9, + vfp_d10, + vfp_d11, + vfp_d12, + vfp_d13, + vfp_d14, + vfp_d15, + vfp_d16, + vfp_d17, + vfp_d18, + vfp_d19, + vfp_d20, + vfp_d21, + vfp_d22, + vfp_d23, + vfp_d24, + vfp_d25, + vfp_d26, + vfp_d27, + vfp_d28, + vfp_d29, + vfp_d30, + vfp_d31 +}; + +enum +{ + exc_far = 0, + exc_esr, + exc_exception +}; + +// These numbers from the "DWARF for the ARM 64-bit Architecture (AArch64)" document. + +enum +{ + dwarf_x0 = 0, + dwarf_x1, + dwarf_x2, + dwarf_x3, + dwarf_x4, + dwarf_x5, + dwarf_x6, + dwarf_x7, + dwarf_x8, + dwarf_x9, + dwarf_x10, + dwarf_x11, + dwarf_x12, + dwarf_x13, + dwarf_x14, + dwarf_x15, + dwarf_x16, + dwarf_x17, + dwarf_x18, + dwarf_x19, + dwarf_x20, + dwarf_x21, + dwarf_x22, + dwarf_x23, + dwarf_x24, + dwarf_x25, + dwarf_x26, + dwarf_x27, + dwarf_x28, + dwarf_x29, + dwarf_x30, + dwarf_x31, + dwarf_pc = 32, + dwarf_elr_mode = 33, + dwarf_fp = dwarf_x29, + dwarf_lr = dwarf_x30, + dwarf_sp = dwarf_x31, + // 34-63 reserved + + // V0-V31 (128 bit vector registers) + dwarf_v0 = 64, + dwarf_v1, + dwarf_v2, + dwarf_v3, + dwarf_v4, + dwarf_v5, + dwarf_v6, + dwarf_v7, + dwarf_v8, + dwarf_v9, + dwarf_v10, + dwarf_v11, + dwarf_v12, + dwarf_v13, + dwarf_v14, + dwarf_v15, + dwarf_v16, + dwarf_v17, + dwarf_v18, + dwarf_v19, + dwarf_v20, + dwarf_v21, + dwarf_v22, + dwarf_v23, + dwarf_v24, + dwarf_v25, + dwarf_v26, + dwarf_v27, + dwarf_v28, + dwarf_v29, + dwarf_v30, + dwarf_v31 + + // 96-127 reserved +}; + +enum +{ + gdb_gpr_x0 = 0, + gdb_gpr_x1, + gdb_gpr_x2, + gdb_gpr_x3, + gdb_gpr_x4, + gdb_gpr_x5, + gdb_gpr_x6, + gdb_gpr_x7, + gdb_gpr_x8, + gdb_gpr_x9, + gdb_gpr_x10, + gdb_gpr_x11, + gdb_gpr_x12, + gdb_gpr_x13, + gdb_gpr_x14, + gdb_gpr_x15, + gdb_gpr_x16, + gdb_gpr_x17, + gdb_gpr_x18, + gdb_gpr_x19, + gdb_gpr_x20, + gdb_gpr_x21, + gdb_gpr_x22, + gdb_gpr_x23, + gdb_gpr_x24, + gdb_gpr_x25, + gdb_gpr_x26, + gdb_gpr_x27, + gdb_gpr_x28, + gdb_gpr_fp, // x29 + gdb_gpr_lr, // x30 + gdb_gpr_sp, // sp aka xsp + gdb_gpr_pc, + gdb_gpr_cpsr, + gdb_vfp_v0, + gdb_vfp_v1, + gdb_vfp_v2, + gdb_vfp_v3, + gdb_vfp_v4, + gdb_vfp_v5, + gdb_vfp_v6, + gdb_vfp_v7, + gdb_vfp_v8, + gdb_vfp_v9, + gdb_vfp_v10, + gdb_vfp_v11, + gdb_vfp_v12, + gdb_vfp_v13, + gdb_vfp_v14, + gdb_vfp_v15, + gdb_vfp_v16, + gdb_vfp_v17, + gdb_vfp_v18, + gdb_vfp_v19, + gdb_vfp_v20, + gdb_vfp_v21, + gdb_vfp_v22, + gdb_vfp_v23, + gdb_vfp_v24, + gdb_vfp_v25, + gdb_vfp_v26, + gdb_vfp_v27, + gdb_vfp_v28, + gdb_vfp_v29, + gdb_vfp_v30, + gdb_vfp_v31, + gdb_vfp_fpsr, + gdb_vfp_fpcr +}; + +const char *g_contained_x0[] {"x0", NULL }; +const char *g_contained_x1[] {"x1", NULL }; +const char *g_contained_x2[] {"x2", NULL }; +const char *g_contained_x3[] {"x3", NULL }; +const char *g_contained_x4[] {"x4", NULL }; +const char *g_contained_x5[] {"x5", NULL }; +const char *g_contained_x6[] {"x6", NULL }; +const char *g_contained_x7[] {"x7", NULL }; +const char *g_contained_x8[] {"x8", NULL }; +const char *g_contained_x9[] {"x9", NULL }; +const char *g_contained_x10[] {"x10", NULL }; +const char *g_contained_x11[] {"x11", NULL }; +const char *g_contained_x12[] {"x12", NULL }; +const char *g_contained_x13[] {"x13", NULL }; +const char *g_contained_x14[] {"x14", NULL }; +const char *g_contained_x15[] {"x15", NULL }; +const char *g_contained_x16[] {"x16", NULL }; +const char *g_contained_x17[] {"x17", NULL }; +const char *g_contained_x18[] {"x18", NULL }; +const char *g_contained_x19[] {"x19", NULL }; +const char *g_contained_x20[] {"x20", NULL }; +const char *g_contained_x21[] {"x21", NULL }; +const char *g_contained_x22[] {"x22", NULL }; +const char *g_contained_x23[] {"x23", NULL }; +const char *g_contained_x24[] {"x24", NULL }; +const char *g_contained_x25[] {"x25", NULL }; +const char *g_contained_x26[] {"x26", NULL }; +const char *g_contained_x27[] {"x27", NULL }; +const char *g_contained_x28[] {"x28", NULL }; + +const char *g_invalidate_x0[] {"x0", "w0", NULL }; +const char *g_invalidate_x1[] {"x1", "w1", NULL }; +const char *g_invalidate_x2[] {"x2", "w2", NULL }; +const char *g_invalidate_x3[] {"x3", "w3", NULL }; +const char *g_invalidate_x4[] {"x4", "w4", NULL }; +const char *g_invalidate_x5[] {"x5", "w5", NULL }; +const char *g_invalidate_x6[] {"x6", "w6", NULL }; +const char *g_invalidate_x7[] {"x7", "w7", NULL }; +const char *g_invalidate_x8[] {"x8", "w8", NULL }; +const char *g_invalidate_x9[] {"x9", "w9", NULL }; +const char *g_invalidate_x10[] {"x10", "w10", NULL }; +const char *g_invalidate_x11[] {"x11", "w11", NULL }; +const char *g_invalidate_x12[] {"x12", "w12", NULL }; +const char *g_invalidate_x13[] {"x13", "w13", NULL }; +const char *g_invalidate_x14[] {"x14", "w14", NULL }; +const char *g_invalidate_x15[] {"x15", "w15", NULL }; +const char *g_invalidate_x16[] {"x16", "w16", NULL }; +const char *g_invalidate_x17[] {"x17", "w17", NULL }; +const char *g_invalidate_x18[] {"x18", "w18", NULL }; +const char *g_invalidate_x19[] {"x19", "w19", NULL }; +const char *g_invalidate_x20[] {"x20", "w20", NULL }; +const char *g_invalidate_x21[] {"x21", "w21", NULL }; +const char *g_invalidate_x22[] {"x22", "w22", NULL }; +const char *g_invalidate_x23[] {"x23", "w23", NULL }; +const char *g_invalidate_x24[] {"x24", "w24", NULL }; +const char *g_invalidate_x25[] {"x25", "w25", NULL }; +const char *g_invalidate_x26[] {"x26", "w26", NULL }; +const char *g_invalidate_x27[] {"x27", "w27", NULL }; +const char *g_invalidate_x28[] {"x28", "w28", NULL }; + +#define GPR_OFFSET_IDX(idx) (offsetof (DNBArchMachARM64::GPR, __x[idx])) + +#define GPR_OFFSET_NAME(reg) (offsetof (DNBArchMachARM64::GPR , __##reg)) + +// These macros will auto define the register name, alt name, register size, +// register offset, encoding, format and native register. This ensures that +// the register state structures are defined correctly and have the correct +// sizes and offsets. +#define DEFINE_GPR_IDX(idx, reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_IDX(idx) , dwarf_##reg, dwarf_##reg, gen, gdb_gpr_##reg, NULL, g_invalidate_x##idx } +#define DEFINE_GPR_NAME(reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_NAME(reg), dwarf_##reg, dwarf_##reg, gen, gdb_gpr_##reg, NULL, NULL } +#define DEFINE_PSEUDO_GPR_IDX(idx, reg) { e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, 4, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_x##idx, g_invalidate_x##idx } + +//_STRUCT_ARM_THREAD_STATE64 +//{ +// uint64_t x[29]; /* General purpose registers x0-x28 */ +// uint64_t fp; /* Frame pointer x29 */ +// uint64_t lr; /* Link register x30 */ +// uint64_t sp; /* Stack pointer x31 */ +// uint64_t pc; /* Program counter */ +// uint32_t cpsr; /* Current program status register */ +//}; + + +// General purpose registers +const DNBRegisterInfo +DNBArchMachARM64::g_gpr_registers[] = +{ + DEFINE_GPR_IDX ( 0, x0, "arg1", GENERIC_REGNUM_ARG1 ), + DEFINE_GPR_IDX ( 1, x1, "arg2", GENERIC_REGNUM_ARG2 ), + DEFINE_GPR_IDX ( 2, x2, "arg3", GENERIC_REGNUM_ARG3 ), + DEFINE_GPR_IDX ( 3, x3, "arg4", GENERIC_REGNUM_ARG4 ), + DEFINE_GPR_IDX ( 4, x4, "arg5", GENERIC_REGNUM_ARG5 ), + DEFINE_GPR_IDX ( 5, x5, "arg6", GENERIC_REGNUM_ARG6 ), + DEFINE_GPR_IDX ( 6, x6, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX ( 7, x7, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX ( 8, x8, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX ( 9, x9, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (10, x10, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (11, x11, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (12, x12, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (13, x13, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (14, x14, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (15, x15, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (16, x16, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (17, x17, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (18, x18, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (19, x19, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (20, x20, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (21, x21, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (22, x22, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (23, x23, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (24, x24, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (25, x25, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (26, x26, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (27, x27, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_IDX (28, x28, NULL, INVALID_NUB_REGNUM ), + DEFINE_GPR_NAME (fp, "x29", GENERIC_REGNUM_FP), + DEFINE_GPR_NAME (lr, "x30", GENERIC_REGNUM_RA), + DEFINE_GPR_NAME (sp, "xsp", GENERIC_REGNUM_SP), + DEFINE_GPR_NAME (pc, NULL, GENERIC_REGNUM_PC), + + // in armv7 we specify that writing to the CPSR should invalidate r8-12, sp, lr. + // this should be spcified for arm64 too even though debugserver is only used for + // userland debugging. + { e_regSetGPR, gpr_cpsr, "cpsr", "flags", Uint, Hex, 4, GPR_OFFSET_NAME(cpsr), dwarf_elr_mode, dwarf_elr_mode, INVALID_NUB_REGNUM, gdb_gpr_cpsr, NULL, NULL }, + + DEFINE_PSEUDO_GPR_IDX ( 0, w0), + DEFINE_PSEUDO_GPR_IDX ( 1, w1), + DEFINE_PSEUDO_GPR_IDX ( 2, w2), + DEFINE_PSEUDO_GPR_IDX ( 3, w3), + DEFINE_PSEUDO_GPR_IDX ( 4, w4), + DEFINE_PSEUDO_GPR_IDX ( 5, w5), + DEFINE_PSEUDO_GPR_IDX ( 6, w6), + DEFINE_PSEUDO_GPR_IDX ( 7, w7), + DEFINE_PSEUDO_GPR_IDX ( 8, w8), + DEFINE_PSEUDO_GPR_IDX ( 9, w9), + DEFINE_PSEUDO_GPR_IDX (10, w10), + DEFINE_PSEUDO_GPR_IDX (11, w11), + DEFINE_PSEUDO_GPR_IDX (12, w12), + DEFINE_PSEUDO_GPR_IDX (13, w13), + DEFINE_PSEUDO_GPR_IDX (14, w14), + DEFINE_PSEUDO_GPR_IDX (15, w15), + DEFINE_PSEUDO_GPR_IDX (16, w16), + DEFINE_PSEUDO_GPR_IDX (17, w17), + DEFINE_PSEUDO_GPR_IDX (18, w18), + DEFINE_PSEUDO_GPR_IDX (19, w19), + DEFINE_PSEUDO_GPR_IDX (20, w20), + DEFINE_PSEUDO_GPR_IDX (21, w21), + DEFINE_PSEUDO_GPR_IDX (22, w22), + DEFINE_PSEUDO_GPR_IDX (23, w23), + DEFINE_PSEUDO_GPR_IDX (24, w24), + DEFINE_PSEUDO_GPR_IDX (25, w25), + DEFINE_PSEUDO_GPR_IDX (26, w26), + DEFINE_PSEUDO_GPR_IDX (27, w27), + DEFINE_PSEUDO_GPR_IDX (28, w28) +}; + +const char *g_contained_v0[] {"v0", NULL }; +const char *g_contained_v1[] {"v1", NULL }; +const char *g_contained_v2[] {"v2", NULL }; +const char *g_contained_v3[] {"v3", NULL }; +const char *g_contained_v4[] {"v4", NULL }; +const char *g_contained_v5[] {"v5", NULL }; +const char *g_contained_v6[] {"v6", NULL }; +const char *g_contained_v7[] {"v7", NULL }; +const char *g_contained_v8[] {"v8", NULL }; +const char *g_contained_v9[] {"v9", NULL }; +const char *g_contained_v10[] {"v10", NULL }; +const char *g_contained_v11[] {"v11", NULL }; +const char *g_contained_v12[] {"v12", NULL }; +const char *g_contained_v13[] {"v13", NULL }; +const char *g_contained_v14[] {"v14", NULL }; +const char *g_contained_v15[] {"v15", NULL }; +const char *g_contained_v16[] {"v16", NULL }; +const char *g_contained_v17[] {"v17", NULL }; +const char *g_contained_v18[] {"v18", NULL }; +const char *g_contained_v19[] {"v19", NULL }; +const char *g_contained_v20[] {"v20", NULL }; +const char *g_contained_v21[] {"v21", NULL }; +const char *g_contained_v22[] {"v22", NULL }; +const char *g_contained_v23[] {"v23", NULL }; +const char *g_contained_v24[] {"v24", NULL }; +const char *g_contained_v25[] {"v25", NULL }; +const char *g_contained_v26[] {"v26", NULL }; +const char *g_contained_v27[] {"v27", NULL }; +const char *g_contained_v28[] {"v28", NULL }; +const char *g_contained_v29[] {"v29", NULL }; +const char *g_contained_v30[] {"v30", NULL }; +const char *g_contained_v31[] {"v31", NULL }; + +const char *g_invalidate_v0[] {"v0", "d0", "s0", NULL }; +const char *g_invalidate_v1[] {"v1", "d1", "s1", NULL }; +const char *g_invalidate_v2[] {"v2", "d2", "s2", NULL }; +const char *g_invalidate_v3[] {"v3", "d3", "s3", NULL }; +const char *g_invalidate_v4[] {"v4", "d4", "s4", NULL }; +const char *g_invalidate_v5[] {"v5", "d5", "s5", NULL }; +const char *g_invalidate_v6[] {"v6", "d6", "s6", NULL }; +const char *g_invalidate_v7[] {"v7", "d7", "s7", NULL }; +const char *g_invalidate_v8[] {"v8", "d8", "s8", NULL }; +const char *g_invalidate_v9[] {"v9", "d9", "s9", NULL }; +const char *g_invalidate_v10[] {"v10", "d10", "s10", NULL }; +const char *g_invalidate_v11[] {"v11", "d11", "s11", NULL }; +const char *g_invalidate_v12[] {"v12", "d12", "s12", NULL }; +const char *g_invalidate_v13[] {"v13", "d13", "s13", NULL }; +const char *g_invalidate_v14[] {"v14", "d14", "s14", NULL }; +const char *g_invalidate_v15[] {"v15", "d15", "s15", NULL }; +const char *g_invalidate_v16[] {"v16", "d16", "s16", NULL }; +const char *g_invalidate_v17[] {"v17", "d17", "s17", NULL }; +const char *g_invalidate_v18[] {"v18", "d18", "s18", NULL }; +const char *g_invalidate_v19[] {"v19", "d19", "s19", NULL }; +const char *g_invalidate_v20[] {"v20", "d20", "s20", NULL }; +const char *g_invalidate_v21[] {"v21", "d21", "s21", NULL }; +const char *g_invalidate_v22[] {"v22", "d22", "s22", NULL }; +const char *g_invalidate_v23[] {"v23", "d23", "s23", NULL }; +const char *g_invalidate_v24[] {"v24", "d24", "s24", NULL }; +const char *g_invalidate_v25[] {"v25", "d25", "s25", NULL }; +const char *g_invalidate_v26[] {"v26", "d26", "s26", NULL }; +const char *g_invalidate_v27[] {"v27", "d27", "s27", NULL }; +const char *g_invalidate_v28[] {"v28", "d28", "s28", NULL }; +const char *g_invalidate_v29[] {"v29", "d29", "s29", NULL }; +const char *g_invalidate_v30[] {"v30", "d30", "s30", NULL }; +const char *g_invalidate_v31[] {"v31", "d31", "s31", NULL }; + +#if defined (__arm64__) +#define VFP_V_OFFSET_IDX(idx) (offsetof (DNBArchMachARM64::FPU, __v) + (idx * 16) + offsetof (DNBArchMachARM64::Context, vfp)) +#else +#define VFP_V_OFFSET_IDX(idx) (offsetof (DNBArchMachARM64::FPU, opaque) + (idx * 16) + offsetof (DNBArchMachARM64::Context, vfp)) +#endif +#define VFP_OFFSET_NAME(reg) (offsetof (DNBArchMachARM64::FPU, reg) + offsetof (DNBArchMachARM64::Context, vfp)) +#define EXC_OFFSET(reg) (offsetof (DNBArchMachARM64::EXC, reg) + offsetof (DNBArchMachARM64::Context, exc)) + +//#define FLOAT_FORMAT Float +#define DEFINE_VFP_V_IDX(idx) { e_regSetVFP, vfp_v##idx, "v" #idx, "q" #idx, Vector, VectorOfUInt8, 16, VFP_V_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_v##idx, INVALID_NUB_REGNUM, gdb_vfp_v##idx, NULL, g_invalidate_v##idx } +#define DEFINE_PSEUDO_VFP_S_IDX(idx) { e_regSetVFP, vfp_s##idx, "s" #idx, NULL, IEEE754, Float, 4, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx } +#define DEFINE_PSEUDO_VFP_D_IDX(idx) { e_regSetVFP, vfp_d##idx, "d" #idx, NULL, IEEE754, Float, 8, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx } + +// Floating point registers +const DNBRegisterInfo +DNBArchMachARM64::g_vfp_registers[] = +{ + DEFINE_VFP_V_IDX ( 0), + DEFINE_VFP_V_IDX ( 1), + DEFINE_VFP_V_IDX ( 2), + DEFINE_VFP_V_IDX ( 3), + DEFINE_VFP_V_IDX ( 4), + DEFINE_VFP_V_IDX ( 5), + DEFINE_VFP_V_IDX ( 6), + DEFINE_VFP_V_IDX ( 7), + DEFINE_VFP_V_IDX ( 8), + DEFINE_VFP_V_IDX ( 9), + DEFINE_VFP_V_IDX (10), + DEFINE_VFP_V_IDX (11), + DEFINE_VFP_V_IDX (12), + DEFINE_VFP_V_IDX (13), + DEFINE_VFP_V_IDX (14), + DEFINE_VFP_V_IDX (15), + DEFINE_VFP_V_IDX (16), + DEFINE_VFP_V_IDX (17), + DEFINE_VFP_V_IDX (18), + DEFINE_VFP_V_IDX (19), + DEFINE_VFP_V_IDX (20), + DEFINE_VFP_V_IDX (21), + DEFINE_VFP_V_IDX (22), + DEFINE_VFP_V_IDX (23), + DEFINE_VFP_V_IDX (24), + DEFINE_VFP_V_IDX (25), + DEFINE_VFP_V_IDX (26), + DEFINE_VFP_V_IDX (27), + DEFINE_VFP_V_IDX (28), + DEFINE_VFP_V_IDX (29), + DEFINE_VFP_V_IDX (30), + DEFINE_VFP_V_IDX (31), + { e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4, VFP_V_OFFSET_IDX (32) + 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, + { e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4, VFP_V_OFFSET_IDX (32) + 4, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, + + DEFINE_PSEUDO_VFP_S_IDX (0), + DEFINE_PSEUDO_VFP_S_IDX (1), + DEFINE_PSEUDO_VFP_S_IDX (2), + DEFINE_PSEUDO_VFP_S_IDX (3), + DEFINE_PSEUDO_VFP_S_IDX (4), + DEFINE_PSEUDO_VFP_S_IDX (5), + DEFINE_PSEUDO_VFP_S_IDX (6), + DEFINE_PSEUDO_VFP_S_IDX (7), + DEFINE_PSEUDO_VFP_S_IDX (8), + DEFINE_PSEUDO_VFP_S_IDX (9), + DEFINE_PSEUDO_VFP_S_IDX (10), + DEFINE_PSEUDO_VFP_S_IDX (11), + DEFINE_PSEUDO_VFP_S_IDX (12), + DEFINE_PSEUDO_VFP_S_IDX (13), + DEFINE_PSEUDO_VFP_S_IDX (14), + DEFINE_PSEUDO_VFP_S_IDX (15), + DEFINE_PSEUDO_VFP_S_IDX (16), + DEFINE_PSEUDO_VFP_S_IDX (17), + DEFINE_PSEUDO_VFP_S_IDX (18), + DEFINE_PSEUDO_VFP_S_IDX (19), + DEFINE_PSEUDO_VFP_S_IDX (20), + DEFINE_PSEUDO_VFP_S_IDX (21), + DEFINE_PSEUDO_VFP_S_IDX (22), + DEFINE_PSEUDO_VFP_S_IDX (23), + DEFINE_PSEUDO_VFP_S_IDX (24), + DEFINE_PSEUDO_VFP_S_IDX (25), + DEFINE_PSEUDO_VFP_S_IDX (26), + DEFINE_PSEUDO_VFP_S_IDX (27), + DEFINE_PSEUDO_VFP_S_IDX (28), + DEFINE_PSEUDO_VFP_S_IDX (29), + DEFINE_PSEUDO_VFP_S_IDX (30), + DEFINE_PSEUDO_VFP_S_IDX (31), + + DEFINE_PSEUDO_VFP_D_IDX (0), + DEFINE_PSEUDO_VFP_D_IDX (1), + DEFINE_PSEUDO_VFP_D_IDX (2), + DEFINE_PSEUDO_VFP_D_IDX (3), + DEFINE_PSEUDO_VFP_D_IDX (4), + DEFINE_PSEUDO_VFP_D_IDX (5), + DEFINE_PSEUDO_VFP_D_IDX (6), + DEFINE_PSEUDO_VFP_D_IDX (7), + DEFINE_PSEUDO_VFP_D_IDX (8), + DEFINE_PSEUDO_VFP_D_IDX (9), + DEFINE_PSEUDO_VFP_D_IDX (10), + DEFINE_PSEUDO_VFP_D_IDX (11), + DEFINE_PSEUDO_VFP_D_IDX (12), + DEFINE_PSEUDO_VFP_D_IDX (13), + DEFINE_PSEUDO_VFP_D_IDX (14), + DEFINE_PSEUDO_VFP_D_IDX (15), + DEFINE_PSEUDO_VFP_D_IDX (16), + DEFINE_PSEUDO_VFP_D_IDX (17), + DEFINE_PSEUDO_VFP_D_IDX (18), + DEFINE_PSEUDO_VFP_D_IDX (19), + DEFINE_PSEUDO_VFP_D_IDX (20), + DEFINE_PSEUDO_VFP_D_IDX (21), + DEFINE_PSEUDO_VFP_D_IDX (22), + DEFINE_PSEUDO_VFP_D_IDX (23), + DEFINE_PSEUDO_VFP_D_IDX (24), + DEFINE_PSEUDO_VFP_D_IDX (25), + DEFINE_PSEUDO_VFP_D_IDX (26), + DEFINE_PSEUDO_VFP_D_IDX (27), + DEFINE_PSEUDO_VFP_D_IDX (28), + DEFINE_PSEUDO_VFP_D_IDX (29), + DEFINE_PSEUDO_VFP_D_IDX (30), + DEFINE_PSEUDO_VFP_D_IDX (31) + +}; + + +//_STRUCT_ARM_EXCEPTION_STATE64 +//{ +// uint64_t far; /* Virtual Fault Address */ +// uint32_t esr; /* Exception syndrome */ +// uint32_t exception; /* number of arm exception taken */ +//}; + +// Exception registers +const DNBRegisterInfo +DNBArchMachARM64::g_exc_registers[] = +{ + { e_regSetEXC, exc_far , "far" , NULL, Uint, Hex, 8, EXC_OFFSET(__far) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, + { e_regSetEXC, exc_esr , "esr" , NULL, Uint, Hex, 4, EXC_OFFSET(__esr) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, + { e_regSetEXC, exc_exception , "exception" , NULL, Uint, Hex, 4, EXC_OFFSET(__exception) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL } +}; + +// Number of registers in each register set +const size_t DNBArchMachARM64::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM64::k_num_vfp_registers = sizeof(g_vfp_registers)/sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM64::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM64::k_num_all_registers = k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers; + +//---------------------------------------------------------------------- +// Register set definitions. The first definitions at register set index +// of zero is for all registers, followed by other registers sets. The +// register information for the all register set need not be filled in. +//---------------------------------------------------------------------- +const DNBRegisterSetInfo +DNBArchMachARM64::g_reg_sets[] = +{ + { "ARM64 Registers", NULL, k_num_all_registers }, + { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, + { "Floating Point Registers", g_vfp_registers, k_num_vfp_registers }, + { "Exception State Registers", g_exc_registers, k_num_exc_registers } +}; +// Total number of register sets for this architecture +const size_t DNBArchMachARM64::k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo); + + +const DNBRegisterSetInfo * +DNBArchMachARM64::GetRegisterSetInfo(nub_size_t *num_reg_sets) +{ + *num_reg_sets = k_num_register_sets; + return g_reg_sets; +} + +bool +DNBArchMachARM64::FixGenericRegisterNumber (int &set, int ®) +{ + if (set == REGISTER_SET_GENERIC) + { + switch (reg) + { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_pc; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_sp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_fp; + break; + + case GENERIC_REGNUM_RA: // Return Address + set = e_regSetGPR; + reg = gpr_lr; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_cpsr; + break; + + case GENERIC_REGNUM_ARG1: + case GENERIC_REGNUM_ARG2: + case GENERIC_REGNUM_ARG3: + case GENERIC_REGNUM_ARG4: + case GENERIC_REGNUM_ARG5: + case GENERIC_REGNUM_ARG6: + set = e_regSetGPR; + reg = gpr_x0 + reg - GENERIC_REGNUM_ARG1; + break; + + default: + return false; + } + } + return true; +} +bool +DNBArchMachARM64::GetRegisterValue(int set, int reg, DNBRegisterValue *value) +{ + if (!FixGenericRegisterNumber (set, reg)) + return false; + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) + { + value->info = *regInfo; + switch (set) + { + case e_regSetGPR: + if (reg <= gpr_pc) + { + value->value.uint64 = m_state.context.gpr.__x[reg]; + return true; + } + else if (reg == gpr_cpsr) + { + value->value.uint32 = m_state.context.gpr.__cpsr; + return true; + } + break; + + case e_regSetVFP: + + if (reg >= vfp_v0 && reg <= vfp_v31) + { +#if defined (__arm64__) + memcpy (&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_v0], 16); +#else + memcpy (&value->value.v_uint8, ((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), 16); +#endif + return true; + } + else if (reg == vfp_fpsr) + { +#if defined (__arm64__) + memcpy (&value->value.uint32, &m_state.context.vfp.__fpsr, 4); +#else + memcpy (&value->value.uint32, ((uint8_t *) &m_state.context.vfp.opaque) + (32 * 16) + 0, 4); +#endif + return true; + } + else if (reg == vfp_fpcr) + { +#if defined (__arm64__) + memcpy (&value->value.uint32, &m_state.context.vfp.__fpcr, 4); +#else + memcpy (&value->value.uint32, ((uint8_t *) &m_state.context.vfp.opaque) + (32 * 16) + 4, 4); +#endif + return true; + } + else if (reg >= vfp_s0 && reg <= vfp_s31) + { +#if defined (__arm64__) + memcpy (&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_s0], 4); +#else + memcpy (&value->value.v_uint8, ((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), 4); +#endif + return true; + } + else if (reg >= vfp_d0 && reg <= vfp_d31) + { +#if defined (__arm64__) + memcpy (&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_d0], 8); +#else + memcpy (&value->value.v_uint8, ((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), 8); +#endif + return true; + } + break; + + case e_regSetEXC: + if (reg == exc_far) + { + value->value.uint64 = m_state.context.exc.__far; + return true; + } + else if (reg == exc_esr) + { + value->value.uint32 = m_state.context.exc.__esr; + return true; + } + else if (reg == exc_exception) + { + value->value.uint32 = m_state.context.exc.__exception; + return true; + } + break; + } + } + return false; +} + +bool +DNBArchMachARM64::SetRegisterValue(int set, int reg, const DNBRegisterValue *value) +{ + if (!FixGenericRegisterNumber (set, reg)) + return false; + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + bool success = false; + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) + { + switch (set) + { + case e_regSetGPR: + if (reg <= gpr_pc) + { + m_state.context.gpr.__x[reg] = value->value.uint64; + success = true; + } + else if (reg == gpr_cpsr) + { + m_state.context.gpr.__cpsr = value->value.uint32; + success = true; + } + break; + + case e_regSetVFP: + if (reg >= vfp_v0 && reg <= vfp_v31) + { +#if defined (__arm64__) + memcpy (&m_state.context.vfp.__v[reg - vfp_v0], &value->value.v_uint8, 16); +#else + memcpy (((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), &value->value.v_uint8, 16); +#endif + success = true; + } + else if (reg == vfp_fpsr) + { +#if defined (__arm64__) + memcpy (&m_state.context.vfp.__fpsr, &value->value.uint32, 4); +#else + memcpy (((uint8_t *) &m_state.context.vfp.opaque) + (32 * 16) + 0, &value->value.uint32, 4); +#endif + success = true; + } + else if (reg == vfp_fpcr) + { +#if defined (__arm64__) + memcpy (&m_state.context.vfp.__fpcr, &value->value.uint32, 4); +#else + memcpy (((uint8_t *) m_state.context.vfp.opaque) + (32 * 16) + 4, &value->value.uint32, 4); +#endif + success = true; + } + else if (reg >= vfp_s0 && reg <= vfp_s31) + { +#if defined (__arm64__) + memcpy (&m_state.context.vfp.__v[reg - vfp_s0], &value->value.v_uint8, 4); +#else + memcpy (((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), &value->value.v_uint8, 4); +#endif + success = true; + } + else if (reg >= vfp_d0 && reg <= vfp_d31) + { +#if defined (__arm64__) + memcpy (&m_state.context.vfp.__v[reg - vfp_d0], &value->value.v_uint8, 8); +#else + memcpy (((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), &value->value.v_uint8, 8); +#endif + success = true; + } + break; + + case e_regSetEXC: + if (reg == exc_far) + { + m_state.context.exc.__far = value->value.uint64; + success = true; + } + else if (reg == exc_esr) + { + m_state.context.exc.__esr = value->value.uint32; + success = true; + } + else if (reg == exc_exception) + { + m_state.context.exc.__exception = value->value.uint32; + success = true; + } + break; + } + + } + if (success) + return SetRegisterState(set) == KERN_SUCCESS; + return false; +} + +kern_return_t +DNBArchMachARM64::GetRegisterState(int set, bool force) +{ + switch (set) + { + case e_regSetALL: return GetGPRState(force) | + GetVFPState(force) | + GetEXCState(force) | + GetDBGState(force); + case e_regSetGPR: return GetGPRState(force); + case e_regSetVFP: return GetVFPState(force); + case e_regSetEXC: return GetEXCState(force); + case e_regSetDBG: return GetDBGState(force); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +kern_return_t +DNBArchMachARM64::SetRegisterState(int set) +{ + // Make sure we have a valid context to set. + kern_return_t err = GetRegisterState(set, false); + if (err != KERN_SUCCESS) + return err; + + switch (set) + { + case e_regSetALL: return SetGPRState() | + SetVFPState() | + SetEXCState() | + SetDBGState(false); + case e_regSetGPR: return SetGPRState(); + case e_regSetVFP: return SetVFPState(); + case e_regSetEXC: return SetEXCState(); + case e_regSetDBG: return SetDBGState(false); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +bool +DNBArchMachARM64::RegisterSetStateIsValid (int set) const +{ + return m_state.RegsAreValid(set); +} + + +nub_size_t +DNBArchMachARM64::GetRegisterContext (void *buf, nub_size_t buf_len) +{ + nub_size_t size = sizeof (m_state.context.gpr) + + sizeof (m_state.context.vfp) + + sizeof (m_state.context.exc); + + if (buf && buf_len) + { + if (size > buf_len) + size = buf_len; + + bool force = false; + if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force)) + return 0; + + // Copy each struct individually to avoid any padding that might be between the structs in m_state.context + uint8_t *p = (uint8_t *)buf; + ::memcpy (p, &m_state.context.gpr, sizeof(m_state.context.gpr)); + p += sizeof(m_state.context.gpr); + ::memcpy (p, &m_state.context.vfp, sizeof(m_state.context.vfp)); + p += sizeof(m_state.context.vfp); + ::memcpy (p, &m_state.context.exc, sizeof(m_state.context.exc)); + p += sizeof(m_state.context.exc); + + size_t bytes_written = p - (uint8_t *)buf; + assert (bytes_written == size); + } + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::GetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size); + // Return the size of the register context even if NULL was passed in + return size; +} + +nub_size_t +DNBArchMachARM64::SetRegisterContext (const void *buf, nub_size_t buf_len) +{ + nub_size_t size = sizeof (m_state.context.gpr) + + sizeof (m_state.context.vfp) + + sizeof (m_state.context.exc); + + if (buf == NULL || buf_len == 0) + size = 0; + + if (size) + { + if (size > buf_len) + size = buf_len; + + // Copy each struct individually to avoid any padding that might be between the structs in m_state.context + uint8_t *p = (uint8_t *)buf; + ::memcpy (&m_state.context.gpr, p, sizeof(m_state.context.gpr)); + p += sizeof(m_state.context.gpr); + ::memcpy (&m_state.context.vfp, p, sizeof(m_state.context.vfp)); + p += sizeof(m_state.context.vfp); + ::memcpy (&m_state.context.exc, p, sizeof(m_state.context.exc)); + p += sizeof(m_state.context.exc); + + size_t bytes_written = p - (uint8_t *)buf; + assert (bytes_written == size); + SetGPRState(); + SetVFPState(); + SetEXCState(); + } + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::SetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size); + return size; +} + +uint32_t +DNBArchMachARM64::SaveRegisterState () +{ + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + // Always re-read the registers because above we call thread_abort_safely(); + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () error: GPR regs failed to read: %u ", kret); + } + else if ((kret = GetVFPState(force)) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () error: %s regs failed to read: %u", "VFP", kret); + } + else + { + const uint32_t save_id = GetNextRegisterStateSaveID (); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return UINT32_MAX; +} + +bool +DNBArchMachARM64::RestoreRegisterState (uint32_t save_id) +{ + SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) + { + m_state.context.gpr = pos->second.gpr; + m_state.context.vfp = pos->second.vfp; + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); + success = false; + } + else if ((kret = SetVFPState()) != KERN_SUCCESS) + { + DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, "VFP", kret); + success = false; + } + m_saved_register_states.erase(pos); + return success; + } + return false; +} + + +#endif // #if defined (ARM_THREAD_STATE64_COUNT) +#endif // #if defined (__arm__) diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h new file mode 100644 index 000000000000..0d2a998265ff --- /dev/null +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h @@ -0,0 +1,272 @@ +//===-- DNBArchMachARM64.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#ifndef __DNBArchImplARM64_h__ +#define __DNBArchImplARM64_h__ + +#if defined (__arm__) || defined (__arm64__) + +#include +#include + +#if defined (ARM_THREAD_STATE64_COUNT) + +#include "DNBArch.h" + +class MachThread; + +class DNBArchMachARM64 : public DNBArchProtocol +{ +public: + enum { kMaxNumThumbITBreakpoints = 4 }; + + DNBArchMachARM64(MachThread *thread) : + m_thread(thread), + m_state(), + m_disabled_watchpoints(), + m_watchpoint_hw_index(-1), + m_watchpoint_did_occur(false), + m_watchpoint_resume_single_step_enabled(false), + m_saved_register_states() + { + m_disabled_watchpoints.resize (16); + memset(&m_dbg_save, 0, sizeof(m_dbg_save)); + } + + virtual ~DNBArchMachARM64() + { + } + + static void Initialize(); + static const DNBRegisterSetInfo * + GetRegisterSetInfo(nub_size_t *num_reg_sets); + + virtual bool GetRegisterValue(int set, int reg, DNBRegisterValue *value); + virtual bool SetRegisterValue(int set, int reg, const DNBRegisterValue *value); + virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); + virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState (); + virtual bool RestoreRegisterState (uint32_t save_id); + + virtual kern_return_t GetRegisterState (int set, bool force); + virtual kern_return_t SetRegisterState (int set); + virtual bool RegisterSetStateIsValid (int set) const; + + virtual uint64_t GetPC(uint64_t failValue); // Get program counter + virtual kern_return_t SetPC(uint64_t value); + virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer + virtual void ThreadWillResume(); + virtual bool ThreadDidStop(); + virtual bool NotifyException(MachException::Data& exc); + + static DNBArchProtocol *Create (MachThread *thread); + static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size); + static uint32_t GetCPUType(); + + virtual uint32_t NumSupportedHardwareWatchpoints(); + virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); + virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); + virtual bool DisableHardwareWatchpoint_helper (uint32_t hw_break_index, bool also_set_on_task); + +protected: + + + kern_return_t EnableHardwareSingleStep (bool enable); + static bool FixGenericRegisterNumber (int &set, int ®); + + typedef enum RegisterSetTag + { + e_regSetALL = REGISTER_SET_ALL, + e_regSetGPR, // ARM_THREAD_STATE64, + e_regSetVFP, // ARM_NEON_STATE64, + e_regSetEXC, // ARM_EXCEPTION_STATE64, + e_regSetDBG, // ARM_DEBUG_STATE64, + kNumRegisterSets + } RegisterSet; + + enum + { + e_regSetGPRCount = ARM_THREAD_STATE64_COUNT, + e_regSetVFPCount = ARM_NEON_STATE64_COUNT, + e_regSetEXCCount = ARM_EXCEPTION_STATE64_COUNT, + e_regSetDBGCount = ARM_DEBUG_STATE64_COUNT, + }; + + enum + { + Read = 0, + Write = 1, + kNumErrors = 2 + }; + + typedef arm_thread_state64_t GPR; + typedef arm_neon_state64_t FPU; + typedef arm_exception_state64_t EXC; + + static const DNBRegisterInfo g_gpr_registers[]; + static const DNBRegisterInfo g_vfp_registers[]; + static const DNBRegisterInfo g_exc_registers[]; + static const DNBRegisterSetInfo g_reg_sets[]; + + static const size_t k_num_gpr_registers; + static const size_t k_num_vfp_registers; + static const size_t k_num_exc_registers; + static const size_t k_num_all_registers; + static const size_t k_num_register_sets; + + struct Context + { + GPR gpr; + FPU vfp; + EXC exc; + }; + + struct State + { + Context context; + arm_debug_state64_t dbg; + kern_return_t gpr_errs[2]; // Read/Write errors + kern_return_t vfp_errs[2]; // Read/Write errors + kern_return_t exc_errs[2]; // Read/Write errors + kern_return_t dbg_errs[2]; // Read/Write errors + State() + { + uint32_t i; + for (i=0; i m_disabled_watchpoints; + + // The following member variables should be updated atomically. + int32_t m_watchpoint_hw_index; + bool m_watchpoint_did_occur; + bool m_watchpoint_resume_single_step_enabled; + + typedef std::map SaveRegisterStates; + SaveRegisterStates m_saved_register_states; +}; + +#endif // #if defined (ARM_THREAD_STATE64_COUNT) +#endif // #if defined (__arm__) +#endif // #ifndef __DNBArchImplARM64_h__ diff --git a/lldb/tools/debugserver/source/RNBContext.h b/lldb/tools/debugserver/source/RNBContext.h index 69bba2c32708..3ca01c1e53a6 100644 --- a/lldb/tools/debugserver/source/RNBContext.h +++ b/lldb/tools/debugserver/source/RNBContext.h @@ -117,6 +117,9 @@ public: const char * GetSTDOUTPath() { return m_stdout.empty() ? NULL : m_stdout.c_str(); } const char * GetSTDERRPath() { return m_stderr.empty() ? NULL : m_stderr.c_str(); } const char * GetWorkingDirPath() { return m_working_dir.empty() ? NULL : m_working_dir.c_str(); } + + void PushProcessEvent (const char *p) { m_process_event.assign(p); } + const char * GetProcessEvent () { return m_process_event.c_str(); } void SetDetachOnError(bool detach) { m_detach_on_error = detach; } bool GetDetachOnError () { return m_detach_on_error; } @@ -138,6 +141,7 @@ protected: std::vector m_arg_vec; std::vector m_env_vec; // This will be unparsed - entries FOO=value std::string m_working_directory; + std::string m_process_event; bool m_detach_on_error; void StartProcessStatusThread(); diff --git a/lldb/tools/debugserver/source/RNBDefs.h b/lldb/tools/debugserver/source/RNBDefs.h index 6611c09997f3..0d94004ca1fe 100644 --- a/lldb/tools/debugserver/source/RNBDefs.h +++ b/lldb/tools/debugserver/source/RNBDefs.h @@ -45,6 +45,10 @@ extern "C" const double debugserverVersionNumber; #define RNB_ARCH "ppc" +#elif defined (__arm64__) + +#define RNB_ARCH "arm64" + #elif defined (__arm__) #define RNB_ARCH "armv7" diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index a74fdf1e1891..b83c9508129c 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -197,6 +197,7 @@ RNBRemote::CreatePacketTable () t.push_back (Packet (get_profile_data, &RNBRemote::HandlePacket_GetProfileData, NULL, "qGetProfileData", "Return profiling data of the current target.")); t.push_back (Packet (set_enable_profiling, &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL, "QSetEnableAsyncProfiling", "Enable or disable the profiling of current target.")); t.push_back (Packet (watchpoint_support_info, &RNBRemote::HandlePacket_WatchpointSupportInfo, NULL, "qWatchpointSupportInfo", "Return the number of supported hardware watchpoints")); + 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 (speed_test, &RNBRemote::HandlePacket_qSpeedTest, NULL, "qSpeedTest:", "Test the maximum speed at which packet can be sent/received.")); } @@ -791,8 +792,15 @@ RNBRemote::ThreadFunctionReadRemoteData(void *arg) static cpu_type_t best_guess_cpu_type () { -#if defined (__arm__) - return CPU_TYPE_ARM; +#if defined (__arm__) || defined (__arm64__) + if (sizeof (char *) == 8) + { + return CPU_TYPE_ARM64; + } + else + { + return CPU_TYPE_ARM; + } #elif defined (__i386__) || defined (__x86_64__) if (sizeof (char*) == 8) { @@ -2085,6 +2093,26 @@ RNBRemote::HandlePacket_QLaunchArch (const char *p) return SendPacket ("E63"); } +rnb_err_t +RNBRemote::HandlePacket_QSetProcessEvent (const char *p) +{ + p += sizeof ("QSetProcessEvent:") - 1; + // If the process is running, then send the event to the process, otherwise + // store it in the context. + if (Context().HasValidProcessID()) + { + if (DNBProcessSendEvent (Context().ProcessID(), p)) + return SendPacket("OK"); + else + return SendPacket ("E80"); + } + else + { + Context().PushProcessEvent(p); + } + return SendPacket ("OK"); +} + void append_hex_value (std::ostream& ostrm, const uint8_t* buf, size_t buf_size, bool swap) { @@ -2354,8 +2382,22 @@ RNBRemote::HandlePacket_last_signal (const char *unused) strncpy (pid_exited_packet, "W00", sizeof(pid_exited_packet)-1); pid_exited_packet[sizeof(pid_exited_packet)-1] = '\0'; } - - return SendPacket (pid_exited_packet); + + const char *exit_info = DNBProcessGetExitInfo (pid); + if (exit_info != NULL && *exit_info != '\0') + { + std::ostringstream exit_packet; + exit_packet << pid_exited_packet; + exit_packet << ';'; + exit_packet << RAW_HEXBASE << "description"; + exit_packet << ':'; + for (size_t i = 0; exit_info[i] != '\0'; i++) + exit_packet << RAWHEX8(exit_info[i]); + exit_packet << ';'; + return SendPacket (exit_packet.str()); + } + else + return SendPacket (pid_exited_packet); } break; } @@ -3767,7 +3809,7 @@ RNBRemote::HandlePacket_qHostInfo (const char *p) // The OS in the triple should be "ios" or "macosx" which doesn't match our // "Darwin" which gets returned from "kern.ostype", so we need to hardcode // this for now. - if (cputype == CPU_TYPE_ARM) + if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) { strm << "ostype:ios;"; // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. @@ -3868,6 +3910,14 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p) rep << "cputype:" << std::hex << cputype << ";"; } + bool host_cpu_is_64bit; + uint32_t is64bit_capable; + size_t is64bit_capable_len = sizeof (is64bit_capable); + if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0) + host_cpu_is_64bit = true; + else + host_cpu_is_64bit = false; + uint32_t cpusubtype; size_t cpusubtype_len = sizeof(cpusubtype); if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &cpusubtype_len, NULL, 0) == 0) @@ -3877,13 +3927,22 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p) cpusubtype = CPU_SUBTYPE_X86_64_ALL; } + // We can query a process' cputype but we cannot query a process' cpusubtype. + // If the process has cputype CPU_TYPE_ARM, then it is an armv7 (32-bit process) and we + // need to override the host cpusubtype (which is in the CPU_SUBTYPE_ARM64 subtype namespace) + // with a reasonable CPU_SUBTYPE_ARMV7 subtype. + if (host_cpu_is_64bit && cputype == CPU_TYPE_ARM) + { + cpusubtype = 11; //CPU_SUBTYPE_ARM_V7S; + } + rep << "cpusubtype:" << std::hex << cpusubtype << ';'; } // The OS in the triple should be "ios" or "macosx" which doesn't match our // "Darwin" which gets returned from "kern.ostype", so we need to hardcode // this for now. - if (cputype == CPU_TYPE_ARM) + if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) rep << "ostype:ios;"; else rep << "ostype:macosx;"; @@ -3914,6 +3973,20 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p) } #elif defined (__arm__) rep << "ptrsize:4;"; +#elif defined (__arm64__) && defined (ARM_UNIFIED_THREAD_STATE) + nub_thread_t thread = DNBProcessGetCurrentThreadMachPort (pid); + kern_return_t kr; + arm_unified_thread_state_t gp_regs; + mach_msg_type_number_t gp_count = ARM_UNIFIED_THREAD_STATE_COUNT; + kr = thread_get_state (thread, ARM_UNIFIED_THREAD_STATE, + (thread_state_t) &gp_regs, &gp_count); + if (kr == KERN_SUCCESS) + { + if (gp_regs.ash.flavor == ARM_THREAD_STATE64) + rep << "ptrsize:8;"; + else + rep << "ptrsize:4;"; + } #endif return SendPacket (rep.str()); diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index feab099f1fd8..94626ceb1acc 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -119,6 +119,7 @@ public: watchpoint_support_info, // 'qWatchpointSupportInfo:' allocate_memory, // '_M' deallocate_memory, // '_m' + set_process_event, // 'QSetProcessEvent:' save_register_state, // '_g' restore_register_state, // '_G' speed_test, // 'qSpeedTest:' @@ -197,6 +198,7 @@ public: rnb_err_t HandlePacket_QListThreadsInStopReply (const char *p); rnb_err_t HandlePacket_QSyncThreadState (const char *p); rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID (const char *p); + rnb_err_t HandlePacket_QSetProcessEvent (const char *p); rnb_err_t HandlePacket_last_signal (const char *p); rnb_err_t HandlePacket_m (const char *p); rnb_err_t HandlePacket_M (const char *p); diff --git a/lldb/tools/debugserver/source/RNBServices.cpp b/lldb/tools/debugserver/source/RNBServices.cpp index 6eb16b07c143..9d76209feb7c 100644 --- a/lldb/tools/debugserver/source/RNBServices.cpp +++ b/lldb/tools/debugserver/source/RNBServices.cpp @@ -22,7 +22,9 @@ #import "DNBLog.h" #include "MacOSX/CFUtils.h" -#ifdef WITH_SPRINGBOARD +// For now only SpringBoard has a notion of "Applications" that it can list for us. +// So we have to use the SpringBoard API's here. +#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) #import #endif @@ -30,7 +32,7 @@ size_t GetAllInfos (std::vector& proc_infos); int -GetPrcoesses (CFMutableArrayRef plistMutableArray, bool all_users) +GetProcesses (CFMutableArrayRef plistMutableArray, bool all_users) { if (plistMutableArray == NULL) return -1; @@ -130,13 +132,12 @@ ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable) const uid_t our_uid = getuid(); -#ifdef WITH_SPRINGBOARD - +#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) if (our_uid == 0) { bool all_users = true; - result = GetPrcoesses (plistMutableArray.get(), all_users); + result = GetProcesses (plistMutableArray.get(), all_users); } else { @@ -190,10 +191,10 @@ ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable) ::CFArrayAppendValue (plistMutableArray.get(), appInfoDict.get()); } } -#else +#else // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) // When root, show all processes bool all_users = (our_uid == 0); - result = GetPrcoesses (plistMutableArray.get(), all_users); + result = GetProcesses (plistMutableArray.get(), all_users); #endif CFReleaser plistData (::CFPropertyListCreateXMLData (alloc, plistMutableArray.get())); @@ -223,16 +224,3 @@ ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable) return result; } - - -bool -IsSBProcess (nub_process_t pid) -{ -#ifdef WITH_SPRINGBOARD - CFReleaser appIdsForPID (::SBSCopyDisplayIdentifiersForProcessID(pid)); - return appIdsForPID.get() != NULL; -#else - return false; -#endif -} - diff --git a/lldb/tools/debugserver/source/RNBServices.h b/lldb/tools/debugserver/source/RNBServices.h index 0164e33b0bf5..b0b9c2193573 100644 --- a/lldb/tools/debugserver/source/RNBServices.h +++ b/lldb/tools/debugserver/source/RNBServices.h @@ -24,6 +24,5 @@ #define DTSERVICES_APP_PID_KEY CFSTR("pid") int ListApplications (std::string &plist, bool opt_runningApps, bool opt_debuggable); -bool IsSBProcess (nub_process_t pid); #endif // __RNBServices_h__ diff --git a/lldb/tools/debugserver/source/debugserver-entitlements.plist b/lldb/tools/debugserver/source/debugserver-entitlements.plist index ce8bd5bc4c09..7de628db2e36 100644 --- a/lldb/tools/debugserver/source/debugserver-entitlements.plist +++ b/lldb/tools/debugserver/source/debugserver-entitlements.plist @@ -4,6 +4,10 @@ com.apple.springboard.debugapplications + com.apple.backboardd.launchapplications + + com.apple.backboardd.debugapplications + run-unsigned-code seatbelt-profiles diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index c9a6ebb37da1..a95e6f597d2d 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -196,7 +196,13 @@ RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char // Our default launch method is posix spawn launch_flavor = eLaunchFlavorPosixSpawn; -#ifdef WITH_SPRINGBOARD +#if defined WITH_BKS + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(inferior_argv[0], ".app")) + { + launch_flavor = eLaunchFlavorBKS; + } +#elif defined WITH_SPRINGBOARD // Check if we have an app bundle, if so launch using SpringBoard. if (strstr(inferior_argv[0], ".app")) { @@ -217,6 +223,7 @@ RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char launch_err_str[0] = '\0'; const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath() : ctx.GetWorkingDirectory()); + const char *process_event = ctx.GetProcessEvent(); nub_process_t pid = DNBProcessLaunch (resolved_path, &inferior_argv[0], &inferior_envp[0], @@ -227,6 +234,7 @@ RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char no_stdio, launch_flavor, g_disable_aslr, + process_event, launch_err_str, sizeof(launch_err_str)); @@ -878,6 +886,14 @@ main (int argc, char *argv[]) // signal (SIGINT, signal_handler); signal (SIGPIPE, signal_handler); signal (SIGHUP, signal_handler); + + // We're always sitting in waitpid or kevent waiting on our target process' death, + // we don't need no stinking SIGCHLD's... + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigset, NULL); g_remoteSP.reset (new RNBRemote ()); @@ -1051,15 +1067,23 @@ main (int argc, char *argv[]) else if (strcasestr(optarg, "spring") == optarg) g_launch_flavor = eLaunchFlavorSpringBoard; #endif +#ifdef WITH_BKS + else if (strcasestr(optarg, "backboard") == optarg) + g_launch_flavor = eLaunchFlavorBKS; +#endif + else { RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg); RNBLogSTDERR ("Valid values TYPE are:\n"); - RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n"); - RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n"); - RNBLogSTDERR (" fork Launch the executable using fork and exec.\n"); + RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n"); + RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n"); + RNBLogSTDERR (" fork Launch the executable using fork and exec.\n"); #ifdef WITH_SPRINGBOARD - RNBLogSTDERR (" spring Launch the executable through Springboard.\n"); + RNBLogSTDERR (" spring Launch the executable through Springboard.\n"); +#endif +#ifdef WITH_BKS + RNBLogSTDERR (" backboard Launch the executable through BackBoard Services.\n"); #endif exit (5); } @@ -1422,7 +1446,13 @@ main (int argc, char *argv[]) // Our default launch method is posix spawn launch_flavor = eLaunchFlavorPosixSpawn; -#ifdef WITH_SPRINGBOARD +#if defined WITH_BKS + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find (".app") != std::string::npos) + { + launch_flavor = eLaunchFlavorBKS; + } +#elif defined WITH_SPRINGBOARD // Check if we have an app bundle, if so launch using SpringBoard. if (waitfor_pid_name.find (".app") != std::string::npos) {