Skip to content

Commit 16eb777

Browse files
authored
Merge pull request #3269 from apple/cherry-82898146-to-20210726
[MachCore] Report arm64 thread exception state
2 parents 77865db + 7b1f0cb commit 16eb777

File tree

10 files changed

+231
-10
lines changed

10 files changed

+231
-10
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*===-- AppleArm64ExceptionClass.def ---------------------------*- C++ -*-=== *\
2+
|*
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
|* See https://llvm.org/LICENSE.txt for license information.
5+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
|*
7+
\*===----------------------------------------------------------------------===*/
8+
9+
// Defines ESR exception classes for Apple arm64* targets.
10+
// These largely map 1:1 to the exception classes defined in ARM's architecture
11+
// reference manual, but there are some Apple-specific additions.
12+
13+
#ifndef APPLE_ARM64_EXCEPTION_CLASS
14+
#error "APPLE_ARM64_EXCEPTION_CLASS(Name, Code) not defined."
15+
#endif
16+
17+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_UNCATEGORIZED, 0x00)
18+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WFI_WFE, 0x01)
19+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCR_MRC_CP15_TRAP, 0x03)
20+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCRR_MRRC_CP15_TRAP, 0x04)
21+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCR_MRC_CP14_TRAP, 0x05)
22+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_LDC_STC_CP14_TRAP, 0x06)
23+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_TRAP_SIMD_FP, 0x07)
24+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PTRAUTH_INSTR_TRAP, 0x09)
25+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MCRR_MRRC_CP14_TRAP, 0x0c)
26+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_ILLEGAL_INSTR_SET, 0x0e)
27+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SVC_32, 0x11)
28+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SVC_64, 0x15)
29+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_MSR_TRAP, 0x18)
30+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PAC_FAIL, 0x1C)
31+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_IABORT_EL0, 0x20)
32+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_IABORT_EL1, 0x21)
33+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PC_ALIGN, 0x22)
34+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_DABORT_EL0, 0x24)
35+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_DABORT_EL1, 0x25)
36+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SP_ALIGN, 0x26)
37+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_FLOATING_POINT_32, 0x28)
38+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_FLOATING_POINT_64, 0x2C)
39+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SERROR_INTERRUPT, 0x2F)
40+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_REG_MATCH_EL0, 0x30)
41+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_REG_MATCH_EL1, 0x31)
42+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SW_STEP_DEBUG_EL0, 0x32)
43+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_SW_STEP_DEBUG_EL1, 0x33)
44+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WATCHPT_MATCH_EL0, 0x34)
45+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_WATCHPT_MATCH_EL1, 0x35)
46+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BKPT_AARCH32, 0x38)
47+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_BRK_AARCH64, 0x3C)
48+
APPLE_ARM64_EXCEPTION_CLASS(ESR_EC_PRIV, 0x3F)
49+
50+
#undef APPLE_ARM64_EXCEPTION_CLASS
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===-- AppleArm64ExceptionClass.h ------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
10+
#define LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H
11+
12+
#include <cstdint>
13+
14+
namespace lldb_private {
15+
16+
enum class AppleArm64ExceptionClass : unsigned {
17+
#define APPLE_ARM64_EXCEPTION_CLASS(Name, Code) Name = Code,
18+
#include "AppleArm64ExceptionClass.def"
19+
};
20+
21+
/// Get the Apple ARM64 exception class encoded within \p esr.
22+
inline AppleArm64ExceptionClass getAppleArm64ExceptionClass(uint32_t esr) {
23+
/*
24+
* Exception Syndrome Register
25+
*
26+
* 31 26 25 24 0
27+
* +------+--+------------------+
28+
* | EC |IL| ISS |
29+
* +------+--+------------------+
30+
*
31+
* EC - Exception Class
32+
* IL - Instruction Length
33+
* ISS - Instruction Specific Syndrome
34+
*/
35+
return static_cast<AppleArm64ExceptionClass>(esr >> 26);
36+
}
37+
38+
inline const char *toString(AppleArm64ExceptionClass EC) {
39+
switch (EC) {
40+
#define APPLE_ARM64_EXCEPTION_CLASS(Name, Code) \
41+
case AppleArm64ExceptionClass::Name: \
42+
return #Name;
43+
#include "AppleArm64ExceptionClass.def"
44+
}
45+
return "Unknown Exception Class";
46+
}
47+
48+
} // namespace lldb_private
49+
50+
#endif // LLDB_TARGET_APPLEARM64EXCEPTIONCLASS_H

