179 lines · cpp
1//===-- ThreadMachCore.cpp ------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include <optional>10#include <string>11#include <vector>12 13#include "RegisterContextUnifiedCore.h"14#include "ThreadMachCore.h"15 16#include "lldb/Breakpoint/Watchpoint.h"17#include "lldb/Host/SafeMachO.h"18#include "lldb/Symbol/ObjectFile.h"19#include "lldb/Target/AppleArm64ExceptionClass.h"20#include "lldb/Target/DynamicRegisterInfo.h"21#include "lldb/Target/Process.h"22#include "lldb/Target/RegisterContext.h"23#include "lldb/Target/StopInfo.h"24#include "lldb/Target/Target.h"25#include "lldb/Target/Unwind.h"26#include "lldb/Utility/ArchSpec.h"27#include "lldb/Utility/DataExtractor.h"28#include "lldb/Utility/RegisterValue.h"29#include "lldb/Utility/State.h"30#include "lldb/Utility/StreamString.h"31#include "lldb/Utility/StructuredData.h"32 33#include "ProcessMachCore.h"34//#include "RegisterContextKDP_arm.h"35//#include "RegisterContextKDP_i386.h"36//#include "RegisterContextKDP_x86_64.h"37 38using namespace lldb;39using namespace lldb_private;40 41// Thread Registers42 43ThreadMachCore::ThreadMachCore(Process &process, lldb::tid_t tid,44 uint32_t objfile_lc_thread_idx)45 : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(),46 m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), m_thread_reg_ctx_sp(),47 m_objfile_lc_thread_idx(objfile_lc_thread_idx) {}48 49ThreadMachCore::~ThreadMachCore() { DestroyThread(); }50 51const char *ThreadMachCore::GetName() {52 if (m_thread_name.empty())53 return nullptr;54 return m_thread_name.c_str();55}56 57void ThreadMachCore::RefreshStateAfterStop() {58 // Invalidate all registers in our register context. We don't set "force" to59 // true because the stop reply packet might have had some register values60 // that were expedited and these will already be copied into the register61 // context by the time this function gets called. The KDPRegisterContext62 // class has been made smart enough to detect when it needs to invalidate63 // which registers are valid by putting hooks in the register read and64 // register supply functions where they check the process stop ID and do the65 // right thing.66 const bool force = false;67 GetRegisterContext()->InvalidateIfNeeded(force);68}69 70bool ThreadMachCore::ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; }71 72lldb::RegisterContextSP ThreadMachCore::GetRegisterContext() {73 if (!m_reg_context_sp)74 m_reg_context_sp = CreateRegisterContextForFrame(nullptr);75 return m_reg_context_sp;76}77 78lldb::RegisterContextSP79ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) {80 uint32_t concrete_frame_idx = 0;81 82 if (frame)83 concrete_frame_idx = frame->GetConcreteFrameIndex();84 if (concrete_frame_idx > 0)85 return GetUnwinder().CreateRegisterContextForFrame(frame);86 87 if (m_thread_reg_ctx_sp)88 return m_thread_reg_ctx_sp;89 90 ProcessSP process_sp(GetProcess());91 assert(process_sp);92 93 ObjectFile *core_objfile =94 static_cast<ProcessMachCore *>(process_sp.get())->GetCoreObjectFile();95 if (!core_objfile)96 return {};97 98 RegisterContextSP core_thread_regctx_sp =99 core_objfile->GetThreadContextAtIndex(m_objfile_lc_thread_idx, *this);100 101 if (!core_thread_regctx_sp)102 return {};103 104 StructuredData::ObjectSP process_md_sp =105 core_objfile->GetCorefileProcessMetadata();106 107 StructuredData::ObjectSP thread_md_sp;108 if (process_md_sp && process_md_sp->GetAsDictionary() &&109 process_md_sp->GetAsDictionary()->HasKey("threads")) {110 StructuredData::Array *threads = process_md_sp->GetAsDictionary()111 ->GetValueForKey("threads")112 ->GetAsArray();113 if (threads && threads->GetSize() == core_objfile->GetNumThreadContexts()) {114 StructuredData::ObjectSP thread_sp =115 threads->GetItemAtIndex(m_objfile_lc_thread_idx);116 if (thread_sp && thread_sp->GetAsDictionary())117 thread_md_sp = thread_sp;118 }119 }120 m_thread_reg_ctx_sp = std::make_shared<RegisterContextUnifiedCore>(121 *this, concrete_frame_idx, core_thread_regctx_sp, thread_md_sp);122 123 return m_thread_reg_ctx_sp;124}125 126static bool IsCrashExceptionClass(AppleArm64ExceptionClass EC) {127 switch (EC) {128 case AppleArm64ExceptionClass::ESR_EC_UNCATEGORIZED:129 case AppleArm64ExceptionClass::ESR_EC_SVC_32:130 case AppleArm64ExceptionClass::ESR_EC_SVC_64:131 // In the ARM exception model, a process takes an exception when asking the132 // kernel to service a system call. Don't treat this like a crash.133 return false;134 default:135 return true;136 }137}138 139bool ThreadMachCore::CalculateStopInfo() {140 ProcessSP process_sp(GetProcess());141 if (process_sp) {142 StopInfoSP stop_info;143 RegisterContextSP reg_ctx_sp = GetRegisterContext();144 145 if (reg_ctx_sp) {146 Target &target = process_sp->GetTarget();147 const ArchSpec arch_spec = target.GetArchitecture();148 const uint32_t cputype = arch_spec.GetMachOCPUType();149 150 if (cputype == llvm::MachO::CPU_TYPE_ARM64 ||151 cputype == llvm::MachO::CPU_TYPE_ARM64_32) {152 const RegisterInfo *esr_info = reg_ctx_sp->GetRegisterInfoByName("esr");153 const RegisterInfo *far_info = reg_ctx_sp->GetRegisterInfoByName("far");154 RegisterValue esr, far;155 if (reg_ctx_sp->ReadRegister(esr_info, esr) &&156 reg_ctx_sp->ReadRegister(far_info, far)) {157 const uint32_t esr_val = esr.GetAsUInt32();158 const AppleArm64ExceptionClass exception_class =159 getAppleArm64ExceptionClass(esr_val);160 if (IsCrashExceptionClass(exception_class)) {161 StreamString S;162 S.Printf("%s (fault address: 0x%" PRIx64 ")",163 toString(exception_class), far.GetAsUInt64());164 stop_info =165 StopInfo::CreateStopReasonWithException(*this, S.GetData());166 }167 }168 }169 }170 171 // Set a stop reason for crashing threads only so that they get selected172 // preferentially.173 if (stop_info)174 SetStopInfo(stop_info);175 return true;176 }177 return false;178}179