Skip to content

Commit fac89bb

Browse files
committed
[lldb] Fix evaluating expressions without JIT in an object context
If a server does not support allocating memory in an inferior process or when debugging a core file, evaluating an expression in the context of a value object results in an error: ``` error: <lldb wrapper prefix>:43:1: use of undeclared identifier '$__lldb_class' 43 | $__lldb_class::$__lldb_expr(void *$__lldb_arg) | ^ ``` Such expressions require a live address to be stored in the value object. However, `EntityResultVariable::Dematerialize()` only sets `ret->m_live_sp` if JIT is available, even if the address points to the process memory and no custom allocations were made. Similarly, `EntityPersistentVariable::Dematerialize()` tries to deallocate memory based on the same check, resulting in an error if the memory was not previously allocated in `EntityPersistentVariable::Materialize()`. As an unintended bonus, the patch also fixes a FIXME case in `TestCxxChar8_t.py`.
1 parent 5ff6c8e commit fac89bb

File tree

6 files changed

+73
-23
lines changed

6 files changed

+73
-23
lines changed

lldb/source/Expression/Materializer.cpp

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -329,22 +329,10 @@ class EntityPersistentVariable : public Materializer::Entity {
329329
return;
330330
}
331331

332-
lldb::ProcessSP process_sp =
333-
map.GetBestExecutionContextScope()->CalculateProcess();
334-
if (!process_sp || !process_sp->CanJIT()) {
335-
// Allocations are not persistent so persistent variables cannot stay
336-
// materialized.
337-
338-
m_persistent_variable_sp->m_flags |=
339-
ExpressionVariable::EVNeedsAllocation;
340-
341-
DestroyAllocation(map, err);
342-
if (!err.Success())
343-
return;
344-
} else if (m_persistent_variable_sp->m_flags &
345-
ExpressionVariable::EVNeedsAllocation &&
346-
!(m_persistent_variable_sp->m_flags &
347-
ExpressionVariable::EVKeepInTarget)) {
332+
if (m_persistent_variable_sp->m_flags &
333+
ExpressionVariable::EVNeedsAllocation &&
334+
!(m_persistent_variable_sp->m_flags &
335+
ExpressionVariable::EVKeepInTarget)) {
348336
DestroyAllocation(map, err);
349337
if (!err.Success())
350338
return;
@@ -1086,9 +1074,8 @@ class EntityResultVariable : public Materializer::Entity {
10861074
m_delegate->DidDematerialize(ret);
10871075
}
10881076

1089-
bool can_persist =
1090-
(m_is_program_reference && process_sp && process_sp->CanJIT() &&
1091-
!(address >= frame_bottom && address < frame_top));
1077+
bool can_persist = m_is_program_reference &&
1078+
!(address >= frame_bottom && address < frame_top);
10921079

10931080
if (can_persist && m_keep_in_memory) {
10941081
ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
@@ -1118,7 +1105,9 @@ class EntityResultVariable : public Materializer::Entity {
11181105
map.Free(m_temporary_allocation, free_error);
11191106
}
11201107
} else {
1121-
ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
1108+
ret->m_flags |= m_is_program_reference
1109+
? ExpressionVariable::EVIsProgramReference
1110+
: ExpressionVariable::EVIsLLDBAllocated;
11221111
}
11231112

11241113
m_temporary_allocation = LLDB_INVALID_ADDRESS;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Test evaluating expressions when debugging core file.
3+
"""
4+
5+
import lldb
6+
from lldbsuite.test.decorators import *
7+
from lldbsuite.test.lldbtest import *
8+
from lldbsuite.test import lldbutil
9+
10+
11+
@skipIfLLVMTargetMissing("X86")
12+
class CoreExprTestCase(TestBase):
13+
def test_result_var(self):
14+
"""Test that the result variable can be used in subsequent expressions."""
15+
16+
target = self.dbg.CreateTarget("linux-x86_64.out")
17+
process = target.LoadCore("linux-x86_64.core")
18+
self.assertTrue(process, PROCESS_IS_VALID)
19+
20+
self.expect_expr(
21+
"outer",
22+
result_type="Outer",
23+
result_children=[ValueCheck(name="inner", type="Inner")],
24+
)
25+
self.expect_expr(
26+
"$0.inner",
27+
result_type="Inner",
28+
result_children=[ValueCheck(name="val", type="int", value="5")],
29+
)
30+
self.expect_expr("$1.val", result_type="int", result_value="5")
31+
32+
def test_context_object(self):
33+
"""Tests expression evaluation in context of an object."""
34+
35+
target = self.dbg.CreateTarget("linux-x86_64.out")
36+
process = target.LoadCore("linux-x86_64.core")
37+
self.assertTrue(process, PROCESS_IS_VALID)
38+
39+
val_outer = self.expect_expr("outer", result_type="Outer")
40+
41+
val_inner = val_outer.EvaluateExpression("inner")
42+
self.assertTrue(val_inner.IsValid())
43+
self.assertEqual("Inner", val_inner.GetDisplayTypeName())
44+
45+
val_val = val_inner.EvaluateExpression("this->val")
46+
self.assertTrue(val_val.IsValid())
47+
self.assertEqual("int", val_val.GetDisplayTypeName())
48+
self.assertEqual(val_val.GetValueAsSigned(), 5)
Binary file not shown.
Binary file not shown.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct Inner {
2+
Inner(int val) : val(val) {}
3+
int val;
4+
};
5+
6+
struct Outer {
7+
Outer(int val) : inner(val) {}
8+
Inner inner;
9+
};
10+
11+
extern "C" void _start(void) {
12+
Outer outer(5);
13+
char *boom = (char *)0;
14+
*boom = 47;
15+
}

lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ def test_without_process(self):
2424

2525
self.expect_expr("a", result_type="char8_t", result_summary="0x61 u8'a'")
2626
self.expect_expr("ab", result_type="const char8_t *", result_summary='u8"你好"')
27-
28-
# FIXME: This should work too.
29-
self.expect("expr abc", substrs=['u8"你好"'], matching=False)
27+
self.expect_expr("abc", result_type="char8_t[9]", result_summary='u8"你好"')
3028

3129
@skipIf(compiler="clang", compiler_version=["<", "7.0"])
3230
def test_with_process(self):

0 commit comments

Comments
 (0)