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
This commit is contained in:
Jason Molenda 2014-03-29 18:54:20 +00:00
parent 61e595be4d
commit a332978b2a
94 changed files with 9223 additions and 438 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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,

View File

@ -374,6 +374,12 @@ namespace lldb_private {
uint32_t
GetByteSize () const;
static uint32_t
GetMaxByteSize ()
{
return kMaxRegisterByteSize;
}
void
Clear();

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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 \

View File

@ -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";

View File

@ -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

View File

@ -94,6 +94,13 @@ public:
bool
AddSuppressFileAction (int fd, bool read, bool write);
void
SetLaunchEventData (const char *data);
const char *
GetLaunchEventData () const;
};
class SBAttachInfo

View File

@ -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

View File

@ -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 ()
{

View File

@ -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())

View File

@ -74,9 +74,11 @@ set( LLDB_USED_LIBS
lldbPluginAppleObjCRuntime
lldbPluginCXXItaniumABI
lldbPluginABIMacOSX_arm
lldbPluginABIMacOSX_arm64
lldbPluginABIMacOSX_i386
lldbPluginABISysV_x86_64
lldbPluginInstructionARM
lldbPluginInstructionARM64
lldbPluginObjectFilePECOFF
lldbPluginOSPython
)

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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()));

View File

@ -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;

View File

@ -10,6 +10,9 @@
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
using namespace lldb_private;
@ -25,7 +28,6 @@ ExpressionSourceCode::g_expression_prefix = R"(
#define nil (__null)
#define YES ((BOOL)1)
#define NO ((BOOL)0)
typedef signed char BOOL;
typedef signed __INT8_TYPE__ int8_t;
typedef unsigned __INT8_TYPE__ uint8_t;
typedef signed __INT16_TYPE__ int16_t;
@ -42,8 +44,29 @@ typedef unsigned short unichar;
)";
bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method) const
bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const
{
const char *target_specific_defines = "typedef signed char BOOL;\n";
static ConstString g_platform_ios_simulator ("PlatformiOSSimulator");
if (Target *target = exe_ctx.GetTargetPtr())
{
if (target->GetArchitecture().GetMachine() == llvm::Triple::arm64)
{
target_specific_defines = "typedef bool BOOL;\n";
}
if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
{
if (lldb::PlatformSP platform_sp = target->GetPlatform())
{
if (platform_sp->GetPluginName() == g_platform_ios_simulator)
{
target_specific_defines = "typedef bool BOOL;\n";
}
}
}
}
if (m_wrap)
{
switch (wrapping_language)
@ -64,6 +87,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
break;
case lldb::eLanguageTypeC:
wrap_stream.Printf("%s \n"
"%s \n"
"%s \n"
"void \n"
"%s(void *$__lldb_arg) \n"
@ -71,12 +95,14 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
" %s; \n"
"} \n",
g_expression_prefix,
target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_body.c_str());
break;
case lldb::eLanguageTypeC_plus_plus:
wrap_stream.Printf("%s \n"
"%s \n"
"%s \n"
"void \n"
"$__lldb_class::%s(void *$__lldb_arg) %s\n"
@ -84,6 +110,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
" %s; \n"
"} \n",
g_expression_prefix,
target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
(const_object ? "const" : ""),
@ -93,6 +120,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
if (static_method)
{
wrap_stream.Printf("%s \n"
"%s \n"
"%s \n"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"+(void)%s:(void *)$__lldb_arg; \n"
@ -104,6 +132,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
"} \n"
"@end \n",
g_expression_prefix,
target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_name.c_str(),
@ -112,6 +141,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
else
{
wrap_stream.Printf("%s \n"
"%s \n"
"%s \n"
"@interface $__lldb_objc_class ($__lldb_category) \n"
"-(void)%s:(void *)$__lldb_arg; \n"
@ -123,6 +153,7 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi
"} \n"
"@end \n",
g_expression_prefix,
target_specific_defines,
m_prefix.c_str(),
m_name.c_str(),
m_name.c_str(),

View File

@ -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);
}

View File

@ -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");

View File

@ -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();

View File

@ -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);

View File

@ -1,3 +1,4 @@
add_subdirectory(SysV-x86_64)
add_subdirectory(MacOSX-i386)
add_subdirectory(MacOSX-arm)
add_subdirectory(MacOSX-arm64)

File diff suppressed because it is too large Load Diff

View File

@ -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_

View File

@ -0,0 +1,5 @@
set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginABIMacOSX_arm64
ABIMacOSX_arm64.cpp
)

View File

@ -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

View File

@ -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();

View File

@ -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);
}

View File

@ -0,0 +1,5 @@
set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginInstructionARM64
EmulateInstructionARM64.cpp
)

