Skip to content

Commit 6344e3a

Browse files
authored
Make result variables obey their dynamic values in subsequent expressions (llvm#168611)
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.
1 parent a50a7ea commit 6344e3a

File tree

10 files changed

+385
-57
lines changed

10 files changed

+385
-57
lines changed

lldb/include/lldb/Expression/ExpressionVariable.h

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ class ExpressionVariable
3333

3434
virtual ~ExpressionVariable() = default;
3535

36-
llvm::Expected<uint64_t> GetByteSize() { return m_frozen_sp->GetByteSize(); }
36+
llvm::Expected<uint64_t> GetByteSize() {
37+
return GetValueObject()->GetByteSize();
38+
}
3739

3840
ConstString GetName() { return m_frozen_sp->GetName(); }
3941

40-
lldb::ValueObjectSP GetValueObject() { return m_frozen_sp; }
42+
lldb::ValueObjectSP GetValueObject() {
43+
lldb::ValueObjectSP dyn_sp =
44+
m_frozen_sp->GetDynamicValue(lldb::eDynamicDontRunTarget);
45+
if (dyn_sp && dyn_sp->UpdateValueIfNeeded())
46+
return dyn_sp;
47+
return m_frozen_sp;
48+
}
4149

4250
uint8_t *GetValueBytes();
4351

@@ -52,31 +60,39 @@ class ExpressionVariable
5260
Value::ContextType::RegisterInfo, const_cast<RegisterInfo *>(reg_info));
5361
}
5462

55-
CompilerType GetCompilerType() { return m_frozen_sp->GetCompilerType(); }
63+
CompilerType GetCompilerType() { return GetValueObject()->GetCompilerType(); }
5664

5765
void SetCompilerType(const CompilerType &compiler_type) {
5866
m_frozen_sp->GetValue().SetCompilerType(compiler_type);
5967
}
6068

6169
void SetName(ConstString name) { m_frozen_sp->SetName(name); }
6270

63-
// this function is used to copy the address-of m_live_sp into m_frozen_sp
64-
// this is necessary because the results of certain cast and pointer-
65-
// arithmetic operations (such as those described in bugzilla issues 11588
66-
// and 11618) generate frozen objects that do not have a valid address-of,
67-
// which can be troublesome when using synthetic children providers.
68-
// Transferring the address-of the live object solves these issues and
69-
// provides the expected user-level behavior
70-
void TransferAddress(bool force = false) {
71-
if (m_live_sp.get() == nullptr)
72-
return;
73-
74-
if (m_frozen_sp.get() == nullptr)
75-
return;
76-
77-
if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS))
78-
m_frozen_sp->SetLiveAddress(m_live_sp->GetLiveAddress());
71+
/// This function is used to copy the address-of m_live_sp into m_frozen_sp.
72+
/// It is necessary because the results of certain cast and pointer-
73+
/// arithmetic operations (such as those described in bugzilla issues 11588
74+
/// and 11618) generate frozen objects that do not have a valid address-of,
75+
/// which can be troublesome when using synthetic children providers.
76+
/// Transferring the address-of the live object solves these issues and
77+
/// provides the expected user-level behavior.
78+
/// The other job we do in TransferAddress is adjust the value in the live
79+
/// address slot in the target for the "offset to top" in multiply inherited
80+
/// class hierarchies.
81+
void TransferAddress(bool force = false);
82+
83+
/// When we build an expression variable we know whether we're going to use
84+
/// the static or dynamic result. If we present the dynamic value once, we
85+
/// should use the dynamic value in future references to the variable, so we
86+
/// record that fact here.
87+
void PreserveDynamicOption(lldb::DynamicValueType dyn_type) {
88+
m_dyn_option = dyn_type;
7989
}
90+
/// We don't try to get the dynamic value of the live object when we fetch
91+
/// it here. The live object describes the container of the value in the
92+
/// target, but it's type is of the object for convenience. So it can't
93+
/// produce the dynamic value. Instead, we use TransferAddress to adjust the
94+
/// value held by the LiveObject.
95+
lldb::ValueObjectSP GetLiveObject() { return m_live_sp; }
8096

