Skip to content

Commit 18c5ad5

Browse files
authored
[lldb] Fix block address resolution for functions in multiple sections (#137955)
Continuing the theme from #116777 and #124931, this patch ensures we compute the correct address when a functions is spread across multiple sections. Due to this, it's not sufficient to adjust the offset in the section+offset pair (Address::Slide). We must actually slide the file offset and then recompute the section using the result. I found this out due to a failure to disassemble some parts of the function, so I'm testing with that, although it's likely there are other things that were broken due to this.
1 parent 47c7e73 commit 18c5ad5

File tree

3 files changed

+137
-18
lines changed

3 files changed

+137
-18
lines changed

lldb/include/lldb/Symbol/Block.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,12 @@ class Block : public UserID, public SymbolContextScope {
354354
// Member variables.
355355
SymbolContextScope &m_parent_scope;
356356
collection m_children;
357+
358+
/// Address ranges of this block. They are relative to the function entry
359+
/// point so one must add/subtract GetFunction().GetAddress().GetFileAddress()
360+
/// when converting from/to to the AddressRange representation.
357361
RangeList m_ranges;
362+
358363
lldb::InlineFunctionInfoSP m_inlineInfoSP; ///< Inlined function information.
359364
lldb::VariableListSP m_variable_list_sp; ///< The variable list for all local,
360365
///static and parameter variables

lldb/source/Symbol/Block.cpp

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -283,39 +283,43 @@ uint32_t Block::GetRangeIndexContainingAddress(const Address &addr) {
283283
return m_ranges.FindEntryIndexThatContains(file_addr - func_file_addr);
284284
}
285285

286+
static AddressRange ToAddressRange(const Address &func_addr,
287+
const Block::Range &block_range) {
288+
assert(func_addr.GetModule());
289+
return AddressRange(func_addr.GetFileAddress() + block_range.base,
290+
block_range.size,
291+
func_addr.GetModule()->GetSectionList());
292+
}
293+
286294
bool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) {
287295
if (range_idx >= m_ranges.GetSize())
288296
return false;
289297

290-
Function &function = GetFunction();
291-
const Range &vm_range = m_ranges.GetEntryRef(range_idx);
292-
range.GetBaseAddress() = function.GetAddress();
293-
range.GetBaseAddress().Slide(vm_range.GetRangeBase());
294-
range.SetByteSize(vm_range.GetByteSize());
298+
Address addr = GetFunction().GetAddress();
299+
if (!addr.GetModule())
300+
return false;
301+
302+
range = ToAddressRange(addr, m_ranges.GetEntryRef(range_idx));
295303
return true;
296304
}
297305

298306
AddressRanges Block::GetRanges() {
307+
Address addr = GetFunction().GetAddress();
308+
if (!addr.GetModule())
309+
return {};
310+
299311
AddressRanges ranges;
300-
Function &function = GetFunction();
301-
for (size_t i = 0, e = m_ranges.GetSize(); i < e; ++i) {
302-
ranges.emplace_back();
303-
auto &range = ranges.back();
304-
const Range &vm_range = m_ranges.GetEntryRef(i);
305-
range.GetBaseAddress() = function.GetAddress();
306-
range.GetBaseAddress().Slide(vm_range.GetRangeBase());
307-
range.SetByteSize(vm_range.GetByteSize());
308-
}
312+
for (size_t i = 0, e = m_ranges.GetSize(); i < e; ++i)
313+
ranges.push_back(ToAddressRange(addr, m_ranges.GetEntryRef(i)));
309314
return ranges;
310315
}
311316

312317
bool Block::GetStartAddress(Address &addr) {
313-
if (m_ranges.IsEmpty())
318+
Address func_addr = GetFunction().GetAddress();
319+
if (!func_addr.GetModule() || m_ranges.IsEmpty())
314320
return false;
315321

316-
Function &function = GetFunction();
317-
addr = function.GetAddress();
318-
addr.Slide(m_ranges.GetEntryRef(0).GetRangeBase());
322+
addr = ToAddressRange(func_addr, m_ranges.GetEntryRef(0)).GetBaseAddress();
319323
return true;
320324
}
321325

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
## Test disassembling of functions which are spread over multiple sections (ELF
2+
## segments are modelled as LLDB sections).
3+
4+
5+
# REQUIRES: x86, lld
6+
7+
# RUN: split-file %s %t
8+
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux %t/file.s -o %t/file.o
9+
# RUN: ld.lld %t/file.o -o %t/file.out -T %t/file.lds
10+
# RUN: %lldb %t/file.out -o "disassemble --name func1" -o exit | FileCheck %s
11+
12+
# CHECK: (lldb) disassemble --name func1
13+
# CHECK: file.out`func1:
14+
# CHECK-NEXT: file.out[0x0] <+0>: int $0x2a
15+
# CHECK: file.out`func1:
16+
# CHECK-NEXT: file.out[0x1000] <+4096>: int $0x2f
17+
18+
19+
#--- file.lds
20+
## Linker script placing the parts of the section into different segments
21+
## (typically one of these would be for the "hot" code).
22+
PHDRS {
23+
text1 PT_LOAD;
24+
text2 PT_LOAD;
25+
}
26+
SECTIONS {
27+
. = 0;
28+
.text.part1 : { *(.text.part1) } :text1
29+
.text.part2 : { *(.text.part2) } :text2
30+
}
31+
32+
#--- file.s
33+
## A very simple function consisting of two parts and DWARF describing the
34+
## function.
35+
.section .text.part1,"ax",@progbits
36+
.p2align 12
37+
func1:
38+
int $42
39+
.Lfunc1_end:
40+
41+
.section .text.part2,"ax",@progbits
42+
.p2align 12
43+
func1.__part.1:
44+
int $47
45+
.Lfunc1.__part.1_end:
46+
47+
48+
49+
.section .debug_abbrev,"",@progbits
50+
.byte 1 # Abbreviation Code
51+
.byte 17 # DW_TAG_compile_unit
52+
.byte 1 # DW_CHILDREN_yes
53+
.byte 37 # DW_AT_producer
54+
.byte 8 # DW_FORM_string
55+
.byte 19 # DW_AT_language
56+
.byte 5 # DW_FORM_data2
57+
.byte 17 # DW_AT_low_pc
58+
.byte 1 # DW_FORM_addr
59+
.byte 85 # DW_AT_ranges
60+
.byte 23 # DW_FORM_sec_offset
61+
.byte 0 # EOM(1)
62+
.byte 0 # EOM(2)
63+
.byte 2 # Abbreviation Code
64+
.byte 46 # DW_TAG_subprogram
65+
.byte 0 # DW_CHILDREN_no
66+
.byte 85 # DW_AT_ranges
67+
.byte 23 # DW_FORM_sec_offset
68+
.byte 3 # DW_AT_name
69+
.byte 8 # DW_FORM_string
70+
.byte 0 # EOM(1)
71+
.byte 0 # EOM(2)
72+
.byte 0 # EOM(3)
73+
74+
.section .debug_info,"",@progbits
75+
.Lcu_begin0:
76+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
77+
.Ldebug_info_start0:
78+
.short 5 # DWARF version number
79+
.byte 1 # DWARF Unit Type
80+
.byte 8 # Address Size (in bytes)
81+
.long .debug_abbrev # Offset Into Abbrev. Section
82+
.byte 1 # Abbrev DW_TAG_compile_unit
83+
.asciz "Hand-written DWARF" # DW_AT_producer
84+
.short 29 # DW_AT_language
85+
.quad 0 # DW_AT_low_pc
86+
.long .Ldebug_ranges0 # DW_AT_ranges
87+
.byte 2 # Abbrev DW_TAG_subprogram
88+
.long .Ldebug_ranges0 # DW_AT_ranges
89+
.asciz "func1" # DW_AT_name
90+
.byte 0 # End Of Children Mark
91+
.Ldebug_info_end0:
92+
93+
.section .debug_rnglists,"",@progbits
94+
.long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
95+
.Ldebug_list_header_start0:
96+
.short 5 # Version
97+
.byte 8 # Address size
98+
.byte 0 # Segment selector size
99+
.long 1 # Offset entry count
100+
.Lrnglists_table_base0:
101+
.long .Ldebug_ranges0-.Lrnglists_table_base0
102+
.Ldebug_ranges0:
103+
.byte 6 # DW_RLE_start_end
104+
.quad func1
105+
.quad .Lfunc1_end
106+
.byte 6 # DW_RLE_start_end
107+
.quad func1.__part.1
108+
.quad .Lfunc1.__part.1_end
109+
.byte 0 # DW_RLE_end_of_list
110+
.Ldebug_list_header_end0:

0 commit comments

Comments
 (0)