View File

@ -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;
}

View File

@ -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_

View File

@ -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

View File

@ -1 +1,2 @@
add_subdirectory(ARM)
add_subdirectory(ARM64)

View File

@ -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 \

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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_

View File

@ -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;

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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_

View File

@ -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))
{

View File

@ -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;
}

View File

@ -27,6 +27,7 @@
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Target.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@ -57,6 +58,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_vCont_S (eLazyBoolCalculate),
m_qHostInfo_is_valid (eLazyBoolCalculate),
m_qProcessInfo_is_valid (eLazyBoolCalculate),
m_qGDBServerVersion_is_valid (eLazyBoolCalculate),
m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
m_supports_memory_region_info (eLazyBoolCalculate),
m_supports_watchpoint_support_info (eLazyBoolCalculate),
@ -65,6 +67,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_attach_or_wait_reply(eLazyBoolCalculate),
m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
m_supports_p (eLazyBoolCalculate),
m_avoid_g_packets (eLazyBoolCalculate),
m_supports_QSaveRegisterState (eLazyBoolCalculate),
m_supports_qXfer_auxv_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_read (eLazyBoolCalculate),
@ -100,6 +103,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_os_build (),
m_os_kernel (),
m_hostname (),
m_gdb_server_name(),
m_gdb_server_version(UINT32_MAX),
m_default_packet_timeout (0),
m_max_packet_size (0)
{
@ -301,10 +306,12 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_QSaveRegisterState = eLazyBoolCalculate;
m_qHostInfo_is_valid = eLazyBoolCalculate;
m_qProcessInfo_is_valid = eLazyBoolCalculate;
m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
m_supports_memory_region_info = eLazyBoolCalculate;
m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
m_attach_or_wait_reply = eLazyBoolCalculate;
m_avoid_g_packets = eLazyBoolCalculate;
m_supports_qXfer_auxv_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
@ -322,8 +329,18 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_z4 = true;
m_supports_QEnvironment = true;
m_supports_QEnvironmentHexEncoded = true;
m_host_arch.Clear();
m_process_arch.Clear();
m_os_version_major = UINT32_MAX;
m_os_version_minor = UINT32_MAX;
m_os_version_update = UINT32_MAX;
m_os_build.clear();
m_os_kernel.clear();
m_hostname.clear();
m_gdb_server_name.clear();
m_gdb_server_version = UINT32_MAX;
m_default_packet_timeout = 0;
m_max_packet_size = 0;
}
@ -1314,6 +1331,41 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)
return -1;
}
int
GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported)
{
if (data && *data != '\0')
{
StreamString packet;
packet.Printf("QSetProcessEvent:%s", data);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
{
if (response.IsOKResponse())
{
if (was_supported)
*was_supported = true;
return 0;
}
else if (response.IsUnsupportedResponse())
{
if (was_supported)
*was_supported = false;
return -1;
}
else
{
uint8_t error = response.GetError();
if (was_supported)
*was_supported = true;
if (error)
return error;
}
}
}
return -1;
}
bool
GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,
uint32_t &minor,
@ -1394,6 +1446,69 @@ GDBRemoteCommunicationClient::GetProcessArchitecture ()
return m_process_arch;
}
bool
GDBRemoteCommunicationClient::GetGDBServerVersion()
{
if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate)
{
m_gdb_server_name.clear();
m_gdb_server_version = 0;
m_qGDBServerVersion_is_valid = eLazyBoolNo;
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success)
{
if (response.IsNormalResponse())
{
std::string name;
std::string value;
bool success = false;
while (response.GetNameColonValue(name, value))
{
if (name.compare("name") == 0)
{
success = true;
m_gdb_server_name.swap(value);
}
else if (name.compare("version") == 0)
{
size_t dot_pos = value.find('.');
if (dot_pos != std::string::npos)
value[dot_pos] = '\0';
const uint32_t version = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0);
if (version != UINT32_MAX)
{
success = true;
m_gdb_server_version = version;
}
}
}
if (success)
m_qGDBServerVersion_is_valid = eLazyBoolYes;
}
}
}
return m_qGDBServerVersion_is_valid == eLazyBoolYes;
}
const char *
GDBRemoteCommunicationClient::GetGDBServerProgramName()
{
if (GetGDBServerVersion())
{
if (!m_gdb_server_name.empty())
return m_gdb_server_name.c_str();
}
return NULL;
}
uint32_t
GDBRemoteCommunicationClient::GetGDBServerProgramVersion()
{
if (GetGDBServerVersion())
return m_gdb_server_version;
return 0;
}
bool
GDBRemoteCommunicationClient::GetHostInfo (bool force)
@ -1558,6 +1673,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
switch (m_host_arch.GetMachine())
{
case llvm::Triple::arm64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
os_name = "ios";
@ -1598,6 +1714,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force)
{
switch (m_host_arch.GetMachine())
{
case llvm::Triple::arm64:
case llvm::Triple::arm:
case llvm::Triple::thumb:
host_triple.setOS(llvm::Triple::IOS);
@ -3228,6 +3345,38 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s
return false;
}
bool
GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process)
{
// Some targets have issues with g/G packets and we need to avoid using them
if (m_avoid_g_packets == eLazyBoolCalculate)
{
if (process)
{
m_avoid_g_packets = eLazyBoolNo;
const ArchSpec &arch = process->GetTarget().GetArchitecture();
if (arch.IsValid()
&& arch.GetTriple().getVendor() == llvm::Triple::Apple
&& arch.GetTriple().getOS() == llvm::Triple::IOS
&& arch.GetTriple().getArch() == llvm::Triple::arm64)
{
m_avoid_g_packets = eLazyBoolYes;
uint32_t gdb_server_version = GetGDBServerProgramVersion();
if (gdb_server_version != 0)
{
const char *gdb_server_name = GetGDBServerProgramName();
if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0)
{
if (gdb_server_version >= 310)
m_avoid_g_packets = eLazyBoolNo;
}
}
}
}
}
return m_avoid_g_packets == eLazyBoolYes;
}
bool
GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
{

View File

@ -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

View File

@ -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))