8197
enum Flags {
8298
EVNone = 0,
@@ -110,6 +126,14 @@ class ExpressionVariable
110126
/// These members should be private.
111127
/// @{
112128
/// A value object whose value's data lives in host (lldb's) memory.
129+
/// The m_frozen_sp holds the data & type of the expression variable or result
130+
/// in the host. The m_frozen_sp also can present a dynamic value if one is
131+
/// available.
132+
/// The m_frozen_sp manages the copy of this value in m_frozen_sp that we
133+
/// insert in the target so that it can be referred to in future expressions.
134+
/// We don't actually use the contents of the live_sp to create the value in
135+
/// the target, that comes from the frozen sp. The live_sp is mostly to track
136+
/// the target-side of the value.
113137
lldb::ValueObjectSP m_frozen_sp;
114138
/// The ValueObject counterpart to m_frozen_sp that tracks the value in
115139
/// inferior memory. This object may not always exist; its presence depends on
@@ -119,6 +143,8 @@ class ExpressionVariable
119143
/// track.
120144
lldb::ValueObjectSP m_live_sp;
121145
/// @}
146+
147+
lldb::DynamicValueType m_dyn_option = lldb::eNoDynamicValues;
122148
};
123149

124150
/// \class ExpressionVariableList ExpressionVariable.h

