//===-- 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/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" 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)); } 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 (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 (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 = ClangASTType::GetClangTypeBitWidth (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::GetOpaqueClangQualType () { if (m_context_type == eContextTypeValue) return ((Value*)m_context)->GetOpaqueClangQualType(); 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 ClangASTType::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->target); if (address != LLDB_INVALID_ADDRESS) { address_type = eAddressTypeLoad; data.SetByteOrder(exe_ctx->process->GetByteOrder()); data.SetAddressByteSize(exe_ctx->process->GetAddressByteSize()); } else { data.SetByteOrder(objfile->GetByteOrder()); data.SetAddressByteSize(objfile->GetAddressByteSize()); } } 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 = const_cast(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; case eContextTypeValue: m_value.Clear(); // TODO: Sean, fill this in 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 (ClangASTType::ReadFromMemory (ast_context, opaque_clang_qual_type, exe_ctx, addr, address_type, data)) { if (ClangASTType::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 (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 *"; case eContextTypeValue: return "Value"; // TODO: Sean, more description here? }; 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(); }