Path: blob/main/contrib/llvm-project/lldb/source/Core/Value.cpp
39587 views
//===-- Value.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/Core/Value.h"910#include "lldb/Core/Address.h"11#include "lldb/Core/Module.h"12#include "lldb/Symbol/CompilerType.h"13#include "lldb/Symbol/ObjectFile.h"14#include "lldb/Symbol/SymbolContext.h"15#include "lldb/Symbol/Type.h"16#include "lldb/Symbol/Variable.h"17#include "lldb/Target/ExecutionContext.h"18#include "lldb/Target/Process.h"19#include "lldb/Target/SectionLoadList.h"20#include "lldb/Target/Target.h"21#include "lldb/Utility/ConstString.h"22#include "lldb/Utility/DataBufferHeap.h"23#include "lldb/Utility/DataExtractor.h"24#include "lldb/Utility/Endian.h"25#include "lldb/Utility/FileSpec.h"26#include "lldb/Utility/State.h"27#include "lldb/Utility/Stream.h"28#include "lldb/lldb-defines.h"29#include "lldb/lldb-forward.h"30#include "lldb/lldb-types.h"3132#include <memory>33#include <optional>34#include <string>3536#include <cinttypes>3738using namespace lldb;39using namespace lldb_private;4041Value::Value() : m_value(), m_compiler_type(), m_data_buffer() {}4243Value::Value(const Scalar &scalar)44: m_value(scalar), m_compiler_type(), m_data_buffer() {}4546Value::Value(const void *bytes, int len)47: m_value(), m_compiler_type(), m_value_type(ValueType::HostAddress),48m_data_buffer() {49SetBytes(bytes, len);50}5152Value::Value(const Value &v)53: m_value(v.m_value), m_compiler_type(v.m_compiler_type),54m_context(v.m_context), m_value_type(v.m_value_type),55m_context_type(v.m_context_type), m_data_buffer() {56const uintptr_t rhs_value =57(uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS);58if ((rhs_value != 0) &&59(rhs_value == (uintptr_t)v.m_data_buffer.GetBytes())) {60m_data_buffer.CopyData(v.m_data_buffer.GetBytes(),61v.m_data_buffer.GetByteSize());6263m_value = (uintptr_t)m_data_buffer.GetBytes();64}65}6667Value &Value::operator=(const Value &rhs) {68if (this != &rhs) {69m_value = rhs.m_value;70m_compiler_type = rhs.m_compiler_type;71m_context = rhs.m_context;72m_value_type = rhs.m_value_type;73m_context_type = rhs.m_context_type;74const uintptr_t rhs_value =75(uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS);76if ((rhs_value != 0) &&77(rhs_value == (uintptr_t)rhs.m_data_buffer.GetBytes())) {78m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(),79rhs.m_data_buffer.GetByteSize());8081m_value = (uintptr_t)m_data_buffer.GetBytes();82}83}84return *this;85}8687void Value::SetBytes(const void *bytes, int len) {88m_value_type = ValueType::HostAddress;89m_data_buffer.CopyData(bytes, len);90m_value = (uintptr_t)m_data_buffer.GetBytes();91}9293void Value::AppendBytes(const void *bytes, int len) {94m_value_type = ValueType::HostAddress;95m_data_buffer.AppendData(bytes, len);96m_value = (uintptr_t)m_data_buffer.GetBytes();97}9899void Value::Dump(Stream *strm) {100if (!strm)101return;102m_value.GetValue(*strm, true);103strm->Printf(", value_type = %s, context = %p, context_type = %s",104Value::GetValueTypeAsCString(m_value_type), m_context,105Value::GetContextTypeAsCString(m_context_type));106}107108Value::ValueType Value::GetValueType() const { return m_value_type; }109110AddressType Value::GetValueAddressType() const {111switch (m_value_type) {112case ValueType::Invalid:113case ValueType::Scalar:114break;115case ValueType::LoadAddress:116return eAddressTypeLoad;117case ValueType::FileAddress:118return eAddressTypeFile;119case ValueType::HostAddress:120return eAddressTypeHost;121}122return eAddressTypeInvalid;123}124125Value::ValueType Value::GetValueTypeFromAddressType(AddressType address_type) {126switch (address_type) {127case eAddressTypeFile:128return Value::ValueType::FileAddress;129case eAddressTypeLoad:130return Value::ValueType::LoadAddress;131case eAddressTypeHost:132return Value::ValueType::HostAddress;133case eAddressTypeInvalid:134return Value::ValueType::Invalid;135}136llvm_unreachable("Unexpected address type!");137}138139RegisterInfo *Value::GetRegisterInfo() const {140if (m_context_type == ContextType::RegisterInfo)141return static_cast<RegisterInfo *>(m_context);142return nullptr;143}144145Type *Value::GetType() {146if (m_context_type == ContextType::LLDBType)147return static_cast<Type *>(m_context);148return nullptr;149}150151size_t Value::AppendDataToHostBuffer(const Value &rhs) {152if (this == &rhs)153return 0;154155size_t curr_size = m_data_buffer.GetByteSize();156Status error;157switch (rhs.GetValueType()) {158case ValueType::Invalid:159return 0;160case ValueType::Scalar: {161const size_t scalar_size = rhs.m_value.GetByteSize();162if (scalar_size > 0) {163const size_t new_size = curr_size + scalar_size;164if (ResizeData(new_size) == new_size) {165rhs.m_value.GetAsMemoryData(m_data_buffer.GetBytes() + curr_size,166scalar_size, endian::InlHostByteOrder(),167error);168return scalar_size;169}170}171} break;172case ValueType::FileAddress:173case ValueType::LoadAddress:174case ValueType::HostAddress: {175const uint8_t *src = rhs.GetBuffer().GetBytes();176const size_t src_len = rhs.GetBuffer().GetByteSize();177if (src && src_len > 0) {178const size_t new_size = curr_size + src_len;179if (ResizeData(new_size) == new_size) {180::memcpy(m_data_buffer.GetBytes() + curr_size, src, src_len);181return src_len;182}183}184} break;185}186return 0;187}188189size_t Value::ResizeData(size_t len) {190m_value_type = ValueType::HostAddress;191m_data_buffer.SetByteSize(len);192m_value = (uintptr_t)m_data_buffer.GetBytes();193return m_data_buffer.GetByteSize();194}195196bool Value::ValueOf(ExecutionContext *exe_ctx) {197switch (m_context_type) {198case ContextType::Invalid:199case ContextType::RegisterInfo: // RegisterInfo *200case ContextType::LLDBType: // Type *201break;202203case ContextType::Variable: // Variable *204ResolveValue(exe_ctx);205return true;206}207return false;208}209210uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) {211switch (m_context_type) {212case ContextType::RegisterInfo: // RegisterInfo *213if (GetRegisterInfo()) {214if (error_ptr)215error_ptr->Clear();216return GetRegisterInfo()->byte_size;217}218break;219220case ContextType::Invalid:221case ContextType::LLDBType: // Type *222case ContextType::Variable: // Variable *223{224auto *scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;225if (std::optional<uint64_t> size = GetCompilerType().GetByteSize(scope)) {226if (error_ptr)227error_ptr->Clear();228return *size;229}230break;231}232}233if (error_ptr && error_ptr->Success())234error_ptr->SetErrorString("Unable to determine byte size.");235return 0;236}237238const CompilerType &Value::GetCompilerType() {239if (!m_compiler_type.IsValid()) {240switch (m_context_type) {241case ContextType::Invalid:242break;243244case ContextType::RegisterInfo:245break; // TODO: Eventually convert into a compiler type?246247case ContextType::LLDBType: {248Type *lldb_type = GetType();249if (lldb_type)250m_compiler_type = lldb_type->GetForwardCompilerType();251} break;252253case ContextType::Variable: {254Variable *variable = GetVariable();255if (variable) {256Type *variable_type = variable->GetType();257if (variable_type)258m_compiler_type = variable_type->GetForwardCompilerType();259}260} break;261}262}263264return m_compiler_type;265}266267void Value::SetCompilerType(const CompilerType &compiler_type) {268m_compiler_type = compiler_type;269}270271lldb::Format Value::GetValueDefaultFormat() {272switch (m_context_type) {273case ContextType::RegisterInfo:274if (GetRegisterInfo())275return GetRegisterInfo()->format;276break;277278case ContextType::Invalid:279case ContextType::LLDBType:280case ContextType::Variable: {281const CompilerType &ast_type = GetCompilerType();282if (ast_type.IsValid())283return ast_type.GetFormat();284} break;285}286287// Return a good default in case we can't figure anything out288return eFormatHex;289}290291bool Value::GetData(DataExtractor &data) {292switch (m_value_type) {293case ValueType::Invalid:294return false;295case ValueType::Scalar:296if (m_value.GetData(data))297return true;298break;299300case ValueType::LoadAddress:301case ValueType::FileAddress:302case ValueType::HostAddress:303if (m_data_buffer.GetByteSize()) {304data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(),305data.GetByteOrder());306return true;307}308break;309}310311return false;312}313314Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,315Module *module) {316data.Clear();317318Status error;319lldb::addr_t address = LLDB_INVALID_ADDRESS;320AddressType address_type = eAddressTypeFile;321Address file_so_addr;322const CompilerType &ast_type = GetCompilerType();323std::optional<uint64_t> type_size = ast_type.GetByteSize(324exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr);325// Nothing to be done for a zero-sized type.326if (type_size && *type_size == 0)327return error;328329switch (m_value_type) {330case ValueType::Invalid:331error.SetErrorString("invalid value");332break;333case ValueType::Scalar: {334data.SetByteOrder(endian::InlHostByteOrder());335if (ast_type.IsValid())336data.SetAddressByteSize(ast_type.GetPointerByteSize());337else338data.SetAddressByteSize(sizeof(void *));339340uint32_t limit_byte_size = UINT32_MAX;341342if (type_size)343limit_byte_size = *type_size;344345if (limit_byte_size <= m_value.GetByteSize()) {346if (m_value.GetData(data, limit_byte_size))347return error; // Success;348}349350error.SetErrorString("extracting data from value failed");351break;352}353case ValueType::LoadAddress:354if (exe_ctx == nullptr) {355error.SetErrorString("can't read load address (no execution context)");356} else {357Process *process = exe_ctx->GetProcessPtr();358if (process == nullptr || !process->IsAlive()) {359Target *target = exe_ctx->GetTargetPtr();360if (target) {361// Allow expressions to run and evaluate things when the target has362// memory sections loaded. This allows you to use "target modules363// load" to load your executable and any shared libraries, then364// execute commands where you can look at types in data sections.365const SectionLoadList &target_sections = target->GetSectionLoadList();366if (!target_sections.IsEmpty()) {367address = m_value.ULongLong(LLDB_INVALID_ADDRESS);368if (target_sections.ResolveLoadAddress(address, file_so_addr)) {369address_type = eAddressTypeLoad;370data.SetByteOrder(target->GetArchitecture().GetByteOrder());371data.SetAddressByteSize(372target->GetArchitecture().GetAddressByteSize());373} else374address = LLDB_INVALID_ADDRESS;375}376} else {377error.SetErrorString("can't read load address (invalid process)");378}379} else {380address = m_value.ULongLong(LLDB_INVALID_ADDRESS);381address_type = eAddressTypeLoad;382data.SetByteOrder(383process->GetTarget().GetArchitecture().GetByteOrder());384data.SetAddressByteSize(385process->GetTarget().GetArchitecture().GetAddressByteSize());386}387}388break;389390case ValueType::FileAddress:391if (exe_ctx == nullptr) {392error.SetErrorString("can't read file address (no execution context)");393} else if (exe_ctx->GetTargetPtr() == nullptr) {394error.SetErrorString("can't read file address (invalid target)");395} else {396address = m_value.ULongLong(LLDB_INVALID_ADDRESS);397if (address == LLDB_INVALID_ADDRESS) {398error.SetErrorString("invalid file address");399} else {400if (module == nullptr) {401// The only thing we can currently lock down to a module so that we402// can resolve a file address, is a variable.403Variable *variable = GetVariable();404if (variable) {405SymbolContext var_sc;406variable->CalculateSymbolContext(&var_sc);407module = var_sc.module_sp.get();408}409}410411if (module) {412bool resolved = false;413ObjectFile *objfile = module->GetObjectFile();414if (objfile) {415Address so_addr(address, objfile->GetSectionList());416addr_t load_address =417so_addr.GetLoadAddress(exe_ctx->GetTargetPtr());418bool process_launched_and_stopped =419exe_ctx->GetProcessPtr()420? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(),421true /* must_exist */)422: false;423// Don't use the load address if the process has exited.424if (load_address != LLDB_INVALID_ADDRESS &&425process_launched_and_stopped) {426resolved = true;427address = load_address;428address_type = eAddressTypeLoad;429data.SetByteOrder(430exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder());431data.SetAddressByteSize(exe_ctx->GetTargetRef()432.GetArchitecture()433.GetAddressByteSize());434} else {435if (so_addr.IsSectionOffset()) {436resolved = true;437file_so_addr = so_addr;438data.SetByteOrder(objfile->GetByteOrder());439data.SetAddressByteSize(objfile->GetAddressByteSize());440}441}442}443if (!resolved) {444Variable *variable = GetVariable();445446if (module) {447if (variable)448error.SetErrorStringWithFormat(449"unable to resolve the module for file address 0x%" PRIx64450" for variable '%s' in %s",451address, variable->GetName().AsCString(""),452module->GetFileSpec().GetPath().c_str());453else454error.SetErrorStringWithFormat(455"unable to resolve the module for file address 0x%" PRIx64456" in %s",457address, module->GetFileSpec().GetPath().c_str());458} else {459if (variable)460error.SetErrorStringWithFormat(461"unable to resolve the module for file address 0x%" PRIx64462" for variable '%s'",463address, variable->GetName().AsCString(""));464else465error.SetErrorStringWithFormat(466"unable to resolve the module for file address 0x%" PRIx64,467address);468}469}470} else {471// Can't convert a file address to anything valid without more472// context (which Module it came from)473error.SetErrorString(474"can't read memory from file address without more context");475}476}477}478break;479480case ValueType::HostAddress:481address = m_value.ULongLong(LLDB_INVALID_ADDRESS);482address_type = eAddressTypeHost;483if (exe_ctx) {484Target *target = exe_ctx->GetTargetPtr();485if (target) {486data.SetByteOrder(target->GetArchitecture().GetByteOrder());487data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());488break;489}490}491// fallback to host settings492data.SetByteOrder(endian::InlHostByteOrder());493data.SetAddressByteSize(sizeof(void *));494break;495}496497// Bail if we encountered any errors498if (error.Fail())499return error;500501if (address == LLDB_INVALID_ADDRESS) {502error.SetErrorStringWithFormat("invalid %s address",503address_type == eAddressTypeHost ? "host"504: "load");505return error;506}507508// If we got here, we need to read the value from memory.509size_t byte_size = GetValueByteSize(&error, exe_ctx);510511// Bail if we encountered any errors getting the byte size.512if (error.Fail())513return error;514515// No memory to read for zero-sized types.516if (byte_size == 0)517return error;518519// Make sure we have enough room within "data", and if we don't make520// something large enough that does521if (!data.ValidOffsetForDataOfSize(0, byte_size)) {522auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');523data.SetData(data_sp);524}525526uint8_t *dst = const_cast<uint8_t *>(data.PeekData(0, byte_size));527if (dst != nullptr) {528if (address_type == eAddressTypeHost) {529// The address is an address in this process, so just copy it.530if (address == 0) {531error.SetErrorString("trying to read from host address of 0.");532return error;533}534memcpy(dst, reinterpret_cast<uint8_t *>(address), byte_size);535} else if ((address_type == eAddressTypeLoad) ||536(address_type == eAddressTypeFile)) {537if (file_so_addr.IsValid()) {538const bool force_live_memory = true;539if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, dst, byte_size,540error, force_live_memory) !=541byte_size) {542error.SetErrorStringWithFormat(543"read memory from 0x%" PRIx64 " failed", (uint64_t)address);544}545} else {546// The execution context might have a NULL process, but it might have a547// valid process in the exe_ctx->target, so use the548// ExecutionContext::GetProcess accessor to ensure we get the process549// if there is one.550Process *process = exe_ctx->GetProcessPtr();551552if (process) {553const size_t bytes_read =554process->ReadMemory(address, dst, byte_size, error);555if (bytes_read != byte_size)556error.SetErrorStringWithFormat(557"read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",558(uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size);559} else {560error.SetErrorStringWithFormat("read memory from 0x%" PRIx64561" failed (invalid process)",562(uint64_t)address);563}564}565} else {566error.SetErrorStringWithFormat("unsupported AddressType value (%i)",567address_type);568}569} else {570error.SetErrorString("out of memory");571}572573return error;574}575576Scalar &Value::ResolveValue(ExecutionContext *exe_ctx, Module *module) {577const CompilerType &compiler_type = GetCompilerType();578if (compiler_type.IsValid()) {579switch (m_value_type) {580case ValueType::Invalid:581case ValueType::Scalar: // raw scalar value582break;583584case ValueType::FileAddress:585case ValueType::LoadAddress: // load address value586case ValueType::HostAddress: // host address value (for memory in the process587// that is using liblldb)588{589DataExtractor data;590lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);591Status error(GetValueAsData(exe_ctx, data, module));592if (error.Success()) {593Scalar scalar;594if (compiler_type.GetValueAsScalar(595data, 0, data.GetByteSize(), scalar,596exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr)) {597m_value = scalar;598m_value_type = ValueType::Scalar;599} else {600if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) {601m_value.Clear();602m_value_type = ValueType::Scalar;603}604}605} else {606if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) {607m_value.Clear();608m_value_type = ValueType::Scalar;609}610}611} break;612}613}614return m_value;615}616617Variable *Value::GetVariable() {618if (m_context_type == ContextType::Variable)619return static_cast<Variable *>(m_context);620return nullptr;621}622623void Value::Clear() {624m_value.Clear();625m_compiler_type.Clear();626m_value_type = ValueType::Scalar;627m_context = nullptr;628m_context_type = ContextType::Invalid;629m_data_buffer.Clear();630}631632const char *Value::GetValueTypeAsCString(ValueType value_type) {633switch (value_type) {634case ValueType::Invalid:635return "invalid";636case ValueType::Scalar:637return "scalar";638case ValueType::FileAddress:639return "file address";640case ValueType::LoadAddress:641return "load address";642case ValueType::HostAddress:643return "host address";644};645llvm_unreachable("enum cases exhausted.");646}647648const char *Value::GetContextTypeAsCString(ContextType context_type) {649switch (context_type) {650case ContextType::Invalid:651return "invalid";652case ContextType::RegisterInfo:653return "RegisterInfo *";654case ContextType::LLDBType:655return "Type *";656case ContextType::Variable:657return "Variable *";658};659llvm_unreachable("enum cases exhausted.");660}661662void Value::ConvertToLoadAddress(Module *module, Target *target) {663if (!module || !target || (GetValueType() != ValueType::FileAddress))664return;665666lldb::addr_t file_addr = GetScalar().ULongLong(LLDB_INVALID_ADDRESS);667if (file_addr == LLDB_INVALID_ADDRESS)668return;669670Address so_addr;671if (!module->ResolveFileAddress(file_addr, so_addr))672return;673lldb::addr_t load_addr = so_addr.GetLoadAddress(target);674if (load_addr == LLDB_INVALID_ADDRESS)675return;676677SetValueType(Value::ValueType::LoadAddress);678GetScalar() = load_addr;679}680681void ValueList::PushValue(const Value &value) { m_values.push_back(value); }682683size_t ValueList::GetSize() { return m_values.size(); }684685Value *ValueList::GetValueAtIndex(size_t idx) {686if (idx < GetSize()) {687return &(m_values[idx]);688} else689return nullptr;690}691692void ValueList::Clear() { m_values.clear(); }693694695