Skip to content

[lldb] Fix Block::GetRangeIndexContainingAddress for discontinuous functions #124931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
53 changes: 21 additions & 32 deletions lldb/source/Symbol/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,25 +243,17 @@ bool Block::GetRangeContainingAddress(const Address &addr,
AddressRange &range) {
Function *function = CalculateSymbolContextFunction();
if (function) {
const AddressRange &func_range = function->GetAddressRange();
if (addr.GetModule() == func_range.GetBaseAddress().GetModule()) {
const addr_t file_addr = addr.GetFileAddress();
const addr_t func_file_addr =
func_range.GetBaseAddress().GetFileAddress();
if (file_addr >= func_file_addr &&
file_addr < func_file_addr + func_range.GetByteSize()) {
addr_t offset = file_addr - func_file_addr;

const Range *range_ptr = m_ranges.FindEntryThatContains(offset);

if (range_ptr) {
range.GetBaseAddress() =
Address(func_file_addr + range_ptr->GetRangeBase(),
addr.GetModule()->GetSectionList());
range.SetByteSize(range_ptr->GetByteSize());
return true;
}
}
if (uint32_t idx = GetRangeIndexContainingAddress(addr);
idx != UINT32_MAX) {
const Range *range_ptr = m_ranges.GetEntryAtIndex(idx);
assert(range_ptr);

Address func_addr = function->GetAddress();
range.GetBaseAddress() =
Address(func_addr.GetFileAddress() + range_ptr->GetRangeBase(),
func_addr.GetModule()->GetSectionList());
range.SetByteSize(range_ptr->GetByteSize());
return true;
}
}
range.Clear();
Expand All @@ -278,19 +270,16 @@ bool Block::GetRangeContainingLoadAddress(lldb::addr_t load_addr,

uint32_t Block::GetRangeIndexContainingAddress(const Address &addr) {
Function *function = CalculateSymbolContextFunction();
if (function) {
const AddressRange &func_range = function->GetAddressRange();
if (addr.GetSection() == func_range.GetBaseAddress().GetSection()) {
const addr_t addr_offset = addr.GetOffset();
const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
if (addr_offset >= func_offset &&
addr_offset < func_offset + func_range.GetByteSize()) {
addr_t offset = addr_offset - func_offset;
return m_ranges.FindEntryIndexThatContains(offset);
}
}
}
return UINT32_MAX;
if (!function)
return UINT32_MAX;

const Address &func_addr = function->GetAddress();
if (addr.GetModule() != func_addr.GetModule())
return UINT32_MAX;

const addr_t file_addr = addr.GetFileAddress();
const addr_t func_file_addr = func_addr.GetFileAddress();
return m_ranges.FindEntryIndexThatContains(file_addr - func_file_addr);
}

bool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) {
Expand Down
39 changes: 26 additions & 13 deletions lldb/test/Shell/ScriptInterpreter/Python/sb_function_ranges.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,24 @@

# CHECK: Found 1 function(s).
# CHECK: foo: [input.o[0x0-0xe), input.o[0x14-0x1c)]
# CHECK-NEXT: input.o[0x0]: cmpl $0x0, %edi
# CHECK-NEXT: input.o[0x3]: je 0x14
# CHECK-NEXT: input.o[0x5]: jmp 0x7
# CHECK-NEXT: input.o[0x7]: callq 0xe
# CHECK-NEXT: input.o[0xc]: jmp 0x1b
# CHECK-NEXT: input.o[0x0]: callq 0xe
# CHECK-NEXT: input.o[0x5]: jmp 0x1b
# CHECK-NEXT: input.o[0x7]: cmpl $0x0, %edi
# CHECK-NEXT: input.o[0xa]: je 0x14
# CHECK-NEXT: input.o[0xc]: jmp 0x0
# CHECK-EMPTY:
# CHECK-NEXT: input.o[0x14]: callq 0x19
# CHECK-NEXT: input.o[0x19]: jmp 0x1b
# CHECK-NEXT: input.o[0x1b]: retq
## Testing the GetRangeIndexForBlockAddress API. "ffffffff" indicates that
## the address does not belong to any range.
# CHECK-NEXT: offset 0x00 => index 0
# CHECK-NEXT: offset 0x0c => index 0
# CHECK-NEXT: offset 0x0e => index ffffffff
# CHECK-NEXT: offset 0x13 => index ffffffff
# CHECK-NEXT: offset 0x14 => index 1
# CHECK-NEXT: offset 0x1b => index 1
# CHECK-NEXT: offset 0x1c => index ffffffff
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have zero idea what's going on here.

You moved foo.__part.1 before foo, presumably because that would give you the wrong answers if it weren't for the changes you made elsewhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Correct, GetRangeIndexForBlockAddress would return wrong results because it assumed that the internal block representation was relative to the lowest address in the function (fn->GetAddressRange().GetBaseAddress()) but they really are (as of #122440) relative to the entry point.

And this is a slightly funny way of testing that interface -- I print the function results in python and then FileCheck the result.

Copy link
Collaborator

Choose a reason for hiding this comment

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

ffffffff means that it's not part of a block, is that right?

So if I have a function that does not cover the offset I ask for, it would return this failure value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yep

Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a comment there saying so, it will help someone who is reading because this failed out of the blue sometime.



#--- script.py
Expand All @@ -28,6 +37,10 @@ def __lldb_init_module(debugger, internal_dict):
fn = ctx.function
print(f"{fn.name}: {fn.GetRanges()}")
print(fn.GetInstructions(target))
text = fn.addr.section
for offset in [0x00, 0x0c, 0x0e, 0x13, 0x14, 0x1b, 0x1c]:
idx = fn.block.GetRangeIndexForBlockAddress(lldb.SBAddress(text, offset))
print(f"offset 0x{offset:02x} => index {idx:x}")

#--- input.s
# An example of a function which has been split into two parts. Roughly
Expand All @@ -40,6 +53,14 @@ def __lldb_init_module(debugger, internal_dict):
.text

.type foo,@function
foo.__part.1:
.cfi_startproc
callq bar
jmp foo.__part.3
.Lfoo.__part.1_end:
.size foo.__part.1, .Lfoo.__part.1_end-foo.__part.1
.cfi_endproc

foo:
.cfi_startproc
cmpl $0, %edi
Expand All @@ -49,14 +70,6 @@ foo:
.Lfoo_end:
.size foo, .Lfoo_end-foo

foo.__part.1:
.cfi_startproc
callq bar
jmp foo.__part.3
.Lfoo.__part.1_end:
.size foo.__part.1, .Lfoo.__part.1_end-foo.__part.1
.cfi_endproc

bar:
.cfi_startproc
movl $47, %eax
Expand Down