[Lldb-commits] [lldb] 7eb6774 - [MachCore] Report arm64 thread exception state
Vedant Kumar via lldb-commits
lldb-commits at lists.llvm.org
Thu Sep 16 13:35:18 PDT 2021
Author: Vedant Kumar
Date: 2021-09-16T13:35:06-07:00
New Revision: 7eb67748f9d7186419d678e807c01fc2a3811a80
URL: https://github.com/llvm/llvm-project/commit/7eb67748f9d7186419d678e807c01fc2a3811a80
DIFF: https://github.com/llvm/llvm-project/commit/7eb67748f9d7186419d678e807c01fc2a3811a80.diff
LOG: [MachCore] Report arm64 thread exception state
A MachO userspace corefile may contain LC_THREAD commands which specify
thread exception state.
For arm64* only (for now), report a human-readable version of this state
as the thread stop reason, instead of 'SIGSTOP'.
As a follow-up, similar functionality can be implemented for x86 cores
by translating the trapno/err exception registers.
rdar://82898146
Differential Revision: https://reviews.llvm.org/D109795
Added:
lldb/include/lldb/Target/AppleArm64ExceptionClass.def
lldb/include/lldb/Target/AppleArm64ExceptionClass.h
lldb/test/API/macosx/corefile-exception-reason/Makefile
lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py
lldb/test/API/macosx/corefile-exception-reason/main.cpp
Modified:
lldb/include/lldb/module.modulemap
lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Target/AppleArm64ExceptionClass.def b/lldb/include/lldb/Target/AppleArm64ExceptionClass.def
new file mode 100644
index 0000000000000..9a938c3b302c8
--- /dev/null
+++ b/lldb/include/lldb/Target/AppleArm64ExceptionClass.def
@@ -0,0 +1,50 @@
+/*===-- AppleArm64ExceptionClass.def ---------------------------*- C++ -*-=== *\
+|*
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+|* See https://llvm.org/LICENSE.txt for license information.
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+|*
+\*===----------------------------------------------------------------------===*/
+
+// Defines ESR exception classes for Apple arm64* targets.
+// These largely map 1:1 to the exception classes defined in ARM's architecture
+// reference manual, but there are some Apple-specific additions.
+
+#ifndef APPLE_ARM64_EXCEPTION_CLASS
+#error "APPLE_ARM64_EXCEPTION_CLASS(Name, Code) not defined."
+#endif
+
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_UNCATEGORIZED, 0x00)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WFI_WFE, 0x01)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCR_MRC_CP15_TRAP, 0x03)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCRR_MRRC_CP15_TRAP, 0x04)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCR_MRC_CP14_TRAP, 0x05)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_LDC_STC_CP14_TRAP, 0x06)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_TRAP_SIMD_FP, 0x07)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PTRAUTH_INSTR_TRAP, 0x09)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCRR_MRRC_CP14_TRAP, 0x0c)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_ILLEGAL_INSTR_SET, 0x0e)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SVC_32, 0x11)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SVC_64, 0x15)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MSR_TRAP, 0x18)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PAC_FAIL, 0x1C)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_IABORT_EL0, 0x20)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_IABORT_EL1, 0x21)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PC_ALIGN, 0x22)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_DABORT_EL0, 0x24)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_DABORT_EL1, 0x25)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SP_ALIGN, 0x26)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_FLOATING_POINT_32, 0x28)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_FLOATING_POINT_64, 0x2C)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SERROR_INTERRUPT, 0x2F)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_REG_MATCH_EL0, 0x30)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_REG_MATCH_EL1, 0x31)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SW_STEP_DEBUG_EL0, 0x32)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SW_STEP_DEBUG_EL1, 0x33)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WATCHPT_MATCH_EL0, 0x34)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WATCHPT_MATCH_EL1, 0x35)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_AARCH32, 0x38)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BRK_AARCH64, 0x3C)
+APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PRIV, 0x3F)
+
+#undef APPLE_ARM64_EXCEPTION_CLASS
diff --git a/lldb/include/lldb/Target/AppleArm64ExceptionClass.h b/lldb/include/lldb/Target/AppleArm64ExceptionClass.h
new file mode 100644
index 0000000000000..95f58ee081abf
--- /dev/null
+++ b/lldb/include/lldb/Target/AppleArm64ExceptionClass.h
@@ -0,0 +1,50 @@
+//===-- AppleArm64ExceptionClass.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
+#define LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
+
+#include <cstdint>
+
+namespace lldb_private {
+
+enum class AppleArm64ExceptionClass : unsigned {
+#define APPLE_ARM64_EXCEPTION_CLASS(Name, Code) Name = Code,
+#include "AppleArm64ExceptionClass.def"
+};
+
+/// Get the Apple ARM64 exception class encoded within \p esr.
+inline AppleArm64ExceptionClass getAppleArm64ExceptionClass(uint32_t esr) {
+ /*
+ * Exception Syndrome Register
+ *
+ * 31 26 25 24 0
+ * +------+--+------------------+
+ * | EC |IL| ISS |
+ * +------+--+------------------+
+ *
+ * EC - Exception Class
+ * IL - Instruction Length
+ * ISS - Instruction Specific Syndrome
+ */
+ return static_cast<AppleArm64ExceptionClass>(esr >> 26);
+}
+
+inline const char *toString(AppleArm64ExceptionClass EC) {
+ switch (EC) {
+#define APPLE_ARM64_EXCEPTION_CLASS(Name, Code) \
+ case AppleArm64ExceptionClass::Name: \
+ return #Name;
+#include "AppleArm64ExceptionClass.def"
+ }
+ return "Unknown Exception Class";
+}
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
diff --git a/lldb/include/lldb/module.modulemap b/lldb/include/lldb/module.modulemap
index 7feea8ee99c34..1ddaa1fb737d7 100644
--- a/lldb/include/lldb/module.modulemap
+++ b/lldb/include/lldb/module.modulemap
@@ -119,6 +119,7 @@ module lldb_Wrapper {
requires cplusplus
umbrella "Target"
+ textual header "Target/AppleArm64ExceptionClass.def"
module * { export * }
}
}
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 99aef04ab6038..e89cdb334009b 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -745,13 +745,14 @@ class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 {
PrintRegisterValue(reg_ctx, "sp", nullptr, 8, data);
PrintRegisterValue(reg_ctx, "pc", nullptr, 8, data);
PrintRegisterValue(reg_ctx, "cpsr", nullptr, 4, data);
+ data.PutHex32(0); // uint32_t pad at the end
// Write out the EXC registers
- // data.PutHex32 (EXCRegSet);
- // data.PutHex32 (EXCWordCount);
- // WriteRegister (reg_ctx, "far", NULL, 8, data);
- // WriteRegister (reg_ctx, "esr", NULL, 4, data);
- // WriteRegister (reg_ctx, "exception", NULL, 4, data);
+ data.PutHex32(EXCRegSet);
+ data.PutHex32(EXCWordCount);
+ PrintRegisterValue(reg_ctx, "far", NULL, 8, data);
+ PrintRegisterValue(reg_ctx, "esr", NULL, 4, data);
+ PrintRegisterValue(reg_ctx, "exception", NULL, 4, data);
return true;
}
return false;
diff --git a/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
index 1950baea41278..8e31d95a8dab5 100644
--- a/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp
@@ -9,7 +9,9 @@
#include "ThreadMachCore.h"
#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Host/SafeMachO.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/AppleArm64ExceptionClass.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
@@ -17,6 +19,7 @@
#include "lldb/Target/Unwind.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
@@ -88,10 +91,55 @@ ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) {
return reg_ctx_sp;
}
+static bool IsCrashExceptionClass(AppleArm64ExceptionClass EC) {
+ switch (EC) {
+ case AppleArm64ExceptionClass::ESR_EC_UNCATEGORIZED:
+ case AppleArm64ExceptionClass::ESR_EC_SVC_32:
+ case AppleArm64ExceptionClass::ESR_EC_SVC_64:
+ // In the ARM exception model, a process takes an exception when asking the
+ // kernel to service a system call. Don't treat this like a crash.
+ return false;
+ default:
+ return true;
+ }
+}
+
bool ThreadMachCore::CalculateStopInfo() {
ProcessSP process_sp(GetProcess());
if (process_sp) {
- SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, SIGSTOP));
+ StopInfoSP stop_info;
+ RegisterContextSP reg_ctx_sp = GetRegisterContext();
+
+ if (reg_ctx_sp) {
+ Target &target = process_sp->GetTarget();
+ const ArchSpec arch_spec = target.GetArchitecture();
+ const uint32_t cputype = arch_spec.GetMachOCPUType();
+
+ if (cputype == llvm::MachO::CPU_TYPE_ARM64 ||
+ cputype == llvm::MachO::CPU_TYPE_ARM64_32) {
+ const RegisterInfo *esr_info = reg_ctx_sp->GetRegisterInfoByName("esr");
+ const RegisterInfo *far_info = reg_ctx_sp->GetRegisterInfoByName("far");
+ RegisterValue esr, far;
+ if (reg_ctx_sp->ReadRegister(esr_info, esr) &&
+ reg_ctx_sp->ReadRegister(far_info, far)) {
+ const uint32_t esr_val = esr.GetAsUInt32();
+ const AppleArm64ExceptionClass exception_class =
+ getAppleArm64ExceptionClass(esr_val);
+ if (IsCrashExceptionClass(exception_class)) {
+ StreamString S;
+ S.Printf("%s (fault address: 0x%" PRIx64 ")",
+ toString(exception_class), far.GetAsUInt64());
+ stop_info =
+ StopInfo::CreateStopReasonWithException(*this, S.GetData());
+ }
+ }
+ }
+ }
+
+ // Set a stop reason for crashing threads only so that they get selected
+ // preferentially.
+ if (stop_info)
+ SetStopInfo(stop_info);
return true;
}
return false;
diff --git a/lldb/test/API/macosx/corefile-exception-reason/Makefile b/lldb/test/API/macosx/corefile-exception-reason/Makefile
new file mode 100644
index 0000000000000..82f96b62609fb
--- /dev/null
+++ b/lldb/test/API/macosx/corefile-exception-reason/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES = main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py b/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py
new file mode 100644
index 0000000000000..0468685110be5
--- /dev/null
+++ b/lldb/test/API/macosx/corefile-exception-reason/TestCorefileExceptionReason.py
@@ -0,0 +1,43 @@
+"""Test that lldb can report the exception reason for threads in a corefile."""
+
+import os
+import re
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestCorefileExceptionReason(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfOutOfTreeDebugserver # newer debugserver required for these qMemoryRegionInfo types
+ @no_debug_info_test
+ @skipUnlessDarwin
+ @skipIf(archs=no_match(['arm64','arm64e']))
+ def test(self):
+
+ corefile = self.getBuildArtifact("process.core")
+ self.build()
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+ self, "// break here", lldb.SBFileSpec("main.cpp"))
+
+ self.runCmd("continue")
+
+ self.runCmd("process save-core -s stack " + corefile)
+ process.Kill()
+ self.dbg.DeleteTarget(target)
+
+ # Now load the corefile
+ target = self.dbg.CreateTarget('')
+ process = target.LoadCore(corefile)
+ thread = process.GetSelectedThread()
+ self.assertTrue(process.GetSelectedThread().IsValid())
+ if self.TraceOn():
+ self.runCmd("image list")
+ self.runCmd("bt")
+ self.runCmd("fr v")
+
+ self.assertTrue(thread.GetStopDescription(256) == "ESR_EC_DABORT_EL0 (fault address: 0x0)")
diff --git a/lldb/test/API/macosx/corefile-exception-reason/main.cpp b/lldb/test/API/macosx/corefile-exception-reason/main.cpp
new file mode 100644
index 0000000000000..aa32441feec69
--- /dev/null
+++ b/lldb/test/API/macosx/corefile-exception-reason/main.cpp
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include <thread>
+#include <unistd.h>
+#include <vector>
+
+void *sleep_worker(void *in) {
+ sleep(30);
+ sleep(30);
+ return nullptr;
+}
+
+void *crash_worker(void *in) {
+ sleep(1);
+ volatile int *p = nullptr; // break here
+ return (void *)*p;
+}
+
+int main() {
+ std::vector<std::thread> threads;
+ threads.push_back(std::move(std::thread(crash_worker, nullptr)));
+ for (int i = 0; i < 15; i++)
+ threads.push_back(std::move(std::thread(sleep_worker, nullptr)));
+ sleep(10);
+}
More information about the lldb-commits
mailing list