forked from OSchip/llvm-project
695 lines
22 KiB
C++
695 lines
22 KiB
C++
//===-- Value.cpp ---------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Core/Value.h"
|
|
|
|
#include "lldb/Core/Address.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Symbol/CompilerType.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Symbol/SymbolContext.h"
|
|
#include "lldb/Symbol/Type.h"
|
|
#include "lldb/Symbol/Variable.h"
|
|
#include "lldb/Target/ExecutionContext.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/SectionLoadList.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Utility/ConstString.h"
|
|
#include "lldb/Utility/DataBufferHeap.h"
|
|
#include "lldb/Utility/DataExtractor.h"
|
|
#include "lldb/Utility/Endian.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/Utility/State.h"
|
|
#include "lldb/Utility/Stream.h"
|
|
#include "lldb/lldb-defines.h"
|
|
#include "lldb/lldb-forward.h"
|
|
#include "lldb/lldb-types.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include <inttypes.h>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
Value::Value()
|
|
: m_value(), m_compiler_type(), m_context(nullptr),
|
|
m_value_type(ValueType::Scalar), m_context_type(ContextType::Invalid),
|
|
m_data_buffer() {}
|
|
|
|
Value::Value(const Scalar &scalar)
|
|
: m_value(scalar), m_compiler_type(), m_context(nullptr),
|
|
m_value_type(ValueType::Scalar), m_context_type(ContextType::Invalid),
|
|
m_data_buffer() {}
|
|
|
|
Value::Value(const void *bytes, int len)
|
|
: m_value(), m_compiler_type(), m_context(nullptr),
|
|
m_value_type(ValueType::HostAddress), m_context_type(ContextType::Invalid),
|
|
m_data_buffer() {
|
|
SetBytes(bytes, len);
|
|
}
|
|
|
|
Value::Value(const Value &v)
|
|
: m_value(v.m_value), m_compiler_type(v.m_compiler_type),
|
|
m_context(v.m_context), m_value_type(v.m_value_type),
|
|
m_context_type(v.m_context_type), m_data_buffer() {
|
|
const uintptr_t rhs_value =
|
|
(uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
if ((rhs_value != 0) &&
|
|
(rhs_value == (uintptr_t)v.m_data_buffer.GetBytes())) {
|
|
m_data_buffer.CopyData(v.m_data_buffer.GetBytes(),
|
|
v.m_data_buffer.GetByteSize());
|
|
|
|
m_value = (uintptr_t)m_data_buffer.GetBytes();
|
|
}
|
|
}
|
|
|
|
Value &Value::operator=(const Value &rhs) {
|
|
if (this != &rhs) {
|
|
m_value = rhs.m_value;
|
|
m_compiler_type = rhs.m_compiler_type;
|
|
m_context = rhs.m_context;
|
|
m_value_type = rhs.m_value_type;
|
|
m_context_type = rhs.m_context_type;
|
|
const uintptr_t rhs_value =
|
|
(uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
if ((rhs_value != 0) &&
|
|
(rhs_value == (uintptr_t)rhs.m_data_buffer.GetBytes())) {
|
|
m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(),
|
|
rhs.m_data_buffer.GetByteSize());
|
|
|
|
m_value = (uintptr_t)m_data_buffer.GetBytes();
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void Value::SetBytes(const void *bytes, int len) {
|
|
m_value_type = ValueType::HostAddress;
|
|
m_data_buffer.CopyData(bytes, len);
|
|
m_value = (uintptr_t)m_data_buffer.GetBytes();
|
|
}
|
|
|
|
void Value::AppendBytes(const void *bytes, int len) {
|
|
m_value_type = ValueType::HostAddress;
|
|
m_data_buffer.AppendData(bytes, len);
|
|
m_value = (uintptr_t)m_data_buffer.GetBytes();
|
|
}
|
|
|
|
void Value::Dump(Stream *strm) {
|
|
m_value.GetValue(strm, true);
|
|
strm->Printf(", value_type = %s, context = %p, context_type = %s",
|
|
Value::GetValueTypeAsCString(m_value_type), m_context,
|
|
Value::GetContextTypeAsCString(m_context_type));
|
|
}
|
|
|
|
Value::ValueType Value::GetValueType() const { return m_value_type; }
|
|
|
|
AddressType Value::GetValueAddressType() const {
|
|
switch (m_value_type) {
|
|
case ValueType::Invalid:
|
|
case ValueType::Scalar:
|
|
break;
|
|
case ValueType::LoadAddress:
|
|
return eAddressTypeLoad;
|
|
case ValueType::FileAddress:
|
|
return eAddressTypeFile;
|
|
case ValueType::HostAddress:
|
|
return eAddressTypeHost;
|
|
}
|
|
return eAddressTypeInvalid;
|
|
}
|
|
|
|
RegisterInfo *Value::GetRegisterInfo() const {
|
|
if (m_context_type == ContextType::RegisterInfo)
|
|
return static_cast<RegisterInfo *>(m_context);
|
|
return nullptr;
|
|
}
|
|
|
|
Type *Value::GetType() {
|
|
if (m_context_type == ContextType::LLDBType)
|
|
return static_cast<Type *>(m_context);
|
|
return nullptr;
|
|
}
|
|
|
|
size_t Value::AppendDataToHostBuffer(const Value &rhs) {
|
|
if (this == &rhs)
|
|
return 0;
|
|
|
|
size_t curr_size = m_data_buffer.GetByteSize();
|
|
Status error;
|
|
switch (rhs.GetValueType()) {
|
|
case ValueType::Invalid:
|
|
return 0;
|
|
case ValueType::Scalar: {
|
|
const size_t scalar_size = rhs.m_value.GetByteSize();
|
|
if (scalar_size > 0) {
|
|
const size_t new_size = curr_size + scalar_size;
|
|
if (ResizeData(new_size) == new_size) {
|
|
rhs.m_value.GetAsMemoryData(m_data_buffer.GetBytes() + curr_size,
|
|
scalar_size, endian::InlHostByteOrder(),
|
|
error);
|
|
return scalar_size;
|
|
}
|
|
}
|
|
} break;
|
|
case ValueType::FileAddress:
|
|
case ValueType::LoadAddress:
|
|
case ValueType::HostAddress: {
|
|
const uint8_t *src = rhs.GetBuffer().GetBytes();
|
|
const size_t src_len = rhs.GetBuffer().GetByteSize();
|
|
if (src && src_len > 0) {
|
|
const size_t new_size = curr_size + src_len;
|
|
if (ResizeData(new_size) == new_size) {
|
|
::memcpy(m_data_buffer.GetBytes() + curr_size, src, src_len);
|
|
return src_len;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t Value::ResizeData(size_t len) {
|
|
m_value_type = ValueType::HostAddress;
|
|
m_data_buffer.SetByteSize(len);
|
|
m_value = (uintptr_t)m_data_buffer.GetBytes();
|
|
return m_data_buffer.GetByteSize();
|
|
}
|
|
|
|
bool Value::ValueOf(ExecutionContext *exe_ctx) {
|
|
switch (m_context_type) {
|
|
case ContextType::Invalid:
|
|
case ContextType::RegisterInfo: // RegisterInfo *
|
|
case ContextType::LLDBType: // Type *
|
|
break;
|
|
|
|
case ContextType::Variable: // Variable *
|
|
ResolveValue(exe_ctx);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) {
|
|
switch (m_context_type) {
|
|
case ContextType::RegisterInfo: // RegisterInfo *
|
|
if (GetRegisterInfo()) {
|
|
if (error_ptr)
|
|
error_ptr->Clear();
|
|
return GetRegisterInfo()->byte_size;
|
|
}
|
|
break;
|
|
|
|
case ContextType::Invalid:
|
|
case ContextType::LLDBType: // Type *
|
|
case ContextType::Variable: // Variable *
|
|
{
|
|
auto *scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
|
|
if (llvm::Optional<uint64_t> size = GetCompilerType().GetByteSize(scope)) {
|
|
if (error_ptr)
|
|
error_ptr->Clear();
|
|
return *size;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (error_ptr && error_ptr->Success())
|
|
error_ptr->SetErrorString("Unable to determine byte size.");
|
|
return 0;
|
|
}
|
|
|
|
const CompilerType &Value::GetCompilerType() {
|
|
if (!m_compiler_type.IsValid()) {
|
|
switch (m_context_type) {
|
|
case ContextType::Invalid:
|
|
break;
|
|
|
|
case ContextType::RegisterInfo:
|
|
break; // TODO: Eventually convert into a compiler type?
|
|
|
|
case ContextType::LLDBType: {
|
|
Type *lldb_type = GetType();
|
|
if (lldb_type)
|
|
m_compiler_type = lldb_type->GetForwardCompilerType();
|
|
} break;
|
|
|
|
case ContextType::Variable: {
|
|
Variable *variable = GetVariable();
|
|
if (variable) {
|
|
Type *variable_type = variable->GetType();
|
|
if (variable_type)
|
|
m_compiler_type = variable_type->GetForwardCompilerType();
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
return m_compiler_type;
|
|
}
|
|
|
|
void Value::SetCompilerType(const CompilerType &compiler_type) {
|
|
m_compiler_type = compiler_type;
|
|
}
|
|
|
|
lldb::Format Value::GetValueDefaultFormat() {
|
|
switch (m_context_type) {
|
|
case ContextType::RegisterInfo:
|
|
if (GetRegisterInfo())
|
|
return GetRegisterInfo()->format;
|
|
break;
|
|
|
|
case ContextType::Invalid:
|
|
case ContextType::LLDBType:
|
|
case ContextType::Variable: {
|
|
const CompilerType &ast_type = GetCompilerType();
|
|
if (ast_type.IsValid())
|
|
return ast_type.GetFormat();
|
|
} break;
|
|
}
|
|
|
|
// Return a good default in case we can't figure anything out
|
|
return eFormatHex;
|
|
}
|
|
|
|
bool Value::GetData(DataExtractor &data) {
|
|
switch (m_value_type) {
|
|
case ValueType::Invalid:
|
|
return false;
|
|
case ValueType::Scalar:
|
|
if (m_value.GetData(data))
|
|
return true;
|
|
break;
|
|
|
|
case ValueType::LoadAddress:
|
|
case ValueType::FileAddress:
|
|
case ValueType::HostAddress:
|
|
if (m_data_buffer.GetByteSize()) {
|
|
data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(),
|
|
data.GetByteOrder());
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
|
|
Module *module) {
|
|
data.Clear();
|
|
|
|
Status error;
|
|
lldb::addr_t address = LLDB_INVALID_ADDRESS;
|
|
AddressType address_type = eAddressTypeFile;
|
|
Address file_so_addr;
|
|
const CompilerType &ast_type = GetCompilerType();
|
|
llvm::Optional<uint64_t> type_size = ast_type.GetByteSize(
|
|
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr);
|
|
// Nothing to be done for a zero-sized type.
|
|
if (type_size && *type_size == 0)
|
|
return error;
|
|
|
|
switch (m_value_type) {
|
|
case ValueType::Invalid:
|
|
error.SetErrorString("invalid value");
|
|
break;
|
|
case ValueType::Scalar: {
|
|
data.SetByteOrder(endian::InlHostByteOrder());
|
|
if (ast_type.IsValid())
|
|
data.SetAddressByteSize(ast_type.GetPointerByteSize());
|
|
else
|
|
data.SetAddressByteSize(sizeof(void *));
|
|
|
|
uint32_t limit_byte_size = UINT32_MAX;
|
|
|
|
if (type_size)
|
|
limit_byte_size = *type_size;
|
|
|
|
if (limit_byte_size <= m_value.GetByteSize()) {
|
|
if (m_value.GetData(data, limit_byte_size))
|
|
return error; // Success;
|
|
}
|
|
|
|
error.SetErrorString("extracting data from value failed");
|
|
break;
|
|
}
|
|
case ValueType::LoadAddress:
|
|
if (exe_ctx == nullptr) {
|
|
error.SetErrorString("can't read load address (no execution context)");
|
|
} else {
|
|
Process *process = exe_ctx->GetProcessPtr();
|
|
if (process == nullptr || !process->IsAlive()) {
|
|
Target *target = exe_ctx->GetTargetPtr();
|
|
if (target) {
|
|
// Allow expressions to run and evaluate things when the target has
|
|
// memory sections loaded. This allows you to use "target modules
|
|
// load" to load your executable and any shared libraries, then
|
|
// execute commands where you can look at types in data sections.
|
|
const SectionLoadList &target_sections = target->GetSectionLoadList();
|
|
if (!target_sections.IsEmpty()) {
|
|
address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
if (target_sections.ResolveLoadAddress(address, file_so_addr)) {
|
|
address_type = eAddressTypeLoad;
|
|
data.SetByteOrder(target->GetArchitecture().GetByteOrder());
|
|
data.SetAddressByteSize(
|
|
target->GetArchitecture().GetAddressByteSize());
|
|
} else
|
|
address = LLDB_INVALID_ADDRESS;
|
|
}
|
|
} else {
|
|
error.SetErrorString("can't read load address (invalid process)");
|
|
}
|
|
} else {
|
|
address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
address_type = eAddressTypeLoad;
|
|
data.SetByteOrder(
|
|
process->GetTarget().GetArchitecture().GetByteOrder());
|
|
data.SetAddressByteSize(
|
|
process->GetTarget().GetArchitecture().GetAddressByteSize());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ValueType::FileAddress:
|
|
if (exe_ctx == nullptr) {
|
|
error.SetErrorString("can't read file address (no execution context)");
|
|
} else if (exe_ctx->GetTargetPtr() == nullptr) {
|
|
error.SetErrorString("can't read file address (invalid target)");
|
|
} else {
|
|
address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
if (address == LLDB_INVALID_ADDRESS) {
|
|
error.SetErrorString("invalid file address");
|
|
} else {
|
|
if (module == nullptr) {
|
|
// The only thing we can currently lock down to a module so that we
|
|
// can resolve a file address, is a variable.
|
|
Variable *variable = GetVariable();
|
|
if (variable) {
|
|
SymbolContext var_sc;
|
|
variable->CalculateSymbolContext(&var_sc);
|
|
module = var_sc.module_sp.get();
|
|
}
|
|
}
|
|
|
|
if (module) {
|
|
bool resolved = false;
|
|
ObjectFile *objfile = module->GetObjectFile();
|
|
if (objfile) {
|
|
Address so_addr(address, objfile->GetSectionList());
|
|
addr_t load_address =
|
|
so_addr.GetLoadAddress(exe_ctx->GetTargetPtr());
|
|
bool process_launched_and_stopped =
|
|
exe_ctx->GetProcessPtr()
|
|
? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(),
|
|
true /* must_exist */)
|
|
: false;
|
|
// Don't use the load address if the process has exited.
|
|
if (load_address != LLDB_INVALID_ADDRESS &&
|
|
process_launched_and_stopped) {
|
|
resolved = true;
|
|
address = load_address;
|
|
address_type = eAddressTypeLoad;
|
|
data.SetByteOrder(
|
|
exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder());
|
|
data.SetAddressByteSize(exe_ctx->GetTargetRef()
|
|
.GetArchitecture()
|
|
.GetAddressByteSize());
|
|
} else {
|
|
if (so_addr.IsSectionOffset()) {
|
|
resolved = true;
|
|
file_so_addr = so_addr;
|
|
data.SetByteOrder(objfile->GetByteOrder());
|
|
data.SetAddressByteSize(objfile->GetAddressByteSize());
|
|
}
|
|
}
|
|
}
|
|
if (!resolved) {
|
|
Variable *variable = GetVariable();
|
|
|
|
if (module) {
|
|
if (variable)
|
|
error.SetErrorStringWithFormat(
|
|
"unable to resolve the module for file address 0x%" PRIx64
|
|
" for variable '%s' in %s",
|
|
address, variable->GetName().AsCString(""),
|
|
module->GetFileSpec().GetPath().c_str());
|
|
else
|
|
error.SetErrorStringWithFormat(
|
|
"unable to resolve the module for file address 0x%" PRIx64
|
|
" in %s",
|
|
address, module->GetFileSpec().GetPath().c_str());
|
|
} else {
|
|
if (variable)
|
|
error.SetErrorStringWithFormat(
|
|
"unable to resolve the module for file address 0x%" PRIx64
|
|
" for variable '%s'",
|
|
address, variable->GetName().AsCString(""));
|
|
else
|
|
error.SetErrorStringWithFormat(
|
|
"unable to resolve the module for file address 0x%" PRIx64,
|
|
address);
|
|
}
|
|
}
|
|
} else {
|
|
// Can't convert a file address to anything valid without more
|
|
// context (which Module it came from)
|
|
error.SetErrorString(
|
|
"can't read memory from file address without more context");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ValueType::HostAddress:
|
|
address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
address_type = eAddressTypeHost;
|
|
if (exe_ctx) {
|
|
Target *target = exe_ctx->GetTargetPtr();
|
|
if (target) {
|
|
data.SetByteOrder(target->GetArchitecture().GetByteOrder());
|
|
data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
|
|
break;
|
|
}
|
|
}
|
|
// fallback to host settings
|
|
data.SetByteOrder(endian::InlHostByteOrder());
|
|
data.SetAddressByteSize(sizeof(void *));
|
|
break;
|
|
}
|
|
|
|
// Bail if we encountered any errors
|
|
if (error.Fail())
|
|
return error;
|
|
|
|
if (address == LLDB_INVALID_ADDRESS) {
|
|
error.SetErrorStringWithFormat("invalid %s address",
|
|
address_type == eAddressTypeHost ? "host"
|
|
: "load");
|
|
return error;
|
|
}
|
|
|
|
// If we got here, we need to read the value from memory.
|
|
size_t byte_size = GetValueByteSize(&error, exe_ctx);
|
|
|
|
// Bail if we encountered any errors getting the byte size.
|
|
if (error.Fail())
|
|
return error;
|
|
|
|
// No memory to read for zero-sized types.
|
|
if (byte_size == 0)
|
|
return error;
|
|
|
|
// Make sure we have enough room within "data", and if we don't make
|
|
// something large enough that does
|
|
if (!data.ValidOffsetForDataOfSize(0, byte_size)) {
|
|
auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');
|
|
data.SetData(data_sp);
|
|
}
|
|
|
|
uint8_t *dst = const_cast<uint8_t *>(data.PeekData(0, byte_size));
|
|
if (dst != nullptr) {
|
|
if (address_type == eAddressTypeHost) {
|
|
// The address is an address in this process, so just copy it.
|
|
if (address == 0) {
|
|
error.SetErrorString("trying to read from host address of 0.");
|
|
return error;
|
|
}
|
|
memcpy(dst, reinterpret_cast<uint8_t *>(address), byte_size);
|
|
} else if ((address_type == eAddressTypeLoad) ||
|
|
(address_type == eAddressTypeFile)) {
|
|
if (file_so_addr.IsValid()) {
|
|
// We have a file address that we were able to translate into a section
|
|
// offset address so we might be able to read this from the object
|
|
// files if we don't have a live process. Lets always try and read from
|
|
// the process if we have one though since we want to read the actual
|
|
// value by setting "prefer_file_cache" to false.
|
|
const bool prefer_file_cache = false;
|
|
if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache,
|
|
dst, byte_size,
|
|
error) != byte_size) {
|
|
error.SetErrorStringWithFormat(
|
|
"read memory from 0x%" PRIx64 " failed", (uint64_t)address);
|
|
}
|
|
} else {
|
|
// The execution context might have a NULL process, but it might have a
|
|
// valid process in the exe_ctx->target, so use the
|
|
// ExecutionContext::GetProcess accessor to ensure we get the process
|
|
// if there is one.
|
|
Process *process = exe_ctx->GetProcessPtr();
|
|
|
|
if (process) {
|
|
const size_t bytes_read =
|
|
process->ReadMemory(address, dst, byte_size, error);
|
|
if (bytes_read != byte_size)
|
|
error.SetErrorStringWithFormat(
|
|
"read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
|
|
(uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size);
|
|
} else {
|
|
error.SetErrorStringWithFormat("read memory from 0x%" PRIx64
|
|
" failed (invalid process)",
|
|
(uint64_t)address);
|
|
}
|
|
}
|
|
} else {
|
|
error.SetErrorStringWithFormat("unsupported AddressType value (%i)",
|
|
address_type);
|
|
}
|
|
} else {
|
|
error.SetErrorString("out of memory");
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) {
|
|
const CompilerType &compiler_type = GetCompilerType();
|
|
if (compiler_type.IsValid()) {
|
|
switch (m_value_type) {
|
|
case ValueType::Invalid:
|
|
case ValueType::Scalar: // raw scalar value
|
|
break;
|
|
|
|
case ValueType::FileAddress:
|
|
case ValueType::LoadAddress: // load address value
|
|
case ValueType::HostAddress: // host address value (for memory in the process
|
|
// that is using liblldb)
|
|
{
|
|
DataExtractor data;
|
|
lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
|
|
Status error(GetValueAsData(exe_ctx, data, nullptr));
|
|
if (error.Success()) {
|
|
Scalar scalar;
|
|
if (compiler_type.GetValueAsScalar(
|
|
data, 0, data.GetByteSize(), scalar,
|
|
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr)) {
|
|
m_value = scalar;
|
|
m_value_type = ValueType::Scalar;
|
|
} else {
|
|
if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) {
|
|
m_value.Clear();
|
|
m_value_type = ValueType::Scalar;
|
|
}
|
|
}
|
|
} else {
|
|
if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) {
|
|
m_value.Clear();
|
|
m_value_type = ValueType::Scalar;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
return m_value;
|
|
}
|
|
|
|
Variable *Value::GetVariable() {
|
|
if (m_context_type == ContextType::Variable)
|
|
return static_cast<Variable *>(m_context);
|
|
return nullptr;
|
|
}
|
|
|
|
void Value::Clear() {
|
|
m_value.Clear();
|
|
m_compiler_type.Clear();
|
|
m_value_type = ValueType::Scalar;
|
|
m_context = nullptr;
|
|
m_context_type = ContextType::Invalid;
|
|
m_data_buffer.Clear();
|
|
}
|
|
|
|
const char *Value::GetValueTypeAsCString(ValueType value_type) {
|
|
switch (value_type) {
|
|
case ValueType::Invalid:
|
|
return "invalid";
|
|
case ValueType::Scalar:
|
|
return "scalar";
|
|
case ValueType::FileAddress:
|
|
return "file address";
|
|
case ValueType::LoadAddress:
|
|
return "load address";
|
|
case ValueType::HostAddress:
|
|
return "host address";
|
|
};
|
|
llvm_unreachable("enum cases exhausted.");
|
|
}
|
|
|
|
const char *Value::GetContextTypeAsCString(ContextType context_type) {
|
|
switch (context_type) {
|
|
case ContextType::Invalid:
|
|
return "invalid";
|
|
case ContextType::RegisterInfo:
|
|
return "RegisterInfo *";
|
|
case ContextType::LLDBType:
|
|
return "Type *";
|
|
case ContextType::Variable:
|
|
return "Variable *";
|
|
};
|
|
llvm_unreachable("enum cases exhausted.");
|
|
}
|
|
|
|
void Value::ConvertToLoadAddress(Module *module, Target *target) {
|
|
if (!module || !target || (GetValueType() != ValueType::FileAddress))
|
|
return;
|
|
|
|
lldb::addr_t file_addr = GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
|
|
if (file_addr == LLDB_INVALID_ADDRESS)
|
|
return;
|
|
|
|
Address so_addr;
|
|
if (!module->ResolveFileAddress(file_addr, so_addr))
|
|
return;
|
|
lldb::addr_t load_addr = so_addr.GetLoadAddress(target);
|
|
if (load_addr == LLDB_INVALID_ADDRESS)
|
|
return;
|
|
|
|
SetValueType(Value::ValueType::LoadAddress);
|
|
GetScalar() = load_addr;
|
|
}
|
|
|
|
ValueList::ValueList(const ValueList &rhs) { m_values = rhs.m_values; }
|
|
|
|
const ValueList &ValueList::operator=(const ValueList &rhs) {
|
|
m_values = rhs.m_values;
|
|
return *this;
|
|
}
|
|
|
|
void ValueList::PushValue(const Value &value) { m_values.push_back(value); }
|
|
|
|
size_t ValueList::GetSize() { return m_values.size(); }
|
|
|
|
Value *ValueList::GetValueAtIndex(size_t idx) {
|
|
if (idx < GetSize()) {
|
|
return &(m_values[idx]);
|
|
} else
|
|
return nullptr;
|
|
}
|
|
|
|
void ValueList::Clear() { m_values.clear(); }
|