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