mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
When you run an expression and the result has a dynamic type that is
different from the expression's static result type, we print the result
variable using the dynamic type, but at present when you use the result
variable in an expression later on, we only give you access to the
static type. For instance:
```
(lldb) expr MakeADerivedReportABase()
(Derived *) $0 = 0x00000001007e93e0
(lldb) expr $0->method_from_derived()
^
error: no member named 'method_from_derived' in 'Base'
(lldb)
```
The static return type of that function is `Base *`, but we printed that
the result was a `Derived *` and then only used the `Base *` part of it
in subsequent expressions. That's not very helpful, and forces you to
guess and then cast the result types to their dynamic type in order to
be able to access the full type you were returned, which is
inconvenient.
This patch makes lldb retain the dynamic type of the result variable
(and ditto for persistent result variables).
It also adds more testing of expression result variables with various
types of dynamic values, to ensure we can access both the ivars and
methods of the type we print the result as.
154 lines
5.5 KiB
C++
154 lines
5.5 KiB
C++
//===-- ExpressionVariable.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/Expression/ExpressionVariable.h"
|
|
#include "lldb/Expression/IRExecutionUnit.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Utility/LLDBLog.h"
|
|
#include "lldb/Utility/Log.h"
|
|
#include <optional>
|
|
|
|
using namespace lldb_private;
|
|
|
|
char ExpressionVariable::ID;
|
|
|
|
ExpressionVariable::ExpressionVariable() : m_flags(0) {}
|
|
|
|
uint8_t *ExpressionVariable::GetValueBytes() {
|
|
lldb::ValueObjectSP valobj_sp = GetValueObject();
|
|
std::optional<uint64_t> byte_size =
|
|
llvm::expectedToOptional(valobj_sp->GetByteSize());
|
|
if (byte_size && *byte_size) {
|
|
if (valobj_sp->GetDataExtractor().GetByteSize() < *byte_size) {
|
|
valobj_sp->GetValue().ResizeData(*byte_size);
|
|
valobj_sp->GetValue().GetData(valobj_sp->GetDataExtractor());
|
|
}
|
|
return const_cast<uint8_t *>(valobj_sp->GetDataExtractor().GetDataStart());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
char PersistentExpressionState::ID;
|
|
|
|
PersistentExpressionState::PersistentExpressionState() = default;
|
|
|
|
void ExpressionVariable::TransferAddress(bool force) {
|
|
if (!m_live_sp)
|
|
return;
|
|
|
|
if (!m_frozen_sp)
|
|
return;
|
|
|
|
if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS)) {
|
|
lldb::addr_t live_addr = m_live_sp->GetLiveAddress();
|
|
m_frozen_sp->SetLiveAddress(live_addr);
|
|
// One more detail, if there's an offset_to_top in the frozen_sp, then we
|
|
// need to appy that offset by hand. The live_sp can't compute this
|
|
// itself as its type is the type of the contained object which confuses
|
|
// the dynamic type calculation. So we have to update the contents of the
|
|
// m_live_sp with the dynamic value.
|
|
// Note: We could get this right when we originally write the address, but
|
|
// that happens in different ways for the various flavors of
|
|
// Entity*::Materialize, but everything comes through here, and it's just
|
|
// one extra memory write.
|
|
|
|
// You can only have an "offset_to_top" with pointers or references:
|
|
if (!m_frozen_sp->GetCompilerType().IsPointerOrReferenceType())
|
|
return;
|
|
|
|
lldb::ProcessSP process_sp = m_frozen_sp->GetProcessSP();
|
|
// If there's no dynamic value, then there can't be an offset_to_top:
|
|
if (!process_sp ||
|
|
!process_sp->IsPossibleDynamicValue(*(m_frozen_sp.get())))
|
|
return;
|
|
|
|
lldb::ValueObjectSP dyn_sp = m_frozen_sp->GetDynamicValue(m_dyn_option);
|
|
if (!dyn_sp)
|
|
return;
|
|
ValueObject::AddrAndType static_addr = m_frozen_sp->GetPointerValue();
|
|
if (static_addr.type != eAddressTypeLoad)
|
|
return;
|
|
|
|
ValueObject::AddrAndType dynamic_addr = dyn_sp->GetPointerValue();
|
|
if (dynamic_addr.type != eAddressTypeLoad ||
|
|
static_addr.address == dynamic_addr.address)
|
|
return;
|
|
|
|
Status error;
|
|
Log *log = GetLog(LLDBLog::Expressions);
|
|
lldb::addr_t cur_value =
|
|
process_sp->ReadPointerFromMemory(live_addr, error);
|
|
if (error.Fail())
|
|
return;
|
|
|
|
if (cur_value != static_addr.address) {
|
|
LLDB_LOG(log,
|
|
"Stored value: {0} read from {1} doesn't "
|
|
"match static addr: {2}",
|
|
cur_value, live_addr, static_addr.address);
|
|
return;
|
|
}
|
|
|
|
if (!process_sp->WritePointerToMemory(live_addr, dynamic_addr.address,
|
|
error)) {
|
|
LLDB_LOG(log, "Got error: {0} writing dynamic value: {1} to {2}", error,
|
|
dynamic_addr.address, live_addr);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
PersistentExpressionState::~PersistentExpressionState() = default;
|
|
|
|
lldb::addr_t PersistentExpressionState::LookupSymbol(ConstString name) {
|
|
SymbolMap::iterator si = m_symbol_map.find(name.GetCString());
|
|
|
|
if (si != m_symbol_map.end())
|
|
return si->second;
|
|
else
|
|
return LLDB_INVALID_ADDRESS;
|
|
}
|
|
|
|
void PersistentExpressionState::RegisterExecutionUnit(
|
|
lldb::IRExecutionUnitSP &execution_unit_sp) {
|
|
Log *log = GetLog(LLDBLog::Expressions);
|
|
|
|
m_execution_units.insert(execution_unit_sp);
|
|
|
|
LLDB_LOGF(log, "Registering JITted Functions:\n");
|
|
|
|
for (const IRExecutionUnit::JittedFunction &jitted_function :
|
|
execution_unit_sp->GetJittedFunctions()) {
|
|
if (jitted_function.m_external &&
|
|
jitted_function.m_name != execution_unit_sp->GetFunctionName() &&
|
|
jitted_function.m_remote_addr != LLDB_INVALID_ADDRESS) {
|
|
m_symbol_map[jitted_function.m_name.GetCString()] =
|
|
jitted_function.m_remote_addr;
|
|
LLDB_LOGF(log, " Function: %s at 0x%" PRIx64 ".",
|
|
jitted_function.m_name.GetCString(),
|
|
jitted_function.m_remote_addr);
|
|
}
|
|
}
|
|
|
|
LLDB_LOGF(log, "Registering JIIted Symbols:\n");
|
|
|
|
for (const IRExecutionUnit::JittedGlobalVariable &global_var :
|
|
execution_unit_sp->GetJittedGlobalVariables()) {
|
|
if (global_var.m_remote_addr != LLDB_INVALID_ADDRESS) {
|
|
// Demangle the name before inserting it, so that lookups by the ConstStr
|
|
// of the demangled name will find the mangled one (needed for looking up
|
|
// metadata pointers.)
|
|
Mangled mangler(global_var.m_name);
|
|
mangler.GetDemangledName();
|
|
m_symbol_map[global_var.m_name.GetCString()] = global_var.m_remote_addr;
|
|
LLDB_LOGF(log, " Symbol: %s at 0x%" PRIx64 ".",
|
|
global_var.m_name.GetCString(), global_var.m_remote_addr);
|
|
}
|
|
}
|
|
}
|