lldb/packages/Python/lldbsuite/test/lldbtest.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2540,6 +2540,7 @@ def expect_expr(
25402540
result_value=None,
25412541
result_type=None,
25422542
result_children=None,
2543+
options=None,
25432544
):
25442545
"""
25452546
Evaluates the given expression and verifies the result.
@@ -2556,7 +2557,8 @@ def expect_expr(
25562557
)
25572558

25582559
frame = self.frame()
2559-
options = lldb.SBExpressionOptions()
2560+
if not options:
2561+
options = lldb.SBExpressionOptions()
25602562

25612563
# Disable fix-its that tests don't pass by accident.
25622564
options.SetAutoApplyFixIts(False)

lldb/source/Expression/ExpressionVariable.cpp

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ char ExpressionVariable::ID;
2020
ExpressionVariable::ExpressionVariable() : m_flags(0) {}
2121

2222
uint8_t *ExpressionVariable::GetValueBytes() {
23+
lldb::ValueObjectSP valobj_sp = GetValueObject();
2324
std::optional<uint64_t> byte_size =
24-
llvm::expectedToOptional(m_frozen_sp->GetByteSize());
25+
llvm::expectedToOptional(valobj_sp->GetByteSize());
2526
if (byte_size && *byte_size) {
26-
if (m_frozen_sp->GetDataExtractor().GetByteSize() < *byte_size) {
27-
m_frozen_sp->GetValue().ResizeData(*byte_size);
28-
m_frozen_sp->GetValue().GetData(m_frozen_sp->GetDataExtractor());
27+
if (valobj_sp->GetDataExtractor().GetByteSize() < *byte_size) {
28+
valobj_sp->GetValue().ResizeData(*byte_size);
29+
valobj_sp->GetValue().GetData(valobj_sp->GetDataExtractor());
2930
}
30-
return const_cast<uint8_t *>(
31-
m_frozen_sp->GetDataExtractor().GetDataStart());
31+
return const_cast<uint8_t *>(valobj_sp->GetDataExtractor().GetDataStart());
3232
}
3333
return nullptr;
3434
}
@@ -37,6 +37,72 @@ char PersistentExpressionState::ID;
3737

3838
PersistentExpressionState::PersistentExpressionState() = default;
3939

40+
void ExpressionVariable::TransferAddress(bool force) {
41+
if (!m_live_sp)
42+
return;
43+
44+
if (!m_frozen_sp)
45+
return;
46+
47+
if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS)) {
48+
lldb::addr_t live_addr = m_live_sp->GetLiveAddress();
49+
m_frozen_sp->SetLiveAddress(live_addr);
50+
// One more detail, if there's an offset_to_top in the frozen_sp, then we
51+
// need to appy that offset by hand. The live_sp can't compute this
52+
// itself as its type is the type of the contained object which confuses
53+
// the dynamic type calculation. So we have to update the contents of the
54+
// m_live_sp with the dynamic value.
55+
// Note: We could get this right when we originally write the address, but
56+
// that happens in different ways for the various flavors of
57+
// Entity*::Materialize, but everything comes through here, and it's just
58+
// one extra memory write.
59+
60+
// You can only have an "offset_to_top" with pointers or references:
61+
if (!m_frozen_sp->GetCompilerType().IsPointerOrReferenceType())
62+
return;
63+
64+
lldb::ProcessSP process_sp = m_frozen_sp->GetProcessSP();
65+
// If there's no dynamic value, then there can't be an offset_to_top:
66+
if (!process_sp ||
67+
!process_sp->IsPossibleDynamicValue(*(m_frozen_sp.get())))
68+
return;
69+
70+
lldb::ValueObjectSP dyn_sp = m_frozen_sp->GetDynamicValue(m_dyn_option);
71+
if (!dyn_sp)
72+
return;
73+
ValueObject::AddrAndType static_addr = m_frozen_sp->GetPointerValue();
74+
if (static_addr.type != eAddressTypeLoad)
75+
return;
76+
77+
ValueObject::AddrAndType dynamic_addr = dyn_sp->GetPointerValue();
78+
if (dynamic_addr.type != eAddressTypeLoad ||
79+
static_addr.address == dynamic_addr.address)
80+
return;
81+
82+
Status error;
83+
Log *log = GetLog(LLDBLog::Expressions);
84+
lldb::addr_t cur_value =
85+
process_sp->ReadPointerFromMemory(live_addr, error);
86+
if (error.Fail())
87+
return;
88+
89+
if (cur_value != static_addr.address) {
90+
LLDB_LOG(log,
91+
"Stored value: {0} read from {1} doesn't "
92+
"match static addr: {2}",
93+
cur_value, live_addr, static_addr.address);
94+
return;
95+
}
96+
97+
if (!process_sp->WritePointerToMemory(live_addr, dynamic_addr.address,
98+
error)) {
99+
LLDB_LOG(log, "Got error: {0} writing dynamic value: {1} to {2}", error,
100+
dynamic_addr.address, live_addr);
101+
return;
102+
}
103+
}
104+
}
105+
40106
PersistentExpressionState::~PersistentExpressionState() = default;
41107

42108
lldb::addr_t PersistentExpressionState::LookupSymbol(ConstString name) {

lldb/source/Expression/LLVMUserExpression.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager,
6565
ExecutionContext &exe_ctx,
6666
const EvaluateExpressionOptions &options,
6767
lldb::UserExpressionSP &shared_ptr_to_me,
68-
lldb::ExpressionVariableSP &result) {
68+
lldb::ExpressionVariableSP &result_sp) {
6969
// The expression log is quite verbose, and if you're just tracking the
7070
// execution of the expression, it's quite convenient to have these logs come
7171
// out with the STEP log as well.
@@ -250,10 +250,9 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager,
250250
}
251251
}
252252

253-
if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result,
254-
function_stack_bottom, function_stack_top)) {
253+
if (FinalizeJITExecution(diagnostic_manager, exe_ctx, result_sp,
254+
function_stack_bottom, function_stack_top))
255255
return lldb::eExpressionCompleted;
256-
}
257256

258257
return lldb::eExpressionResultUnavailable;
259258
}
@@ -289,8 +288,13 @@ bool LLVMUserExpression::FinalizeJITExecution(
289288
result =
290289
GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope());
291290

292-
if (result)
291+
if (result) {
292+
// TransferAddress also does the offset_to_top calculation, so record the
293+
// dynamic option before we do that.
294+
if (EvaluateExpressionOptions *options = GetOptions())
295+
result->PreserveDynamicOption(options->GetUseDynamic());
293296
result->TransferAddress();
297+
}
294298

295299
m_dematerializer_sp.reset();
296300

lldb/source/Expression/Materializer.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,11 @@ class EntityPersistentVariable : public Materializer::Entity {
7676

7777
const bool zero_memory = false;
7878
IRMemoryMap::AllocationPolicy used_policy;
79-
auto address_or_error = map.Malloc(
79+
const uint64_t malloc_size =
8080
llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
81-
.value_or(0),
82-
8, lldb::ePermissionsReadable | lldb::ePermissionsWritable,
81+
.value_or(0);
82+
auto address_or_error = map.Malloc(
83+
malloc_size, 8, lldb::ePermissionsReadable | lldb::ePermissionsWritable,
8384
IRMemoryMap::eAllocationPolicyMirror, zero_memory, &used_policy);
8485
if (!address_or_error) {
8586
err = Status::FromErrorStringWithFormat(
@@ -90,8 +91,9 @@ class EntityPersistentVariable : public Materializer::Entity {
9091
}
9192
lldb::addr_t mem = *address_or_error;
9293

93-
LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
94-
m_persistent_variable_sp->GetName().GetCString(), mem);
94+
LLDB_LOGF(
95+
log, "Allocated 0x%" PRIx64 "bytes for %s (0x%" PRIx64 ") successfully",
96+
malloc_size, m_persistent_variable_sp->GetName().GetCString(), mem);
9597

9698
// Put the location of the spare memory into the live data of the
9799
// ValueObject.
@@ -143,12 +145,12 @@ class EntityPersistentVariable : public Materializer::Entity {
143145
void DestroyAllocation(IRMemoryMap &map, Status &err) {
144146
Status deallocate_error;
145147

146-
map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
147-
.GetScalar()
148-
.ULongLong(),
148+
lldb::ValueObjectSP live_valobj_sp =
149+
m_persistent_variable_sp->GetLiveObject();
150+
map.Free((lldb::addr_t)live_valobj_sp->GetValue().GetScalar().ULongLong(),
149151
deallocate_error);
150152

151-
m_persistent_variable_sp->m_live_sp.reset();
153+
live_valobj_sp.reset();
152154

153155
if (!deallocate_error.Success()) {
154156
err = Status::FromErrorStringWithFormat(
@@ -183,17 +185,17 @@ class EntityPersistentVariable : public Materializer::Entity {
183185
return;
184186
}
185187

188+
lldb::ValueObjectSP live_valobj_sp =
189+
m_persistent_variable_sp->GetLiveObject();
186190
if ((m_persistent_variable_sp->m_flags &
187191
ExpressionVariable::EVIsProgramReference &&
188-
m_persistent_variable_sp->m_live_sp) ||
192+
live_valobj_sp) ||
189193
m_persistent_variable_sp->m_flags &
190194
ExpressionVariable::EVIsLLDBAllocated) {
191195
Status write_error;
192196

193-
map.WriteScalarToMemory(
194-
load_addr,
195-
m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
196-
map.GetAddressByteSize(), write_error);
197+
map.WriteScalarToMemory(load_addr, live_valobj_sp->GetValue().GetScalar(),
198+
map.GetAddressByteSize(), write_error);
197199

198200
if (!write_error.Success()) {
199201
err = Status::FromErrorStringWithFormat(
@@ -229,13 +231,15 @@ class EntityPersistentVariable : public Materializer::Entity {
229231
m_delegate->DidDematerialize(m_persistent_variable_sp);
230232
}
231233

234+
lldb::ValueObjectSP live_valobj_sp =
235+
m_persistent_variable_sp->GetLiveObject();
232236
if ((m_persistent_variable_sp->m_flags &
233237
ExpressionVariable::EVIsLLDBAllocated) ||
234238
(m_persistent_variable_sp->m_flags &
235239
ExpressionVariable::EVIsProgramReference)) {
236240
if (m_persistent_variable_sp->m_flags &
237241
ExpressionVariable::EVIsProgramReference &&
238-
!m_persistent_variable_sp->m_live_sp) {
242+
!live_valobj_sp) {
239243
// If the reference comes from the program, then the
240244
// ClangExpressionVariable's live variable data hasn't been set up yet.
241245
// Do this now.
@@ -255,7 +259,7 @@ class EntityPersistentVariable : public Materializer::Entity {
255259

256260
m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
257261
map.GetBestExecutionContextScope(),
258-
m_persistent_variable_sp.get()->GetCompilerType(),
262+
m_persistent_variable_sp->GetCompilerType(),
259263
m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
260264
llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
261265
.value_or(0));
@@ -277,19 +281,17 @@ class EntityPersistentVariable : public Materializer::Entity {
277281
}
278282
}
279283

280-
lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
281-
.GetScalar()
282-
.ULongLong();
283-
284-
if (!m_persistent_variable_sp->m_live_sp) {
284+
if (!live_valobj_sp) {
285285
err = Status::FromErrorStringWithFormat(
286286
"couldn't find the memory area used to store %s",
287287
m_persistent_variable_sp->GetName().GetCString());
288288
return;
289289
}
290290

291-
if (m_persistent_variable_sp->m_live_sp->GetValue()
292-
.GetValueAddressType() != eAddressTypeLoad) {
291+
lldb::addr_t mem = live_valobj_sp->GetValue().GetScalar().ULongLong();
292+
293+
if (live_valobj_sp->GetValue().GetValueAddressType() !=
294+
eAddressTypeLoad) {
293295
err = Status::FromErrorStringWithFormat(
294296
"the address of the memory area for %s is in an incorrect format",
295297
m_persistent_variable_sp->GetName().GetCString());
@@ -326,7 +328,6 @@ class EntityPersistentVariable : public Materializer::Entity {
326328
read_error.AsCString());
327329
return;
328330
}
329-
330331
m_persistent_variable_sp->m_flags &=
331332
~ExpressionVariable::EVNeedsFreezeDry;
332333
}

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,6 @@ ClangExpressionVariable::ClangExpressionVariable(
5959
}
6060

6161
TypeFromUser ClangExpressionVariable::GetTypeFromUser() {
62-
TypeFromUser tfu(m_frozen_sp->GetCompilerType());
62+
TypeFromUser tfu(GetValueObject()->GetCompilerType());
6363
return tfu;
6464
}

lldb/source/Target/ABI.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type,
136136
ExpressionVariable::EVNeedsAllocation;
137137
break;
138138
case Value::ValueType::LoadAddress:
139-
expr_variable_sp->m_live_sp = live_valobj_sp;
139+
expr_variable_sp->GetLiveObject() = live_valobj_sp;
140140
expr_variable_sp->m_flags |=
141141
ExpressionVariable::EVIsProgramReference;
142142
break;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := two-bases.cpp
2+
3+
include Makefile.rules

0 commit comments

Comments
 (0)