180814287SRaphael Isemann //===-- ThreadMachCore.cpp ------------------------------------------------===//
2c3776bf2SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c3776bf2SGreg Clayton //
7c3776bf2SGreg Clayton //===----------------------------------------------------------------------===//
8c3776bf2SGreg Clayton
9c3776bf2SGreg Clayton #include "ThreadMachCore.h"
10c3776bf2SGreg Clayton
11b9c1b51eSKate Stone #include "lldb/Breakpoint/Watchpoint.h"
12*3b14d80aSVedant Kumar #include "lldb/Host/SafeMachO.h"
131f746071SGreg Clayton #include "lldb/Symbol/ObjectFile.h"
14*3b14d80aSVedant Kumar #include "lldb/Target/AppleArm64ExceptionClass.h"
15c3776bf2SGreg Clayton #include "lldb/Target/Process.h"
16c3776bf2SGreg Clayton #include "lldb/Target/RegisterContext.h"
17c3776bf2SGreg Clayton #include "lldb/Target/StopInfo.h"
18c3776bf2SGreg Clayton #include "lldb/Target/Target.h"
19c3776bf2SGreg Clayton #include "lldb/Target/Unwind.h"
202da1b597SPavel Labath #include "lldb/Utility/ArchSpec.h"
21666cc0b2SZachary Turner #include "lldb/Utility/DataExtractor.h"
22*3b14d80aSVedant Kumar #include "lldb/Utility/RegisterValue.h"
23d821c997SPavel Labath #include "lldb/Utility/State.h"
24bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
25c3776bf2SGreg Clayton
26c3776bf2SGreg Clayton #include "ProcessMachCore.h"
27c3776bf2SGreg Clayton //#include "RegisterContextKDP_arm.h"
28c3776bf2SGreg Clayton //#include "RegisterContextKDP_i386.h"
29c3776bf2SGreg Clayton //#include "RegisterContextKDP_x86_64.h"
30c3776bf2SGreg Clayton
31c3776bf2SGreg Clayton using namespace lldb;
32c3776bf2SGreg Clayton using namespace lldb_private;
33c3776bf2SGreg Clayton
34c3776bf2SGreg Clayton // Thread Registers
35c3776bf2SGreg Clayton
ThreadMachCore(Process & process,lldb::tid_t tid)36b9c1b51eSKate Stone ThreadMachCore::ThreadMachCore(Process &process, lldb::tid_t tid)
37b9c1b51eSKate Stone : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(),
38b9c1b51eSKate Stone m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), m_thread_reg_ctx_sp() {}
39c3776bf2SGreg Clayton
~ThreadMachCore()40b9c1b51eSKate Stone ThreadMachCore::~ThreadMachCore() { DestroyThread(); }
41c3776bf2SGreg Clayton
GetName()42b9c1b51eSKate Stone const char *ThreadMachCore::GetName() {
43c3776bf2SGreg Clayton if (m_thread_name.empty())
4445d8134cSStella Stamenova return nullptr;
45c3776bf2SGreg Clayton return m_thread_name.c_str();
46c3776bf2SGreg Clayton }
47c3776bf2SGreg Clayton
RefreshStateAfterStop()48b9c1b51eSKate Stone void ThreadMachCore::RefreshStateAfterStop() {
49c3776bf2SGreg Clayton // Invalidate all registers in our register context. We don't set "force" to
50c3776bf2SGreg Clayton // true because the stop reply packet might have had some register values
51c3776bf2SGreg Clayton // that were expedited and these will already be copied into the register
52c3776bf2SGreg Clayton // context by the time this function gets called. The KDPRegisterContext
53c3776bf2SGreg Clayton // class has been made smart enough to detect when it needs to invalidate
54c3776bf2SGreg Clayton // which registers are valid by putting hooks in the register read and
5505097246SAdrian Prantl // register supply functions where they check the process stop ID and do the
5605097246SAdrian Prantl // right thing.
57c3776bf2SGreg Clayton const bool force = false;
58c3776bf2SGreg Clayton GetRegisterContext()->InvalidateIfNeeded(force);
59c3776bf2SGreg Clayton }
60c3776bf2SGreg Clayton
ThreadIDIsValid(lldb::tid_t thread)61b9c1b51eSKate Stone bool ThreadMachCore::ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; }
62c3776bf2SGreg Clayton
GetRegisterContext()63b9c1b51eSKate Stone lldb::RegisterContextSP ThreadMachCore::GetRegisterContext() {
6445d8134cSStella Stamenova if (!m_reg_context_sp)
6545d8134cSStella Stamenova m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
66c3776bf2SGreg Clayton return m_reg_context_sp;
67c3776bf2SGreg Clayton }
68c3776bf2SGreg Clayton
69c3776bf2SGreg Clayton lldb::RegisterContextSP
CreateRegisterContextForFrame(StackFrame * frame)70b9c1b51eSKate Stone ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) {
71c3776bf2SGreg Clayton lldb::RegisterContextSP reg_ctx_sp;
72c3776bf2SGreg Clayton uint32_t concrete_frame_idx = 0;
73c3776bf2SGreg Clayton
74c3776bf2SGreg Clayton if (frame)
75c3776bf2SGreg Clayton concrete_frame_idx = frame->GetConcreteFrameIndex();
76c3776bf2SGreg Clayton
77b9c1b51eSKate Stone if (concrete_frame_idx == 0) {
78b9c1b51eSKate Stone if (!m_thread_reg_ctx_sp) {
791ac04c30SGreg Clayton ProcessSP process_sp(GetProcess());
801ac04c30SGreg Clayton
81b9c1b51eSKate Stone ObjectFile *core_objfile =
82b9c1b51eSKate Stone static_cast<ProcessMachCore *>(process_sp.get())->GetCoreObjectFile();
83c3776bf2SGreg Clayton if (core_objfile)
84b9c1b51eSKate Stone m_thread_reg_ctx_sp =
85b9c1b51eSKate Stone core_objfile->GetThreadContextAtIndex(GetID(), *this);
861ac04c30SGreg Clayton }
871ac04c30SGreg Clayton reg_ctx_sp = m_thread_reg_ctx_sp;
88b9c1b51eSKate Stone } else {
89c0b1af68SPavel Labath reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
901ac04c30SGreg Clayton }
91c3776bf2SGreg Clayton return reg_ctx_sp;
92c3776bf2SGreg Clayton }
93c3776bf2SGreg Clayton
IsCrashExceptionClass(AppleArm64ExceptionClass EC)94*3b14d80aSVedant Kumar static bool IsCrashExceptionClass(AppleArm64ExceptionClass EC) {
95*3b14d80aSVedant Kumar switch (EC) {
96*3b14d80aSVedant Kumar case AppleArm64ExceptionClass::ESR_EC_UNCATEGORIZED:
97*3b14d80aSVedant Kumar case AppleArm64ExceptionClass::ESR_EC_SVC_32:
98*3b14d80aSVedant Kumar case AppleArm64ExceptionClass::ESR_EC_SVC_64:
99*3b14d80aSVedant Kumar // In the ARM exception model, a process takes an exception when asking the
100*3b14d80aSVedant Kumar // kernel to service a system call. Don't treat this like a crash.
101*3b14d80aSVedant Kumar return false;
102*3b14d80aSVedant Kumar default:
103*3b14d80aSVedant Kumar return true;
104*3b14d80aSVedant Kumar }
105*3b14d80aSVedant Kumar }
106*3b14d80aSVedant Kumar
CalculateStopInfo()107b9c1b51eSKate Stone bool ThreadMachCore::CalculateStopInfo() {
1081ac04c30SGreg Clayton ProcessSP process_sp(GetProcess());
109b9c1b51eSKate Stone if (process_sp) {
110*3b14d80aSVedant Kumar StopInfoSP stop_info;
111*3b14d80aSVedant Kumar RegisterContextSP reg_ctx_sp = GetRegisterContext();
112*3b14d80aSVedant Kumar
113*3b14d80aSVedant Kumar if (reg_ctx_sp) {
114*3b14d80aSVedant Kumar Target &target = process_sp->GetTarget();
115*3b14d80aSVedant Kumar const ArchSpec arch_spec = target.GetArchitecture();
116*3b14d80aSVedant Kumar const uint32_t cputype = arch_spec.GetMachOCPUType();
117*3b14d80aSVedant Kumar
118*3b14d80aSVedant Kumar if (cputype == llvm::MachO::CPU_TYPE_ARM64 ||
119*3b14d80aSVedant Kumar cputype == llvm::MachO::CPU_TYPE_ARM64_32) {
120*3b14d80aSVedant Kumar const RegisterInfo *esr_info = reg_ctx_sp->GetRegisterInfoByName("esr");
121*3b14d80aSVedant Kumar const RegisterInfo *far_info = reg_ctx_sp->GetRegisterInfoByName("far");
122*3b14d80aSVedant Kumar RegisterValue esr, far;
123*3b14d80aSVedant Kumar if (reg_ctx_sp->ReadRegister(esr_info, esr) &&
124*3b14d80aSVedant Kumar reg_ctx_sp->ReadRegister(far_info, far)) {
125*3b14d80aSVedant Kumar const uint32_t esr_val = esr.GetAsUInt32();
126*3b14d80aSVedant Kumar const AppleArm64ExceptionClass exception_class =
127*3b14d80aSVedant Kumar getAppleArm64ExceptionClass(esr_val);
128*3b14d80aSVedant Kumar if (IsCrashExceptionClass(exception_class)) {
129*3b14d80aSVedant Kumar StreamString S;
130*3b14d80aSVedant Kumar S.Printf("%s (fault address: 0x%" PRIx64 ")",
131*3b14d80aSVedant Kumar toString(exception_class), far.GetAsUInt64());
132*3b14d80aSVedant Kumar stop_info =
133*3b14d80aSVedant Kumar StopInfo::CreateStopReasonWithException(*this, S.GetData());
134*3b14d80aSVedant Kumar }
135*3b14d80aSVedant Kumar }
136*3b14d80aSVedant Kumar }
137*3b14d80aSVedant Kumar }
138*3b14d80aSVedant Kumar
139*3b14d80aSVedant Kumar // Set a stop reason for crashing threads only so that they get selected
140*3b14d80aSVedant Kumar // preferentially.
141*3b14d80aSVedant Kumar if (stop_info)
142*3b14d80aSVedant Kumar SetStopInfo(stop_info);
1436e0ff1a3SGreg Clayton return true;
144c3776bf2SGreg Clayton }
1456e0ff1a3SGreg Clayton return false;
146c3776bf2SGreg Clayton }
147