Skip to content

[LLDB][ELF] Fix section unification to not just use names. #90099

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 5 commits into from
May 1, 2024
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
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
Loading