mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 01:15:50 +08:00
Add support for ARM and ARM64 breakpad generated minidump files
In this patch I add support for ARM and ARM64 break pad files. There are two flavors of ARM: Apple where FP is R7, and non Apple where FP is R11. Added minimal tests that load up ARM64 and the two flavors or ARM core files with a single thread and known register values in each register. Each register is checked for the exact value. Differential Revision: https://reviews.llvm.org/D49750 llvm-svn: 338734
This commit is contained in:
@@ -913,28 +913,30 @@ public:
|
||||
/// Set the architecture for this target.
|
||||
///
|
||||
/// If the current target has no Images read in, then this just sets the
|
||||
/// architecture, which will
|
||||
/// be used to select the architecture of the ExecutableModule when that is
|
||||
/// set.
|
||||
/// If the current target has an ExecutableModule, then calling
|
||||
/// SetArchitecture with a different
|
||||
/// architecture, which will be used to select the architecture of the
|
||||
/// ExecutableModule when that is set. If the current target has an
|
||||
/// ExecutableModule, then calling SetArchitecture with a different
|
||||
/// architecture from the currently selected one will reset the
|
||||
/// ExecutableModule to that slice
|
||||
/// of the file backing the ExecutableModule. If the file backing the
|
||||
/// ExecutableModule does not
|
||||
/// contain a fork of this architecture, then this code will return false, and
|
||||
/// the architecture
|
||||
/// won't be changed.
|
||||
/// If the input arch_spec is the same as the already set architecture, this
|
||||
/// is a no-op.
|
||||
/// ExecutableModule to that slice of the file backing the ExecutableModule.
|
||||
/// If the file backing the ExecutableModule does not contain a fork of this
|
||||
/// architecture, then this code will return false, and the architecture
|
||||
/// won't be changed. If the input arch_spec is the same as the already set
|
||||
/// architecture, this is a no-op.
|
||||
///
|
||||
/// @param[in] arch_spec
|
||||
/// The new architecture.
|
||||
///
|
||||
/// @param[in] set_platform
|
||||
/// If \b true, then the platform will be adjusted if the currently
|
||||
/// selected platform is not compatible with the archicture being set.
|
||||
/// If \b false, then just the architecture will be set even if the
|
||||
/// currently selected platform isn't compatible (in case it might be
|
||||
/// manually set following this function call).
|
||||
///
|
||||
/// @return
|
||||
/// \b true if the architecture was successfully set, \bfalse otherwise.
|
||||
//------------------------------------------------------------------
|
||||
bool SetArchitecture(const ArchSpec &arch_spec);
|
||||
bool SetArchitecture(const ArchSpec &arch_spec, bool set_platform = false);
|
||||
|
||||
bool MergeArchitecture(const ArchSpec &arch_spec);
|
||||
|
||||
|
||||
@@ -665,6 +665,10 @@
|
||||
26474CBE18D0CB2D0073DEBA /* RegisterContextMach_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26474CB818D0CB2D0073DEBA /* RegisterContextMach_i386.cpp */; };
|
||||
26474CC018D0CB2D0073DEBA /* RegisterContextMach_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26474CBA18D0CB2D0073DEBA /* RegisterContextMach_x86_64.cpp */; };
|
||||
26474CC918D0CB5B0073DEBA /* RegisterContextMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26474CC218D0CB5B0073DEBA /* RegisterContextMemory.cpp */; };
|
||||
2619C4852107A9A2009CDE81 /* RegisterContextMinidump_ARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2619C4812107A9A1009CDE81 /* RegisterContextMinidump_ARM.cpp */; };
|
||||
2619C4872107A9A2009CDE81 /* RegisterContextMinidump_ARM.h in Headers */ = {isa = PBXBuildFile; fileRef = 2619C4832107A9A2009CDE81 /* RegisterContextMinidump_ARM.h */; };
|
||||
2619C4842107A9A2009CDE81 /* RegisterContextMinidump_ARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2619C4802107A9A1009CDE81 /* RegisterContextMinidump_ARM64.cpp */; };
|
||||
2619C4862107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h in Headers */ = {isa = PBXBuildFile; fileRef = 2619C4822107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h */; };
|
||||
947CF7761DC7B20D00EF980B /* RegisterContextMinidump_x86_32.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 947CF7741DC7B20D00EF980B /* RegisterContextMinidump_x86_32.cpp */; };
|
||||
AFD65C811D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */; };
|
||||
AFD65C821D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h */; };
|
||||
@@ -2542,6 +2546,10 @@
|
||||
26474CC218D0CB5B0073DEBA /* RegisterContextMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextMemory.cpp; path = Utility/RegisterContextMemory.cpp; sourceTree = "<group>"; };
|
||||
262D24E513FB8710002D1960 /* RegisterContextMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMemory.h; path = Utility/RegisterContextMemory.h; sourceTree = "<group>"; };
|
||||
26474CC318D0CB5B0073DEBA /* RegisterContextMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMemory.h; path = Utility/RegisterContextMemory.h; sourceTree = "<group>"; };
|
||||
2619C4812107A9A1009CDE81 /* RegisterContextMinidump_ARM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_ARM.cpp; sourceTree = "<group>"; };
|
||||
2619C4832107A9A2009CDE81 /* RegisterContextMinidump_ARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_ARM.h; sourceTree = "<group>"; };
|
||||
2619C4802107A9A1009CDE81 /* RegisterContextMinidump_ARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_ARM64.cpp; sourceTree = "<group>"; };
|
||||
2619C4822107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_ARM64.h; sourceTree = "<group>"; };
|
||||
947CF7741DC7B20D00EF980B /* RegisterContextMinidump_x86_32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_x86_32.cpp; sourceTree = "<group>"; };
|
||||
947CF7721DC7B20300EF980B /* RegisterContextMinidump_x86_32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_x86_32.h; sourceTree = "<group>"; };
|
||||
AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_x86_64.cpp; sourceTree = "<group>"; };
|
||||
@@ -3787,6 +3795,10 @@
|
||||
23E2E5351D9048E7006F38BB /* minidump */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2619C4812107A9A1009CDE81 /* RegisterContextMinidump_ARM.cpp */,
|
||||
2619C4832107A9A2009CDE81 /* RegisterContextMinidump_ARM.h */,
|
||||
2619C4802107A9A1009CDE81 /* RegisterContextMinidump_ARM64.cpp */,
|
||||
2619C4822107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h */,
|
||||
AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */,
|
||||
AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h */,
|
||||
23E2E5361D9048FB006F38BB /* CMakeLists.txt */,
|
||||
@@ -6939,8 +6951,10 @@
|
||||
AF6CA6681FBBAF37005A0DC3 /* ArchSpec.h in Headers */,
|
||||
AF235EB41FBE7858009C5541 /* RegisterInfoPOSIX_ppc64le.h in Headers */,
|
||||
AF2E02A41FA2CEAF00A86C34 /* ArchitectureArm.h in Headers */,
|
||||
2619C4872107A9A2009CDE81 /* RegisterContextMinidump_ARM.h in Headers */,
|
||||
267F685A1CC02EBE0086832B /* RegisterInfos_s390x.h in Headers */,
|
||||
267F68541CC02E920086832B /* RegisterContextLinux_s390x.h in Headers */,
|
||||
2619C4862107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h in Headers */,
|
||||
AF235EB11FBE77B6009C5541 /* RegisterContextPOSIX_ppc64le.h in Headers */,
|
||||
267F68501CC02E270086832B /* RegisterContextPOSIXCore_s390x.h in Headers */,
|
||||
4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */,
|
||||
@@ -7643,6 +7657,7 @@
|
||||
2689002113353DDE00698AC0 /* CommandObjectQuit.cpp in Sources */,
|
||||
2689002213353DDE00698AC0 /* CommandObjectRegister.cpp in Sources */,
|
||||
26BC17AF18C7F4CB00D2196D /* RegisterContextPOSIXCore_x86_64.cpp in Sources */,
|
||||
2619C4842107A9A2009CDE81 /* RegisterContextMinidump_ARM64.cpp in Sources */,
|
||||
2689002313353DDE00698AC0 /* CommandObjectScript.cpp in Sources */,
|
||||
2689002413353DDE00698AC0 /* CommandObjectSettings.cpp in Sources */,
|
||||
2689002513353DDE00698AC0 /* CommandObjectSource.cpp in Sources */,
|
||||
@@ -7723,6 +7738,7 @@
|
||||
2689005113353E0400698AC0 /* StringList.cpp in Sources */,
|
||||
2689005213353E0400698AC0 /* Timer.cpp in Sources */,
|
||||
2689005413353E0400698AC0 /* UserSettingsController.cpp in Sources */,
|
||||
2619C4852107A9A2009CDE81 /* RegisterContextMinidump_ARM.cpp in Sources */,
|
||||
23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */,
|
||||
8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */,
|
||||
9A77AD541E64E2760025CE04 /* RegisterInfoPOSIX_arm.cpp in Sources */,
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "DebugClang"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "1"
|
||||
|
||||
@@ -189,6 +189,161 @@ class MiniDumpNewTestCase(TestBase):
|
||||
stop_description = thread.GetStopDescription(256)
|
||||
self.assertEqual(stop_description, "")
|
||||
|
||||
def check_register_unsigned(self, set, name, expected):
|
||||
reg_value = set.GetChildMemberWithName(name)
|
||||
self.assertTrue(reg_value.IsValid(),
|
||||
'Verify we have a register named "%s"' % (name))
|
||||
self.assertEqual(reg_value.GetValueAsUnsigned(), expected,
|
||||
'Verify "%s" == %i' % (name, expected))
|
||||
|
||||
def check_register_string_value(self, set, name, expected, format):
|
||||
reg_value = set.GetChildMemberWithName(name)
|
||||
self.assertTrue(reg_value.IsValid(),
|
||||
'Verify we have a register named "%s"' % (name))
|
||||
if format is not None:
|
||||
reg_value.SetFormat(format)
|
||||
self.assertEqual(reg_value.GetValue(), expected,
|
||||
'Verify "%s" has string value "%s"' % (name,
|
||||
expected))
|
||||
|
||||
def test_arm64_registers(self):
|
||||
"""Test ARM64 registers from a breakpad created minidump."""
|
||||
# target create -c arm64-macos.dmp
|
||||
self.dbg.CreateTarget(None)
|
||||
self.target = self.dbg.GetSelectedTarget()
|
||||
self.process = self.target.LoadCore("arm64-macos.dmp")
|
||||
self.check_state()
|
||||
self.assertEqual(self.process.GetNumThreads(), 1)
|
||||
thread = self.process.GetThreadAtIndex(0)
|
||||
self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone)
|
||||
stop_description = thread.GetStopDescription(256)
|
||||
self.assertEqual(stop_description, "")
|
||||
registers = thread.GetFrameAtIndex(0).GetRegisters()
|
||||
# Verify the GPR registers are all correct
|
||||
# Verify x0 - x31 register values
|
||||
gpr = registers.GetValueAtIndex(0)
|
||||
for i in range(32):
|
||||
v = i+1 | i+2 << 32 | i+3 << 48
|
||||
w = i+1
|
||||
self.check_register_unsigned(gpr, 'x%i' % (i), v)
|
||||
self.check_register_unsigned(gpr, 'w%i' % (i), w)
|
||||
# Verify arg1 - arg8 register values
|
||||
for i in range(1, 9):
|
||||
v = i | i+1 << 32 | i+2 << 48
|
||||
self.check_register_unsigned(gpr, 'arg%i' % (i), v)
|
||||
i = 29
|
||||
v = i+1 | i+2 << 32 | i+3 << 48
|
||||
self.check_register_unsigned(gpr, 'fp', v)
|
||||
i = 30
|
||||
v = i+1 | i+2 << 32 | i+3 << 48
|
||||
self.check_register_unsigned(gpr, 'lr', v)
|
||||
i = 31
|
||||
v = i+1 | i+2 << 32 | i+3 << 48
|
||||
self.check_register_unsigned(gpr, 'sp', v)
|
||||
self.check_register_unsigned(gpr, 'pc', 0x1000)
|
||||
self.check_register_unsigned(gpr, 'cpsr', 0x11223344)
|
||||
self.check_register_unsigned(gpr, 'psr', 0x11223344)
|
||||
|
||||
# Verify the FPR registers are all correct
|
||||
fpr = registers.GetValueAtIndex(1)
|
||||
for i in range(32):
|
||||
v = "0x"
|
||||
d = "0x"
|
||||
s = "0x"
|
||||
h = "0x"
|
||||
for j in range(i+15, i-1, -1):
|
||||
v += "%2.2x" % (j)
|
||||
for j in range(i+7, i-1, -1):
|
||||
d += "%2.2x" % (j)
|
||||
for j in range(i+3, i-1, -1):
|
||||
s += "%2.2x" % (j)
|
||||
for j in range(i+1, i-1, -1):
|
||||
h += "%2.2x" % (j)
|
||||
self.check_register_string_value(fpr, "v%i" % (i), v,
|
||||
lldb.eFormatHex)
|
||||
self.check_register_string_value(fpr, "d%i" % (i), d,
|
||||
lldb.eFormatHex)
|
||||
self.check_register_string_value(fpr, "s%i" % (i), s,
|
||||
lldb.eFormatHex)
|
||||
self.check_register_string_value(fpr, "h%i" % (i), h,
|
||||
lldb.eFormatHex)
|
||||
self.check_register_unsigned(gpr, 'fpsr', 0x55667788)
|
||||
self.check_register_unsigned(gpr, 'fpcr', 0x99aabbcc)
|
||||
|
||||
def verify_arm_registers(self, apple=False):
|
||||
"""
|
||||
Verify values of all ARM registers from a breakpad created
|
||||
minidump.
|
||||
"""
|
||||
self.dbg.CreateTarget(None)
|
||||
self.target = self.dbg.GetSelectedTarget()
|
||||
if apple:
|
||||
self.process = self.target.LoadCore("arm-macos.dmp")
|
||||
else:
|
||||
self.process = self.target.LoadCore("arm-linux.dmp")
|
||||
self.check_state()
|
||||
self.assertEqual(self.process.GetNumThreads(), 1)
|
||||
thread = self.process.GetThreadAtIndex(0)
|
||||
self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone)
|
||||
stop_description = thread.GetStopDescription(256)
|
||||
self.assertEqual(stop_description, "")
|
||||
registers = thread.GetFrameAtIndex(0).GetRegisters()
|
||||
# Verify the GPR registers are all correct
|
||||
# Verify x0 - x31 register values
|
||||
gpr = registers.GetValueAtIndex(0)
|
||||
for i in range(1, 16):
|
||||
self.check_register_unsigned(gpr, 'r%i' % (i), i+1)
|
||||
# Verify arg1 - arg4 register values
|
||||
for i in range(1, 5):
|
||||
self.check_register_unsigned(gpr, 'arg%i' % (i), i)
|
||||
if apple:
|
||||
self.check_register_unsigned(gpr, 'fp', 0x08)
|
||||
else:
|
||||
self.check_register_unsigned(gpr, 'fp', 0x0c)
|
||||
self.check_register_unsigned(gpr, 'lr', 0x0f)
|
||||
self.check_register_unsigned(gpr, 'sp', 0x0e)
|
||||
self.check_register_unsigned(gpr, 'pc', 0x10)
|
||||
self.check_register_unsigned(gpr, 'cpsr', 0x11223344)
|
||||
|
||||
# Verify the FPR registers are all correct
|
||||
fpr = registers.GetValueAtIndex(1)
|
||||
# Check d0 - d31
|
||||
self.check_register_unsigned(gpr, 'fpscr', 0x55667788aabbccdd)
|
||||
for i in range(32):
|
||||
value = (i+1) | (i+1) << 8 | (i+1) << 32 | (i+1) << 48
|
||||
self.check_register_unsigned(fpr, "d%i" % (i), value)
|
||||
# Check s0 - s31
|
||||
for i in range(32):
|
||||
i_val = (i >> 1) + 1
|
||||
if i & 1:
|
||||
value = "%#8.8x" % (i_val | i_val << 16)
|
||||
else:
|
||||
value = "%#8.8x" % (i_val | i_val << 8)
|
||||
self.check_register_string_value(fpr, "s%i" % (i), value,
|
||||
lldb.eFormatHex)
|
||||
# Check q0 - q15
|
||||
for i in range(15):
|
||||
a = i * 2 + 1
|
||||
b = a + 1
|
||||
value = ("0x00%2.2x00%2.2x0000%2.2x%2.2x"
|
||||
"00%2.2x00%2.2x0000%2.2x%2.2x") % (b, b, b, b, a, a, a, a)
|
||||
self.check_register_string_value(fpr, "q%i" % (i), value,
|
||||
lldb.eFormatHex)
|
||||
|
||||
def test_linux_arm_registers(self):
|
||||
"""Test Linux ARM registers from a breakpad created minidump.
|
||||
|
||||
The frame pointer is R11 for linux.
|
||||
"""
|
||||
self.verify_arm_registers(apple=False)
|
||||
|
||||
def test_apple_arm_registers(self):
|
||||
"""Test Apple ARM registers from a breakpad created minidump.
|
||||
|
||||
The frame pointer is R7 for linux.
|
||||
"""
|
||||
self.verify_arm_registers(apple=True)
|
||||
|
||||
def do_test_deeper_stack(self, binary, core, pid):
|
||||
target = self.dbg.CreateTarget(binary)
|
||||
process = target.LoadCore(core)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -145,71 +145,7 @@ const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
|
||||
return MinidumpSystemInfo::Parse(data);
|
||||
}
|
||||
|
||||
ArchSpec MinidumpParser::GetArchitecture() {
|
||||
ArchSpec arch_spec;
|
||||
const MinidumpSystemInfo *system_info = GetSystemInfo();
|
||||
|
||||
if (!system_info)
|
||||
return arch_spec;
|
||||
|
||||
// TODO what to do about big endiand flavors of arm ?
|
||||
// TODO set the arm subarch stuff if the minidump has info about it
|
||||
|
||||
llvm::Triple triple;
|
||||
triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
|
||||
|
||||
const MinidumpCPUArchitecture arch =
|
||||
static_cast<const MinidumpCPUArchitecture>(
|
||||
static_cast<const uint32_t>(system_info->processor_arch));
|
||||
|
||||
switch (arch) {
|
||||
case MinidumpCPUArchitecture::X86:
|
||||
triple.setArch(llvm::Triple::ArchType::x86);
|
||||
break;
|
||||
case MinidumpCPUArchitecture::AMD64:
|
||||
triple.setArch(llvm::Triple::ArchType::x86_64);
|
||||
break;
|
||||
case MinidumpCPUArchitecture::ARM:
|
||||
triple.setArch(llvm::Triple::ArchType::arm);
|
||||
break;
|
||||
case MinidumpCPUArchitecture::ARM64:
|
||||
triple.setArch(llvm::Triple::ArchType::aarch64);
|
||||
break;
|
||||
default:
|
||||
triple.setArch(llvm::Triple::ArchType::UnknownArch);
|
||||
break;
|
||||
}
|
||||
|
||||
const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
|
||||
static_cast<const uint32_t>(system_info->platform_id));
|
||||
|
||||
// TODO add all of the OSes that Minidump/breakpad distinguishes?
|
||||
switch (os) {
|
||||
case MinidumpOSPlatform::Win32S:
|
||||
case MinidumpOSPlatform::Win32Windows:
|
||||
case MinidumpOSPlatform::Win32NT:
|
||||
case MinidumpOSPlatform::Win32CE:
|
||||
triple.setOS(llvm::Triple::OSType::Win32);
|
||||
break;
|
||||
case MinidumpOSPlatform::Linux:
|
||||
triple.setOS(llvm::Triple::OSType::Linux);
|
||||
break;
|
||||
case MinidumpOSPlatform::MacOSX:
|
||||
triple.setOS(llvm::Triple::OSType::MacOSX);
|
||||
break;
|
||||
case MinidumpOSPlatform::Android:
|
||||
triple.setOS(llvm::Triple::OSType::Linux);
|
||||
triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
|
||||
break;
|
||||
default:
|
||||
triple.setOS(llvm::Triple::OSType::UnknownOS);
|
||||
break;
|
||||
}
|
||||
|
||||
arch_spec.SetTriple(triple);
|
||||
|
||||
return arch_spec;
|
||||
}
|
||||
ArchSpec MinidumpParser::GetArchitecture() { return m_arch; }
|
||||
|
||||
const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
|
||||
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
|
||||
@@ -552,5 +488,79 @@ Status MinidumpParser::Initialize() {
|
||||
return error;
|
||||
}
|
||||
|
||||
// Set the architecture in m_arch
|
||||
const MinidumpSystemInfo *system_info = GetSystemInfo();
|
||||
|
||||
if (!system_info) {
|
||||
error.SetErrorString("invalid minidump: missing system info");
|
||||
return error;
|
||||
}
|
||||
|
||||
// TODO what to do about big endiand flavors of arm ?
|
||||
// TODO set the arm subarch stuff if the minidump has info about it
|
||||
|
||||
llvm::Triple triple;
|
||||
triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
|
||||
|
||||
const MinidumpCPUArchitecture arch =
|
||||
static_cast<const MinidumpCPUArchitecture>(
|
||||
static_cast<const uint32_t>(system_info->processor_arch));
|
||||
|
||||
switch (arch) {
|
||||
case MinidumpCPUArchitecture::X86:
|
||||
triple.setArch(llvm::Triple::ArchType::x86);
|
||||
break;
|
||||
case MinidumpCPUArchitecture::AMD64:
|
||||
triple.setArch(llvm::Triple::ArchType::x86_64);
|
||||
break;
|
||||
case MinidumpCPUArchitecture::ARM:
|
||||
triple.setArch(llvm::Triple::ArchType::arm);
|
||||
break;
|
||||
case MinidumpCPUArchitecture::ARM64:
|
||||
triple.setArch(llvm::Triple::ArchType::aarch64);
|
||||
break;
|
||||
default:
|
||||
triple.setArch(llvm::Triple::ArchType::UnknownArch);
|
||||
break;
|
||||
}
|
||||
|
||||
const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
|
||||
static_cast<const uint32_t>(system_info->platform_id));
|
||||
|
||||
// TODO add all of the OSes that Minidump/breakpad distinguishes?
|
||||
switch (os) {
|
||||
case MinidumpOSPlatform::Win32S:
|
||||
case MinidumpOSPlatform::Win32Windows:
|
||||
case MinidumpOSPlatform::Win32NT:
|
||||
case MinidumpOSPlatform::Win32CE:
|
||||
triple.setOS(llvm::Triple::OSType::Win32);
|
||||
break;
|
||||
case MinidumpOSPlatform::Linux:
|
||||
triple.setOS(llvm::Triple::OSType::Linux);
|
||||
break;
|
||||
case MinidumpOSPlatform::MacOSX:
|
||||
triple.setOS(llvm::Triple::OSType::MacOSX);
|
||||
triple.setVendor(llvm::Triple::Apple);
|
||||
break;
|
||||
case MinidumpOSPlatform::IOS:
|
||||
triple.setOS(llvm::Triple::OSType::IOS);
|
||||
triple.setVendor(llvm::Triple::Apple);
|
||||
break;
|
||||
case MinidumpOSPlatform::Android:
|
||||
triple.setOS(llvm::Triple::OSType::Linux);
|
||||
triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
|
||||
break;
|
||||
default: {
|
||||
triple.setOS(llvm::Triple::OSType::UnknownOS);
|
||||
std::string csd_version;
|
||||
if (auto s = GetMinidumpString(system_info->csd_version_rva))
|
||||
csd_version = *s;
|
||||
if (csd_version.find("Linux") != std::string::npos)
|
||||
triple.setOS(llvm::Triple::OSType::Linux);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_arch.SetTriple(triple);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ private:
|
||||
private:
|
||||
lldb::DataBufferSP m_data_sp;
|
||||
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map;
|
||||
ArchSpec m_arch;
|
||||
};
|
||||
|
||||
} // end namespace minidump
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Threading.h"
|
||||
|
||||
#include "Plugins/Process/Utility/StopInfoMachException.h"
|
||||
// C includes
|
||||
// C++ includes
|
||||
|
||||
@@ -174,19 +175,21 @@ Status ProcessMinidump::DoLoadCore() {
|
||||
switch (arch.GetMachine()) {
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
// supported
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::aarch64:
|
||||
// Any supported architectures must be listed here and also supported in
|
||||
// ThreadMinidump::CreateRegisterContextForFrame().
|
||||
break;
|
||||
|
||||
default:
|
||||
error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
|
||||
arch.GetArchitectureName());
|
||||
return error;
|
||||
}
|
||||
GetTarget().SetArchitecture(arch, true /*set_platform*/);
|
||||
|
||||
m_thread_list = m_minidump_parser.GetThreads();
|
||||
m_active_exception = m_minidump_parser.GetExceptionStream();
|
||||
ReadModuleList();
|
||||
GetTarget().SetArchitecture(arch);
|
||||
|
||||
llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
|
||||
if (!pid) {
|
||||
@@ -229,6 +232,11 @@ void ProcessMinidump::RefreshStateAfterStop() {
|
||||
if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
|
||||
stop_info = StopInfo::CreateStopReasonWithSignal(
|
||||
*stop_thread, m_active_exception->exception_record.exception_code);
|
||||
} else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
|
||||
stop_info = StopInfoMachException::CreateStopReasonWithMachException(
|
||||
*stop_thread, m_active_exception->exception_record.exception_code, 2,
|
||||
m_active_exception->exception_record.exception_flags,
|
||||
m_active_exception->exception_record.exception_address, 0);
|
||||
} else {
|
||||
std::string desc;
|
||||
llvm::raw_string_ostream desc_stream(desc);
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
//===-- RegisterContextMinidump_ARM.cpp -------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Project includes
|
||||
#include "RegisterContextMinidump_ARM.h"
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "Utility/ARM_DWARF_Registers.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Utility/DataExtractor.h"
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
#include "lldb/lldb-enumerations.h"
|
||||
|
||||
// C includes
|
||||
#include <assert.h>
|
||||
|
||||
// C++ includes
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace minidump;
|
||||
|
||||
#define INV LLDB_INVALID_REGNUM
|
||||
#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r))
|
||||
|
||||
#define DEF_R(i) \
|
||||
{ \
|
||||
"r" #i, nullptr, 4, OFFSET(r[i]), eEncodingUint, eFormatHex, \
|
||||
{INV, dwarf_r##i, INV, INV, reg_r##i}, nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_R_ARG(i, n) \
|
||||
{ \
|
||||
"r" #i, "arg" #n, 4, OFFSET(r[i]), eEncodingUint, eFormatHex, \
|
||||
{INV, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_r##i}, \
|
||||
nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_D(i) \
|
||||
{ \
|
||||
"d" #i, nullptr, 8, OFFSET(d[i]), eEncodingVector, eFormatVectorOfUInt8, \
|
||||
{INV, dwarf_d##i, INV, INV, reg_d##i}, nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_S(i) \
|
||||
{ \
|
||||
"s" #i, nullptr, 4, OFFSET(s[i]), eEncodingIEEE754, eFormatFloat, \
|
||||
{INV, dwarf_s##i, INV, INV, reg_s##i}, nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_Q(i) \
|
||||
{ \
|
||||
"q" #i, nullptr, 16, OFFSET(q[i]), eEncodingVector, eFormatVectorOfUInt8, \
|
||||
{INV, dwarf_q##i, INV, INV, reg_q##i}, nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
// Zero based LLDB register numbers for this register context
|
||||
enum {
|
||||
// General Purpose Registers
|
||||
reg_r0,
|
||||
reg_r1,
|
||||
reg_r2,
|
||||
reg_r3,
|
||||
reg_r4,
|
||||
reg_r5,
|
||||
reg_r6,
|
||||
reg_r7,
|
||||
reg_r8,
|
||||
reg_r9,
|
||||
reg_r10,
|
||||
reg_r11,
|
||||
reg_r12,
|
||||
reg_sp,
|
||||
reg_lr,
|
||||
reg_pc,
|
||||
reg_cpsr,
|
||||
// Floating Point Registers
|
||||
reg_fpscr,
|
||||
reg_d0,
|
||||
reg_d1,
|
||||
reg_d2,
|
||||
reg_d3,
|
||||
reg_d4,
|
||||
reg_d5,
|
||||
reg_d6,
|
||||
reg_d7,
|
||||
reg_d8,
|
||||
reg_d9,
|
||||
reg_d10,
|
||||
reg_d11,
|
||||
reg_d12,
|
||||
reg_d13,
|
||||
reg_d14,
|
||||
reg_d15,
|
||||
reg_d16,
|
||||
reg_d17,
|
||||
reg_d18,
|
||||
reg_d19,
|
||||
reg_d20,
|
||||
reg_d21,
|
||||
reg_d22,
|
||||
reg_d23,
|
||||
reg_d24,
|
||||
reg_d25,
|
||||
reg_d26,
|
||||
reg_d27,
|
||||
reg_d28,
|
||||
reg_d29,
|
||||
reg_d30,
|
||||
reg_d31,
|
||||
reg_s0,
|
||||
reg_s1,
|
||||
reg_s2,
|
||||
reg_s3,
|
||||
reg_s4,
|
||||
reg_s5,
|
||||
reg_s6,
|
||||
reg_s7,
|
||||
reg_s8,
|
||||
reg_s9,
|
||||
reg_s10,
|
||||
reg_s11,
|
||||
reg_s12,
|
||||
reg_s13,
|
||||
reg_s14,
|
||||
reg_s15,
|
||||
reg_s16,
|
||||
reg_s17,
|
||||
reg_s18,
|
||||
reg_s19,
|
||||
reg_s20,
|
||||
reg_s21,
|
||||
reg_s22,
|
||||
reg_s23,
|
||||
reg_s24,
|
||||
reg_s25,
|
||||
reg_s26,
|
||||
reg_s27,
|
||||
reg_s28,
|
||||
reg_s29,
|
||||
reg_s30,
|
||||
reg_s31,
|
||||
reg_q0,
|
||||
reg_q1,
|
||||
reg_q2,
|
||||
reg_q3,
|
||||
reg_q4,
|
||||
reg_q5,
|
||||
reg_q6,
|
||||
reg_q7,
|
||||
reg_q8,
|
||||
reg_q9,
|
||||
reg_q10,
|
||||
reg_q11,
|
||||
reg_q12,
|
||||
reg_q13,
|
||||
reg_q14,
|
||||
reg_q15,
|
||||
k_num_regs
|
||||
};
|
||||
|
||||
static RegisterInfo g_reg_info_apple_fp = {
|
||||
"fp",
|
||||
"r7",
|
||||
4,
|
||||
OFFSET(r[7]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0};
|
||||
|
||||
static RegisterInfo g_reg_info_fp = {
|
||||
"fp",
|
||||
"r11",
|
||||
4,
|
||||
OFFSET(r[11]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0};
|
||||
|
||||
// Register info definitions for this register context
|
||||
static RegisterInfo g_reg_infos[] = {
|
||||
DEF_R_ARG(0, 1),
|
||||
DEF_R_ARG(1, 2),
|
||||
DEF_R_ARG(2, 3),
|
||||
DEF_R_ARG(3, 4),
|
||||
DEF_R(4),
|
||||
DEF_R(5),
|
||||
DEF_R(6),
|
||||
DEF_R(7),
|
||||
DEF_R(8),
|
||||
DEF_R(9),
|
||||
DEF_R(10),
|
||||
DEF_R(11),
|
||||
DEF_R(12),
|
||||
{"sp",
|
||||
"r13",
|
||||
4,
|
||||
OFFSET(r[13]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"lr",
|
||||
"r14",
|
||||
4,
|
||||
OFFSET(r[14]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"pc",
|
||||
"r15",
|
||||
4,
|
||||
OFFSET(r[15]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"cpsr",
|
||||
"psr",
|
||||
4,
|
||||
OFFSET(cpsr),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"fpscr",
|
||||
nullptr,
|
||||
8,
|
||||
OFFSET(fpscr),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, INV, INV, INV, reg_fpscr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
DEF_D(0),
|
||||
DEF_D(1),
|
||||
DEF_D(2),
|
||||
DEF_D(3),
|
||||
DEF_D(4),
|
||||
DEF_D(5),
|
||||
DEF_D(6),
|
||||
DEF_D(7),
|
||||
DEF_D(8),
|
||||
DEF_D(9),
|
||||
DEF_D(10),
|
||||
DEF_D(11),
|
||||
DEF_D(12),
|
||||
DEF_D(13),
|
||||
DEF_D(14),
|
||||
DEF_D(15),
|
||||
DEF_D(16),
|
||||
DEF_D(17),
|
||||
DEF_D(18),
|
||||
DEF_D(19),
|
||||
DEF_D(20),
|
||||
DEF_D(21),
|
||||
DEF_D(22),
|
||||
DEF_D(23),
|
||||
DEF_D(24),
|
||||
DEF_D(25),
|
||||
DEF_D(26),
|
||||
DEF_D(27),
|
||||
DEF_D(28),
|
||||
DEF_D(29),
|
||||
DEF_D(30),
|
||||
DEF_D(31),
|
||||
DEF_S(0),
|
||||
DEF_S(1),
|
||||
DEF_S(2),
|
||||
DEF_S(3),
|
||||
DEF_S(4),
|
||||
DEF_S(5),
|
||||
DEF_S(6),
|
||||
DEF_S(7),
|
||||
DEF_S(8),
|
||||
DEF_S(9),
|
||||
DEF_S(10),
|
||||
DEF_S(11),
|
||||
DEF_S(12),
|
||||
DEF_S(13),
|
||||
DEF_S(14),
|
||||
DEF_S(15),
|
||||
DEF_S(16),
|
||||
DEF_S(17),
|
||||
DEF_S(18),
|
||||
DEF_S(19),
|
||||
DEF_S(20),
|
||||
DEF_S(21),
|
||||
DEF_S(22),
|
||||
DEF_S(23),
|
||||
DEF_S(24),
|
||||
DEF_S(25),
|
||||
DEF_S(26),
|
||||
DEF_S(27),
|
||||
DEF_S(28),
|
||||
DEF_S(29),
|
||||
DEF_S(30),
|
||||
DEF_S(31),
|
||||
DEF_Q(0),
|
||||
DEF_Q(1),
|
||||
DEF_Q(2),
|
||||
DEF_Q(3),
|
||||
DEF_Q(4),
|
||||
DEF_Q(5),
|
||||
DEF_Q(6),
|
||||
DEF_Q(7),
|
||||
DEF_Q(8),
|
||||
DEF_Q(9),
|
||||
DEF_Q(10),
|
||||
DEF_Q(11),
|
||||
DEF_Q(12),
|
||||
DEF_Q(13),
|
||||
DEF_Q(14),
|
||||
DEF_Q(15)};
|
||||
|
||||
constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos);
|
||||
|
||||
// ARM general purpose registers.
|
||||
const uint32_t g_gpr_regnums[] = {
|
||||
reg_r0,
|
||||
reg_r1,
|
||||
reg_r2,
|
||||
reg_r3,
|
||||
reg_r4,
|
||||
reg_r5,
|
||||
reg_r6,
|
||||
reg_r7,
|
||||
reg_r8,
|
||||
reg_r9,
|
||||
reg_r10,
|
||||
reg_r11,
|
||||
reg_r12,
|
||||
reg_sp,
|
||||
reg_lr,
|
||||
reg_pc,
|
||||
reg_cpsr,
|
||||
LLDB_INVALID_REGNUM // register sets need to end with this flag
|
||||
};
|
||||
const uint32_t g_fpu_regnums[] = {
|
||||
reg_fpscr,
|
||||
reg_d0,
|
||||
reg_d1,
|
||||
reg_d2,
|
||||
reg_d3,
|
||||
reg_d4,
|
||||
reg_d5,
|
||||
reg_d6,
|
||||
reg_d7,
|
||||
reg_d8,
|
||||
reg_d9,
|
||||
reg_d10,
|
||||
reg_d11,
|
||||
reg_d12,
|
||||
reg_d13,
|
||||
reg_d14,
|
||||
reg_d15,
|
||||
reg_d16,
|
||||
reg_d17,
|
||||
reg_d18,
|
||||
reg_d19,
|
||||
reg_d20,
|
||||
reg_d21,
|
||||
reg_d22,
|
||||
reg_d23,
|
||||
reg_d24,
|
||||
reg_d25,
|
||||
reg_d26,
|
||||
reg_d27,
|
||||
reg_d28,
|
||||
reg_d29,
|
||||
reg_d30,
|
||||
reg_d31,
|
||||
reg_s0,
|
||||
reg_s1,
|
||||
reg_s2,
|
||||
reg_s3,
|
||||
reg_s4,
|
||||
reg_s5,
|
||||
reg_s6,
|
||||
reg_s7,
|
||||
reg_s8,
|
||||
reg_s9,
|
||||
reg_s10,
|
||||
reg_s11,
|
||||
reg_s12,
|
||||
reg_s13,
|
||||
reg_s14,
|
||||
reg_s15,
|
||||
reg_s16,
|
||||
reg_s17,
|
||||
reg_s18,
|
||||
reg_s19,
|
||||
reg_s20,
|
||||
reg_s21,
|
||||
reg_s22,
|
||||
reg_s23,
|
||||
reg_s24,
|
||||
reg_s25,
|
||||
reg_s26,
|
||||
reg_s27,
|
||||
reg_s28,
|
||||
reg_s29,
|
||||
reg_s30,
|
||||
reg_s31,
|
||||
reg_q0,
|
||||
reg_q1,
|
||||
reg_q2,
|
||||
reg_q3,
|
||||
reg_q4,
|
||||
reg_q5,
|
||||
reg_q6,
|
||||
reg_q7,
|
||||
reg_q8,
|
||||
reg_q9,
|
||||
reg_q10,
|
||||
reg_q11,
|
||||
reg_q12,
|
||||
reg_q13,
|
||||
reg_q14,
|
||||
reg_q15,
|
||||
LLDB_INVALID_REGNUM // register sets need to end with this flag
|
||||
};
|
||||
|
||||
// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1
|
||||
constexpr size_t k_num_gpr_regs = llvm::array_lengthof(g_gpr_regnums) - 1;
|
||||
constexpr size_t k_num_fpu_regs = llvm::array_lengthof(g_fpu_regnums) - 1;
|
||||
|
||||
static RegisterSet g_reg_sets[] = {
|
||||
{"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums},
|
||||
{"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums},
|
||||
};
|
||||
|
||||
constexpr size_t k_num_reg_sets = llvm::array_lengthof(g_reg_sets);
|
||||
|
||||
RegisterContextMinidump_ARM::RegisterContextMinidump_ARM(
|
||||
Thread &thread, const DataExtractor &data, bool apple)
|
||||
: RegisterContext(thread, 0), m_apple(apple) {
|
||||
lldb::offset_t offset = 0;
|
||||
m_regs.context_flags = data.GetU32(&offset);
|
||||
for (unsigned i = 0; i < llvm::array_lengthof(m_regs.r); ++i)
|
||||
m_regs.r[i] = data.GetU32(&offset);
|
||||
m_regs.cpsr = data.GetU32(&offset);
|
||||
m_regs.fpscr = data.GetU64(&offset);
|
||||
for (unsigned i = 0; i < llvm::array_lengthof(m_regs.d); ++i)
|
||||
m_regs.d[i] = data.GetU64(&offset);
|
||||
lldbassert(k_num_regs == k_num_reg_infos);
|
||||
}
|
||||
|
||||
size_t RegisterContextMinidump_ARM::GetRegisterCount() { return k_num_regs; }
|
||||
|
||||
const RegisterInfo *
|
||||
RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) {
|
||||
if (reg < k_num_reg_infos) {
|
||||
if (m_apple) {
|
||||
if (reg == reg_r7)
|
||||
return &g_reg_info_apple_fp;
|
||||
} else {
|
||||
if (reg == reg_r11)
|
||||
return &g_reg_info_fp;
|
||||
}
|
||||
return &g_reg_infos[reg];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t RegisterContextMinidump_ARM::GetRegisterSetCount() {
|
||||
return k_num_reg_sets;
|
||||
}
|
||||
|
||||
const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) {
|
||||
if (set < k_num_reg_sets)
|
||||
return &g_reg_sets[set];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) {
|
||||
if (reg < k_num_reg_infos)
|
||||
return g_reg_infos[reg].name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info,
|
||||
RegisterValue ®_value) {
|
||||
Status error;
|
||||
reg_value.SetFromMemoryData(
|
||||
reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset,
|
||||
reg_info->byte_size, lldb::eByteOrderLittle, error);
|
||||
return error.Success();
|
||||
}
|
||||
|
||||
bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *,
|
||||
const RegisterValue &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t RegisterContextMinidump_ARM::ConvertRegisterKindToRegisterNumber(
|
||||
lldb::RegisterKind kind, uint32_t num) {
|
||||
for (size_t i = 0; i < k_num_regs; ++i) {
|
||||
if (g_reg_infos[i].kinds[kind] == num)
|
||||
return i;
|
||||
}
|
||||
return LLDB_INVALID_REGNUM;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//===-- RegisterContextMinidump_ARM.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_RegisterContextMinidump_ARM_h_
|
||||
#define liblldb_RegisterContextMinidump_ARM_h_
|
||||
|
||||
// Project includes
|
||||
#include "MinidumpTypes.h"
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "Plugins/Process/Utility/RegisterInfoInterface.h"
|
||||
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
|
||||
// C includes
|
||||
// C++ includes
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
namespace minidump {
|
||||
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
|
||||
class RegisterContextMinidump_ARM : public lldb_private::RegisterContext {
|
||||
public:
|
||||
RegisterContextMinidump_ARM(lldb_private::Thread &thread,
|
||||
const DataExtractor &data, bool apple);
|
||||
|
||||
~RegisterContextMinidump_ARM() override = default;
|
||||
|
||||
void InvalidateAllRegisters() override {
|
||||
// Do nothing... registers are always valid...
|
||||
}
|
||||
|
||||
size_t GetRegisterCount() override;
|
||||
|
||||
const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
|
||||
|
||||
size_t GetRegisterSetCount() override;
|
||||
|
||||
const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
|
||||
|
||||
const char *GetRegisterName(unsigned reg);
|
||||
|
||||
bool ReadRegister(const RegisterInfo *reg_info,
|
||||
RegisterValue ®_value) override;
|
||||
|
||||
bool WriteRegister(const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_value) override;
|
||||
|
||||
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
|
||||
uint32_t num) override;
|
||||
|
||||
// Reference: see breakpad/crashpad source
|
||||
struct QRegValue {
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
};
|
||||
|
||||
struct Context {
|
||||
uint32_t context_flags;
|
||||
uint32_t r[16];
|
||||
uint32_t cpsr;
|
||||
uint64_t fpscr;
|
||||
union {
|
||||
uint64_t d[32];
|
||||
uint32_t s[32];
|
||||
QRegValue q[16];
|
||||
};
|
||||
uint32_t extra[8];
|
||||
};
|
||||
|
||||
protected:
|
||||
enum class Flags : uint32_t {
|
||||
ARM_Flag = 0x40000000,
|
||||
Integer = ARM_Flag | 0x00000002,
|
||||
FloatingPoint = ARM_Flag | 0x00000004,
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint)
|
||||
};
|
||||
Context m_regs;
|
||||
const bool m_apple; // True if this is an Apple ARM where FP is R7
|
||||
};
|
||||
|
||||
} // end namespace minidump
|
||||
} // end namespace lldb_private
|
||||
#endif // liblldb_RegisterContextMinidump_ARM_h_
|
||||
@@ -0,0 +1,836 @@
|
||||
//===-- RegisterContextMinidump_ARM64.cpp -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Project includes
|
||||
#include "RegisterContextMinidump_ARM64.h"
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "Utility/ARM64_DWARF_Registers.h"
|
||||
#include "lldb/Core/RegisterValue.h"
|
||||
#include "lldb/Utility/DataExtractor.h"
|
||||
#include "lldb/lldb-enumerations.h"
|
||||
|
||||
// C includes
|
||||
#include <assert.h>
|
||||
|
||||
// C++ includes
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace minidump;
|
||||
|
||||
#define INV LLDB_INVALID_REGNUM
|
||||
#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM64::Context, r))
|
||||
|
||||
#define DEF_X(i) \
|
||||
{ \
|
||||
"x" #i, nullptr, 8, OFFSET(x[i]), eEncodingUint, eFormatHex, \
|
||||
{INV, arm64_dwarf::x##i, INV, INV, reg_x##i}, nullptr, nullptr, \
|
||||
nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_W(i) \
|
||||
{ \
|
||||
"w" #i, nullptr, 4, OFFSET(x[i]), eEncodingUint, eFormatHex, \
|
||||
{INV, INV, INV, INV, reg_w##i}, nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_X_ARG(i, n) \
|
||||
{ \
|
||||
"x" #i, "arg" #n, 8, OFFSET(x[i]), eEncodingUint, eFormatHex, \
|
||||
{INV, arm64_dwarf::x##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_x##i}, \
|
||||
nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_V(i) \
|
||||
{ \
|
||||
"v" #i, nullptr, 16, OFFSET(v[i * 16]), eEncodingVector, \
|
||||
eFormatVectorOfUInt8, {INV, arm64_dwarf::v##i, INV, INV, reg_v##i}, \
|
||||
nullptr, nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_D(i) \
|
||||
{ \
|
||||
"d" #i, nullptr, 8, OFFSET(v[i * 16]), eEncodingVector, \
|
||||
eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_d##i}, nullptr, \
|
||||
nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_S(i) \
|
||||
{ \
|
||||
"s" #i, nullptr, 4, OFFSET(v[i * 16]), eEncodingVector, \
|
||||
eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_s##i}, nullptr, \
|
||||
nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
#define DEF_H(i) \
|
||||
{ \
|
||||
"h" #i, nullptr, 2, OFFSET(v[i * 16]), eEncodingVector, \
|
||||
eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_h##i}, nullptr, \
|
||||
nullptr, nullptr, 0 \
|
||||
}
|
||||
|
||||
// Zero based LLDB register numbers for this register context
|
||||
enum {
|
||||
// General Purpose Registers
|
||||
reg_x0 = 0,
|
||||
reg_x1,
|
||||
reg_x2,
|
||||
reg_x3,
|
||||
reg_x4,
|
||||
reg_x5,
|
||||
reg_x6,
|
||||
reg_x7,
|
||||
reg_x8,
|
||||
reg_x9,
|
||||
reg_x10,
|
||||
reg_x11,
|
||||
reg_x12,
|
||||
reg_x13,
|
||||
reg_x14,
|
||||
reg_x15,
|
||||
reg_x16,
|
||||
reg_x17,
|
||||
reg_x18,
|
||||
reg_x19,
|
||||
reg_x20,
|
||||
reg_x21,
|
||||
reg_x22,
|
||||
reg_x23,
|
||||
reg_x24,
|
||||
reg_x25,
|
||||
reg_x26,
|
||||
reg_x27,
|
||||
reg_x28,
|
||||
reg_fp,
|
||||
reg_lr,
|
||||
reg_sp,
|
||||
reg_pc,
|
||||
reg_w0,
|
||||
reg_w1,
|
||||
reg_w2,
|
||||
reg_w3,
|
||||
reg_w4,
|
||||
reg_w5,
|
||||
reg_w6,
|
||||
reg_w7,
|
||||
reg_w8,
|
||||
reg_w9,
|
||||
reg_w10,
|
||||
reg_w11,
|
||||
reg_w12,
|
||||
reg_w13,
|
||||
reg_w14,
|
||||
reg_w15,
|
||||
reg_w16,
|
||||
reg_w17,
|
||||
reg_w18,
|
||||
reg_w19,
|
||||
reg_w20,
|
||||
reg_w21,
|
||||
reg_w22,
|
||||
reg_w23,
|
||||
reg_w24,
|
||||
reg_w25,
|
||||
reg_w26,
|
||||
reg_w27,
|
||||
reg_w28,
|
||||
reg_w29,
|
||||
reg_w30,
|
||||
reg_w31,
|
||||
reg_cpsr,
|
||||
// Floating Point Registers
|
||||
reg_fpsr,
|
||||
reg_fpcr,
|
||||
reg_v0,
|
||||
reg_v1,
|
||||
reg_v2,
|
||||
reg_v3,
|
||||
reg_v4,
|
||||
reg_v5,
|
||||
reg_v6,
|
||||
reg_v7,
|
||||
reg_v8,
|
||||
reg_v9,
|
||||
reg_v10,
|
||||
reg_v11,
|
||||
reg_v12,
|
||||
reg_v13,
|
||||
reg_v14,
|
||||
reg_v15,
|
||||
reg_v16,
|
||||
reg_v17,
|
||||
reg_v18,
|
||||
reg_v19,
|
||||
reg_v20,
|
||||
reg_v21,
|
||||
reg_v22,
|
||||
reg_v23,
|
||||
reg_v24,
|
||||
reg_v25,
|
||||
reg_v26,
|
||||
reg_v27,
|
||||
reg_v28,
|
||||
reg_v29,
|
||||
reg_v30,
|
||||
reg_v31,
|
||||
reg_d0,
|
||||
reg_d1,
|
||||
reg_d2,
|
||||
reg_d3,
|
||||
reg_d4,
|
||||
reg_d5,
|
||||
reg_d6,
|
||||
reg_d7,
|
||||
reg_d8,
|
||||
reg_d9,
|
||||
reg_d10,
|
||||
reg_d11,
|
||||
reg_d12,
|
||||
reg_d13,
|
||||
reg_d14,
|
||||
reg_d15,
|
||||
reg_d16,
|
||||
reg_d17,
|
||||
reg_d18,
|
||||
reg_d19,
|
||||
reg_d20,
|
||||
reg_d21,
|
||||
reg_d22,
|
||||
reg_d23,
|
||||
reg_d24,
|
||||
reg_d25,
|
||||
reg_d26,
|
||||
reg_d27,
|
||||
reg_d28,
|
||||
reg_d29,
|
||||
reg_d30,
|
||||
reg_d31,
|
||||
reg_s0,
|
||||
reg_s1,
|
||||
reg_s2,
|
||||
reg_s3,
|
||||
reg_s4,
|
||||
reg_s5,
|
||||
reg_s6,
|
||||
reg_s7,
|
||||
reg_s8,
|
||||
reg_s9,
|
||||
reg_s10,
|
||||
reg_s11,
|
||||
reg_s12,
|
||||
reg_s13,
|
||||
reg_s14,
|
||||
reg_s15,
|
||||
reg_s16,
|
||||
reg_s17,
|
||||
reg_s18,
|
||||
reg_s19,
|
||||
reg_s20,
|
||||
reg_s21,
|
||||
reg_s22,
|
||||
reg_s23,
|
||||
reg_s24,
|
||||
reg_s25,
|
||||
reg_s26,
|
||||
reg_s27,
|
||||
reg_s28,
|
||||
reg_s29,
|
||||
reg_s30,
|
||||
reg_s31,
|
||||
reg_h0,
|
||||
reg_h1,
|
||||
reg_h2,
|
||||
reg_h3,
|
||||
reg_h4,
|
||||
reg_h5,
|
||||
reg_h6,
|
||||
reg_h7,
|
||||
reg_h8,
|
||||
reg_h9,
|
||||
reg_h10,
|
||||
reg_h11,
|
||||
reg_h12,
|
||||
reg_h13,
|
||||
reg_h14,
|
||||
reg_h15,
|
||||
reg_h16,
|
||||
reg_h17,
|
||||
reg_h18,
|
||||
reg_h19,
|
||||
reg_h20,
|
||||
reg_h21,
|
||||
reg_h22,
|
||||
reg_h23,
|
||||
reg_h24,
|
||||
reg_h25,
|
||||
reg_h26,
|
||||
reg_h27,
|
||||
reg_h28,
|
||||
reg_h29,
|
||||
reg_h30,
|
||||
reg_h31,
|
||||
k_num_regs
|
||||
};
|
||||
|
||||
// Register info definitions for this register context
|
||||
static RegisterInfo g_reg_infos[] = {
|
||||
DEF_X_ARG(0, 1),
|
||||
DEF_X_ARG(1, 2),
|
||||
DEF_X_ARG(2, 3),
|
||||
DEF_X_ARG(3, 4),
|
||||
DEF_X_ARG(4, 5),
|
||||
DEF_X_ARG(5, 6),
|
||||
DEF_X_ARG(6, 7),
|
||||
DEF_X_ARG(7, 8),
|
||||
DEF_X(8),
|
||||
DEF_X(9),
|
||||
DEF_X(10),
|
||||
DEF_X(11),
|
||||
DEF_X(12),
|
||||
DEF_X(13),
|
||||
DEF_X(14),
|
||||
DEF_X(15),
|
||||
DEF_X(16),
|
||||
DEF_X(17),
|
||||
DEF_X(18),
|
||||
DEF_X(19),
|
||||
DEF_X(20),
|
||||
DEF_X(21),
|
||||
DEF_X(22),
|
||||
DEF_X(23),
|
||||
DEF_X(24),
|
||||
DEF_X(25),
|
||||
DEF_X(26),
|
||||
DEF_X(27),
|
||||
DEF_X(28),
|
||||
{"fp",
|
||||
"x29",
|
||||
8,
|
||||
OFFSET(x[29]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, INV, reg_fp},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"lr",
|
||||
"x30",
|
||||
8,
|
||||
OFFSET(x[30]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"sp",
|
||||
"x31",
|
||||
8,
|
||||
OFFSET(x[31]),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"pc",
|
||||
nullptr,
|
||||
8,
|
||||
OFFSET(pc),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
// w0 - w31
|
||||
DEF_W(0),
|
||||
DEF_W(1),
|
||||
DEF_W(2),
|
||||
DEF_W(3),
|
||||
DEF_W(4),
|
||||
DEF_W(5),
|
||||
DEF_W(6),
|
||||
DEF_W(7),
|
||||
DEF_W(8),
|
||||
DEF_W(9),
|
||||
DEF_W(10),
|
||||
DEF_W(11),
|
||||
DEF_W(12),
|
||||
DEF_W(13),
|
||||
DEF_W(14),
|
||||
DEF_W(15),
|
||||
DEF_W(16),
|
||||
DEF_W(17),
|
||||
DEF_W(18),
|
||||
DEF_W(19),
|
||||
DEF_W(20),
|
||||
DEF_W(21),
|
||||
DEF_W(22),
|
||||
DEF_W(23),
|
||||
DEF_W(24),
|
||||
DEF_W(25),
|
||||
DEF_W(26),
|
||||
DEF_W(27),
|
||||
DEF_W(28),
|
||||
DEF_W(29),
|
||||
DEF_W(30),
|
||||
DEF_W(31),
|
||||
{"cpsr",
|
||||
"psr",
|
||||
4,
|
||||
OFFSET(cpsr),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"fpsr",
|
||||
nullptr,
|
||||
4,
|
||||
OFFSET(fpsr),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, INV, INV, INV, reg_fpsr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
{"fpcr",
|
||||
nullptr,
|
||||
4,
|
||||
OFFSET(fpcr),
|
||||
eEncodingUint,
|
||||
eFormatHex,
|
||||
{INV, INV, INV, INV, reg_fpcr},
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0},
|
||||
// v0 - v31
|
||||
DEF_V(0),
|
||||
DEF_V(1),
|
||||
DEF_V(2),
|
||||
DEF_V(3),
|
||||
DEF_V(4),
|
||||
DEF_V(5),
|
||||
DEF_V(6),
|
||||
DEF_V(7),
|
||||
DEF_V(8),
|
||||
DEF_V(9),
|
||||
DEF_V(10),
|
||||
DEF_V(11),
|
||||
DEF_V(12),
|
||||
DEF_V(13),
|
||||
DEF_V(14),
|
||||
DEF_V(15),
|
||||
DEF_V(16),
|
||||
DEF_V(17),
|
||||
DEF_V(18),
|
||||
DEF_V(19),
|
||||
DEF_V(20),
|
||||
DEF_V(21),
|
||||
DEF_V(22),
|
||||
DEF_V(23),
|
||||
DEF_V(24),
|
||||
DEF_V(25),
|
||||
DEF_V(26),
|
||||
DEF_V(27),
|
||||
DEF_V(28),
|
||||
DEF_V(29),
|
||||
DEF_V(30),
|
||||
DEF_V(31),
|
||||
// d0 - d31
|
||||
DEF_D(0),
|
||||
DEF_D(1),
|
||||
DEF_D(2),
|
||||
DEF_D(3),
|
||||
DEF_D(4),
|
||||
DEF_D(5),
|
||||
DEF_D(6),
|
||||
DEF_D(7),
|
||||
DEF_D(8),
|
||||
DEF_D(9),
|
||||
DEF_D(10),
|
||||
DEF_D(11),
|
||||
DEF_D(12),
|
||||
DEF_D(13),
|
||||
DEF_D(14),
|
||||
DEF_D(15),
|
||||
DEF_D(16),
|
||||
DEF_D(17),
|
||||
DEF_D(18),
|
||||
DEF_D(19),
|
||||
DEF_D(20),
|
||||
DEF_D(21),
|
||||
DEF_D(22),
|
||||
DEF_D(23),
|
||||
DEF_D(24),
|
||||
DEF_D(25),
|
||||
DEF_D(26),
|
||||
DEF_D(27),
|
||||
DEF_D(28),
|
||||
DEF_D(29),
|
||||
DEF_D(30),
|
||||
DEF_D(31),
|
||||
// s0 - s31
|
||||
DEF_S(0),
|
||||
DEF_S(1),
|
||||
DEF_S(2),
|
||||
DEF_S(3),
|
||||
DEF_S(4),
|
||||
DEF_S(5),
|
||||
DEF_S(6),
|
||||
DEF_S(7),
|
||||
DEF_S(8),
|
||||
DEF_S(9),
|
||||
DEF_S(10),
|
||||
DEF_S(11),
|
||||
DEF_S(12),
|
||||
DEF_S(13),
|
||||
DEF_S(14),
|
||||
DEF_S(15),
|
||||
DEF_S(16),
|
||||
DEF_S(17),
|
||||
DEF_S(18),
|
||||
DEF_S(19),
|
||||
DEF_S(20),
|
||||
DEF_S(21),
|
||||
DEF_S(22),
|
||||
DEF_S(23),
|
||||
DEF_S(24),
|
||||
DEF_S(25),
|
||||
DEF_S(26),
|
||||
DEF_S(27),
|
||||
DEF_S(28),
|
||||
DEF_S(29),
|
||||
DEF_S(30),
|
||||
DEF_S(31),
|
||||
// h0 - h31
|
||||
DEF_H(0),
|
||||
DEF_H(1),
|
||||
DEF_H(2),
|
||||
DEF_H(3),
|
||||
DEF_H(4),
|
||||
DEF_H(5),
|
||||
DEF_H(6),
|
||||
DEF_H(7),
|
||||
DEF_H(8),
|
||||
DEF_H(9),
|
||||
DEF_H(10),
|
||||
DEF_H(11),
|
||||
DEF_H(12),
|
||||
DEF_H(13),
|
||||
DEF_H(14),
|
||||
DEF_H(15),
|
||||
DEF_H(16),
|
||||
DEF_H(17),
|
||||
DEF_H(18),
|
||||
DEF_H(19),
|
||||
DEF_H(20),
|
||||
DEF_H(21),
|
||||
DEF_H(22),
|
||||
DEF_H(23),
|
||||
DEF_H(24),
|
||||
DEF_H(25),
|
||||
DEF_H(26),
|
||||
DEF_H(27),
|
||||
DEF_H(28),
|
||||
DEF_H(29),
|
||||
DEF_H(30),
|
||||
DEF_H(31),
|
||||
};
|
||||
|
||||
constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos);
|
||||
|
||||
// ARM64 general purpose registers.
|
||||
const uint32_t g_gpr_regnums[] = {
|
||||
reg_x0,
|
||||
reg_x1,
|
||||
reg_x2,
|
||||
reg_x3,
|
||||
reg_x4,
|
||||
reg_x5,
|
||||
reg_x6,
|
||||
reg_x7,
|
||||
reg_x8,
|
||||
reg_x9,
|
||||
reg_x10,
|
||||
reg_x11,
|
||||
reg_x12,
|
||||
reg_x13,
|
||||
reg_x14,
|
||||
reg_x15,
|
||||
reg_x16,
|
||||
reg_x17,
|
||||
reg_x18,
|
||||
reg_x19,
|
||||
reg_x20,
|
||||
reg_x21,
|
||||
reg_x22,
|
||||
reg_x23,
|
||||
reg_x24,
|
||||
reg_x25,
|
||||
reg_x26,
|
||||
reg_x27,
|
||||
reg_x28,
|
||||
reg_fp,
|
||||
reg_lr,
|
||||
reg_sp,
|
||||
reg_w0,
|
||||
reg_w1,
|
||||
reg_w2,
|
||||
reg_w3,
|
||||
reg_w4,
|
||||
reg_w5,
|
||||
reg_w6,
|
||||
reg_w7,
|
||||
reg_w8,
|
||||
reg_w9,
|
||||
reg_w10,
|
||||
reg_w11,
|
||||
reg_w12,
|
||||
reg_w13,
|
||||
reg_w14,
|
||||
reg_w15,
|
||||
reg_w16,
|
||||
reg_w17,
|
||||
reg_w18,
|
||||
reg_w19,
|
||||
reg_w20,
|
||||
reg_w21,
|
||||
reg_w22,
|
||||
reg_w23,
|
||||
reg_w24,
|
||||
reg_w25,
|
||||
reg_w26,
|
||||
reg_w27,
|
||||
reg_w28,
|
||||
reg_w29,
|
||||
reg_w30,
|
||||
reg_w31,
|
||||
reg_pc,
|
||||
reg_cpsr,
|
||||
LLDB_INVALID_REGNUM // register sets need to end with this flag
|
||||
};
|
||||
const uint32_t g_fpu_regnums[] = {
|
||||
reg_v0,
|
||||
reg_v1,
|
||||
reg_v2,
|
||||
reg_v3,
|
||||
reg_v4,
|
||||
reg_v5,
|
||||
reg_v6,
|
||||
reg_v7,
|
||||
reg_v8,
|
||||
reg_v9,
|
||||
reg_v10,
|
||||
reg_v11,
|
||||
reg_v12,
|
||||
reg_v13,
|
||||
reg_v14,
|
||||
reg_v15,
|
||||
reg_v16,
|
||||
reg_v17,
|
||||
reg_v18,
|
||||
reg_v19,
|
||||
reg_v20,
|
||||
reg_v21,
|
||||
reg_v22,
|
||||
reg_v23,
|
||||
reg_v24,
|
||||
reg_v25,
|
||||
reg_v26,
|
||||
reg_v27,
|
||||
reg_v28,
|
||||
reg_v29,
|
||||
reg_v30,
|
||||
reg_v31,
|
||||
reg_d0,
|
||||
reg_d1,
|
||||
reg_d2,
|
||||
reg_d3,
|
||||
reg_d4,
|
||||
reg_d5,
|
||||
reg_d6,
|
||||
reg_d7,
|
||||
reg_d8,
|
||||
reg_d9,
|
||||
reg_d10,
|
||||
reg_d11,
|
||||
reg_d12,
|
||||
reg_d13,
|
||||
reg_d14,
|
||||
reg_d15,
|
||||
reg_d16,
|
||||
reg_d17,
|
||||
reg_d18,
|
||||
reg_d19,
|
||||
reg_d20,
|
||||
reg_d21,
|
||||
reg_d22,
|
||||
reg_d23,
|
||||
reg_d24,
|
||||
reg_d25,
|
||||
reg_d26,
|
||||
reg_d27,
|
||||
reg_d28,
|
||||
reg_d29,
|
||||
reg_d30,
|
||||
reg_d31,
|
||||
reg_s0,
|
||||
reg_s1,
|
||||
reg_s2,
|
||||
reg_s3,
|
||||
reg_s4,
|
||||
reg_s5,
|
||||
reg_s6,
|
||||
reg_s7,
|
||||
reg_s8,
|
||||
reg_s9,
|
||||
reg_s10,
|
||||
reg_s11,
|
||||
reg_s12,
|
||||
reg_s13,
|
||||
reg_s14,
|
||||
reg_s15,
|
||||
reg_s16,
|
||||
reg_s17,
|
||||
reg_s18,
|
||||
reg_s19,
|
||||
reg_s20,
|
||||
reg_s21,
|
||||
reg_s22,
|
||||
reg_s23,
|
||||
reg_s24,
|
||||
reg_s25,
|
||||
reg_s26,
|
||||
reg_s27,
|
||||
reg_s28,
|
||||
reg_s29,
|
||||
reg_s30,
|
||||
reg_s31,
|
||||
reg_h0,
|
||||
reg_h1,
|
||||
reg_h2,
|
||||
reg_h3,
|
||||
reg_h4,
|
||||
reg_h5,
|
||||
reg_h6,
|
||||
reg_h7,
|
||||
reg_h8,
|
||||
reg_h9,
|
||||
reg_h10,
|
||||
reg_h11,
|
||||
reg_h12,
|
||||
reg_h13,
|
||||
reg_h14,
|
||||
reg_h15,
|
||||
reg_h16,
|
||||
reg_h17,
|
||||
reg_h18,
|
||||
reg_h19,
|
||||
reg_h20,
|
||||
reg_h21,
|
||||
reg_h22,
|
||||
reg_h23,
|
||||
reg_h24,
|
||||
reg_h25,
|
||||
reg_h26,
|
||||
reg_h27,
|
||||
reg_h28,
|
||||
reg_h29,
|
||||
reg_h30,
|
||||
reg_h31,
|
||||
reg_fpsr,
|
||||
reg_fpcr,
|
||||
LLDB_INVALID_REGNUM // register sets need to end with this flag
|
||||
};
|
||||
|
||||
// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1
|
||||
constexpr size_t k_num_gpr_regs = llvm::array_lengthof(g_gpr_regnums) - 1;
|
||||
constexpr size_t k_num_fpu_regs = llvm::array_lengthof(g_fpu_regnums) - 1;
|
||||
|
||||
static RegisterSet g_reg_sets[] = {
|
||||
{"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums},
|
||||
{"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums},
|
||||
};
|
||||
|
||||
constexpr size_t k_num_reg_sets = llvm::array_lengthof(g_reg_sets);
|
||||
|
||||
RegisterContextMinidump_ARM64::RegisterContextMinidump_ARM64(
|
||||
Thread &thread, const DataExtractor &data)
|
||||
: RegisterContext(thread, 0) {
|
||||
lldb::offset_t offset = 0;
|
||||
m_regs.context_flags = data.GetU64(&offset);
|
||||
for (unsigned i = 0; i < 32; ++i)
|
||||
m_regs.x[i] = data.GetU64(&offset);
|
||||
m_regs.pc = data.GetU64(&offset);
|
||||
m_regs.cpsr = data.GetU32(&offset);
|
||||
m_regs.fpsr = data.GetU32(&offset);
|
||||
m_regs.fpcr = data.GetU32(&offset);
|
||||
auto regs_data = data.GetData(&offset, sizeof(m_regs.v));
|
||||
if (regs_data)
|
||||
memcpy(m_regs.v, regs_data, sizeof(m_regs.v));
|
||||
assert(k_num_regs == k_num_reg_infos);
|
||||
}
|
||||
size_t RegisterContextMinidump_ARM64::GetRegisterCount() { return k_num_regs; }
|
||||
|
||||
const RegisterInfo *
|
||||
RegisterContextMinidump_ARM64::GetRegisterInfoAtIndex(size_t reg) {
|
||||
if (reg < k_num_reg_infos)
|
||||
return &g_reg_infos[reg];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t RegisterContextMinidump_ARM64::GetRegisterSetCount() {
|
||||
return k_num_reg_sets;
|
||||
}
|
||||
|
||||
const RegisterSet *RegisterContextMinidump_ARM64::GetRegisterSet(size_t set) {
|
||||
if (set < k_num_reg_sets)
|
||||
return &g_reg_sets[set];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *RegisterContextMinidump_ARM64::GetRegisterName(unsigned reg) {
|
||||
if (reg < k_num_reg_infos)
|
||||
return g_reg_infos[reg].name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool RegisterContextMinidump_ARM64::ReadRegister(const RegisterInfo *reg_info,
|
||||
RegisterValue ®_value) {
|
||||
Status error;
|
||||
reg_value.SetFromMemoryData(
|
||||
reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset,
|
||||
reg_info->byte_size, lldb::eByteOrderLittle, error);
|
||||
return error.Success();
|
||||
}
|
||||
|
||||
bool RegisterContextMinidump_ARM64::WriteRegister(const RegisterInfo *,
|
||||
const RegisterValue &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t RegisterContextMinidump_ARM64::ConvertRegisterKindToRegisterNumber(
|
||||
lldb::RegisterKind kind, uint32_t num) {
|
||||
for (size_t i = 0; i < k_num_regs; ++i) {
|
||||
if (g_reg_infos[i].kinds[kind] == num)
|
||||
return i;
|
||||
}
|
||||
return LLDB_INVALID_REGNUM;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//===-- RegisterContextMinidump_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_RegisterContextMinidump_ARM64_h_
|
||||
#define liblldb_RegisterContextMinidump_ARM64_h_
|
||||
|
||||
// Project includes
|
||||
#include "MinidumpTypes.h"
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "Plugins/Process/Utility/RegisterInfoInterface.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
|
||||
// C includes
|
||||
// C++ includes
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
namespace minidump {
|
||||
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
|
||||
class RegisterContextMinidump_ARM64 : public lldb_private::RegisterContext {
|
||||
public:
|
||||
RegisterContextMinidump_ARM64(lldb_private::Thread &thread,
|
||||
const DataExtractor &data);
|
||||
|
||||
~RegisterContextMinidump_ARM64() override = default;
|
||||
|
||||
void InvalidateAllRegisters() override {
|
||||
// Do nothing... registers are always valid...
|
||||
}
|
||||
|
||||
size_t GetRegisterCount() override;
|
||||
|
||||
const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
|
||||
|
||||
size_t GetRegisterSetCount() override;
|
||||
|
||||
const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
|
||||
|
||||
const char *GetRegisterName(unsigned reg);
|
||||
|
||||
bool ReadRegister(const RegisterInfo *reg_info,
|
||||
RegisterValue ®_value) override;
|
||||
|
||||
bool WriteRegister(const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_value) override;
|
||||
|
||||
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
|
||||
uint32_t num) override;
|
||||
|
||||
// Reference: see breakpad/crashpad source
|
||||
struct Context {
|
||||
uint64_t context_flags;
|
||||
uint64_t x[32];
|
||||
uint64_t pc;
|
||||
uint32_t cpsr;
|
||||
uint32_t fpsr;
|
||||
uint32_t fpcr;
|
||||
uint8_t v[32 * 16]; // 32 128-bit floating point registers
|
||||
};
|
||||
|
||||
protected:
|
||||
enum class Flags : uint32_t {
|
||||
ARM64_Flag = 0x80000000,
|
||||
Integer = ARM64_Flag | 0x00000002,
|
||||
FloatingPoint = ARM64_Flag | 0x00000004,
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint)
|
||||
};
|
||||
Context m_regs;
|
||||
};
|
||||
|
||||
} // end namespace minidump
|
||||
} // end namespace lldb_private
|
||||
#endif // liblldb_RegisterContextMinidump_ARM64_h_
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "ThreadMinidump.h"
|
||||
#include "ProcessMinidump.h"
|
||||
|
||||
#include "RegisterContextMinidump_ARM.h"
|
||||
#include "RegisterContextMinidump_ARM64.h"
|
||||
#include "RegisterContextMinidump_x86_32.h"
|
||||
#include "RegisterContextMinidump_x86_64.h"
|
||||
|
||||
@@ -88,15 +90,22 @@ ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) {
|
||||
*this, reg_interface, gpregset, {}));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case llvm::Triple::aarch64: {
|
||||
DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(),
|
||||
lldb::eByteOrderLittle, 8);
|
||||
m_thread_reg_ctx_sp.reset(new RegisterContextMinidump_ARM64(*this, data));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reg_interface) {
|
||||
if (log)
|
||||
log->Printf("elf-core::%s:: Architecture(%d) not supported",
|
||||
__FUNCTION__, arch.GetMachine());
|
||||
assert(false && "Architecture not supported");
|
||||
case llvm::Triple::arm: {
|
||||
DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(),
|
||||
lldb::eByteOrderLittle, 8);
|
||||
const bool apple = arch.GetTriple().getVendor() == llvm::Triple::Apple;
|
||||
m_thread_reg_ctx_sp.reset(
|
||||
new RegisterContextMinidump_ARM(*this, data, apple));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
reg_ctx_sp = m_thread_reg_ctx_sp;
|
||||
|
||||
@@ -1426,13 +1426,33 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
|
||||
}
|
||||
}
|
||||
|
||||
bool Target::SetArchitecture(const ArchSpec &arch_spec) {
|
||||
bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform) {
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET));
|
||||
bool missing_local_arch = !m_arch.GetSpec().IsValid();
|
||||
bool replace_local_arch = true;
|
||||
bool compatible_local_arch = false;
|
||||
ArchSpec other(arch_spec);
|
||||
|
||||
// Changing the architecture might mean that the currently selected platform
|
||||
// isn't compatible. Set the platform correctly if we are asked to do so,
|
||||
// otherwise assume the user will set the platform manually.
|
||||
if (set_platform) {
|
||||
if (other.IsValid()) {
|
||||
auto platform_sp = GetPlatform();
|
||||
if (!platform_sp ||
|
||||
!platform_sp->IsCompatibleArchitecture(other, false, nullptr)) {
|
||||
ArchSpec platform_arch;
|
||||
auto arch_platform_sp =
|
||||
Platform::GetPlatformForArchitecture(other, &platform_arch);
|
||||
if (arch_platform_sp) {
|
||||
SetPlatform(arch_platform_sp);
|
||||
if (platform_arch.IsValid())
|
||||
other = platform_arch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!missing_local_arch) {
|
||||
if (m_arch.GetSpec().IsCompatibleMatch(arch_spec)) {
|
||||
other.MergeFrom(m_arch.GetSpec());
|
||||
|
||||
Reference in New Issue
Block a user