View File

@ -21,6 +21,7 @@
#include "lldb/Interpreter/PythonDataObjects.h"
#endif
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Utils.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@ -502,6 +503,8 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
StringExtractorGDBRemote response;
const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
{
@ -519,29 +522,62 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
packet_len = ::snprintf (packet, sizeof(packet), "g");
assert (packet_len < ((int)sizeof(packet) - 1));
if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
{
if (response.IsErrorResponse())
return false;
std::string &response_str = response.GetStringRef();
if (isxdigit(response_str[0]))
int packet_len = 0;
if (thread_suffix_supported)
packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
else
packet_len = ::snprintf (packet, sizeof(packet), "g");
assert (packet_len < ((int)sizeof(packet) - 1));
if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
{
response_str.insert(0, 1, 'G');
if (thread_suffix_supported)
if (response.IsErrorResponse())
return false;
std::string &response_str = response.GetStringRef();
if (isxdigit(response_str[0]))
{
char thread_id_cstr[64];
::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
response_str.append (thread_id_cstr);
response_str.insert(0, 1, 'G');
if (thread_suffix_supported)
{
char thread_id_cstr[64];
::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
response_str.append (thread_id_cstr);
}
data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
return true;
}
data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
return true;
}
}
else
{
// For the use_g_packet == false case, we're going to read each register
// individually and store them as binary data in a buffer instead of as ascii
// characters.
const RegisterInfo *reg_info;
// data_sp will take ownership of this DataBufferHeap pointer soon.
DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
{
if (reg_info->value_regs) // skip registers that are slices of real registers
continue;
ReadRegisterBytes (reg_info, m_reg_data);
// ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer
}
memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize());
data_sp = reg_ctx;
return true;
}
}
}
else
{
Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
if (log)
{
@ -575,6 +611,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
StringExtractorGDBRemote response;
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
@ -588,63 +626,126 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
// as well.
const char *G_packet = (const char *)data_sp->GetBytes();
size_t G_packet_len = data_sp->GetByteSize();
if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
G_packet_len,
response,
false) == GDBRemoteCommunication::PacketResult::Success)
if (use_g_packet
&& gdb_comm.SendPacketAndWaitForResponse (G_packet,
G_packet_len,
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
if (response.IsOKResponse())
return true;
else if (response.IsErrorResponse())
// The data_sp contains the entire G response packet including the
// G, and if the thread suffix is supported, it has the thread suffix
// as well.
const char *G_packet = (const char *)data_sp->GetBytes();
size_t G_packet_len = data_sp->GetByteSize();
if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
G_packet_len,
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
uint32_t num_restored = 0;
// We need to manually go through all of the registers and
// restore them manually
response.GetStringRef().assign (G_packet, G_packet_len);
response.SetFilePos(1); // Skip the leading 'G'
DataBufferHeap buffer (m_reg_data.GetByteSize(), 0);
DataExtractor restore_data (buffer.GetBytes(),
buffer.GetByteSize(),
m_reg_data.GetByteOrder(),
m_reg_data.GetAddressByteSize());
const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
restore_data.GetByteSize(),
'\xcc');
if (bytes_extracted < restore_data.GetByteSize())
restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
//ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data)
const RegisterInfo *reg_info;
// We have to march the offset of each register along in the
// buffer to make sure we get the right offset.
uint32_t reg_byte_offset = 0;
for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size)
if (response.IsOKResponse())
return true;
else if (response.IsErrorResponse())
{
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
uint32_t num_restored = 0;
// We need to manually go through all of the registers and
// restore them manually
response.GetStringRef().assign (G_packet, G_packet_len);
response.SetFilePos(1); // Skip the leading 'G'
// Skip composite registers.
if (reg_info->value_regs)
continue;
// G_packet_len is hex-ascii characters plus prefix 'G' plus suffix therad specifier.
// This means buffer will be a little more than 2x larger than necessary but we resize
// it down once we've extracted all hex ascii chars from the packet.
DataBufferHeap buffer (G_packet_len, 0);
DataExtractor restore_data (buffer.GetBytes(),
buffer.GetByteSize(),
m_reg_data.GetByteOrder(),
m_reg_data.GetAddressByteSize());
const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
restore_data.GetByteSize(),
'\xcc');
if (bytes_extracted < restore_data.GetByteSize())
restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
const RegisterInfo *reg_info;
// Only write down the registers that need to be written
// if we are going to be doing registers individually.
bool write_reg = true;
const uint32_t reg_byte_size = reg_info->byte_size;
// The g packet contents may either include the slice registers (registers defined in
// terms of other registers, e.g. eax is a subset of rax) or not. The slice registers
// should NOT be in the g packet, but some implementations may incorrectly include them.
//
// If the slice registers are included in the packet, we must step over the slice registers
// when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect.
// If the slice registers are not included, then using the byte_offset values into the
// data buffer is the best way to find individual register values.
const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
if (restore_src)
int size_including_slice_registers = 0;
int size_not_including_slice_registers = 0;
int size_by_highest_offset = 0;
for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx)
{
if (GetRegisterIsValid(reg))
size_including_slice_registers += reg_info->byte_size;
if (reg_info->value_regs == NULL)
size_not_including_slice_registers += reg_info->byte_size;
if (reg_info->byte_offset >= size_by_highest_offset)
size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size;
}
bool use_byte_offset_into_buffer;
if (size_by_highest_offset == restore_data.GetByteSize())
{
// The size of the packet agrees with the highest offset: + size in the register file
use_byte_offset_into_buffer = true;
}
else if (size_not_including_slice_registers == restore_data.GetByteSize())
{
// The size of the packet is the same as concenating all of the registers sequentially,
// skipping the slice registers
use_byte_offset_into_buffer = true;
}
else if (size_including_slice_registers == restore_data.GetByteSize())
{
// The slice registers are present in the packet (when they shouldn't be).
// Don't try to use the RegisterInfo byte_offset into the restore_data, it will
// point to the wrong place.
use_byte_offset_into_buffer = false;
}
else {
// None of our expected sizes match the actual g packet data we're looking at.
// The most conservative approach here is to use the running total byte offset.
use_byte_offset_into_buffer = false;
}
// In case our register definitions don't include the correct offsets,
// keep track of the size of each reg & compute offset based on that.
uint32_t running_byte_offset = 0;
for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size)
{
// Skip composite aka slice registers (e.g. eax is a slice of rax).
if (reg_info->value_regs)
continue;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
uint32_t register_offset;
if (use_byte_offset_into_buffer)
{
const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size);
if (current_src)
write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
register_offset = reg_info->byte_offset;
}
else
{
register_offset = running_byte_offset;
}
if (write_reg)
// Only write down the registers that need to be written
// if we are going to be doing registers individually.
bool write_reg = true;
const uint32_t reg_byte_size = reg_info->byte_size;
const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size);
if (restore_src)
{
StreamString packet;
packet.Printf ("P%x=", reg);
@ -662,15 +763,89 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
if (response.IsOKResponse())
++num_restored;
const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size);
if (current_src)
write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
}
if (write_reg)
{
StreamString packet;
packet.Printf ("P%x=", reg);
packet.PutBytesAsRawHex8 (restore_src,
reg_byte_size,
lldb::endian::InlHostByteOrder(),
lldb::endian::InlHostByteOrder());
if (thread_suffix_supported)
packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
SetRegisterIsValid(reg, false);
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
if (response.IsOKResponse())
++num_restored;
}
}
}
}
return num_restored > 0;
}
return num_restored > 0;
}
}
else
{
// For the use_g_packet == false case, we're going to write each register
// individually. The data buffer is binary data in this case, instead of
// ascii characters.
bool arm64_debugserver = false;
if (m_thread.GetProcess().get())
{
const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
if (arch.IsValid()
&& arch.GetMachine() == llvm::Triple::arm64
&& arch.GetTriple().getVendor() == llvm::Triple::Apple
&& arch.GetTriple().getOS() == llvm::Triple::IOS)
{
arm64_debugserver = true;
}
}
uint32_t num_restored = 0;
const RegisterInfo *reg_info;
for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
{
if (reg_info->value_regs) // skip registers that are slices of real registers
continue;
// Skip the fpsr and fpcr floating point status/control register writing to
// work around a bug in an older version of debugserver that would lead to
// register context corruption when writing fpsr/fpcr.
if (arm64_debugserver &&
(strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0))
{
continue;
}
StreamString packet;
packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]);
packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
if (thread_suffix_supported)
packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
SetRegisterIsValid(reg_info, false);
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false) == GDBRemoteCommunication::PacketResult::Success)
{
if (response.IsOKResponse())
++num_restored;
}
}
return num_restored > 0;
}
}
}
else

