Skip to content

Commit

Permalink
[LLDB][ELF] Fix section unification to not just use names. (#90099)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
al45tair committed May 1, 2024
1 parent 6e31714 commit 4cbe760
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 12 deletions.
59 changes: 47 additions & 12 deletions lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1854,6 +1854,39 @@ class VMAddressProvider {
};
}

// We have to do this because ELF doesn't have section IDs, and also
// doesn't require section names to be unique. (We use the section index
// for section IDs, but that isn't guaranteed to be the same in separate
// debug images.)
static SectionSP FindMatchingSection(const SectionList &section_list,
SectionSP section) {
SectionSP sect_sp;

addr_t vm_addr = section->GetFileAddress();
ConstString name = section->GetName();
offset_t byte_size = section->GetByteSize();
bool thread_specific = section->IsThreadSpecific();
uint32_t permissions = section->GetPermissions();
uint32_t alignment = section->GetLog2Align();

for (auto sect : section_list) {
if (sect->GetName() == name &&
sect->IsThreadSpecific() == thread_specific &&
sect->GetPermissions() == permissions &&
sect->GetByteSize() == byte_size && sect->GetFileAddress() == vm_addr &&
sect->GetLog2Align() == alignment) {
sect_sp = sect;
break;
} else {
sect_sp = FindMatchingSection(sect->GetChildren(), section);
if (sect_sp)
break;
}
}

return sect_sp;
}

void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
if (m_sections_up)
return;
Expand Down Expand Up @@ -2067,10 +2100,12 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
SectionList *module_section_list =
module_sp ? module_sp->GetSectionList() : nullptr;

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

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

if (symbol_section_sp && module_section_list &&
module_section_list != section_list) {
ConstString sect_name = symbol_section_sp->GetName();
auto section_it = section_name_to_section.find(sect_name.GetCString());
if (section_it == section_name_to_section.end())
section_it =
section_name_to_section
.emplace(sect_name.GetCString(),
module_section_list->FindSectionByName(sect_name))
.first;
auto section_it = section_map.find(symbol_section_sp);
if (section_it == section_map.end()) {
section_it = section_map
.emplace(symbol_section_sp,
FindMatchingSection(*module_section_list,
symbol_section_sp))
.first;
}
if (section_it->second)
symbol_section_sp = section_it->second;
}
Expand Down
48 changes: 48 additions & 0 deletions lldb/test/Shell/ObjectFile/ELF/two-text-sections.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Test handling of object files that have duplicate sections. This is legal,
# according to the System V ABI (Edition 4.1); see 4-20 where it says:
#
# Section names with a dot (.) prefix are reserved for the system,
# although applications may use these sections if their existing
# meanings are satisfactory. ... **An object file may have more than
# one section with the same name.**
#
# (See https://github.com/llvm/llvm-project/issues/88001)

# RUN: yaml2obj %s -o %t
# RUN: lldb-test symbols %t | FileCheck %s

# CHECK: 0x0000000000400010 {{.*}} my_function
# CHECK: 0x0000000000401020 {{.*}} my_other_function

!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
ProgramHeaders:
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
FirstSec: .text
LastSec: '.text (1)'
VAddr: 0x400000
Align: 0x1000
Offset: 0x0
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x400010
AddressAlign: 0x10
- Name: '.text (1)'
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GNU_RETAIN ]
Address: 0x401000
AddressAlign: 0x10
Symbols:
- Name: my_function
Section: .text
Value: 0x400010
- Name: my_other_function
Section: '.text (1)'
Value: 0x401020

0 comments on commit 4cbe760

Please sign in to comment.