aboutsummaryrefslogtreecommitdiff
path: root/source/Core/Value.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/Value.cpp')
-rw-r--r--source/Core/Value.cpp761
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();
+}
+