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

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

677 lines
21 KiB
C++
Raw Normal View History

//===-- 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 <cinttypes>
using namespace lldb;
using namespace lldb_private;
Value::Value() : m_value(), m_compiler_type(), m_data_buffer() {}
Value::Value(const Scalar &scalar)
: m_value(scalar), m_compiler_type(), m_data_buffer() {}
Value::Value(const void *bytes, int len)
: m_value(), m_compiler_type(), m_value_type(ValueType::HostAddress),
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: {
Final bit of type system cleanup that abstracts declaration contexts into lldb_private::CompilerDeclContext and renames ClangType to CompilerType in many accessors and functions. Create a new "lldb_private::CompilerDeclContext" class that will replace all direct uses of "clang::DeclContext" when used in compiler agnostic code, yet still allow for conversion to clang::DeclContext subclasses by clang specific code. This completes the abstraction of type parsing by removing all "clang::" references from the SymbolFileDWARF. The new "lldb_private::CompilerDeclContext" class abstracts decl contexts found in compiler type systems so they can be used in internal API calls. The TypeSystem is required to support CompilerDeclContexts with new pure virtual functions that start with "DeclContext" in the member function names. Converted all code that used lldb_private::ClangNamespaceDecl over to use the new CompilerDeclContext class and removed the ClangNamespaceDecl.cpp and ClangNamespaceDecl.h files. Removed direct use of clang APIs from SBType and now use the abstract type systems to correctly explore types. Bulk renames for things that used to return a ClangASTType which is now CompilerType: "Type::GetClangFullType()" to "Type::GetFullCompilerType()" "Type::GetClangLayoutType()" to "Type::GetLayoutCompilerType()" "Type::GetClangForwardType()" to "Type::GetForwardCompilerType()" "Value::GetClangType()" to "Value::GetCompilerType()" "Value::SetClangType (const CompilerType &)" to "Value::SetCompilerType (const CompilerType &)" "ValueObject::GetClangType ()" to "ValueObject::GetCompilerType()" many more renames that are similar. llvm-svn: 245905
2015-08-25 07:46:31 +08:00
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: {
Final bit of type system cleanup that abstracts declaration contexts into lldb_private::CompilerDeclContext and renames ClangType to CompilerType in many accessors and functions. Create a new "lldb_private::CompilerDeclContext" class that will replace all direct uses of "clang::DeclContext" when used in compiler agnostic code, yet still allow for conversion to clang::DeclContext subclasses by clang specific code. This completes the abstraction of type parsing by removing all "clang::" references from the SymbolFileDWARF. The new "lldb_private::CompilerDeclContext" class abstracts decl contexts found in compiler type systems so they can be used in internal API calls. The TypeSystem is required to support CompilerDeclContexts with new pure virtual functions that start with "DeclContext" in the member function names. Converted all code that used lldb_private::ClangNamespaceDecl over to use the new CompilerDeclContext class and removed the ClangNamespaceDecl.cpp and ClangNamespaceDecl.h files. Removed direct use of clang APIs from SBType and now use the abstract type systems to correctly explore types. Bulk renames for things that used to return a ClangASTType which is now CompilerType: "Type::GetClangFullType()" to "Type::GetFullCompilerType()" "Type::GetClangLayoutType()" to "Type::GetLayoutCompilerType()" "Type::GetClangForwardType()" to "Type::GetForwardCompilerType()" "Value::GetClangType()" to "Value::GetCompilerType()" "Value::SetClangType (const CompilerType &)" to "Value::SetCompilerType (const CompilerType &)" "ValueObject::GetClangType ()" to "ValueObject::GetCompilerType()" many more renames that are similar. llvm-svn: 245905
2015-08-25 07:46:31 +08:00
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;
}
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
bool Value::GetData(DataExtractor &data) {
switch (m_value_type) {
case ValueType::Invalid:
return false;
case ValueType::Scalar:
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
if (m_value.GetData(data))
return true;
break;
case ValueType::LoadAddress:
case ValueType::FileAddress:
case ValueType::HostAddress:
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
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) {
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
data.Clear();
Status error;
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
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;
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
switch (m_value_type) {
case ValueType::Invalid:
error.SetErrorString("invalid value");
break;
case ValueType::Scalar: {
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
data.SetByteOrder(endian::InlHostByteOrder());
if (ast_type.IsValid())
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
data.SetAddressByteSize(ast_type.GetPointerByteSize());
else
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
data.SetAddressByteSize(sizeof(void *));
uint32_t limit_byte_size = UINT32_MAX;
if (type_size)
limit_byte_size = *type_size;
Modified LLDB expressions to not have to JIT and run code just to see variable values or persistent expression variables. Now if an expression consists of a value that is a child of a variable, or of a persistent variable only, we will create a value object for it and make a ValueObjectConstResult from it to freeze the value (for program variables only, not persistent variables) and avoid running JITed code. For everything else we still parse up and JIT code and run it in the inferior. There was also a lot of clean up in the expression code. I made the ClangExpressionVariables be stored in collections of shared pointers instead of in collections of objects. This will help stop a lot of copy constructors on these large objects and also cleans up the code considerably. The persistent clang expression variables were moved over to the Target to ensure they persist across process executions. Added the ability for lldb_private::Target objects to evaluate expressions. We want to evaluate expressions at the target level in case we aren't running yet, or we have just completed running. We still want to be able to access the persistent expression variables between runs, and also evaluate constant expressions. Added extra logging to the dynamic loader plug-in for MacOSX. ModuleList objects can now dump their contents with the UUID, arch and full paths being logged with appropriate prefix values. Thread hardened the Communication class a bit by making the connection auto_ptr member into a shared pointer member and then making a local copy of the shared pointer in each method that uses it to make sure another thread can't nuke the connection object while it is being used by another thread. Added a new file to the lldb/test/load_unload test that causes the test a.out file to link to the libd.dylib file all the time. This will allow us to test using the DYLD_LIBRARY_PATH environment variable after moving libd.dylib somewhere else. llvm-svn: 121745
2010-12-14 10:59:59 +08:00
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()) {
const bool force_live_memory = true;
if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, dst, byte_size,
error, force_live_memory) !=
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;
}
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(); }