Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lldb/include/lldb/Expression/IRMemoryMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ class IRMemoryMap {
///only in the process.
};

// If 'policy' is 'eAllocationPolicyMirror' but it is impossible to allocate
// memory in the process, 'eAllocationPolicyHostOnly' will be used instead.
// The actual policy is returned via 'used_policy'.
lldb::addr_t Malloc(size_t size, uint8_t alignment, uint32_t permissions,
AllocationPolicy policy, bool zero_memory, Status &error);
AllocationPolicy policy, bool zero_memory, Status &error,
AllocationPolicy *used_policy = nullptr);
void Leak(lldb::addr_t process_address, Status &error);
void Free(lldb::addr_t process_address, Status &error);

Expand Down
6 changes: 5 additions & 1 deletion lldb/source/Expression/IRMemoryMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc,

lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
uint32_t permissions, AllocationPolicy policy,
bool zero_memory, Status &error) {
bool zero_memory, Status &error,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put error last here? We generally put the error return last among the out parameters.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would mean more intrusive code changes because used_policy would become a required parameter. Maybe it would make more sense to switch to using llvm::Expected<> for this method?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #146016, PTAL.

AllocationPolicy *used_policy) {
lldb_private::Log *log(GetLog(LLDBLog::Expressions));
error.Clear();

Expand Down Expand Up @@ -455,6 +456,9 @@ lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
(uint64_t)permissions, policy_string, aligned_address);
}

if (used_policy)
*used_policy = policy;

return aligned_address;
}

Expand Down
53 changes: 26 additions & 27 deletions lldb/source/Expression/Materializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@ class EntityPersistentVariable : public Materializer::Entity {

Status allocate_error;
const bool zero_memory = false;
IRMemoryMap::AllocationPolicy used_policy;

lldb::addr_t mem = map.Malloc(
llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
.value_or(0),
8, lldb::ePermissionsReadable | lldb::ePermissionsWritable,
IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error,
&used_policy);

if (!allocate_error.Success()) {
err = Status::FromErrorStringWithFormat(
Expand All @@ -103,14 +105,22 @@ class EntityPersistentVariable : public Materializer::Entity {
m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
map.GetAddressByteSize());

// Clear the flag if the variable will never be deallocated.

if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget) {
Status leak_error;
map.Leak(mem, leak_error);
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVNeedsAllocation;
if (used_policy == IRMemoryMap::eAllocationPolicyMirror) {
// Clear the flag if the variable will never be deallocated.
Status leak_error;
map.Leak(mem, leak_error);
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVNeedsAllocation;
} else {
// If the variable cannot be kept in target, clear this flag...
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVKeepInTarget;
// ...and set the flag to copy the value during dematerialization.
m_persistent_variable_sp->m_flags |=
ExpressionVariable::EVNeedsFreezeDry;
}
}

// Write the contents of the variable to the area.
Expand Down Expand Up @@ -329,22 +339,10 @@ class EntityPersistentVariable : public Materializer::Entity {
return;
}

lldb::ProcessSP process_sp =
map.GetBestExecutionContextScope()->CalculateProcess();
if (!process_sp || !process_sp->CanJIT()) {
// Allocations are not persistent so persistent variables cannot stay
// materialized.

m_persistent_variable_sp->m_flags |=
ExpressionVariable::EVNeedsAllocation;

DestroyAllocation(map, err);
if (!err.Success())
return;
} else if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVNeedsAllocation &&
!(m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget)) {
if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVNeedsAllocation &&
!(m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget)) {
DestroyAllocation(map, err);
if (!err.Success())
return;
Expand Down Expand Up @@ -1086,9 +1084,8 @@ class EntityResultVariable : public Materializer::Entity {
m_delegate->DidDematerialize(ret);
}

bool can_persist =
(m_is_program_reference && process_sp && process_sp->CanJIT() &&
!(address >= frame_bottom && address < frame_top));
bool can_persist = m_is_program_reference &&
!(address >= frame_bottom && address < frame_top);

if (can_persist && m_keep_in_memory) {
ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
Expand Down Expand Up @@ -1118,7 +1115,9 @@ class EntityResultVariable : public Materializer::Entity {
map.Free(m_temporary_allocation, free_error);
}
} else {
ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
ret->m_flags |= m_is_program_reference
? ExpressionVariable::EVIsProgramReference
: ExpressionVariable::EVIsLLDBAllocated;
}

m_temporary_allocation = LLDB_INVALID_ADDRESS;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
Test evaluating expressions when debugging core file.
"""

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


@skipIfLLVMTargetMissing("X86")
class CoreExprTestCase(TestBase):
def setUp(self):
TestBase.setUp(self)
self.target = self.dbg.CreateTarget("linux-x86_64.out")
self.process = self.target.LoadCore("linux-x86_64.core")
self.assertTrue(self.process, PROCESS_IS_VALID)

def test_result_var(self):
"""Test that the result variable can be used in subsequent expressions."""

self.expect_expr(
"outer",
result_type="Outer",
result_children=[ValueCheck(name="inner", type="Inner")],
)
self.expect_expr(
"$0.inner",
result_type="Inner",
result_children=[ValueCheck(name="val", type="int", value="5")],
)
self.expect_expr("$1.val", result_type="int", result_value="5")

def test_persist_var(self):
"""Test that user-defined variables can be used in subsequent expressions."""

self.target.EvaluateExpression("int $my_int = 5")
self.expect_expr("$my_int * 2", result_type="int", result_value="10")

def test_context_object(self):
"""Test expression evaluation in context of an object."""

val_outer = self.expect_expr("outer", result_type="Outer")

val_inner = val_outer.EvaluateExpression("inner")
self.assertTrue(val_inner.IsValid())
self.assertEqual("Inner", val_inner.GetDisplayTypeName())

val_val = val_inner.EvaluateExpression("this->val")
self.assertTrue(val_val.IsValid())
self.assertEqual("int", val_val.GetDisplayTypeName())
self.assertEqual(val_val.GetValueAsSigned(), 5)
Binary file not shown.
Binary file not shown.
15 changes: 15 additions & 0 deletions lldb/test/API/functionalities/postmortem/elf-core/expr/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
struct Inner {
Inner(int val) : val(val) {}
int val;
};

struct Outer {
Outer(int val) : inner(val) {}
Inner inner;
};

extern "C" void _start(void) {
Outer outer(5);
char *boom = (char *)0;
*boom = 47;
}
4 changes: 1 addition & 3 deletions lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ def test_without_process(self):

self.expect_expr("a", result_type="char8_t", result_summary="0x61 u8'a'")
self.expect_expr("ab", result_type="const char8_t *", result_summary='u8"你好"')

# FIXME: This should work too.
self.expect("expr abc", substrs=['u8"你好"'], matching=False)
self.expect_expr("abc", result_type="char8_t[9]", result_summary='u8"你好"')

@skipIf(compiler="clang", compiler_version=["<", "7.0"])
def test_with_process(self):
Expand Down
Loading