Skip to content

Commit 4cbe760

Browse files
authored
[LLDB][ELF] Fix section unification to not just use names. (#90099)
Section unification cannot just use names, because it's valid for ELF binaries to have multiple sections with the same name. We should check other section properties too. Fixes #88001. rdar://124467787
1 parent 6e31714 commit 4cbe760

File tree

2 files changed

+95
-12
lines changed

2 files changed

+95
-12
lines changed

lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,39 @@ class VMAddressProvider {
18541854
};
18551855
}
18561856

1857+
// We have to do this because ELF doesn't have section IDs, and also
1858+
// doesn't require section names to be unique. (We use the section index
1859+
// for section IDs, but that isn't guaranteed to be the same in separate
1860+
// debug images.)
1861+
static SectionSP FindMatchingSection(const SectionList &section_list,
1862+
SectionSP section) {
1863+
SectionSP sect_sp;
1864+
1865+
addr_t vm_addr = section->GetFileAddress();
1866+
ConstString name = section->GetName();
1867+
offset_t byte_size = section->GetByteSize();
1868+
bool thread_specific = section->IsThreadSpecific();
1869+
uint32_t permissions = section->GetPermissions();
1870+
uint32_t alignment = section->GetLog2Align();
1871+
1872+
for (auto sect : section_list) {
1873+
if (sect->GetName() == name &&
1874+
sect->IsThreadSpecific() == thread_specific &&
1875+
sect->GetPermissions() == permissions &&
1876+
sect->GetByteSize() == byte_size && sect->GetFileAddress() == vm_addr &&
1877+
sect->GetLog2Align() == alignment) {
1878+
sect_sp = sect;
1879+
break;
1880+
} else {
1881+
sect_sp = FindMatchingSection(sect->GetChildren(), section);
1882+
if (sect_sp)
1883+
break;
1884+
}
1885+
}
1886+
1887+
return sect_sp;
1888+
}
1889+
18571890
void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
18581891
if (m_sections_up)
18591892
return;
@@ -2067,10 +2100,12 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
20672100
SectionList *module_section_list =
20682101
module_sp ? module_sp->GetSectionList() : nullptr;
20692102

2070-
// Local cache to avoid doing a FindSectionByName for each symbol. The "const
2071-
// char*" key must came from a ConstString object so they can be compared by
2072-
// pointer
2073-
std::unordered_map<const char *, lldb::SectionSP> section_name_to_section;
2103+
// We might have debug information in a separate object, in which case
2104+
// we need to map the sections from that object to the sections in the
2105+
// main object during symbol lookup. If we had to compare the sections
2106+
// for every single symbol, that would be expensive, so this map is
2107+
// used to accelerate the process.
2108+
std::unordered_map<lldb::SectionSP, lldb::SectionSP> section_map;
20742109

20752110
unsigned i;
20762111
for (i = 0; i < num_symbols; ++i) {
@@ -2275,14 +2310,14 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
22752310

22762311
if (symbol_section_sp && module_section_list &&
22772312
module_section_list != section_list) {
2278-
ConstString sect_name = symbol_section_sp->GetName();
2279-
auto section_it = section_name_to_section.find(sect_name.GetCString());
2280-
if (section_it == section_name_to_section.end())
2281-
section_it =
2282-
section_name_to_section
2283-
.emplace(sect_name.GetCString(),
2284-
module_section_list->FindSectionByName(sect_name))
2285-
.first;
2313+
auto section_it = section_map.find(symbol_section_sp);
2314+
if (section_it == section_map.end()) {
2315+
section_it = section_map
2316+
.emplace(symbol_section_sp,
2317+
FindMatchingSection(*module_section_list,
2318+
symbol_section_sp))
2319+
.first;
2320+
}
22862321
if (section_it->second)
22872322
symbol_section_sp = section_it->second;
22882323
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Test handling of object files that have duplicate sections. This is legal,
2+
# according to the System V ABI (Edition 4.1); see 4-20 where it says:
3+
#
4+
# Section names with a dot (.) prefix are reserved for the system,
5+
# although applications may use these sections if their existing
6+
# meanings are satisfactory. ... **An object file may have more than
7+
# one section with the same name.**
8+
#
9+
# (See https://github.com/llvm/llvm-project/issues/88001)
10+
11+
# RUN: yaml2obj %s -o %t
12+
# RUN: lldb-test symbols %t | FileCheck %s
13+
14+
# CHECK: 0x0000000000400010 {{.*}} my_function
15+
# CHECK: 0x0000000000401020 {{.*}} my_other_function
16+
17+
!ELF
18+
FileHeader:
19+
Class: ELFCLASS64
20+
Data: ELFDATA2LSB
21+
Type: ET_EXEC
22+
Machine: EM_X86_64
23+
ProgramHeaders:
24+
- Type: PT_LOAD
25+
Flags: [ PF_X, PF_R ]
26+
FirstSec: .text
27+
LastSec: '.text (1)'
28+
VAddr: 0x400000
29+
Align: 0x1000
30+
Offset: 0x0
31+
Sections:
32+
- Name: .text
33+
Type: SHT_PROGBITS
34+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
35+
Address: 0x400010
36+
AddressAlign: 0x10
37+
- Name: '.text (1)'
38+
Type: SHT_PROGBITS
39+
Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GNU_RETAIN ]
40+
Address: 0x401000
41+
AddressAlign: 0x10
42+
Symbols:
43+
- Name: my_function
44+
Section: .text
45+
Value: 0x400010
46+
- Name: my_other_function
47+
Section: '.text (1)'
48+
Value: 0x401020

0 commit comments

Comments
 (0)