summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2014-03-29 18:54:20 +0000
committerJason Molenda <jmolenda@apple.com>2014-03-29 18:54:20 +0000
commita332978b2ab53306acdef10858c7e954e605ab37 (patch)
treedb0802288ce9a50156d440b82ae606eae60cf129
parent61e595be4dcd9e63bc3a2b6787ffb647457969cd (diff)
downloadbcm5719-llvm-a332978b2ab53306acdef10858c7e954e605ab37.tar.gz
bcm5719-llvm-a332978b2ab53306acdef10858c7e954e605ab37.zip
lldb arm64 import.
These changes were written by Greg Clayton, Jim Ingham, Jason Molenda. It builds cleanly against TOT llvm with xcodebuild. I updated the cmake files by visual inspection but did not try a build. I haven't built these sources on any non-Mac platforms - I don't think this patch adds any code that requires darwin, but please let me know if I missed something. In debugserver, MachProcess.cpp and MachTask.cpp were renamed to MachProcess.mm and MachTask.mm as they picked up some new Objective-C code needed to launch processes when running on iOS. llvm-svn: 205113
-rw-r--r--lldb/include/lldb/API/SBProcess.h3
-rw-r--r--lldb/include/lldb/API/SBTarget.h6
-rw-r--r--lldb/include/lldb/Core/ArchSpec.h4
-rw-r--r--lldb/include/lldb/Core/RegisterValue.h6
-rw-r--r--lldb/include/lldb/Expression/ExpressionSourceCode.h5
-rw-r--r--lldb/include/lldb/Symbol/ClangASTType.h3
-rw-r--r--lldb/include/lldb/Target/Process.h24
-rw-r--r--lldb/lib/Makefile2
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj89
-rw-r--r--lldb/scripts/Python/interface/SBProcess.i3
-rw-r--r--lldb/scripts/Python/interface/SBTarget.i7
-rw-r--r--lldb/scripts/build-llvm.pl8
-rw-r--r--lldb/source/API/SBProcess.cpp26
-rw-r--r--lldb/source/API/SBTarget.cpp11
-rw-r--r--lldb/source/CMakeLists.txt2
-rw-r--r--lldb/source/Core/ArchSpec.cpp6
-rw-r--r--lldb/source/Core/Error.cpp2
-rw-r--r--lldb/source/Core/Module.cpp1
-rw-r--r--lldb/source/Expression/ClangExpressionParser.cpp10
-rw-r--r--lldb/source/Expression/ClangUserExpression.cpp2
-rw-r--r--lldb/source/Expression/ExpressionSourceCode.cpp35
-rw-r--r--lldb/source/Host/common/Host.cpp4
-rw-r--r--lldb/source/Host/macosx/Host.mm36
-rw-r--r--lldb/source/Host/macosx/Symbols.cpp4
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp2
-rw-r--r--lldb/source/Plugins/ABI/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp1102
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h145
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt5
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-arm64/Makefile14
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp2
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp2
-rw-r--r--lldb/source/Plugins/Instruction/ARM64/CMakeLists.txt5
-rw-r--r--lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp722
-rw-r--r--lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h300
-rw-r--r--lldb/source/Plugins/Instruction/ARM64/Makefile14
-rw-r--r--lldb/source/Plugins/Instruction/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Makefile6
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp157
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp60
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp3
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp2
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp18
-rw-r--r--lldb/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp161
-rw-r--r--lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h61
-rw-r--r--lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp4
-rw-r--r--lldb/source/Plugins/Process/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp1235
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h296
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp31
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp149
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h20
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp7
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp303
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp50
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h4
-rw-r--r--lldb/source/Symbol/ClangASTType.cpp97
-rw-r--r--lldb/source/Target/Thread.cpp1
-rw-r--r--lldb/source/Utility/ARM64_DWARF_Registers.cpp146
-rw-r--r--lldb/source/Utility/ARM64_DWARF_Registers.h102
-rw-r--r--lldb/source/Utility/ARM64_GCC_Registers.h92
-rw-r--r--lldb/source/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/lldb.cpp7
-rw-r--r--lldb/test/functionalities/data-formatter/data-formatter-objc/main.m2
-rw-r--r--lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj63
-rw-r--r--lldb/tools/debugserver/source/DNB.cpp150
-rw-r--r--lldb/tools/debugserver/source/DNB.h78
-rw-r--r--lldb/tools/debugserver/source/DNBArch.cpp11
-rw-r--r--lldb/tools/debugserver/source/DNBArch.h1
-rw-r--r--lldb/tools/debugserver/source/DNBDefs.h12
-rw-r--r--lldb/tools/debugserver/source/DNBError.cpp10
-rw-r--r--lldb/tools/debugserver/source/DNBError.h9
-rw-r--r--lldb/tools/debugserver/source/MacOSX/CMakeLists.txt5
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachException.h2
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h27
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.mm (renamed from lldb/tools/debugserver/source/MacOSX/MachProcess.cpp)737
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachTask.mm (renamed from lldb/tools/debugserver/source/MacOSX/MachTask.cpp)29
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp9
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp9
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp295
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h41
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp2093
-rw-r--r--lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h272
-rw-r--r--lldb/tools/debugserver/source/RNBContext.h4
-rw-r--r--lldb/tools/debugserver/source/RNBDefs.h4
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp85
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h2
-rw-r--r--lldb/tools/debugserver/source/RNBServices.cpp28
-rw-r--r--lldb/tools/debugserver/source/RNBServices.h1
-rw-r--r--lldb/tools/debugserver/source/debugserver-entitlements.plist4
-rw-r--r--lldb/tools/debugserver/source/debugserver.cpp42
94 files changed, 9221 insertions, 436 deletions
diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index f2846710c61..448e9593492 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 230dffc6825..bcb9fc5d783 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 1ccb385783a..4593bf4116a 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 cf29cea46d3..1b1a71a11c5 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 be1014ae304..2dd09378fcd 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 19b5d6ec672..ad980ce50c8 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 b40a02ef9ee..55775b501ef 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 88e4329033b..fd06e483775 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 10482147f0e..73efbcd25aa 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 = "<group>"; };
26491E3A15E1DB8600CBFFC2 /* OptionValueRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionValueRegex.h; path = include/lldb/Interpreter/OptionValueRegex.h; sourceTree = "<group>"; };
26491E3D15E1DB9F00CBFFC2 /* OptionValueRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionValueRegex.cpp; path = source/Interpreter/OptionValueRegex.cpp; sourceTree = "<group>"; };
+ 264A12FA1372522000875C42 /* EmulateInstructionARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EmulateInstructionARM64.cpp; sourceTree = "<group>"; };
+ 264A12FB1372522000875C42 /* EmulateInstructionARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmulateInstructionARM64.h; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ 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 = "<group>"; };
264A43BB1320B3B4005B4096 /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Platform.h; path = include/lldb/Target/Platform.h; sourceTree = "<group>"; };
264A43BD1320BCEB005B4096 /* Platform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Platform.cpp; path = source/Target/Platform.cpp; sourceTree = "<group>"; };
264A97BD133918BC0017F0BE /* PlatformRemoteGDBServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformRemoteGDBServer.cpp; path = "gdb-server/PlatformRemoteGDBServer.cpp"; sourceTree = "<group>"; };
@@ -1143,7 +1154,7 @@
2670F8111862B44A006B332C /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = /usr/lib/libncurses.dylib; sourceTree = "<absolute>"; };
2671A0CD134825F6003A87BB /* ConnectionMachPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConnectionMachPort.h; path = include/lldb/Core/ConnectionMachPort.h; sourceTree = "<group>"; };
2671A0CF13482601003A87BB /* ConnectionMachPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConnectionMachPort.cpp; path = source/Core/ConnectionMachPort.cpp; sourceTree = "<group>"; };
- 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ 2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; };
2672D8471189055500FF4019 /* CommandObjectFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFrame.h; path = source/Commands/CommandObjectFrame.h; sourceTree = "<group>"; };
26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteCommunicationClient.cpp; sourceTree = "<group>"; };
26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationClient.h; sourceTree = "<group>"; };
@@ -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 = "<group>"; };
26BC7D8010F1B77400F91463 /* UserID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserID.h; path = include/lldb/Core/UserID.h; sourceTree = "<group>"; };
26BC7D8110F1B77400F91463 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Value.h; path = include/lldb/Core/Value.h; sourceTree = "<group>"; };
- 26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = "<group>"; 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 = "<group>"; };
26BC7D8310F1B77400F91463 /* ValueObjectChild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectChild.h; path = include/lldb/Core/ValueObjectChild.h; sourceTree = "<group>"; };
26BC7D8410F1B77400F91463 /* ValueObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectList.h; path = include/lldb/Core/ValueObjectList.h; sourceTree = "<group>"; };
26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectVariable.h; path = include/lldb/Core/ValueObjectVariable.h; sourceTree = "<group>"; };
@@ -1457,7 +1468,7 @@
26BC7E9610F1B85900F91463 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Timer.cpp; path = source/Core/Timer.cpp; sourceTree = "<group>"; };
26BC7E9810F1B85900F91463 /* UserID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserID.cpp; path = source/Core/UserID.cpp; sourceTree = "<group>"; };
26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = "<group>"; };
- 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectChild.cpp; path = source/Core/ValueObjectChild.cpp; sourceTree = "<group>"; };
26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = "<group>"; };
26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = "<group>"; };
@@ -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 = "<group>"; };
26DB3E071379E7AD0080DC73 /* ABIMacOSX_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABIMacOSX_arm.cpp; sourceTree = "<group>"; };
26DB3E081379E7AD0080DC73 /* ABIMacOSX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABIMacOSX_arm.h; sourceTree = "<group>"; };
+ 26DB3E0B1379E7AD0080DC73 /* ABIMacOSX_arm64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABIMacOSX_arm64.cpp; sourceTree = "<group>"; };
+ 26DB3E0C1379E7AD0080DC73 /* ABIMacOSX_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABIMacOSX_arm64.h; sourceTree = "<group>"; };
26DB3E0F1379E7AD0080DC73 /* ABIMacOSX_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABIMacOSX_i386.cpp; sourceTree = "<group>"; };
26DB3E101379E7AD0080DC73 /* ABIMacOSX_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABIMacOSX_i386.h; sourceTree = "<group>"; };
26DB3E131379E7AD0080DC73 /* ABISysV_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ABISysV_x86_64.cpp; sourceTree = "<group>"; };
@@ -1903,6 +1916,8 @@
AF061F86182C97ED00B6A19C /* RegisterContextHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextHistory.h; path = Utility/RegisterContextHistory.h; sourceTree = "<group>"; };
AF061F89182C980000B6A19C /* HistoryThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryThread.h; path = Utility/HistoryThread.h; sourceTree = "<group>"; };
AF061F8A182C980000B6A19C /* HistoryUnwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryUnwind.h; path = Utility/HistoryUnwind.h; sourceTree = "<group>"; };
+ AF0F6E4E1739A76D009180FE /* RegisterContextKDP_arm64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextKDP_arm64.cpp; sourceTree = "<group>"; };
+ AF0F6E4F1739A76D009180FE /* RegisterContextKDP_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextKDP_arm64.h; sourceTree = "<group>"; };
AF0C112718580CD800C4C45B /* QueueItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QueueItem.cpp; path = source/Target/QueueItem.cpp; sourceTree = "<group>"; };
AF0E22EE18A09FB20009B7D1 /* AppleGetItemInfoHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleGetItemInfoHandler.cpp; sourceTree = "<group>"; };
AF0E22EF18A09FB20009B7D1 /* AppleGetItemInfoHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleGetItemInfoHandler.h; sourceTree = "<group>"; };
@@ -1933,6 +1948,9 @@
AF68D3301255A110002FF25B /* UnwindLLDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindLLDB.h; path = Utility/UnwindLLDB.h; sourceTree = "<group>"; };
AF81DEF91828A23F0042CF19 /* SystemRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SystemRuntime.cpp; path = source/Target/SystemRuntime.cpp; sourceTree = "<group>"; };
AF90106315AB7C5700FF120D /* lldb.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = lldb.1; path = docs/lldb.1; sourceTree = "<group>"; };
+ 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 = "<group>"; };
+ AF9107EC168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextDarwin_arm64.cpp; path = Utility/RegisterContextDarwin_arm64.cpp; sourceTree = "<group>"; };
+ AF9107ED168570D200DBCD3C /* RegisterContextDarwin_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextDarwin_arm64.h; path = Utility/RegisterContextDarwin_arm64.h; sourceTree = "<group>"; };
AF94005711C03F6500085DB9 /* SymbolVendor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolVendor.cpp; path = source/Symbol/SymbolVendor.cpp; sourceTree = "<group>"; };
AF9B8F31182DB52900DA866F /* SystemRuntimeMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemRuntimeMacOSX.cpp; sourceTree = "<group>"; };
AF9B8F32182DB52900DA866F /* SystemRuntimeMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemRuntimeMacOSX.h; sourceTree = "<group>"; };
@@ -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 = "<group>";
};
+ 264A12F91372522000875C42 /* ARM64 */ = {
+ isa = PBXGroup;
+ children = (
+ 264A12FA1372522000875C42 /* EmulateInstructionARM64.cpp */,
+ 264A12FB1372522000875C42 /* EmulateInstructionARM64.h */,
+ );
+ path = ARM64;
+ sourceTree = "<group>";
+ };
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 = "<group>";
@@ -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 = "<group>";
};
+ 26DB3E0A1379E7AD0080DC73 /* MacOSX-arm64 */ = {
+ isa = PBXGroup;
+ children = (
+ 26DB3E0B1379E7AD0080DC73 /* ABIMacOSX_arm64.cpp */,
+ 26DB3E0C1379E7AD0080DC73 /* ABIMacOSX_arm64.h */,
+ );
+ path = "MacOSX-arm64";
+ sourceTree = "<group>";
+ };
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 7abbf919af2..d023b2472cc 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 d26b3faacee..87d5c5b13b0 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 4f9a2bfd1a1..1c7492470e4 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 47a6ee48cf3..52de0cd4fe3 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 224349c0bce..9f006f51312 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 2ab37c9707b..4e697eeba81 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 4cf27894803..b1303462572 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 7aabe5b386d..bbcf39d7438 100644
--- a/lldb/source/Core/Error.cpp
+++ b/lldb/source/Core/Error.cpp
@@ -21,7 +21,7 @@
#include <cerrno>
#include <cstdarg>
-#if defined (__arm__) && defined (__APPLE__)
+#if (defined (__arm__) || defined (__arm64__)) && defined (__APPLE__)
#include <SpringBoardServices/SpringBoardServer.h>
#endif
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 0cc1bc8b777..a6ffbd2b76a 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 44f1e535ec7..bde24691142 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 4eefddda41a..e29995674df 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 aef3b9e301e..c79a2d795ce 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)
@@ -65,12 +88,14 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
case lldb::eLanguageTypeC:
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"void \n"
"%s(void *$__lldb_arg) \n"
"{ \n"
" %s; \n"
"} \n",
g_expression_prefix,
+ target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_body.c_str());
@@ -78,12 +103,14 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
case lldb::eLanguageTypeC_plus_plus:
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"void \n"
"$__lldb_class::%s(void *$__lldb_arg) %s\n"
"{ \n"
" %s; \n"
"} \n",
g_expression_prefix,
+ target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
(const_object ? "const" : ""),
@@ -94,6 +121,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
{
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"+(void)%s:(void *)$__lldb_arg; \n"
"@end \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(),
@@ -113,6 +142,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
{
wrap_stream.Printf("%s \n"
"%s \n"
+ "%s \n"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"-(void)%s:(void *)$__lldb_arg; \n"
"@end \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 e5a0f339e9d..197be193e6b 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 ef3ecfb0a9c..b9d2419dcdf 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 <objc/objc-auto.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
-#if !defined(__arm__)
+#if !defined(__arm__) && !defined(__arm64__)
#include <Carbon/Carbon.h>
#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 935c9ffc945..f7f74f34c1d 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 832ccbb06f3..18f108bb58a 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 5d4fb5ce337..4ce15a11292 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 00000000000..1b6c7ef55ae
--- /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 <vector>
+
+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<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+size_t
+ABIMacOSX_arm64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABIMacOSX_arm64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::arm64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_arm64);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABIMacOSX_arm64::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t return_addr,
+ llvm::ArrayRef<lldb::addr_t> 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<DataBufferHeap> 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; i<homogeneous_count; ++i)
+ {
+ char v_name[8];
+ ::snprintf (v_name, sizeof(v_name), "v%u", NSRN);
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(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<size_t>(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<DataBufferHeap> 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<DataBufferHeap> 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 00000000000..0753b23ce2a
--- /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<lldb::addr_t> 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 00000000000..35dc034a547
--- /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 00000000000..7fc6909e43c
--- /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 5c279c91613..d9f06a4bc46 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 30ba80c0ba3..f475dbd773d 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 00000000000..03031bf5dc8
--- /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 00000000000..9cc1cc5ec1f
--- /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 <stdlib.h>
+
+#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<EmulateInstructionARM64> 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 &reg_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<lldb::kNumRegisterKinds; ++i)
+ reg_info.kinds[reg_kind] = LLDB_INVALID_REGNUM;
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ return true;
+
+ default: return false;
+ }
+ }
+
+ if (reg_kind == eRegisterKindDWARF)
+ return arm64_dwarf::GetRegisterInfo(reg_num, reg_info);
+ return false;
+}
+
+EmulateInstructionARM64::Opcode*
+EmulateInstructionARM64::GetOpcodeForInstruction (const uint32_t opcode)
+{
+ static EmulateInstructionARM64::Opcode
+ g_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue instructions
+ //----------------------------------------------------------------------
+
+ // push register(s)
+ { 0xff000000, 0xd1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0xf1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x91000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Xd|SP>, <Xn|SP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0xb1000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Xd>, <Xn|SP>, #<imm> {, <shift>}" },
+
+
+ { 0xff000000, 0x51000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUB <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x71000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "SUBS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x11000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADD <Wd|WSP>, <Wn|WSP>, #<imm> {, <shift>}" },
+ { 0xff000000, 0x31000000, No_VFP, &EmulateInstructionARM64::Emulate_addsub_imm, "ADDS <Wd>, <Wn|WSP>, #<imm> {, <shift>}" },
+
+ { 0xffc00000, 0x29000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Wt>, <Wt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xa9000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Xt>, <Xt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x2d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <St>, <St2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0x6d000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Dt>, <Dt2>, [<Xn|SP>{, #<imm>}]" },
+ { 0xffc00000, 0xad000000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_off, "STP <Qt>, <Qt2>, [<Xn|SP>{, #<imm>}]" },
+
+ { 0xffc00000, 0xad800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Qt>, <Qt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x2d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <St>, <St2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x29800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Wt>, <Wt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0x6d800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Dt>, <Dt2>, [<Xn|SP>, #<imm>]!" },
+ { 0xffc00000, 0xa9800000, No_VFP, &EmulateInstructionARM64::Emulate_ldstpair_pre, "STP <Xt>, <Xt2>, [<Xn|SP>, #<imm>]!" },
+
+ };
+ static const size_t k_num_arm_opcodes = sizeof(g_opcodes)/sizeof(EmulateInstructionARM64::Opcode);
+
+ for (size_t i=0; i<k_num_arm_opcodes; ++i)
+ {
+ if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
+ return &g_opcodes[i];
+ }
+ return NULL;
+}
+
+bool
+EmulateInstructionARM64::ReadInstruction ()
+{
+ bool success = false;
+ m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
+ if (success)
+ {
+ Context read_inst_context;
+ read_inst_context.type = eContextReadOpcode;
+ read_inst_context.SetNoArgs ();
+ m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder());
+ }
+ if (!success)
+ m_addr = LLDB_INVALID_ADDRESS;
+ return success;
+}
+
+
+bool
+EmulateInstructionARM64::EvaluateInstruction (uint32_t evaluate_options)
+{
+ const uint32_t opcode = m_opcode.GetOpcode32();
+ Opcode *opcode_data = GetOpcodeForInstruction(opcode);
+ if (opcode_data == NULL)
+ return false;
+
+ //printf ("opcode template for 0x%8.8x: %s\n", opcode, opcode_data->name);
+ 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 (&reg_info_Rt, data_Rt))
+ return false;
+
+ if (data_Rt.GetAsMemoryData(&reg_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 (&reg_info_Rt2, data_Rt2))
+ return false;
+
+ if (data_Rt2.GetAsMemoryData(&reg_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(&reg_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, &reg_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(&reg_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, &reg_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, &reg_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 00000000000..333e0a9dba5
--- /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 &reg_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 00000000000..b07a6020dd3
--- /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 3eef5f4922e..21fd82a7ab3 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 7b39dd53627..eb15cf97993 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 a4bfc5caec5..814df8897a4 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 <dlfcn.h>
#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 <mach-o/dyld_images.h>
if (*version >= 13)
{
- uuid_t *sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID <mach-o/dyld_images.h>
+ 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 <mach-o/dyld_images.h>
+ }
+ else
+ {
+ sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID <mach-o/dyld_images.h>
+ }
uuid.SetBytes (sharedCacheUUID_address);
}
}
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index f98fe9d0198..8d05eb60921 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 67ff026081e..820f18e124c 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 fe84e5f0a2e..7acde1804a8 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 7b5ab9aec41..545ac073c97 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 ac0a96cfbdb..0a809503d1e 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 4203a87cfd8..b0172037b04 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 00000000000..ed62f1982d3
--- /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<ProcessKDP *>(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<ProcessKDP *>(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<ProcessKDP *>(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<ProcessKDP *>(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<ProcessKDP *>(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<ProcessKDP *>(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<ProcessKDP *>(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<ProcessKDP *>(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 00000000000..8780b7be4a9
--- /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 bb7e8a317a0..562ba8b0a16 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 6cd8e645900..e1a64ecfdc8 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 00000000000..b42f35b927b
--- /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 <mach/mach_types.h>
+#include <mach/thread_act.h>
+#include <sys/sysctl.h>
+
+// 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; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[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; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+// if (log) log->Printf ("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 00000000000..44479c81058
--- /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 &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_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 <mach/arm/thread_status.h> 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 <mach/arm/thread_status.h> arm_neon_state64_t
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // mirrors <mach/arm/thread_status.h> 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 <mach/arm/thread_status.h> 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 5b6d9fe9f3b..131aa452e3e 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 8aa21c61856..d1862398086 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 e27186ff86c..f436799a86a 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);
@@ -3229,6 +3346,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s
}
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)
{
Mutex::Locker locker;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 4e404b6ab44..8de845fa5fe 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 5542f7915a1..2fadf3359f5 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 73b9b3e8267..9e5b0d79e10 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];
-
- // Skip composite registers.
- if (reg_info->value_regs)
- continue;
+ 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'
+
+ // 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;
+
+ // 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.
+
+ 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)
+ {
+ 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;
+ }
- // 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;
+ 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;
+ }
- const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
- if (restore_src)
+ // 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)
{
- if (GetRegisterIsValid(reg))
+ // 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)
+ {
+ register_offset = reg_info->byte_offset;
+ }
+ else
{
- 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 = 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,14 +763,88 @@ 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;
+ }
+ }
+ }
+ 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;
}
+ return num_restored > 0;
}
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 1bee5806e5f..48db3b0ffae 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 1d4a23509e6..4f5cca57659 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 fdb92f2ba3b..aff032f4cf2 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<RecordType>(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<VectorType>(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<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsHomogeneousAggregate (base_type_ptr);
+
+ case clang::Type::Elaborated:
+ return ClangASTType(m_ast, cast<ElaboratedType>(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 15768b087a2..1d7da985fba 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 00000000000..760ee052a4c
--- /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 &reg_info)
+{
+ ::memset (&reg_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 00000000000..832f25d45b5
--- /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 &reg_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 00000000000..960b5e046f9
--- /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 19dcde5930b..167a9d4ad39 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 4afd74e7f54..30f446d5bb5 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 eb3f4a2a620..6c6cbd46165 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 <Foundation/Foundation.h>
#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 fbe621b5486..ce63f89d696 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 = "<group>"; };
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 = "<group>"; };
+ 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplARM64.h; sourceTree = "<group>"; };
2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = "<group>"; };
2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = "<group>"; };
2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = "<group>"; };
@@ -77,7 +80,7 @@
26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = "<group>"; };
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 = "<group>"; };
- 26B67DE10EE9BC30006C8BC0 /* MachTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachTask.cpp; sourceTree = "<group>"; };
+ 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MachTask.mm; sourceTree = "<group>"; };
26C636AD0C71303A0024798E /* dbgnub-config.pl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.perl; path = "dbgnub-config.pl"; sourceTree = "<group>"; };
26C637D60C71334A0024798E /* DNB.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNB.cpp; sourceTree = "<group>"; };
26C637D70C71334A0024798E /* DNB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNB.h; sourceTree = "<group>"; };
@@ -99,7 +102,7 @@
26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = "<group>"; };
26C637EE0C71334A0024798E /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = "<group>"; };
26C637EF0C71334A0024798E /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = "<group>"; };
- 26C637F00C71334A0024798E /* MachProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachProcess.cpp; sourceTree = "<group>"; };
+ 26C637F00C71334A0024798E /* MachProcess.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = MachProcess.mm; sourceTree = "<group>"; };
26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = "<group>"; };
26C637F20C71334A0024798E /* MachThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThread.cpp; sourceTree = "<group>"; };
26C637F30C71334A0024798E /* MachThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachThread.h; sourceTree = "<group>"; };
@@ -167,6 +170,15 @@
name = Products;
sourceTree = "<group>";
};
+ 266B5ECE1460A68200E43F0A /* arm64 */ = {
+ isa = PBXGroup;
+ children = (
+ 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */,
+ 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */,
+ );
+ path = arm64;
+ sourceTree = "<group>";
+ };
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 cd23a401e21..0fb08e2c4fd 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -26,6 +26,16 @@
#include <vector>
#include <libproc.h>
+#define TRY_KQUEUE 1
+
+#ifdef TRY_KQUEUE
+ #include <sys/event.h>
+ #include <sys/time.h>
+ #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(&reg_event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT|NOTE_EXIT_DETAIL, 0, NULL);
+ // Register the event:
+ int result = kevent (kq_id, &reg_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 c70ede989d5..8a215cf452d 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -18,6 +18,12 @@
#include <mach/thread_info.h>
#include <string>
+#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 f56c6a3181e..c3f1fdf2682 100644
--- a/lldb/tools/debugserver/source/DNBArch.cpp
+++ b/lldb/tools/debugserver/source/DNBArch.cpp
@@ -21,18 +21,7 @@
typedef std::map<uint32_t, DNBArchPluginInfo> 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 e4f6bd2fada..54300374c78 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 b08885874a2..70df4ba5ea6 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 84727e77fa2..b4f39901089 100644
--- a/lldb/tools/debugserver/source/DNBError.cpp
+++ b/lldb/tools/debugserver/source/DNBError.cpp
@@ -48,6 +48,16 @@ DNBError::AsString() const
}
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 78b2c8b50f3..3f8fa2f1db8 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 8e2ec1c66e4..24342c84f87 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 08d22cd28e6..74041e0c4bd 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 5fa5dbdcfc7..c98700c0fc5 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<std::string> 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
index c077f9be002..ca7a5b5dab5 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 <Foundation/Foundation.h>
+extern "C"
+{
+#import <BackBoardServices/BackBoardServices.h>
+#import <BackBoardServices/BKSSystemService_LaunchServices.h>
+#import <BackBoardServices/BKSOpenApplicationConstants_Private.h>
+}
+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;
+#if defined (WITH_BKS)
+ if (launch_flavor == eLaunchFlavorBKS)
+ {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- const char *stdout_err = "/dev/null";
- CFString stdio_path;
- stdio_path.SetFileSystemRepresentation (stdout_err);
+ 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)];
- 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);
+ 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];
- if (sbs_error != SBSApplicationLaunchErrorSuccess)
+ 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)
{
- err_str.SetError(sbs_error, DNBError::SpringBoard);
- 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)
+ {
+ 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 <servers/bootstrap.h>
-// 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 = "<Unknown Bundle ID>";
+
+ 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 : "<unknown error>",
+ open_app_error);
+ // REMOVE ME
+ DNBLogError ("In completion handler for send event, got error \"%s\"(%d).",
+ error_str ? error_str : "<unknown error>",
+ 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
index 30fc22c7dfd..8b3a4f076e1 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 <Foundation/Foundation.h>
+ #import <BackBoardServices/BackBoardServices.h>
+ #import <BackBoardServices/BKSWatchdogAssertion.h>
+}
+#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<BKSWatchdogAssertionRef> 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 adad95f2f7c..634d2576332 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 f11906afd63..fc4108d94ea 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 e9781717d94..dc149666f0c 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 <inttypes.h>
#include <sys/sysctl.h>
// 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()
-{
- 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()
+nub_addr_t
+DNBArchMachARM::GetWatchpointAddressByIndex (uint32_t hw_index)
{
- 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 8cda8025395..4d4609184e8 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<disabled_watchpoint> 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 00000000000..909fac69f31
--- /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 <inttypes.h>
+#include <sys/sysctl.h>
+
+// 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<num_hw_watchpoints; ++i)
+ {
+ if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw watchpoint slot (in i)
+ }
+
+ // See if we found an available hw watchpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ //DumpDBGState(m_state.dbg);
+
+ // 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] = 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?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::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);
+
+ DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint() SetDBGState() => 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<n> 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<n> 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 &reg)
+{
+ 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 00000000000..0d2a998265f
--- /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 <map>
+#include <mach/thread_status.h>
+
+#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 &reg);
+
+ 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<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ vfp_errs[i] = -1;
+ exc_errs[i] = -1;
+ dbg_errs[i] = -1;
+ }
+ }
+ void InvalidateRegisterSetState(int set)
+ {
+ SetError (set, Read, -1);
+ }
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (e_regSetALL, Read, -1);
+ }
+
+ kern_return_t GetError (int set, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (set)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case e_regSetALL: return gpr_errs[err_idx] |
+ vfp_errs[err_idx] |
+ exc_errs[err_idx] |
+ dbg_errs[err_idx] ;
+ case e_regSetGPR: return gpr_errs[err_idx];
+ case e_regSetVFP: return vfp_errs[err_idx];
+ case e_regSetEXC: return exc_errs[err_idx];
+ //case e_regSetDBG: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+ bool SetError (int set, uint32_t err_idx, kern_return_t err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (set)
+ {
+ case e_regSetALL:
+ gpr_errs[err_idx] = err;
+ vfp_errs[err_idx] = err;
+ dbg_errs[err_idx] = err;
+ exc_errs[err_idx] = err;
+ return true;
+
+ case e_regSetGPR:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case e_regSetVFP:
+ vfp_errs[err_idx] = err;
+ return true;
+
+ case e_regSetEXC:
+ exc_errs[err_idx] = err;
+ return true;
+
+// case e_regSetDBG:
+// dbg_errs[err_idx] = err;
+// return true;
+ default: break;
+ }
+ }
+ return false;
+ }
+ bool RegsAreValid (int set) const
+ {
+ return GetError(set, Read) == KERN_SUCCESS;
+ }
+ };
+
+ kern_return_t GetGPRState (bool force);
+ kern_return_t GetVFPState (bool force);
+ kern_return_t GetEXCState (bool force);
+ kern_return_t GetDBGState (bool force);
+
+ kern_return_t SetGPRState ();
+ kern_return_t SetVFPState ();
+ kern_return_t SetEXCState ();
+ kern_return_t SetDBGState (bool also_set_on_task);
+
+ // Helper functions for watchpoint implementaions.
+
+ typedef arm_debug_state64_t DBG;
+
+ void ClearWatchpointOccurred();
+ bool HasWatchpointOccurred();
+ 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);
+ virtual bool ReenableHardwareWatchpoint (uint32_t hw_break_index);
+ virtual bool ReenableHardwareWatchpoint_helper (uint32_t hw_break_index);
+ virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr);
+
+
+ class disabled_watchpoint {
+ public:
+ disabled_watchpoint () { addr = 0; control = 0; }
+ nub_addr_t addr;
+ uint32_t control;
+ };
+
+protected:
+ MachThread * m_thread;
+ State m_state;
+ arm_debug_state64_t m_dbg_save;
+
+ // arm64 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<disabled_watchpoint> 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<uint32_t, Context> 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 69bba2c3270..3ca01c1e53a 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<std::string> m_arg_vec;
std::vector<std::string> 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 6611c09997f..0d94004ca1f 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 a74fdf1e189..b83c9508129 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 feab099f1fd..94626ceb1ac 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 6eb16b07c14..9d76209feb7 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 <SpringBoardServices/SpringBoardServices.h>
#endif
@@ -30,7 +32,7 @@
size_t GetAllInfos (std::vector<struct kinfo_proc>& 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<CFDataRef> 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<CFArrayRef> 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 0164e33b0bf..b0b9c219357 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 ce8bd5bc4c0..7de628db2e3 100644
--- a/lldb/tools/debugserver/source/debugserver-entitlements.plist
+++ b/lldb/tools/debugserver/source/debugserver-entitlements.plist
@@ -4,6 +4,10 @@
<dict>
<key>com.apple.springboard.debugapplications</key>
<true/>
+ <key>com.apple.backboardd.launchapplications</key>
+ <true/>
+ <key>com.apple.backboardd.debugapplications</key>
+ <true/>
<key>run-unsigned-code</key>
<true/>
<key>seatbelt-profiles</key>
diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp
index c9a6ebb37da..a95e6f597d2 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)
{
OpenPOWER on IntegriCloud