brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · de7de9e Raw
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