diff options
Diffstat (limited to 'source/Core/Value.cpp')
-rw-r--r-- | source/Core/Value.cpp | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/source/Core/Value.cpp b/source/Core/Value.cpp new file mode 100644 index 000000000000..3fe75d3d4ce5 --- /dev/null +++ b/source/Core/Value.cpp @@ -0,0 +1,761 @@ +//===-- Value.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Value.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/State.h" +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/ClangASTType.h" +#include "lldb/Symbol/ClangASTContext.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/Target.h" + +using namespace lldb; +using namespace lldb_private; + +Value::Value() : + m_value (), + m_vector (), + m_clang_type (), + m_context (NULL), + m_value_type (eValueTypeScalar), + m_context_type (eContextTypeInvalid), + m_data_buffer () +{ +} + +Value::Value(const Scalar& scalar) : + m_value (scalar), + m_vector (), + m_clang_type (), + m_context (NULL), + m_value_type (eValueTypeScalar), + m_context_type (eContextTypeInvalid), + m_data_buffer () +{ +} + + +Value::Value(const uint8_t *bytes, int len) : + m_value (), + m_vector (), + m_clang_type (), + m_context (NULL), + m_value_type (eValueTypeHostAddress), + m_context_type (eContextTypeInvalid), + m_data_buffer () +{ + m_data_buffer.CopyData(bytes, len); + m_value = (uintptr_t)m_data_buffer.GetBytes(); +} + +Value::Value(const Value &v) : + m_value (v.m_value), + m_vector (v.m_vector), + m_clang_type (v.m_clang_type), + m_context (v.m_context), + m_value_type (v.m_value_type), + m_context_type (v.m_context_type), + m_data_buffer () +{ + if ((uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (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_vector = rhs.m_vector; + m_clang_type = rhs.m_clang_type; + m_context = rhs.m_context; + m_value_type = rhs.m_value_type; + m_context_type = rhs.m_context_type; + if ((uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (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::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) + { + default: + case eValueTypeScalar: + break; + case eValueTypeLoadAddress: return eAddressTypeLoad; + case eValueTypeFileAddress: return eAddressTypeFile; + case eValueTypeHostAddress: return eAddressTypeHost; + } + return eAddressTypeInvalid; +} + +RegisterInfo * +Value::GetRegisterInfo() const +{ + if (m_context_type == eContextTypeRegisterInfo) + return static_cast<RegisterInfo *> (m_context); + return NULL; +} + +Type * +Value::GetType() +{ + if (m_context_type == eContextTypeLLDBType) + return static_cast<Type *> (m_context); + return NULL; +} + +void +Value::ResizeData(size_t len) +{ + m_value_type = eValueTypeHostAddress; + m_data_buffer.SetByteSize(len); + m_value = (uintptr_t)m_data_buffer.GetBytes(); +} + +bool +Value::ValueOf(ExecutionContext *exe_ctx) +{ + switch (m_context_type) + { + case eContextTypeInvalid: + case eContextTypeRegisterInfo: // RegisterInfo * + case eContextTypeLLDBType: // Type * + break; + + case eContextTypeVariable: // Variable * + ResolveValue(exe_ctx); + return true; + } + return false; +} + +uint64_t +Value::GetValueByteSize (Error *error_ptr) +{ + uint64_t byte_size = 0; + + switch (m_context_type) + { + case eContextTypeRegisterInfo: // RegisterInfo * + if (GetRegisterInfo()) + byte_size = GetRegisterInfo()->byte_size; + break; + + case eContextTypeInvalid: + case eContextTypeLLDBType: // Type * + case eContextTypeVariable: // Variable * + { + const ClangASTType &ast_type = GetClangType(); + if (ast_type.IsValid()) + byte_size = ast_type.GetByteSize(); + } + break; + } + + if (error_ptr) + { + if (byte_size == 0) + { + if (error_ptr->Success()) + error_ptr->SetErrorString("Unable to determine byte size."); + } + else + { + error_ptr->Clear(); + } + } + return byte_size; +} + +const ClangASTType & +Value::GetClangType () +{ + if (!m_clang_type.IsValid()) + { + switch (m_context_type) + { + case eContextTypeInvalid: + break; + + case eContextTypeRegisterInfo: + break; // TODO: Eventually convert into a clang type? + + case eContextTypeLLDBType: + { + Type *lldb_type = GetType(); + if (lldb_type) + m_clang_type = lldb_type->GetClangForwardType(); + } + break; + + case eContextTypeVariable: + { + Variable *variable = GetVariable(); + if (variable) + { + Type *variable_type = variable->GetType(); + if (variable_type) + m_clang_type = variable_type->GetClangForwardType(); + } + } + break; + } + } + + return m_clang_type; +} + +void +Value::SetClangType (const ClangASTType &clang_type) +{ + m_clang_type = clang_type; +} + +lldb::Format +Value::GetValueDefaultFormat () +{ + switch (m_context_type) + { + case eContextTypeRegisterInfo: + if (GetRegisterInfo()) + return GetRegisterInfo()->format; + break; + + case eContextTypeInvalid: + case eContextTypeLLDBType: + case eContextTypeVariable: + { + const ClangASTType &ast_type = GetClangType(); + 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) + { + default: + break; + + case eValueTypeScalar: + if (m_value.GetData (data)) + return true; + break; + + case eValueTypeLoadAddress: + case eValueTypeFileAddress: + case eValueTypeHostAddress: + if (m_data_buffer.GetByteSize()) + { + data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(), data.GetByteOrder()); + return true; + } + break; + } + + return false; + +} + +Error +Value::GetValueAsData (ExecutionContext *exe_ctx, + DataExtractor &data, + uint32_t data_offset, + Module *module) +{ + data.Clear(); + + Error error; + lldb::addr_t address = LLDB_INVALID_ADDRESS; + AddressType address_type = eAddressTypeFile; + Address file_so_addr; + const ClangASTType &ast_type = GetClangType(); + switch (m_value_type) + { + case eValueTypeVector: + if (ast_type.IsValid()) + data.SetAddressByteSize (ast_type.GetPointerByteSize()); + else + data.SetAddressByteSize(sizeof(void *)); + data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order); + break; + + case eValueTypeScalar: + data.SetByteOrder (lldb::endian::InlHostByteOrder()); + if (ast_type.IsValid()) + data.SetAddressByteSize (ast_type.GetPointerByteSize()); + else + data.SetAddressByteSize(sizeof(void *)); + if (m_value.GetData (data)) + return error; // Success; + error.SetErrorStringWithFormat("extracting data from value failed"); + break; + + case eValueTypeLoadAddress: + if (exe_ctx == NULL) + { + error.SetErrorString ("can't read load address (no execution context)"); + } + else + { + Process *process = exe_ctx->GetProcessPtr(); + if (process == NULL || !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 +// { +// ModuleSP exe_module_sp (target->GetExecutableModule()); +// if (exe_module_sp) +// { +// address = m_value.ULongLong(LLDB_INVALID_ADDRESS); +// if (address != LLDB_INVALID_ADDRESS) +// { +// if (exe_module_sp->ResolveFileAddress(address, file_so_addr)) +// { +// data.SetByteOrder(target->GetArchitecture().GetByteOrder()); +// data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); +// address_type = eAddressTypeFile; +// } +// 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 eValueTypeFileAddress: + if (exe_ctx == NULL) + { + error.SetErrorString ("can't read file address (no execution context)"); + } + else if (exe_ctx->GetTargetPtr() == NULL) + { + 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 == NULL) + { + // 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 eValueTypeHostAddress: + 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(lldb::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); + + // Bail if we encountered any errors getting the byte size + if (error.Fail()) + return error; + + // Make sure we have enough room within "data", and if we don't make + // something large enough that does + if (!data.ValidOffsetForDataOfSize (data_offset, byte_size)) + { + DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0')); + data.SetData(data_sp); + } + + uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size)); + if (dst != NULL) + { + if (address_type == eAddressTypeHost) + { + // The address is an address in this process, so just copy it + memcpy (dst, (uint8_t*)NULL + 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.SetErrorStringWithFormat ("out of memory"); + } + + return error; +} + +Scalar & +Value::ResolveValue(ExecutionContext *exe_ctx) +{ + const ClangASTType &clang_type = GetClangType(); + if (clang_type.IsValid()) + { + switch (m_value_type) + { + case eValueTypeScalar: // raw scalar value + break; + + default: + case eValueTypeFileAddress: + case eValueTypeLoadAddress: // load address value + case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb) + { + DataExtractor data; + lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS); + Error error (GetValueAsData (exe_ctx, data, 0, NULL)); + if (error.Success()) + { + Scalar scalar; + if (clang_type.GetValueAsScalar (data, 0, data.GetByteSize(), scalar)) + { + m_value = scalar; + m_value_type = eValueTypeScalar; + } + else + { + if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) + { + m_value.Clear(); + m_value_type = eValueTypeScalar; + } + } + } + else + { + if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) + { + m_value.Clear(); + m_value_type = eValueTypeScalar; + } + } + } + break; + } + } + return m_value; +} + +Variable * +Value::GetVariable() +{ + if (m_context_type == eContextTypeVariable) + return static_cast<Variable *> (m_context); + return NULL; +} + +void +Value::Clear() +{ + m_value.Clear(); + m_vector.Clear(); + m_clang_type.Clear(); + m_value_type = eValueTypeScalar; + m_context = NULL; + m_context_type = eContextTypeInvalid; + m_data_buffer.Clear(); +} + + +const char * +Value::GetValueTypeAsCString (ValueType value_type) +{ + switch (value_type) + { + case eValueTypeScalar: return "scalar"; + case eValueTypeVector: return "vector"; + case eValueTypeFileAddress: return "file address"; + case eValueTypeLoadAddress: return "load address"; + case eValueTypeHostAddress: return "host address"; + }; + return "???"; +} + +const char * +Value::GetContextTypeAsCString (ContextType context_type) +{ + switch (context_type) + { + case eContextTypeInvalid: return "invalid"; + case eContextTypeRegisterInfo: return "RegisterInfo *"; + case eContextTypeLLDBType: return "Type *"; + case eContextTypeVariable: return "Variable *"; + }; + return "???"; +} + +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 NULL; +} + +void +ValueList::Clear () +{ + m_values.clear(); +} + |