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:
parent
61e595be4d
commit
a332978b2a
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -374,6 +374,12 @@ namespace lldb_private {
|
|||
uint32_t
|
||||
GetByteSize () const;
|
||||
|
||||
static uint32_t
|
||||
GetMaxByteSize ()
|
||||
{
|
||||
return kMaxRegisterByteSize;
|
||||
}
|
||||
|
||||
void
|
||||
Clear();
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -94,6 +94,13 @@ public:
|
|||
|
||||
bool
|
||||
AddSuppressFileAction (int fd, bool read, bool write);
|
||||
|
||||
void
|
||||
SetLaunchEventData (const char *data);
|
||||
|
||||
const char *
|
||||
GetLaunchEventData () const;
|
||||
|
||||
};
|
||||
|
||||
class SBAttachInfo
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -74,9 +74,11 @@ set( LLDB_USED_LIBS
|
|||
lldbPluginAppleObjCRuntime
|
||||
lldbPluginCXXItaniumABI
|
||||
lldbPluginABIMacOSX_arm
|
||||
lldbPluginABIMacOSX_arm64
|
||||
lldbPluginABIMacOSX_i386
|
||||
lldbPluginABISysV_x86_64
|
||||
lldbPluginInstructionARM
|
||||
lldbPluginInstructionARM64
|
||||
lldbPluginObjectFilePECOFF
|
||||
lldbPluginOSPython
|
||||
)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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_
|
|
@ -0,0 +1,5 @@
|
|||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
add_lldb_library(lldbPluginABIMacOSX_arm64
|
||||
ABIMacOSX_arm64.cpp
|
||||
)
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
add_lldb_library(lldbPluginInstructionARM64
|
||||
EmulateInstructionARM64.cpp
|
||||
)
|
|
@ -0,0 +1,722 @@
|
|||
//===-- EmulateInstructionARM64.cpp -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "EmulateInstructionARM64.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Symbol/UnwindPlan.h"
|
||||
|
||||
#include "Plugins/Process/Utility/ARMDefines.h"
|
||||
#include "Plugins/Process/Utility/ARMUtils.h"
|
||||
#include "Utility/ARM64_DWARF_Registers.h"
|
||||
|
||||
#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
|
||||
// and CountTrailingZeros_32 function
|
||||
|
||||
#include "Plugins/Process/Utility/InstructionUtils.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
#define No_VFP 0
|
||||
#define VFPv1 (1u << 1)
|
||||
#define VFPv2 (1u << 2)
|
||||
#define VFPv3 (1u << 3)
|
||||
#define AdvancedSIMD (1u << 4)
|
||||
|
||||
#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
|
||||
#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
|
||||
#define VFPv2v3 (VFPv2 | VFPv3)
|
||||
|
||||
#define UInt(x) ((uint64_t)x)
|
||||
#define SInt(x) ((int64_t)x)
|
||||
#define bit bool
|
||||
#define boolean bool
|
||||
#define integer int64_t
|
||||
|
||||
static inline bool
|
||||
IsZero(uint64_t x)
|
||||
{
|
||||
return x == 0;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
NOT(uint64_t x)
|
||||
{
|
||||
return ~x;
|
||||
}
|
||||
|
||||
|
||||
static inline int64_t
|
||||
SignExtend64(uint64_t x, uint32_t msbit)
|
||||
{
|
||||
return int64_t(x << (64 - msbit)) >> (64 - msbit);
|
||||
}
|
||||
|
||||
|
||||
// LSL_C()
|
||||
// =======
|
||||
static inline uint64_t
|
||||
LSL_C (uint64_t x, integer shift, bool &carry_out)
|
||||
{
|
||||
assert (shift >= 0);
|
||||
uint64_t result = x << shift;
|
||||
carry_out = ((1ull << (64-1)) >> (shift - 1)) != 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
// LSL()
|
||||
// =====
|
||||
|
||||
static inline uint64_t
|
||||
LSL(uint64_t x, integer shift)
|
||||
{
|
||||
if (shift == 0)
|
||||
return x;
|
||||
return x << shift;
|
||||
}
|
||||
|
||||
// AddWithCarry()
|
||||
// ===============
|
||||
static inline uint64_t
|
||||
AddWithCarry (uint32_t N, uint64_t x, uint64_t y, bit carry_in, EmulateInstructionARM64::ProcState &proc_state)
|
||||
{
|
||||
uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
|
||||
int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in);
|
||||
uint64_t result = unsigned_sum;
|
||||
if (N < 64)
|
||||
result = Bits64 (result, N-1, 0);
|
||||
proc_state.N = Bit64(result, N-1);
|
||||
proc_state.Z = IsZero(result);
|
||||
proc_state.C = UInt(result) == unsigned_sum;
|
||||
proc_state.V = SInt(result) == signed_sum;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ConstrainUnpredictable()
|
||||
// ========================
|
||||
|
||||
EmulateInstructionARM64::ConstraintType
|
||||
ConstrainUnpredictable (EmulateInstructionARM64::Unpredictable which)
|
||||
{
|
||||
EmulateInstructionARM64::ConstraintType result = EmulateInstructionARM64::Constraint_UNKNOWN;
|
||||
switch (which)
|
||||
{
|
||||
case EmulateInstructionARM64::Unpredictable_WBOVERLAP:
|
||||
case EmulateInstructionARM64::Unpredictable_LDPOVERLAP:
|
||||
// TODO: don't know what to really do here? Pseudo code says:
|
||||
// set result to one of above Constraint behaviours or UNDEFINED
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// EmulateInstructionARM implementation
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
EmulateInstructionARM64::Initialize ()
|
||||
{
|
||||
PluginManager::RegisterPlugin (GetPluginNameStatic (),
|
||||
GetPluginDescriptionStatic (),
|
||||
CreateInstance);
|
||||
}
|
||||
|
||||
void
|
||||
EmulateInstructionARM64::Terminate ()
|
||||
{
|
||||
PluginManager::UnregisterPlugin (CreateInstance);
|
||||
}
|
||||
|
||||
ConstString
|
||||
EmulateInstructionARM64::GetPluginNameStatic ()
|
||||
{
|
||||
ConstString g_plugin_name ("lldb.emulate-instruction.arm64");
|
||||
return g_plugin_name;
|
||||
}
|
||||
|
||||
lldb_private::ConstString
|
||||
EmulateInstructionARM64::GetPluginName()
|
||||
{
|
||||
static ConstString g_plugin_name ("EmulateInstructionARM64");
|
||||
return g_plugin_name;
|
||||
}
|
||||
|
||||
const char *
|
||||
EmulateInstructionARM64::GetPluginDescriptionStatic ()
|
||||
{
|
||||
return "Emulate instructions for the ARM64 architecture.";
|
||||
}
|
||||
|
||||
EmulateInstruction *
|
||||
EmulateInstructionARM64::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
|
||||
{
|
||||
if (EmulateInstructionARM64::SupportsEmulatingInstructionsOfTypeStatic(inst_type))
|
||||
{
|
||||
if (arch.GetTriple().getArch() == llvm::Triple::arm64)
|
||||
{
|
||||
std::auto_ptr<EmulateInstructionARM64> emulate_insn_ap (new EmulateInstructionARM64 (arch));
|
||||
if (emulate_insn_ap.get())
|
||||
return emulate_insn_ap.release();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
EmulateInstructionARM64::SetTargetTriple (const ArchSpec &arch)
|
||||
{
|
||||
if (arch.GetTriple().getArch () == llvm::Triple::arm)
|
||||
return true;
|
||||
else if (arch.GetTriple().getArch () == llvm::Triple::thumb)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EmulateInstructionARM64::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo ®_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 (®_info_Rt, data_Rt))
|
||||
return false;
|
||||
|
||||
if (data_Rt.GetAsMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0)
|
||||
return false;
|
||||
|
||||
if (!WriteMemory(context_t, address + 0, buffer, reg_info_Rt.byte_size))
|
||||
return false;
|
||||
|
||||
if (!ReadRegister (®_info_Rt2, data_Rt2))
|
||||
return false;
|
||||
|
||||
if (data_Rt2.GetAsMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0)
|
||||
return false;
|
||||
|
||||
if (!WriteMemory(context_t2, address + size, buffer, reg_info_Rt2.byte_size))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemOp_LOAD:
|
||||
{
|
||||
if (rt_unknown)
|
||||
memset (buffer, 'U', reg_info_Rt.byte_size);
|
||||
else
|
||||
{
|
||||
if (!ReadMemory (context_t, address, buffer, reg_info_Rt.byte_size))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data_Rt.SetFromMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0)
|
||||
return false;
|
||||
|
||||
if (!vector && is_signed && !data_Rt.SignExtend (datasize))
|
||||
return false;
|
||||
|
||||
if (!WriteRegister (context_t, ®_info_Rt, data_Rt))
|
||||
return false;
|
||||
|
||||
if (!rt_unknown)
|
||||
{
|
||||
if (!ReadMemory (context_t2, address + size, buffer, reg_info_Rt2.byte_size))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data_Rt2.SetFromMemoryData(®_info_Rt2, buffer, reg_info_Rt2.byte_size, eByteOrderLittle, error) == 0)
|
||||
return false;
|
||||
|
||||
if (!vector && is_signed && !data_Rt2.SignExtend (datasize))
|
||||
return false;
|
||||
|
||||
if (!WriteRegister (context_t2, ®_info_Rt2, data_Rt2))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (wback)
|
||||
{
|
||||
if (wb_unknown)
|
||||
wb_address = LLDB_INVALID_ADDRESS;
|
||||
Context context;
|
||||
context.SetImmediateSigned (idx);
|
||||
if (n == 31)
|
||||
context.type = eContextAdjustStackPointer;
|
||||
else
|
||||
context.type = eContextAdjustBaseRegister;
|
||||
WriteRegisterUnsigned (context, ®_info_base, wb_address);
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
//===-- EmulateInstructionARM64.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef EmulateInstructionARM64_h_
|
||||
#define EmulateInstructionARM64_h_
|
||||
|
||||
#include "lldb/Core/EmulateInstruction.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Interpreter/OptionValue.h"
|
||||
#include "Plugins/Process/Utility/ARMDefines.h"
|
||||
|
||||
class EmulateInstructionARM64 : public lldb_private::EmulateInstruction
|
||||
{
|
||||
public:
|
||||
static void
|
||||
Initialize ();
|
||||
|
||||
static void
|
||||
Terminate ();
|
||||
|
||||
static lldb_private::ConstString
|
||||
GetPluginNameStatic ();
|
||||
|
||||
static const char *
|
||||
GetPluginDescriptionStatic ();
|
||||
|
||||
static lldb_private::EmulateInstruction *
|
||||
CreateInstance (const lldb_private::ArchSpec &arch,
|
||||
lldb_private::InstructionType inst_type);
|
||||
|
||||
static bool
|
||||
SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type)
|
||||
{
|
||||
switch (inst_type)
|
||||
{
|
||||
case lldb_private::eInstructionTypeAny:
|
||||
case lldb_private::eInstructionTypePrologueEpilogue:
|
||||
return true;
|
||||
|
||||
case lldb_private::eInstructionTypePCModifying:
|
||||
case lldb_private::eInstructionTypeAll:
|
||||
return false;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual lldb_private::ConstString
|
||||
GetPluginName();
|
||||
|
||||
virtual lldb_private::ConstString
|
||||
GetShortPluginName()
|
||||
{
|
||||
return GetPluginNameStatic();
|
||||
}
|
||||
|
||||
virtual uint32_t
|
||||
GetPluginVersion()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool
|
||||
SetTargetTriple (const lldb_private::ArchSpec &arch);
|
||||
|
||||
EmulateInstructionARM64 (const lldb_private::ArchSpec &arch) :
|
||||
EmulateInstruction (arch),
|
||||
m_opcode_pstate (),
|
||||
m_emulated_pstate (),
|
||||
m_ignore_conditions (false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool
|
||||
SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type)
|
||||
{
|
||||
return SupportsEmulatingInstructionsOfTypeStatic (inst_type);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
ReadInstruction ();
|
||||
|
||||
virtual bool
|
||||
EvaluateInstruction (uint32_t evaluate_options);
|
||||
|
||||
virtual bool
|
||||
TestEmulation (lldb_private::Stream *out_stream,
|
||||
lldb_private::ArchSpec &arch,
|
||||
lldb_private::OptionValueDictionary *test_data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
GetRegisterInfo (uint32_t reg_kind,
|
||||
uint32_t reg_num,
|
||||
lldb_private::RegisterInfo ®_info);
|
||||
|
||||
virtual bool
|
||||
CreateFunctionEntryUnwind (lldb_private::UnwindPlan &unwind_plan);
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AddrMode_OFF,
|
||||
AddrMode_PRE,
|
||||
AddrMode_POST
|
||||
} AddrMode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BranchType_CALL,
|
||||
BranchType_ERET,
|
||||
BranchType_DRET,
|
||||
BranchType_RET,
|
||||
BranchType_JMP
|
||||
} BranchType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CountOp_CLZ,
|
||||
CountOp_CLS,
|
||||
CountOp_CNT
|
||||
} CountOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RevOp_RBIT,
|
||||
RevOp_REV16,
|
||||
RevOp_REV32,
|
||||
RevOp_REV64
|
||||
} RevOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BitwiseOp_NOT,
|
||||
BitwiseOp_RBIT
|
||||
} BitwiseOp;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EL0 = 0,
|
||||
EL1 = 1,
|
||||
EL2 = 2,
|
||||
EL3 = 3
|
||||
} ExceptionLevel;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ExtendType_SXTB,
|
||||
ExtendType_SXTH,
|
||||
ExtendType_SXTW,
|
||||
ExtendType_SXTX,
|
||||
ExtendType_UXTB,
|
||||
ExtendType_UXTH,
|
||||
ExtendType_UXTW,
|
||||
ExtendType_UXTX
|
||||
} ExtendType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ExtractType_LEFT,
|
||||
ExtractType_RIGHT
|
||||
} ExtractType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LogicalOp_AND,
|
||||
LogicalOp_EOR,
|
||||
LogicalOp_ORR
|
||||
} LogicalOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MemOp_LOAD,
|
||||
MemOp_STORE,
|
||||
MemOp_PREFETCH,
|
||||
MemOp_NOP
|
||||
} MemOp;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MoveWideOp_N,
|
||||
MoveWideOp_Z,
|
||||
MoveWideOp_K
|
||||
} MoveWideOp;
|
||||
|
||||
typedef enum {
|
||||
ShiftType_LSL,
|
||||
ShiftType_LSR,
|
||||
ShiftType_ASR,
|
||||
ShiftType_ROR
|
||||
} ShiftType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SP0 = 0,
|
||||
SPx = 1
|
||||
} StackPointerSelection;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Unpredictable_WBOVERLAP,
|
||||
Unpredictable_LDPOVERLAP
|
||||
} Unpredictable;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
Constraint_NONE,
|
||||
Constraint_UNKNOWN,
|
||||
Constraint_SUPPRESSWB,
|
||||
Constraint_NOP
|
||||
} ConstraintType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AccType_NORMAL,
|
||||
AccType_UNPRIV,
|
||||
AccType_STREAM,
|
||||
AccType_ALIGNED,
|
||||
AccType_ORDERED
|
||||
} AccType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t
|
||||
N:1,
|
||||
V:1,
|
||||
C:1,
|
||||
Z:1, // condition code flags – can also be accessed as PSTATE.[N,Z,C,V]
|
||||
Q:1, // AArch32 only – CSPR.Q bit
|
||||
IT:8, // AArch32 only – CPSR.IT bits
|
||||
J:1, // AArch32 only – CSPR.J bit
|
||||
T:1, // AArch32 only – CPSR.T bit
|
||||
SS:1, // Single step process state bit
|
||||
IL:1, // Illegal state bit
|
||||
D:1,
|
||||
A:1,
|
||||
I:1,
|
||||
F:1, // Interrupt masks – can also be accessed as PSTATE.[D,A,I,F]
|
||||
E:1, // AArch32 only – CSPR.E bit
|
||||
M:5, // AArch32 only – mode encodings
|
||||
RW:1, // Current register width – 0 is AArch64, 1 is AArch32
|
||||
EL:2, // Current exception level (see ExceptionLevel enum)
|
||||
SP:1; // AArch64 only - Stack Pointer selection (see StackPointerSelection enum)
|
||||
} ProcState;
|
||||
|
||||
protected:
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t mask;
|
||||
uint32_t value;
|
||||
uint32_t vfp_variants;
|
||||
bool (EmulateInstructionARM64::*callback) (const uint32_t opcode);
|
||||
const char *name;
|
||||
} Opcode;
|
||||
|
||||
static Opcode*
|
||||
GetOpcodeForInstruction (const uint32_t opcode);
|
||||
|
||||
bool
|
||||
Emulate_addsub_imm (const uint32_t opcode);
|
||||
|
||||
// bool
|
||||
// Emulate_STP_Q_ldstpair_off (const uint32_t opcode);
|
||||
//
|
||||
// bool
|
||||
// Emulate_STP_S_ldstpair_off (const uint32_t opcode);
|
||||
//
|
||||
// bool
|
||||
// Emulate_STP_32_ldstpair_off (const uint32_t opcode);
|
||||
//
|
||||
// bool
|
||||
// Emulate_STP_D_ldstpair_off (const uint32_t opcode);
|
||||
//
|
||||
bool
|
||||
Emulate_ldstpair_off (const uint32_t opcode);
|
||||
|
||||
bool
|
||||
Emulate_ldstpair_pre (const uint32_t opcode);
|
||||
|
||||
bool
|
||||
Emulate_ldstpair (const uint32_t opcode, AddrMode a_mode);
|
||||
|
||||
ProcState m_opcode_pstate;
|
||||
ProcState m_emulated_pstate; // This can get updated by the opcode.
|
||||
bool m_ignore_conditions;
|
||||
};
|
||||
|
||||
#endif // EmulateInstructionARM64_h_
|
|
@ -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
|
|
@ -1 +1,2 @@
|
|||
add_subdirectory(ARM)
|
||||
add_subdirectory(ARM64)
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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_
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -0,0 +1,296 @@
|
|||
//===-- RegisterContextDarwin_arm64.h -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_RegisterContextDarwin_arm64_h_
|
||||
#define liblldb_RegisterContextDarwin_arm64_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
|
||||
// Break only in privileged or user mode
|
||||
#define S_RSVD ((uint32_t)(0u << 1))
|
||||
#define S_PRIV ((uint32_t)(1u << 1))
|
||||
#define S_USER ((uint32_t)(2u << 1))
|
||||
#define S_PRIV_USER ((S_PRIV) | (S_USER))
|
||||
|
||||
#define WCR_ENABLE ((uint32_t)(1u))
|
||||
|
||||
// Watchpoint load/store
|
||||
#define WCR_LOAD ((uint32_t)(1u << 3))
|
||||
#define WCR_STORE ((uint32_t)(1u << 4))
|
||||
|
||||
class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext
|
||||
{
|
||||
public:
|
||||
|
||||
RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
|
||||
|
||||
virtual
|
||||
~RegisterContextDarwin_arm64();
|
||||
|
||||
virtual void
|
||||
InvalidateAllRegisters ();
|
||||
|
||||
virtual size_t
|
||||
GetRegisterCount ();
|
||||
|
||||
virtual const lldb_private::RegisterInfo *
|
||||
GetRegisterInfoAtIndex (size_t reg);
|
||||
|
||||
virtual size_t
|
||||
GetRegisterSetCount ();
|
||||
|
||||
virtual const lldb_private::RegisterSet *
|
||||
GetRegisterSet (size_t set);
|
||||
|
||||
virtual bool
|
||||
ReadRegister (const lldb_private::RegisterInfo *reg_info,
|
||||
lldb_private::RegisterValue ®_value);
|
||||
|
||||
virtual bool
|
||||
WriteRegister (const lldb_private::RegisterInfo *reg_info,
|
||||
const lldb_private::RegisterValue ®_value);
|
||||
|
||||
virtual bool
|
||||
ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
|
||||
|
||||
virtual bool
|
||||
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
|
||||
|
||||
virtual uint32_t
|
||||
ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
|
||||
|
||||
virtual uint32_t
|
||||
NumSupportedHardwareWatchpoints ();
|
||||
|
||||
virtual uint32_t
|
||||
SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
|
||||
|
||||
virtual bool
|
||||
ClearHardwareWatchpoint (uint32_t hw_index);
|
||||
|
||||
// mirrors <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_
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
//===-- ARM64_DWARF_Registers.c ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARM64_DWARF_Registers.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace arm64_dwarf;
|
||||
|
||||
const char *
|
||||
arm64_dwarf::GetRegisterName (unsigned reg_num, bool altnernate_name)
|
||||
{
|
||||
if (altnernate_name)
|
||||
{
|
||||
switch (reg_num)
|
||||
{
|
||||
case fp: return "x29";
|
||||
case lr: return "x30";
|
||||
case sp: return "x31";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (reg_num)
|
||||
{
|
||||
case x0: return "x0";
|
||||
case x1: return "x1";
|
||||
case x2: return "x2";
|
||||
case x3: return "x3";
|
||||
case x4: return "x4";
|
||||
case x5: return "x5";
|
||||
case x6: return "x6";
|
||||
case x7: return "x7";
|
||||
case x8: return "x8";
|
||||
case x9: return "x9";
|
||||
case x10: return "x10";
|
||||
case x11: return "x11";
|
||||
case x12: return "x12";
|
||||
case x13: return "x13";
|
||||
case x14: return "x14";
|
||||
case x15: return "x15";
|
||||
case x16: return "x16";
|
||||
case x17: return "x17";
|
||||
case x18: return "x18";
|
||||
case x19: return "x19";
|
||||
case x20: return "x20";
|
||||
case x21: return "x21";
|
||||
case x22: return "x22";
|
||||
case x23: return "x23";
|
||||
case x24: return "x24";
|
||||
case x25: return "x25";
|
||||
case x26: return "x26";
|
||||
case x27: return "x27";
|
||||
case x28: return "x28";
|
||||
case fp: return "fp";
|
||||
case lr: return "lr";
|
||||
case sp: return "sp";
|
||||
case pc: return "pc";
|
||||
case cpsr: return "cpsr";
|
||||
case v0: return "v0";
|
||||
case v1: return "v1";
|
||||
case v2: return "v2";
|
||||
case v3: return "v3";
|
||||
case v4: return "v4";
|
||||
case v5: return "v5";
|
||||
case v6: return "v6";
|
||||
case v7: return "v7";
|
||||
case v8: return "v8";
|
||||
case v9: return "v9";
|
||||
case v10: return "v10";
|
||||
case v11: return "v11";
|
||||
case v12: return "v12";
|
||||
case v13: return "v13";
|
||||
case v14: return "v14";
|
||||
case v15: return "v15";
|
||||
case v16: return "v16";
|
||||
case v17: return "v17";
|
||||
case v18: return "v18";
|
||||
case v19: return "v19";
|
||||
case v20: return "v20";
|
||||
case v21: return "v21";
|
||||
case v22: return "v22";
|
||||
case v23: return "v23";
|
||||
case v24: return "v24";
|
||||
case v25: return "v25";
|
||||
case v26: return "v26";
|
||||
case v27: return "v27";
|
||||
case v28: return "v28";
|
||||
case v29: return "v29";
|
||||
case v30: return "v30";
|
||||
case v31: return "v31";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
arm64_dwarf::GetRegisterInfo (unsigned reg_num, RegisterInfo ®_info)
|
||||
{
|
||||
::memset (®_info, 0, sizeof(RegisterInfo));
|
||||
::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
|
||||
|
||||
if (reg_num >= x0 && reg_num <= pc)
|
||||
{
|
||||
reg_info.byte_size = 8;
|
||||
reg_info.format = eFormatHex;
|
||||
reg_info.encoding = eEncodingUint;
|
||||
}
|
||||
else if (reg_num >= v0 && reg_num <= v31)
|
||||
{
|
||||
reg_info.byte_size = 16;
|
||||
reg_info.format = eFormatVectorOfFloat32;
|
||||
reg_info.encoding = eEncodingVector;
|
||||
}
|
||||
else if (reg_num == cpsr)
|
||||
{
|
||||
reg_info.byte_size = 4;
|
||||
reg_info.format = eFormatHex;
|
||||
reg_info.encoding = eEncodingUint;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
reg_info.name = arm64_dwarf::GetRegisterName (reg_num, false);
|
||||
reg_info.alt_name = arm64_dwarf::GetRegisterName (reg_num, true);
|
||||
reg_info.kinds[eRegisterKindDWARF] = reg_num;
|
||||
|
||||
switch (reg_num)
|
||||
{
|
||||
case fp: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break;
|
||||
case lr: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break;
|
||||
case sp: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break;
|
||||
case pc: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break;
|
||||
default: break;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
//===-- ARM64_DWARF_Registers.h ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef utility_ARM64_DWARF_Registers_h_
|
||||
#define utility_ARM64_DWARF_Registers_h_
|
||||
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
namespace arm64_dwarf {
|
||||
|
||||
enum
|
||||
{
|
||||
x0 = 0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
x4,
|
||||
x5,
|
||||
x6,
|
||||
x7,
|
||||
x8,
|
||||
x9,
|
||||
x10,
|
||||
x11,
|
||||
x12,
|
||||
x13,
|
||||
x14,
|
||||
x15,
|
||||
x16,
|
||||
x17,
|
||||
x18,
|
||||
x19,
|
||||
x20,
|
||||
x21,
|
||||
x22,
|
||||
x23,
|
||||
x24,
|
||||
x25,
|
||||
x26,
|
||||
x27,
|
||||
x28,
|
||||
x29 = 29, fp = x29,
|
||||
x30 = 30, lr = x30,
|
||||
x31 = 31, sp = x31,
|
||||
pc = 32,
|
||||
cpsr = 33,
|
||||
// 34-63 reserved
|
||||
|
||||
// V0-V31 (128 bit vector registers)
|
||||
v0 = 64,
|
||||
v1,
|
||||
v2,
|
||||
v3,
|
||||
v4,
|
||||
v5,
|
||||
v6,
|
||||
v7,
|
||||
v8,
|
||||
v9,
|
||||
v10,
|
||||
v11,
|
||||
v12,
|
||||
v13,
|
||||
v14,
|
||||
v15,
|
||||
v16,
|
||||
v17,
|
||||
v18,
|
||||
v19,
|
||||
v20,
|
||||
v21,
|
||||
v22,
|
||||
v23,
|
||||
v24,
|
||||
v25,
|
||||
v26,
|
||||
v27,
|
||||
v28,
|
||||
v29,
|
||||
v30,
|
||||
v31
|
||||
|
||||
// 96-127 reserved
|
||||
};
|
||||
|
||||
const char *
|
||||
GetRegisterName (unsigned reg_num, bool altnernate_name);
|
||||
|
||||
bool
|
||||
GetRegisterInfo (unsigned reg_num,
|
||||
lldb_private::RegisterInfo ®_info);
|
||||
|
||||
} // namespace arm64_dwarf
|
||||
|
||||
#endif // utility_ARM64_DWARF_Registers_h_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__arm__)
|
||||
#if defined(__arm__) || defined(__arm64__)
|
||||
#define IOS
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(®_event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT|NOTE_EXIT_DETAIL, 0, NULL);
|
||||
// Register the event:
|
||||
int result = kevent (kq_id, ®_event, 1, NULL, 0, NULL);
|
||||
if (result != 0)
|
||||
{
|
||||
DNBLogError ("Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, result);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = ::pthread_create (&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id);
|
||||
|
||||
// pthread_create returns 0 if successful
|
||||
if (ret == 0)
|
||||
{
|
||||
::pthread_detach (thread);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // #if USE_KQUEUE
|
||||
|
||||
static void *
|
||||
waitpid_thread (void *arg)
|
||||
|
@ -161,10 +260,15 @@ waitpid_thread (void *arg)
|
|||
DNBProcessSetExitStatus (pid, -1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
spawn_waitpid_thread (pid_t pid)
|
||||
{
|
||||
#ifdef USE_KQUEUE
|
||||
bool success = spawn_kqueue_thread (pid);
|
||||
if (success)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
pthread_t thread;
|
||||
int ret = ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid);
|
||||
// pthread_create returns 0 if successful
|
||||
|
@ -187,6 +291,7 @@ DNBProcessLaunch (const char *path,
|
|||
bool no_stdio,
|
||||
nub_launch_flavor_t launch_flavor,
|
||||
int disable_aslr,
|
||||
const char *event_data,
|
||||
char *err_str,
|
||||
size_t err_len)
|
||||
{
|
||||
|
@ -229,7 +334,8 @@ DNBProcessLaunch (const char *path,
|
|||
stderr_path,
|
||||
no_stdio,
|
||||
launch_flavor,
|
||||
disable_aslr,
|
||||
disable_aslr,
|
||||
event_data,
|
||||
launch_err);
|
||||
if (err_str)
|
||||
{
|
||||
|
@ -681,6 +787,19 @@ DNBProcessSignal (nub_process_t pid, int signal)
|
|||
return false;
|
||||
}
|
||||
|
||||
nub_bool_t
|
||||
DNBProcessSendEvent (nub_process_t pid, const char *event)
|
||||
{
|
||||
MachProcessSP procSP;
|
||||
if (GetProcessSP (pid, procSP))
|
||||
{
|
||||
// FIXME: Do something with the error...
|
||||
DNBError send_error;
|
||||
return procSP->SendEvent (event, send_error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
nub_bool_t
|
||||
DNBProcessIsAlive (nub_process_t pid)
|
||||
|
@ -733,6 +852,28 @@ DNBProcessSetExitStatus (nub_process_t pid, int status)
|
|||
return false;
|
||||
}
|
||||
|
||||
const char *
|
||||
DNBProcessGetExitInfo (nub_process_t pid)
|
||||
{
|
||||
MachProcessSP procSP;
|
||||
if (GetProcessSP (pid, procSP))
|
||||
{
|
||||
return procSP->GetExitInfo();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nub_bool_t
|
||||
DNBProcessSetExitInfo (nub_process_t pid, const char *info)
|
||||
{
|
||||
MachProcessSP procSP;
|
||||
if (GetProcessSP (pid, procSP))
|
||||
{
|
||||
procSP->SetExitInfo(info);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *
|
||||
DNBThreadGetName (nub_process_t pid, nub_thread_t tid)
|
||||
|
@ -2054,8 +2195,9 @@ DNBInitialize()
|
|||
#if defined (__i386__) || defined (__x86_64__)
|
||||
DNBArchImplI386::Initialize();
|
||||
DNBArchImplX86_64::Initialize();
|
||||
#elif defined (__arm__)
|
||||
#elif defined (__arm__) || defined (__arm64__)
|
||||
DNBArchMachARM::Initialize();
|
||||
DNBArchMachARM64::Initialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2073,6 +2215,8 @@ DNBSetArchitecture (const char *arch)
|
|||
return DNBArchProtocol::SetArchitecture (CPU_TYPE_I386);
|
||||
else if ((strcasecmp (arch, "x86_64") == 0) || (strcasecmp (arch, "x86_64h") == 0))
|
||||
return DNBArchProtocol::SetArchitecture (CPU_TYPE_X86_64);
|
||||
else if (strstr (arch, "arm64") == arch || strstr (arch, "armv8") == arch)
|
||||
return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM64);
|
||||
else if (strstr (arch, "arm") == arch)
|
||||
return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 ||\
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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 ®);
|
||||
|
||||
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__
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue