Skip to content

Commit

Permalink
Add support for ARM and ARM64 breakpad generated minidump files
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Greg Clayton committed Aug 2, 2018
1 parent 92b1673 commit 2d953f2
Show file tree
Hide file tree
Showing 16 changed files with 1,860 additions and 91 deletions.
30 changes: 16 additions & 14 deletions lldb/include/lldb/Target/Target.h
Expand Up @@ -913,28 +913,30 @@ class Target : public std::enable_shared_from_this<Target>,
/// 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);

Expand Down
16 changes: 16 additions & 0 deletions lldb/lldb.xcodeproj/project.pbxproj
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down
Expand Up @@ -42,7 +42,7 @@
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "DebugClang"
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "1"
Expand Down
Expand Up @@ -189,6 +189,161 @@ def test_snapshot_minidump(self):
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)
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 2d953f2

Please sign in to comment.