lldb/include/lldb/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ module lldb_Wrapper {
119119
requires cplusplus
120120

121121
umbrella "Target"
122+
textual header "Target/AppleArm64ExceptionClass.def"
122123
module * { export * }
123124
}
124125
}

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -749,13 +749,14 @@ class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 {
749749
PrintRegisterValue(reg_ctx, "sp", nullptr, 8, data);
750750
PrintRegisterValue(reg_ctx, "pc", nullptr, 8, data);
751751
PrintRegisterValue(reg_ctx, "cpsr", nullptr, 4, data);
752+
data.PutHex32(0); // uint32_t pad at the end
752753

753754
// Write out the EXC registers
754-
// data.PutHex32 (EXCRegSet);
755-
// data.PutHex32 (EXCWordCount);
756-
// WriteRegister (reg_ctx, "far", NULL, 8, data);
757-
// WriteRegister (reg_ctx, "esr", NULL, 4, data);
758-
// WriteRegister (reg_ctx, "exception", NULL, 4, data);
755+
data.PutHex32(EXCRegSet);
756+
data.PutHex32(EXCWordCount);
757+
PrintRegisterValue(reg_ctx, "far", NULL, 8, data);
758+
PrintRegisterValue(reg_ctx, "esr", NULL, 4, data);
759+
PrintRegisterValue(reg_ctx, "exception", NULL, 4, data);
759760
return true;
760761
}
761762
return false;

lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@
99
#include "ThreadMachCore.h"
1010

1111
#include "lldb/Breakpoint/Watchpoint.h"
12+
#include "lldb/Host/SafeMachO.h"
1213
#include "lldb/Symbol/ObjectFile.h"
14+
#include "lldb/Target/AppleArm64ExceptionClass.h"
1315
#include "lldb/Target/Process.h"
1416
#include "lldb/Target/RegisterContext.h"
1517
#include "lldb/Target/StopInfo.h"
1618
#include "lldb/Target/Target.h"
1719
#include "lldb/Target/Unwind.h"
1820
#include "lldb/Utility/ArchSpec.h"
1921
#include "lldb/Utility/DataExtractor.h"
22+
#include "lldb/Utility/RegisterValue.h"
2023
#include "lldb/Utility/State.h"
2124
#include "lldb/Utility/StreamString.h"
2225

@@ -88,10 +91,55 @@ ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) {
8891
return reg_ctx_sp;
8992
}
9093

94+
static bool IsCrashExceptionClass(AppleArm64ExceptionClass EC) {
95+
switch (EC) {
96+
case AppleArm64ExceptionClass::ESR_EC_UNCATEGORIZED:
97+
case AppleArm64ExceptionClass::ESR_EC_SVC_32:
98+
case AppleArm64ExceptionClass::ESR_EC_SVC_64:
99+
// In the ARM exception model, a process takes an exception when asking the
100+
// kernel to service a system call. Don't treat this like a crash.
101+
return false;
102+
default:
103+
return true;
104+
}
105+
}
106+
91107
bool ThreadMachCore::CalculateStopInfo() {
92108
ProcessSP process_sp(GetProcess());
93109
if (process_sp) {
94-
SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, SIGSTOP));
110+
StopInfoSP stop_info;
111+
RegisterContextSP reg_ctx_sp = GetRegisterContext();
112+
113+
if (reg_ctx_sp) {
114+
Target &target = process_sp->GetTarget();
115+
const ArchSpec arch_spec = target.GetArchitecture();
116+
const uint32_t cputype = arch_spec.GetMachOCPUType();
117+
118+
if (cputype == llvm::MachO::CPU_TYPE_ARM64 ||
119+
cputype == llvm::MachO::CPU_TYPE_ARM64_32) {
120+
const RegisterInfo *esr_info = reg_ctx_sp->GetRegisterInfoByName("esr");
121+
const RegisterInfo *far_info = reg_ctx_sp->GetRegisterInfoByName("far");
122+
RegisterValue esr, far;
123+
if (reg_ctx_sp->ReadRegister(esr_info, esr) &&
124+
reg_ctx_sp->ReadRegister(far_info, far)) {
125+
const uint32_t esr_val = esr.GetAsUInt32();
126+
const AppleArm64ExceptionClass exception_class =
127+
getAppleArm64ExceptionClass(esr_val);
128+
if (IsCrashExceptionClass(exception_class)) {
129+
StreamString S;
130+
S.Printf("%s (fault address: 0x%" PRIx64 ")",
131+
toString(exception_class), far.GetAsUInt64());
132+
stop_info =
133+
StopInfo::CreateStopReasonWithException(*this, S.GetData());
134+
}
135+
}
136+
}
137+
}
138+
139+
// Set a stop reason for crashing threads only so that they get selected
140+
// preferentially.
141+
if (stop_info)
142+
SetStopInfo(stop_info);
95143
return true;
96144
}
97145
return false;

