Path: blob/main/contrib/llvm-project/lldb/source/Host/common/NativeRegisterContext.cpp
96353 views
//===-- NativeRegisterContext.cpp -----------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Host/common/NativeRegisterContext.h"9#include "lldb/Utility/LLDBLog.h"10#include "lldb/Utility/RegisterValue.h"1112#include "lldb/Host/PosixApi.h"13#include "lldb/Host/common/NativeProcessProtocol.h"14#include "lldb/Host/common/NativeThreadProtocol.h"1516using namespace lldb;17using namespace lldb_private;1819NativeRegisterContext::NativeRegisterContext(NativeThreadProtocol &thread)20: m_thread(thread) {}2122// Destructor23NativeRegisterContext::~NativeRegisterContext() = default;2425// FIXME revisit invalidation, process stop ids, etc. Right now we don't26// support caching in NativeRegisterContext. We can do this later by utilizing27// NativeProcessProtocol::GetStopID () and adding a stop id to28// NativeRegisterContext.2930// void31// NativeRegisterContext::InvalidateIfNeeded (bool force) {32// ProcessSP process_sp (m_thread.GetProcess());33// bool invalidate = force;34// uint32_t process_stop_id = UINT32_MAX;3536// if (process_sp)37// process_stop_id = process_sp->GetStopID();38// else39// invalidate = true;4041// if (!invalidate)42// invalidate = process_stop_id != GetStopID();4344// if (invalidate)45// {46// InvalidateAllRegisters ();47// SetStopID (process_stop_id);48// }49// }5051const RegisterInfo *52NativeRegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name,53uint32_t start_idx) {54if (reg_name.empty())55return nullptr;5657// Generic register names take precedence over specific register names.58// For example, on x86 we want "sp" to refer to the complete RSP/ESP register59// rather than the 16-bit SP pseudo-register.60uint32_t generic_reg = Args::StringToGenericRegister(reg_name);61if (generic_reg != LLDB_INVALID_REGNUM) {62const RegisterInfo *reg_info =63GetRegisterInfo(eRegisterKindGeneric, generic_reg);64if (reg_info)65return reg_info;66}6768const uint32_t num_registers = GetRegisterCount();69for (uint32_t reg = start_idx; reg < num_registers; ++reg) {70const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);7172if (reg_name.equals_insensitive(reg_info->name) ||73reg_name.equals_insensitive(reg_info->alt_name))74return reg_info;75}7677return nullptr;78}7980const RegisterInfo *NativeRegisterContext::GetRegisterInfo(uint32_t kind,81uint32_t num) {82const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);83if (reg_num == LLDB_INVALID_REGNUM)84return nullptr;85return GetRegisterInfoAtIndex(reg_num);86}8788const char *NativeRegisterContext::GetRegisterName(uint32_t reg) {89const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);90if (reg_info)91return reg_info->name;92return nullptr;93}9495const char *NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex(96uint32_t reg_index) const {97const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);98if (!reg_info)99return nullptr;100101for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) {102const RegisterSet *const reg_set = GetRegisterSet(set_index);103if (!reg_set)104continue;105106for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers;107++reg_num_index) {108const uint32_t reg_num = reg_set->registers[reg_num_index];109// FIXME double check we're checking the right register kind here.110if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) {111// The given register is a member of this register set. Return the112// register set name.113return reg_set->name;114}115}116}117118// Didn't find it.119return nullptr;120}121122lldb::addr_t NativeRegisterContext::GetPC(lldb::addr_t fail_value) {123Log *log = GetLog(LLDBLog::Thread);124125uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,126LLDB_REGNUM_GENERIC_PC);127LLDB_LOGF(log, "Using reg index %" PRIu32 " (default %" PRIu64 ")", reg,128fail_value);129130const uint64_t retval = ReadRegisterAsUnsigned(reg, fail_value);131132LLDB_LOGF(log, PRIu32 " retval %" PRIu64, retval);133134return retval;135}136137lldb::addr_t138NativeRegisterContext::GetPCfromBreakpointLocation(lldb::addr_t fail_value) {139return GetPC(fail_value);140}141142Status NativeRegisterContext::SetPC(lldb::addr_t pc) {143uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,144LLDB_REGNUM_GENERIC_PC);145return WriteRegisterFromUnsigned(reg, pc);146}147148lldb::addr_t NativeRegisterContext::GetSP(lldb::addr_t fail_value) {149uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,150LLDB_REGNUM_GENERIC_SP);151return ReadRegisterAsUnsigned(reg, fail_value);152}153154Status NativeRegisterContext::SetSP(lldb::addr_t sp) {155uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,156LLDB_REGNUM_GENERIC_SP);157return WriteRegisterFromUnsigned(reg, sp);158}159160lldb::addr_t NativeRegisterContext::GetFP(lldb::addr_t fail_value) {161uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,162LLDB_REGNUM_GENERIC_FP);163return ReadRegisterAsUnsigned(reg, fail_value);164}165166Status NativeRegisterContext::SetFP(lldb::addr_t fp) {167uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,168LLDB_REGNUM_GENERIC_FP);169return WriteRegisterFromUnsigned(reg, fp);170}171172lldb::addr_t NativeRegisterContext::GetReturnAddress(lldb::addr_t fail_value) {173uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,174LLDB_REGNUM_GENERIC_RA);175return ReadRegisterAsUnsigned(reg, fail_value);176}177178lldb::addr_t NativeRegisterContext::GetFlags(lldb::addr_t fail_value) {179uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,180LLDB_REGNUM_GENERIC_FLAGS);181return ReadRegisterAsUnsigned(reg, fail_value);182}183184lldb::addr_t185NativeRegisterContext::ReadRegisterAsUnsigned(uint32_t reg,186lldb::addr_t fail_value) {187if (reg != LLDB_INVALID_REGNUM)188return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value);189return fail_value;190}191192uint64_t193NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info,194lldb::addr_t fail_value) {195Log *log = GetLog(LLDBLog::Thread);196197if (reg_info) {198RegisterValue value;199Status error = ReadRegister(reg_info, value);200if (error.Success()) {201LLDB_LOGF(log,202"Read register succeeded: value "203"%" PRIu64,204value.GetAsUInt64());205return value.GetAsUInt64();206} else {207LLDB_LOGF(log, "Read register failed: error %s", error.AsCString());208}209} else {210LLDB_LOGF(log, "Read register failed: null reg_info");211}212return fail_value;213}214215Status NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg,216uint64_t uval) {217if (reg == LLDB_INVALID_REGNUM)218return Status("Write register failed: reg is invalid");219return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval);220}221222Status223NativeRegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info,224uint64_t uval) {225assert(reg_info);226if (!reg_info)227return Status("reg_info is nullptr");228229RegisterValue value;230if (!value.SetUInt(uval, reg_info->byte_size))231return Status("RegisterValue::SetUInt () failed");232233return WriteRegister(reg_info, value);234}235236lldb::tid_t NativeRegisterContext::GetThreadID() const {237return m_thread.GetID();238}239240uint32_t NativeRegisterContext::NumSupportedHardwareBreakpoints() { return 0; }241242uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr,243size_t size) {244return LLDB_INVALID_INDEX32;245}246247Status NativeRegisterContext::ClearAllHardwareBreakpoints() {248return Status("not implemented");249}250251bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) {252return false;253}254255Status NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index,256lldb::addr_t trap_addr) {257bp_index = LLDB_INVALID_INDEX32;258return Status("not implemented");259}260261uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; }262263uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr,264size_t size,265uint32_t watch_flags) {266return LLDB_INVALID_INDEX32;267}268269bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) {270return false;271}272273Status NativeRegisterContext::ClearWatchpointHit(uint32_t hw_index) {274return Status("not implemented");275}276277Status NativeRegisterContext::ClearAllHardwareWatchpoints() {278return Status("not implemented");279}280281Status NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) {282is_hit = false;283return Status("not implemented");284}285286Status NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index,287lldb::addr_t trap_addr) {288wp_index = LLDB_INVALID_INDEX32;289return Status("not implemented");290}291292Status NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index,293bool &is_vacant) {294is_vacant = false;295return Status("not implemented");296}297298lldb::addr_t NativeRegisterContext::GetWatchpointAddress(uint32_t wp_index) {299return LLDB_INVALID_ADDRESS;300}301302lldb::addr_t NativeRegisterContext::GetWatchpointHitAddress(uint32_t wp_index) {303return LLDB_INVALID_ADDRESS;304}305306bool NativeRegisterContext::HardwareSingleStep(bool enable) { return false; }307308Status NativeRegisterContext::ReadRegisterValueFromMemory(309const RegisterInfo *reg_info, lldb::addr_t src_addr, size_t src_len,310RegisterValue ®_value) {311Status error;312if (reg_info == nullptr) {313error.SetErrorString("invalid register info argument.");314return error;315}316317// Moving from addr into a register318//319// Case 1: src_len == dst_len320//321// |AABBCCDD| Address contents322// |AABBCCDD| Register contents323//324// Case 2: src_len > dst_len325//326// Status! (The register should always be big enough to hold the data)327//328// Case 3: src_len < dst_len329//330// |AABB| Address contents331// |AABB0000| Register contents [on little-endian hardware]332// |0000AABB| Register contents [on big-endian hardware]333const size_t dst_len = reg_info->byte_size;334335if (src_len > dst_len) {336error.SetErrorStringWithFormat(337"%" PRIu64 " bytes is too big to store in register %s (%" PRIu64338" bytes)",339static_cast<uint64_t>(src_len), reg_info->name,340static_cast<uint64_t>(dst_len));341return error;342}343344NativeProcessProtocol &process = m_thread.GetProcess();345RegisterValue::BytesContainer src(src_len);346347// Read the memory348size_t bytes_read;349error = process.ReadMemory(src_addr, src.data(), src_len, bytes_read);350if (error.Fail())351return error;352353// Make sure the memory read succeeded...354if (bytes_read != src_len) {355// This might happen if we read _some_ bytes but not all356error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes",357static_cast<uint64_t>(bytes_read),358static_cast<uint64_t>(src_len));359return error;360}361362// We now have a memory buffer that contains the part or all of the register363// value. Set the register value using this memory data.364// TODO: we might need to add a parameter to this function in case the byte365// order of the memory data doesn't match the process. For now we are366// assuming they are the same.367reg_value.SetFromMemoryData(*reg_info, src.data(), src_len,368process.GetByteOrder(), error);369370return error;371}372373Status NativeRegisterContext::WriteRegisterValueToMemory(374const RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len,375const RegisterValue ®_value) {376Status error;377if (reg_info == nullptr) {378error.SetErrorString("Invalid register info argument.");379return error;380}381382RegisterValue::BytesContainer dst(dst_len);383NativeProcessProtocol &process = m_thread.GetProcess();384385// TODO: we might need to add a parameter to this function in case the byte386// order of the memory data doesn't match the process. For now we are387// assuming they are the same.388const size_t bytes_copied = reg_value.GetAsMemoryData(389*reg_info, dst.data(), dst_len, process.GetByteOrder(), error);390391if (error.Success()) {392if (bytes_copied == 0) {393error.SetErrorString("byte copy failed.");394} else {395size_t bytes_written;396error = process.WriteMemory(dst_addr, dst.data(), bytes_copied,397bytes_written);398if (error.Fail())399return error;400401if (bytes_written != bytes_copied) {402// This might happen if we read _some_ bytes but not all403error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64404" bytes",405static_cast<uint64_t>(bytes_written),406static_cast<uint64_t>(bytes_copied));407}408}409}410411return error;412}413414uint32_t415NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind,416uint32_t num) const {417const uint32_t num_regs = GetRegisterCount();418419assert(kind < kNumRegisterKinds);420for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {421const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);422423if (reg_info->kinds[kind] == num)424return reg_idx;425}426427return LLDB_INVALID_REGNUM;428}429430std::vector<uint32_t>431NativeRegisterContext::GetExpeditedRegisters(ExpeditedRegs expType) const {432if (expType == ExpeditedRegs::Minimal) {433// Expedite only a minimum set of important generic registers.434static const uint32_t k_expedited_registers[] = {435LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP,436LLDB_REGNUM_GENERIC_RA};437438std::vector<uint32_t> expedited_reg_nums;439for (uint32_t gen_reg : k_expedited_registers) {440uint32_t reg_num =441ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, gen_reg);442if (reg_num == LLDB_INVALID_REGNUM)443continue; // Target does not support the given register.444else445expedited_reg_nums.push_back(reg_num);446}447448return expedited_reg_nums;449}450451if (GetRegisterSetCount() > 0 && expType == ExpeditedRegs::Full)452return std::vector<uint32_t>(GetRegisterSet(0)->registers,453GetRegisterSet(0)->registers +454GetRegisterSet(0)->num_registers);455456return std::vector<uint32_t>();457}458459460