brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.2 KiB · 7015c3c Raw
560 lines · cpp
1//===-- ThreadElfCore.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 "lldb/Target/RegisterContext.h"10#include "lldb/Target/StopInfo.h"11#include "lldb/Target/Target.h"12#include "lldb/Target/UnixSignals.h"13#include "lldb/Target/Unwind.h"14#include "lldb/Utility/DataExtractor.h"15#include "lldb/Utility/LLDBLog.h"16#include "lldb/Utility/Log.h"17#include "lldb/Utility/ProcessInfo.h"18 19#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"20#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"21#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"22#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"23#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"24#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"25#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"26#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"27#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"28#include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h"29#include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"30#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"31#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"32#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"33#include "ProcessElfCore.h"34#include "RegisterContextLinuxCore_x86_64.h"35#include "RegisterContextPOSIXCore_arm.h"36#include "RegisterContextPOSIXCore_arm64.h"37#include "RegisterContextPOSIXCore_loongarch64.h"38#include "RegisterContextPOSIXCore_mips64.h"39#include "RegisterContextPOSIXCore_powerpc.h"40#include "RegisterContextPOSIXCore_ppc64le.h"41#include "RegisterContextPOSIXCore_riscv32.h"42#include "RegisterContextPOSIXCore_riscv64.h"43#include "RegisterContextPOSIXCore_s390x.h"44#include "RegisterContextPOSIXCore_x86_64.h"45#include "ThreadElfCore.h"46 47#include <memory>48 49using namespace lldb;50using namespace lldb_private;51 52// Construct a Thread object with given data53ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td)54    : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(),55      m_gpregset_data(td.gpregset), m_notes(td.notes),56      m_siginfo_bytes(std::move(td.siginfo_bytes)), m_signo(td.signo) {}57 58ThreadElfCore::~ThreadElfCore() { DestroyThread(); }59 60void ThreadElfCore::RefreshStateAfterStop() {61  GetRegisterContext()->InvalidateIfNeeded(false);62}63 64RegisterContextSP ThreadElfCore::GetRegisterContext() {65  if (!m_reg_context_sp) {66    m_reg_context_sp = CreateRegisterContextForFrame(nullptr);67  }68  return m_reg_context_sp;69}70 71RegisterContextSP72ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {73  RegisterContextSP reg_ctx_sp;74  uint32_t concrete_frame_idx = 0;75  Log *log = GetLog(LLDBLog::Thread);76 77  if (frame)78    concrete_frame_idx = frame->GetConcreteFrameIndex();79 80  bool is_linux = false;81  if (concrete_frame_idx == 0) {82    if (m_thread_reg_ctx_sp)83      return m_thread_reg_ctx_sp;84 85    ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());86    ArchSpec arch = process->GetArchitecture();87    RegisterInfoInterface *reg_interface = nullptr;88 89    switch (arch.GetTriple().getOS()) {90    case llvm::Triple::FreeBSD: {91      switch (arch.GetMachine()) {92      case llvm::Triple::aarch64:93      case llvm::Triple::arm:94        break;95      case llvm::Triple::ppc:96        reg_interface = new RegisterContextFreeBSD_powerpc32(arch);97        break;98      case llvm::Triple::ppc64:99      case llvm::Triple::ppc64le:100        reg_interface = new RegisterContextFreeBSD_powerpc64(arch);101        break;102      case llvm::Triple::mips64:103        reg_interface = new RegisterContextFreeBSD_mips64(arch);104        break;105      case llvm::Triple::x86:106        reg_interface = new RegisterContextFreeBSD_i386(arch);107        break;108      case llvm::Triple::x86_64:109        reg_interface = new RegisterContextFreeBSD_x86_64(arch);110        break;111      default:112        break;113      }114      break;115    }116 117    case llvm::Triple::NetBSD: {118      switch (arch.GetMachine()) {119      case llvm::Triple::aarch64:120        break;121      case llvm::Triple::x86:122        reg_interface = new RegisterContextNetBSD_i386(arch);123        break;124      case llvm::Triple::x86_64:125        reg_interface = new RegisterContextNetBSD_x86_64(arch);126        break;127      default:128        break;129      }130      break;131    }132 133    case llvm::Triple::Linux: {134      is_linux = true;135      switch (arch.GetMachine()) {136      case llvm::Triple::aarch64:137        break;138      case llvm::Triple::ppc64le:139        reg_interface = new RegisterInfoPOSIX_ppc64le(arch);140        break;141      case llvm::Triple::systemz:142        reg_interface = new RegisterContextLinux_s390x(arch);143        break;144      case llvm::Triple::x86:145        reg_interface = new RegisterContextLinux_i386(arch);146        break;147      case llvm::Triple::x86_64:148        reg_interface = new RegisterContextLinux_x86_64(arch);149        break;150      default:151        break;152      }153      break;154    }155 156    case llvm::Triple::OpenBSD: {157      switch (arch.GetMachine()) {158      case llvm::Triple::aarch64:159        break;160      case llvm::Triple::x86:161        reg_interface = new RegisterContextOpenBSD_i386(arch);162        break;163      case llvm::Triple::x86_64:164        reg_interface = new RegisterContextOpenBSD_x86_64(arch);165        break;166      default:167        break;168      }169      break;170    }171 172    default:173      break;174    }175 176    if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 &&177        arch.GetMachine() != llvm::Triple::arm &&178        arch.GetMachine() != llvm::Triple::loongarch64 &&179        arch.GetMachine() != llvm::Triple::riscv64 &&180        arch.GetMachine() != llvm::Triple::riscv32) {181      LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported",182                __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS());183      assert(false && "Architecture or OS not supported");184    }185 186    switch (arch.GetMachine()) {187    case llvm::Triple::aarch64:188      m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create(189          *this, arch, m_gpregset_data, m_notes);190      break;191    case llvm::Triple::arm:192      m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>(193          *this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data,194          m_notes);195      break;196    case llvm::Triple::loongarch64:197      m_thread_reg_ctx_sp = RegisterContextCorePOSIX_loongarch64::Create(198          *this, arch, m_gpregset_data, m_notes);199      break;200    case llvm::Triple::riscv32:201      m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv32::Create(202          *this, arch, m_gpregset_data, m_notes);203      break;204    case llvm::Triple::riscv64:205      m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv64::Create(206          *this, arch, m_gpregset_data, m_notes);207      break;208    case llvm::Triple::mipsel:209    case llvm::Triple::mips:210      m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(211          *this, reg_interface, m_gpregset_data, m_notes);212      break;213    case llvm::Triple::mips64:214    case llvm::Triple::mips64el:215      m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>(216          *this, reg_interface, m_gpregset_data, m_notes);217      break;218    case llvm::Triple::ppc:219    case llvm::Triple::ppc64:220      m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_powerpc>(221          *this, reg_interface, m_gpregset_data, m_notes);222      break;223    case llvm::Triple::ppc64le:224      m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_ppc64le>(225          *this, reg_interface, m_gpregset_data, m_notes);226      break;227    case llvm::Triple::systemz:228      m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_s390x>(229          *this, reg_interface, m_gpregset_data, m_notes);230      break;231    case llvm::Triple::x86:232    case llvm::Triple::x86_64:233      if (is_linux) {234        m_thread_reg_ctx_sp = std::make_shared<RegisterContextLinuxCore_x86_64>(235              *this, reg_interface, m_gpregset_data, m_notes);236      } else {237        m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(238              *this, reg_interface, m_gpregset_data, m_notes);239      }240      break;241    default:242      break;243    }244 245    reg_ctx_sp = m_thread_reg_ctx_sp;246  } else {247    reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);248  }249  return reg_ctx_sp;250}251 252llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>253ThreadElfCore::GetSiginfo(size_t max_size) const {254  if (m_siginfo_bytes.empty())255    return llvm::createStringError(llvm::inconvertibleErrorCode(),256                                   "no siginfo note");257 258  return llvm::MemoryBuffer::getMemBufferCopy(m_siginfo_bytes,259                                              "siginfo note bytes");260}261 262bool ThreadElfCore::CalculateStopInfo() {263  ProcessSP process_sp(GetProcess());264  if (!process_sp)265    return false;266 267  PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();268  if (platform_sp) {269    lldb::StopInfoSP stopinfo_sp = platform_sp->GetStopInfoFromSiginfo(*this);270    // The platform SP can optionally handle creating the stop info from the271    // siginfo value however it's not guaraunteed to be implemented on every272    // platform, so if we fall through this case, we create from just the signo.273    if (stopinfo_sp) {274      SetStopInfo(std::move(stopinfo_sp));275      return true;276    }277  }278 279  SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, m_signo));280  return true;281}282 283// Parse PRSTATUS from NOTE entry284ELFLinuxPrStatus::ELFLinuxPrStatus() {285  memset(this, 0, sizeof(ELFLinuxPrStatus));286}287 288size_t ELFLinuxPrStatus::GetSize(const lldb_private::ArchSpec &arch) {289  constexpr size_t mips_linux_pr_status_size_o32 = 96;290  constexpr size_t mips_linux_pr_status_size_n32 = 72;291  constexpr size_t num_ptr_size_members = 10;292  if (arch.IsMIPS()) {293    std::string abi = arch.GetTargetABI();294    assert(!abi.empty() && "ABI is not set");295    if (abi == "n64")296      return sizeof(ELFLinuxPrStatus);297    else if (abi == "o32")298      return mips_linux_pr_status_size_o32;299    // N32 ABI300    return mips_linux_pr_status_size_n32;301  }302  switch (arch.GetCore()) {303  case lldb_private::ArchSpec::eCore_x86_32_i386:304  case lldb_private::ArchSpec::eCore_x86_32_i486:305    return 72;306  default:307    if (arch.GetAddressByteSize() == 8)308      return sizeof(ELFLinuxPrStatus);309    else310      return sizeof(ELFLinuxPrStatus) - num_ptr_size_members * 4;311  }312}313 314Status ELFLinuxPrStatus::Parse(const DataExtractor &data,315                               const ArchSpec &arch) {316  Status error;317  if (GetSize(arch) > data.GetByteSize()) {318    error = Status::FromErrorStringWithFormat(319        "NT_PRSTATUS size should be %zu, but the remaining bytes are: %" PRIu64,320        GetSize(arch), data.GetByteSize());321    return error;322  }323 324  // Read field by field to correctly account for endianess of both the core325  // dump and the platform running lldb.326  offset_t offset = 0;327  si_signo = data.GetU32(&offset);328  si_code = data.GetU32(&offset);329  si_errno = data.GetU32(&offset);330 331  pr_cursig = data.GetU16(&offset);332  offset += 2; // pad333 334  pr_sigpend = data.GetAddress(&offset);335  pr_sighold = data.GetAddress(&offset);336 337  pr_pid = data.GetU32(&offset);338  pr_ppid = data.GetU32(&offset);339  pr_pgrp = data.GetU32(&offset);340  pr_sid = data.GetU32(&offset);341 342  pr_utime.tv_sec = data.GetAddress(&offset);343  pr_utime.tv_usec = data.GetAddress(&offset);344 345  pr_stime.tv_sec = data.GetAddress(&offset);346  pr_stime.tv_usec = data.GetAddress(&offset);347 348  pr_cutime.tv_sec = data.GetAddress(&offset);349  pr_cutime.tv_usec = data.GetAddress(&offset);350 351  pr_cstime.tv_sec = data.GetAddress(&offset);352  pr_cstime.tv_usec = data.GetAddress(&offset);353 354  return error;355}356 357static struct compat_timeval358copy_timespecs(const ProcessInstanceInfo::timespec &oth) {359  using sec_t = decltype(compat_timeval::tv_sec);360  using usec_t = decltype(compat_timeval::tv_usec);361  return {static_cast<sec_t>(oth.tv_sec), static_cast<usec_t>(oth.tv_usec)};362}363 364std::optional<ELFLinuxPrStatus>365ELFLinuxPrStatus::Populate(const lldb::ThreadSP &thread_sp) {366  ELFLinuxPrStatus prstatus{};367  prstatus.pr_pid = thread_sp->GetID();368  lldb::ProcessSP process_sp = thread_sp->GetProcess();369  ProcessInstanceInfo info;370  if (!process_sp->GetProcessInfo(info))371    return std::nullopt;372 373  prstatus.pr_ppid = info.GetParentProcessID();374  prstatus.pr_pgrp = info.GetProcessGroupID();375  prstatus.pr_sid = info.GetProcessSessionID();376  prstatus.pr_utime = copy_timespecs(info.GetUserTime());377  prstatus.pr_stime = copy_timespecs(info.GetSystemTime());378  prstatus.pr_cutime = copy_timespecs(info.GetCumulativeUserTime());379  prstatus.pr_cstime = copy_timespecs(info.GetCumulativeSystemTime());380  return prstatus;381}382 383// Parse PRPSINFO from NOTE entry384ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() {385  memset(this, 0, sizeof(ELFLinuxPrPsInfo));386}387 388size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) {389  constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128;390  if (arch.IsMIPS()) {391    uint8_t address_byte_size = arch.GetAddressByteSize();392    if (address_byte_size == 8)393      return sizeof(ELFLinuxPrPsInfo);394    return mips_linux_pr_psinfo_size_o32_n32;395  }396 397  switch (arch.GetCore()) {398  case lldb_private::ArchSpec::eCore_s390x_generic:399  case lldb_private::ArchSpec::eCore_x86_64_x86_64:400    return sizeof(ELFLinuxPrPsInfo);401  case lldb_private::ArchSpec::eCore_x86_32_i386:402  case lldb_private::ArchSpec::eCore_x86_32_i486:403    return 124;404  default:405    return 0;406  }407}408 409Status ELFLinuxPrPsInfo::Parse(const DataExtractor &data,410                               const ArchSpec &arch) {411  Status error;412  ByteOrder byteorder = data.GetByteOrder();413  if (GetSize(arch) > data.GetByteSize()) {414    error = Status::FromErrorStringWithFormat(415        "NT_PRPSINFO size should be %zu, but the remaining bytes are: %" PRIu64,416        GetSize(arch), data.GetByteSize());417    return error;418  }419  size_t size = 0;420  offset_t offset = 0;421 422  pr_state = data.GetU8(&offset);423  pr_sname = data.GetU8(&offset);424  pr_zomb = data.GetU8(&offset);425  pr_nice = data.GetU8(&offset);426  if (data.GetAddressByteSize() == 8) {427    // Word align the next field on 64 bit.428    offset += 4;429  }430 431  pr_flag = data.GetAddress(&offset);432 433  if (arch.IsMIPS()) {434    // The pr_uid and pr_gid is always 32 bit irrespective of platforms435    pr_uid = data.GetU32(&offset);436    pr_gid = data.GetU32(&offset);437  } else {438    // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms439    pr_uid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);440    pr_gid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);441  }442 443  pr_pid = data.GetU32(&offset);444  pr_ppid = data.GetU32(&offset);445  pr_pgrp = data.GetU32(&offset);446  pr_sid = data.GetU32(&offset);447 448  size = 16;449  data.ExtractBytes(offset, size, byteorder, pr_fname);450  offset += size;451 452  size = 80;453  data.ExtractBytes(offset, size, byteorder, pr_psargs);454  offset += size;455 456  return error;457}458 459std::optional<ELFLinuxPrPsInfo>460ELFLinuxPrPsInfo::Populate(const lldb::ProcessSP &process_sp) {461  ProcessInstanceInfo info;462  if (!process_sp->GetProcessInfo(info))463    return std::nullopt;464 465  return Populate(info, process_sp->GetState());466}467 468std::optional<ELFLinuxPrPsInfo>469ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info,470                           lldb::StateType process_state) {471  ELFLinuxPrPsInfo prpsinfo{};472  prpsinfo.pr_pid = info.GetProcessID();473  prpsinfo.pr_nice = info.GetPriorityValue().value_or(0);474  prpsinfo.pr_zomb = 0;475  if (auto zombie_opt = info.IsZombie(); zombie_opt.value_or(false)) {476    prpsinfo.pr_zomb = 1;477  }478  /**479   * In the linux kernel this comes from:480   * state = READ_ONCE(p->__state);481   * i = state ? ffz(~state) + 1 : 0;482   * psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i];483   *484   * So we replicate that here. From proc_pid_stats(5)485   * R = Running486   * S = Sleeping on uninterrutible wait487   * D = Waiting on uninterruptable disk sleep488   * T = Tracing stop489   * Z = Zombie490   * W = Paging491   */492  switch (process_state) {493  case lldb::StateType::eStateSuspended:494    prpsinfo.pr_sname = 'S';495    prpsinfo.pr_state = 1;496    break;497  case lldb::StateType::eStateStopped:498    [[fallthrough]];499  case lldb::StateType::eStateStepping:500    prpsinfo.pr_sname = 'T';501    prpsinfo.pr_state = 3;502    break;503  case lldb::StateType::eStateUnloaded:504    [[fallthrough]];505  case lldb::StateType::eStateRunning:506    prpsinfo.pr_sname = 'R';507    prpsinfo.pr_state = 0;508    break;509  default:510    break;511  }512 513  /**514   * pr_flags is left as 0. The values (in linux) are specific515   * to the kernel. We recover them from the proc filesystem516   * but don't put them in ProcessInfo because it would really517   * become very linux specific and the utility here seems pretty518   * dubious519   */520 521  if (info.EffectiveUserIDIsValid())522    prpsinfo.pr_uid = info.GetUserID();523 524  if (info.EffectiveGroupIDIsValid())525    prpsinfo.pr_gid = info.GetGroupID();526 527  if (info.ParentProcessIDIsValid())528    prpsinfo.pr_ppid = info.GetParentProcessID();529 530  if (info.ProcessGroupIDIsValid())531    prpsinfo.pr_pgrp = info.GetProcessGroupID();532 533  if (info.ProcessSessionIDIsValid())534    prpsinfo.pr_sid = info.GetProcessSessionID();535 536  constexpr size_t fname_len = std::extent_v<decltype(prpsinfo.pr_fname)>;537  static_assert(fname_len > 0, "This should always be non zero");538  const llvm::StringRef fname = info.GetNameAsStringRef();539  auto fname_begin = fname.begin();540  std::copy_n(fname_begin, std::min(fname_len, fname.size()),541              prpsinfo.pr_fname);542  prpsinfo.pr_fname[fname_len - 1] = '\0';543  auto args = info.GetArguments();544  auto argentry_iterator = std::begin(args);545  char *psargs = prpsinfo.pr_psargs;546  char *psargs_end = std::end(prpsinfo.pr_psargs);547  while (psargs < psargs_end && argentry_iterator != args.end()) {548    llvm::StringRef argentry = argentry_iterator->ref();549    size_t len =550        std::min<size_t>(std::distance(psargs, psargs_end), argentry.size());551    auto arg_iterator = std::begin(argentry);552    psargs = std::copy_n(arg_iterator, len, psargs);553    if (psargs != psargs_end)554      *(psargs++) = ' ';555    ++argentry_iterator;556  }557  *(psargs - 1) = '\0';558  return prpsinfo;559}560