lldb/test/API/functionalities/postmortem/mach-core/TestMachCore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@ def test_selected_thread(self):
5858

5959
# Verify that the correct thread is selected
6060
thread = process.GetSelectedThread()
61-
self.assertEqual(thread.GetThreadID(), 0x333333333)
61+
self.assertEqual(thread.GetThreadID(), 0x111111111)

lldb/test/API/functionalities/postmortem/mach-core/operating_system.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,25 @@ def get_target(self):
2121

2222
def get_thread_info(self):
2323
if not self.threads:
24+
# FIXME: LLDB is not actually parsing thread stop reasons.
2425
self.threads = [{
2526
'tid': 0x111111111,
2627
'name': 'one',
2728
'queue': 'queue1',
2829
'state': 'stopped',
29-
'stop_reason': 'none'
30+
'stop_reason': 'not parsed'
3031
}, {
3132
'tid': 0x222222222,
3233
'name': 'two',
3334
'queue': 'queue2',
3435
'state': 'stopped',
35-
'stop_reason': 'none'
36+
'stop_reason': 'not parsed'
3637
}, {
3738
'tid': 0x333333333,
3839
'name': 'three',
3940
'queue': 'queue3',
4041
'state': 'stopped',
41-
'stop_reason': 'sigstop',
42+
'stop_reason': 'not parsed - should be "sigstop" though',
4243
'core': 0
4344
}]
4445
return self.threads
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES = main.cpp
2+
3+
include Makefile.rules
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Test that lldb can report the exception reason for threads in a corefile."""
2+
3+
import os
4+
import re
5+
import subprocess
6+
7+
import lldb
8+
from lldbsuite.test.decorators import *
9+
from lldbsuite.test.lldbtest import *
10+
from lldbsuite.test import lldbutil
11+
12+
class TestCorefileExceptionReason(TestBase):
13+
14+
mydir = TestBase.compute_mydir(__file__)
15+
16+
@skipIfOutOfTreeDebugserver # newer debugserver required for these qMemoryRegionInfo types
17+
@no_debug_info_test
18+
@skipUnlessDarwin
19+
@skipIf(archs=no_match(['arm64','arm64e']))
20+
def test(self):
21+
22+
corefile = self.getBuildArtifact("process.core")
23+
self.build()
24+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
25+
self, "// break here", lldb.SBFileSpec("main.cpp"))
26+
27+
self.runCmd("continue")
28+
29+
self.runCmd("process save-core -s stack " + corefile)
30+
process.Kill()
31+
self.dbg.DeleteTarget(target)
32+
33+
# Now load the corefile
34+
target = self.dbg.CreateTarget('')
35+
process = target.LoadCore(corefile)
36+
thread = process.GetSelectedThread()
37+
self.assertTrue(process.GetSelectedThread().IsValid())
38+
if self.TraceOn():
39+
self.runCmd("image list")
40+
self.runCmd("bt")
41+
self.runCmd("fr v")
42+
43+
self.assertTrue(thread.GetStopDescription(256) == "ESR_EC_DABORT_EL0 (fault address: 0x0)")
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <stdlib.h>
2+
#include <thread>
3+
#include <unistd.h>
4+
#include <vector>
5+
6+
void *sleep_worker(void *in) {
7+
sleep(30);
8+
sleep(30);
9+
return nullptr;
10+
}
11+
12+
void *crash_worker(void *in) {
13+
sleep(1);
14+
volatile int *p = nullptr; // break here
15+
return (void *)*p;
16+
}
17+
18+
int main() {
19+
std::vector<std::thread> threads;
20+
threads.push_back(std::move(std::thread(crash_worker, nullptr)));
21+
for (int i = 0; i < 15; i++)
22+
threads.push_back(std::move(std::thread(sleep_worker, nullptr)));
23+
sleep(10);
24+
}

0 commit comments

Comments
 (0)