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