llvm-project/lldb/source/Core/Value.cpp

804 lines
21 KiB
C++
Raw Normal View History

//===-- 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/Stream.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"
using namespace lldb;
using namespace lldb_private;
Value::Value() :
m_value(),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(const Scalar& scalar) :
m_value(scalar),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(int v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(unsigned int v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(long v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(unsigned long v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(long long v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(unsigned long long v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(float v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(double v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(long double v) :
m_value(v),
m_value_type(eValueTypeScalar),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
}
Value::Value(const uint8_t *bytes, int len) :
m_value(),
m_value_type(eValueTypeHostAddress),
m_context(NULL),
m_context_type(eContextTypeInvalid)
{
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_value_type(v.m_value_type),
m_context(v.m_context),
m_context_type(v.m_context_type)
{
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::CreateProxy()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->CreateProxy ();
Value *ret = new Value;
ret->SetContext(eContextTypeValue, this);
return ret;
}
Value *
Value::GetProxyTarget()
{
if (m_context_type == eContextTypeValue)
return (Value*)m_context;
else
return NULL;
}
//#include "clang/Lex/LiteralSupport.h"
//#include "clang/AST/ASTContext.h"
//#include "clang/Frontend/CompilerInstance.h"
//
//Value::Value (const char *data, llvm::CompilerInstance *compiler)
//{
// clang::NumericLiteralParser parser(data, data + strlen(data), clang::SourceLocation(),
// compiler->getPreprocessor());
// if (parser.had_error)
// {
// }
// else if (parser.isBool)
// {
// APInt value;
// parser.GetIntegerValue(value);
// }
// else if (parser.isLong)
// {
// }
// else if (parser.isLongLong)
// {
// }
// else if (parser.isFloat)
// {
// }
//
//}
//
void
Value::Dump (Stream* strm)
{
if (m_context_type == eContextTypeValue)
{
((Value*)m_context)->Dump (strm);
return;
}
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));
}
void *
Value::GetOpaqueClangQualType()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetOpaqueClangQualType ();
if (m_context_type == eContextTypeOpaqueClangQualType)
return m_context;
return NULL;
}
Value::ValueType
Value::GetValueType() const
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetValueType ();
return m_value_type;
}
lldb::AddressType
Value::GetValueAddressType () const
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetValueAddressType ();
switch (m_value_type)
{
default:
case eValueTypeScalar:
break;
case eValueTypeLoadAddress: return eAddressTypeLoad;
case eValueTypeFileAddress: return eAddressTypeFile;
case eValueTypeHostAddress: return eAddressTypeHost;
}
return eAddressTypeInvalid;
}
Value::ContextType
Value::GetContextType() const
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetContextType ();
return m_context_type;
}
void
Value::SetValueType (Value::ValueType value_type)
{
if (m_context_type == eContextTypeValue)
{
((Value*)m_context)->SetValueType(value_type);
return;
}
m_value_type = value_type;
}
void
Value::ClearContext ()
{
if (m_context_type == eContextTypeValue)
{
((Value*)m_context)->ClearContext();
return;
}
m_context = NULL;
m_context_type = eContextTypeInvalid;
}
void
Value::SetContext (Value::ContextType context_type, void *p)
{
if (m_context_type == eContextTypeValue)
{
((Value*)m_context)->SetContext(context_type, p);
return;
}
m_context_type = context_type;
m_context = p;
}
RegisterInfo *
Value::GetRegisterInfo()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetRegisterInfo();
if (m_context_type == eContextTypeDCRegisterInfo)
return static_cast<RegisterInfo *> (m_context);
return NULL;
}
Type *
Value::GetType()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetType();
if (m_context_type == eContextTypeDCType)
return static_cast<Type *> (m_context);
return NULL;
}
Scalar &
Value::GetScalar()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetScalar();
return m_value;
}
void
Value::ResizeData(int len)
{
if (m_context_type == eContextTypeValue)
{
((Value*)m_context)->ResizeData(len);
return;
}
m_value_type = eValueTypeHostAddress;
m_data_buffer.SetByteSize(len);
m_value = (uintptr_t)m_data_buffer.GetBytes();
}
bool
Value::ValueOf(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->ValueOf(exe_ctx, ast_context);
switch (m_context_type)
{
default:
case eContextTypeInvalid:
case eContextTypeOpaqueClangQualType: // clang::Type *
case eContextTypeDCRegisterInfo: // RegisterInfo *
case eContextTypeDCType: // Type *
break;
case eContextTypeDCVariable: // Variable *
ResolveValue(exe_ctx, ast_context);
return true;
}
return false;
}
size_t
Value::GetValueByteSize (clang::ASTContext *ast_context, Error *error_ptr)
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetValueByteSize(ast_context, error_ptr);
size_t byte_size = 0;
switch (m_context_type)
{
default:
case eContextTypeInvalid:
// If we have no context, there is no way to know how much memory to read
if (error_ptr)
error_ptr->SetErrorString ("Invalid context type, there is no way to know how much memory to read.");
break;
case eContextTypeOpaqueClangQualType:
if (ast_context == NULL)
{
if (error_ptr)
error_ptr->SetErrorString ("Can't determine size of opaque clang type with NULL ASTContext *.");
}
else
{
uint64_t bit_width = ClangASTContext::GetTypeBitSize (ast_context, m_context);
byte_size = (bit_width + 7 ) / 8;
}
break;
case eContextTypeDCRegisterInfo: // RegisterInfo *
if (GetRegisterInfo())
byte_size = GetRegisterInfo()->byte_size;
else if (error_ptr)
error_ptr->SetErrorString ("Can't determine byte size with NULL RegisterInfo *.");
break;
case eContextTypeDCType: // Type *
if (GetType())
byte_size = GetType()->GetByteSize();
else if (error_ptr)
error_ptr->SetErrorString ("Can't determine byte size with NULL Type *.");
break;
case eContextTypeDCVariable: // Variable *
if (GetVariable())
byte_size = GetVariable()->GetType()->GetByteSize();
else if (error_ptr)
error_ptr->SetErrorString ("Can't determine byte size with NULL Variable *.");
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;
}
void *
Value::GetValueOpaqueClangQualType ()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetValueOpaqueClangQualType();
switch (m_context_type)
{
default:
case eContextTypeInvalid:
break;
case eContextTypeOpaqueClangQualType:
return m_context;
case eContextTypeDCRegisterInfo:
break; // TODO: Eventually convert into a clang type?
case eContextTypeDCType:
if (GetType())
return GetType()->GetOpaqueClangQualType();
break;
case eContextTypeDCVariable:
if (GetVariable())
return GetVariable()->GetType()->GetOpaqueClangQualType();
break;
}
return NULL;
}
lldb::Format
Value::GetValueDefaultFormat ()
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetValueDefaultFormat();
switch (m_context_type)
{
default:
case eContextTypeInvalid:
break;
case eContextTypeOpaqueClangQualType:
return Type::GetFormat (m_context);
case eContextTypeDCRegisterInfo:
if (GetRegisterInfo())
return GetRegisterInfo()->format;
break;
case eContextTypeDCType:
if (GetType())
return GetType()->GetFormat();
break;
case eContextTypeDCVariable:
if (GetVariable())
return GetVariable()->GetType()->GetFormat();
break;
}
// Return a good default in case we can't figure anything out
return eFormatHex;
}
Error
Value::GetValueAsData (ExecutionContext *exe_ctx, clang::ASTContext *ast_context, DataExtractor &data, uint32_t data_offset)
{
if (m_context_type == eContextTypeValue)
return ((Value*)m_context)->GetValueAsData(exe_ctx, ast_context, data, data_offset);
data.Clear();
Error error;
lldb::addr_t address = LLDB_INVALID_ADDRESS;
lldb::AddressType address_type = eAddressTypeFile;
switch (m_value_type)
{
default:
error.SetErrorStringWithFormat("Invalid value type %i.\n", m_value_type);
break;
case eValueTypeScalar:
data.SetByteOrder (eByteOrderHost);
data.SetAddressByteSize(sizeof(void *));
if (m_value.GetData (data))
return error; // Success;
error.SetErrorStringWithFormat("Extracting data from value failed.\n");
break;
case eValueTypeLoadAddress:
if (exe_ctx == NULL)
{
error.SetErrorString ("Can't read memory (no execution context).");
}
else if (exe_ctx->process == NULL)
{
error.SetErrorString ("Can't read memory (invalid process).");
}
else
{
address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
address_type = eAddressTypeLoad;
data.SetByteOrder(exe_ctx->process->GetByteOrder());
data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize());
}
break;
case eValueTypeFileAddress:
{
// 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 (GetVariable())
{
lldb::addr_t file_addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
if (file_addr != LLDB_INVALID_ADDRESS)
{
SymbolContext var_sc;
variable->CalculateSymbolContext(&var_sc);
if (var_sc.module_sp)
{
ObjectFile *objfile = var_sc.module_sp->GetObjectFile();
if (objfile)
{
Address so_addr(file_addr, objfile->GetSectionList());
address = so_addr.GetLoadAddress (exe_ctx->process);
if (address != LLDB_INVALID_ADDRESS)
address_type = eAddressTypeLoad;
}
if (address_type == eAddressTypeFile)
error.SetErrorStringWithFormat ("%s is not loaded.\n", var_sc.module_sp->GetFileSpec().GetFilename().AsCString());
}
else
{
error.SetErrorStringWithFormat ("Unable to resolve the module for file address 0x%llx for variable '%s'.\n", file_addr, variable->GetName().AsCString(""));
}
}
else
{
error.SetErrorString ("Invalid file 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);
data.SetByteOrder(eByteOrderHost);
data.SetAddressByteSize(sizeof(void *));
address_type = eAddressTypeHost;
break;
}
// Bail if we encountered any errors
if (error.Fail())
return error;
if (address == LLDB_INVALID_ADDRESS)
{
error.SetErrorStringWithFormat ("Invalid %s address.\n", address_type == eAddressTypeHost ? "host" : "load");
return error;
}
// If we got here, we need to read the value from memory
uint32_t byte_size = GetValueByteSize (ast_context, &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 = (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)
{
if (exe_ctx->process->ReadMemory(address, dst, byte_size, error) != byte_size)
{
if (error.Success())
error.SetErrorStringWithFormat("read %u bytes of memory from 0x%llx failed", (uint64_t)address, byte_size);
}
}
else
{
error.SetErrorStringWithFormat ("Unsupported lldb::AddressType value (%i).\n", address_type);
}
}
else
{
error.SetErrorStringWithFormat ("Out of memory.\n");
}
return error;
}
Scalar &
Value::ResolveValue(ExecutionContext *exe_ctx, clang::ASTContext *ast_context)
{
Scalar scalar;
if (m_context_type == eContextTypeValue)
{
// Resolve the proxy
Value * v = (Value*)m_context;
m_value = v->m_value;
m_value_type = v->m_value_type;
m_context = v->m_context;
m_context_type = v->m_context_type;
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();
}
}
if (m_context_type == eContextTypeOpaqueClangQualType)
{
void *opaque_clang_qual_type = GetOpaqueClangQualType();
switch (m_value_type)
{
case eValueTypeScalar: // raw scalar value
break;
default:
case eValueTypeFileAddress:
m_value.Clear();
break;
case eValueTypeLoadAddress: // load address value
case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
{
lldb::AddressType address_type = m_value_type == eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost;
lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
DataExtractor data;
if (Type::ReadFromMemory (exe_ctx, ast_context, opaque_clang_qual_type, addr, address_type, data))
{
if (Type::GetValueAsScalar (ast_context, opaque_clang_qual_type, 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 == eContextTypeValue)
return ((Value*)m_context)->GetVariable();
if (m_context_type == eContextTypeDCVariable)
return static_cast<Variable *> (m_context);
return NULL;
}
const char *
Value::GetValueTypeAsCString (ValueType value_type)
{
switch (value_type)
{
case eValueTypeScalar: return "scalar";
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 eContextTypeOpaqueClangQualType: return "clang::Type *";
case eContextTypeDCRegisterInfo: return "RegisterInfo *";
case eContextTypeDCType: return "Type *";
case eContextTypeDCVariable: 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();
}