View File

@ -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:

View File

@ -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;

View File

@ -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
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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();

View File

@ -10,7 +10,7 @@
#import <Foundation/Foundation.h>
#if defined(__APPLE__)
#if defined(__arm__)
#if defined(__arm__) || defined(__arm64__)
#define IOS
#endif
#endif

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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"

View File

@ -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 ||\

View File

@ -47,6 +47,16 @@ DNBError::AsString() const
m_str.clear();
}
break;
#endif
#ifdef WITH_BKS
case BackBoard:
{
// You have to call ObjC routines to get the error string from BackBoardServices.
// Not sure I want to make DNBError.cpp an .mm file. For now just make sure you
// pre-populate the error string when you make the DNBError of type BackBoard.
m_str.assign("Should have set Backboard error when making the error string.");
}
break;
#endif
default:
break;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
const char *stdout_err = "/dev/null";
CFString stdio_path;
stdio_path.SetFileSystemRepresentation (stdout_err);
DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", bundleIDStr.c_str(), stdout_err, stdout_err);
sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
(CFURLRef)NULL, // openURL
NULL, // launch_argv.get(),
NULL, // launch_envp.get(), // CFDictionaryRef environment
stdio_path.get(),
stdio_path.get(),
SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger);
if (sbs_error != SBSApplicationLaunchErrorSuccess)
#if defined (WITH_BKS)
if (launch_flavor == eLaunchFlavorBKS)
{
err_str.SetError(sbs_error, DNBError::SpringBoard);
return NULL;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *stdio_path = nil;
NSFileManager *file_manager = [NSFileManager defaultManager];
const char *null_path = "/dev/null";
stdio_path = [file_manager stringWithFileSystemRepresentation: null_path length: strlen(null_path)];
NSMutableDictionary *debug_options = [NSMutableDictionary dictionary];
NSMutableDictionary *options = [NSMutableDictionary dictionary];
DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: @\"%s\",options include stdio path: \"%s\", "
"BKSDebugOptionKeyDebugOnNextLaunch & BKSDebugOptionKeyWaitForDebugger )",
bundleIDStr.c_str(),
null_path);
[debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardOutPath];
[debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardErrorPath];
[debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyWaitForDebugger];
[debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyDebugOnNextLaunch];
[options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions];
BKSSystemService *system_service = [[BKSSystemService alloc] init];
mach_port_t client_port = [system_service createClientPort];
__block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block BKSOpenApplicationErrorCode attach_error_code = BKSOpenApplicationErrorCodeNone;
NSString *bundleIDNSStr = (NSString *) bundleIDCFStr;
[system_service openApplication: bundleIDNSStr
options: options
clientPort: client_port
withResult: ^(NSError *error)
{
// The system service will cleanup the client port we created for us.
if (error)
attach_error_code = (BKSOpenApplicationErrorCode)[error code];
[system_service release];
dispatch_semaphore_signal(semaphore);
}
];
const uint32_t timeout_secs = 9;
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC);
long success = dispatch_semaphore_wait(semaphore, timeout) == 0;
if (!success)
{
DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str());
attach_err.SetErrorString("debugserver timed out waiting for openApplication to complete.");
attach_err.SetError (BKS_OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic);
}
else if (attach_error_code != BKSOpenApplicationErrorCodeNone)
{
SetBKSError (attach_error_code, attach_err);
DNBLogError("unable to launch the application with CFBundleIdentifier '%s' bks_error = %u",
bundleIDStr.c_str(),
attach_error_code);
}
dispatch_release(semaphore);
[pool drain];
}
#elif defined (WITH_SPRINGBOARD)
if (launch_flavor == eLaunchFlavorSpringBoard)
{
SBSApplicationLaunchError sbs_error = 0;
const char *stdout_err = "/dev/null";
CFString stdio_path;
stdio_path.SetFileSystemRepresentation (stdout_err);
DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", "
"SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )",
bundleIDStr.c_str(),
stdout_err,
stdout_err);
sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr,
(CFURLRef)NULL, // openURL
NULL, // launch_argv.get(),
NULL, // launch_envp.get(), // CFDictionaryRef environment
stdio_path.get(),
stdio_path.get(),
SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger);
if (sbs_error != SBSApplicationLaunchErrorSuccess)
{
attach_err.SetError(sbs_error, DNBError::SpringBoard);
return NULL;
}
}
#endif // WITH_SPRINGBOARD
DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch.");
return bundleIDCFStr;
# else
# else // defined (WITH_SPRINGBOARD) || defined (WITH_BKS)
return NULL;
#endif
}
@ -1593,7 +1736,16 @@ MachProcess::CheckForProcess (const void *attach_token)
if (attach_token == NULL)
return INVALID_NUB_PROCESS;
#ifdef WITH_SPRINGBOARD
#if defined (WITH_BKS)
NSString *bundleIDNSStr = (NSString *) attach_token;
BKSSystemService *systemService = [[BKSSystemService alloc] init];
pid_t pid = [systemService pidForApplication: bundleIDNSStr];
[systemService release];
if (pid == 0)
return INVALID_NUB_PROCESS;
else
return pid;
#elif defined (WITH_SPRINGBOARD)
CFStringRef bundleIDCFStr = (CFStringRef) attach_token;
Boolean got_it;
nub_process_t attach_pid;
@ -1602,8 +1754,9 @@ MachProcess::CheckForProcess (const void *attach_token)
return attach_pid;
else
return INVALID_NUB_PROCESS;
#endif
#else
return INVALID_NUB_PROCESS;
#endif
}
// Call this to clean up after you have either attached or given up on the attach.
@ -1614,10 +1767,18 @@ MachProcess::CheckForProcess (const void *attach_token)
void
MachProcess::CleanupAfterAttach (const void *attach_token, bool success, DNBError &err_str)
{
#ifdef WITH_SPRINGBOARD
if (attach_token == NULL)
return;
#if defined (WITH_BKS)
if (!success)
{
BKSCleanupAfterAttach (attach_token, err_str);
}
CFRelease((CFStringRef) attach_token);
#elif defined (WITH_SPRINGBOARD)
// Tell SpringBoard to cancel the debug on next launch of this application
// if we failed to attach
if (!success)
@ -1657,6 +1818,7 @@ MachProcess::LaunchForDebug
bool no_stdio,
nub_launch_flavor_t launch_flavor,
int disable_aslr,
const char *event_data,
DNBError &launch_err
)
{
@ -1673,7 +1835,23 @@ MachProcess::LaunchForDebug
case eLaunchFlavorForkExec:
m_pid = MachProcess::ForkChildForPTraceDebugging (path, argv, envp, this, launch_err);
break;
#ifdef WITH_BKS
case eLaunchFlavorBKS:
{
const char *app_ext = strstr(path, ".app");
if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/'))
{
std::string app_bundle_path(path, app_ext + strlen(".app"));
if (BKSLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0)
return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid.
else
break; // We tried a BKS launch, but didn't succeed lets get out
}
}
// In case the executable name has a ".app" fragment which confuses our debugserver,
// let's do an intentional fallthrough here...
launch_flavor = eLaunchFlavorPosixSpawn;
#endif
#ifdef WITH_SPRINGBOARD
case eLaunchFlavorSpringBoard:
@ -1696,7 +1874,7 @@ MachProcess::LaunchForDebug
if (app_ext)
{
std::string app_bundle_path(path, app_ext + strlen(".app"));
if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, launch_err) != 0)
if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, launch_err) != 0)
return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid.
else
break; // We tried a springboard launch, but didn't succeed lets get out
@ -2063,10 +2241,47 @@ MachProcess::ForkChildForPTraceDebugging
return pid;
}
#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS)
// This returns a CFRetained pointer to the Bundle ID for app_bundle_path,
// or NULL if there was some problem getting the bundle id.
static CFStringRef
CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str)
{
CFBundle bundle(app_bundle_path);
CFStringRef bundleIDCFStr = bundle.GetIdentifier();
std::string bundleID;
if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL)
{
struct stat app_bundle_stat;
char err_msg[PATH_MAX];
if (::stat (app_bundle_path, &app_bundle_stat) < 0)
{
err_str.SetError(errno, DNBError::POSIX);
snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path);
err_str.SetErrorString(err_msg);
DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg);
}
else
{
err_str.SetError(-1, DNBError::Generic);
snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path);
err_str.SetErrorString(err_msg);
DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path);
}
return NULL;
}
DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str());
CFRetain (bundleIDCFStr);
return bundleIDCFStr;
}
#endif // #if defined 9WITH_SPRINGBOARD) || defined (WITH_BKS)
#ifdef WITH_SPRINGBOARD
pid_t
MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, DNBError &launch_err)
MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, DNBError &launch_err)
{
// Clear out and clean up from any current state
Clear();
@ -2115,42 +2330,6 @@ MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const
#include <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

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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()
nub_addr_t
DNBArchMachARM::GetWatchpointAddressByIndex (uint32_t hw_index)
{
uint32_t register_DBGDSCR;
asm("mrc p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR));
if (bits(register_DBGDSCR, 5, 2) == WATCHPOINT_OCCURRED)
{
uint32_t mask = ~(0xF << 2);
register_DBGDSCR &= mask;
asm("mcr p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR));
}
return;
}
// NotifyException() calls this to double check that a watchpoint has occurred
// by inspecting the bits[5:2] field of the Debug Status and Control Register
// (DSCR).
//
// b0010 = a watchpoint occurred
bool
DNBArchMachARM::HasWatchpointOccurred()
{
uint32_t register_DBGDSCR;
asm("mrc p14, 0, %0, c0, c1, 0" : "=r" (register_DBGDSCR));
return (bits(register_DBGDSCR, 5, 2) == WATCHPOINT_OCCURRED);
kern_return_t kret = GetDBGState(true);
if (kret != KERN_SUCCESS)
return INVALID_NUB_ADDRESS;
const uint32_t num = NumSupportedHardwareWatchpoints();
if (hw_index >= num)
return INVALID_NUB_ADDRESS;
if (IsWatchpointEnabled (m_state.dbg, hw_index))
return GetWatchAddress (m_state.dbg, hw_index);
return INVALID_NUB_ADDRESS;
}
bool

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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__

View File

@ -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();

View File

@ -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"

View File

@ -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());

View File

@ -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);

View File

@ -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
}

View File

@ -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__

View File

@ -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>

View File

@ -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)
{