diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -2637,6 +2637,43 @@ } } +static void ApplyELF32ABS32Relocation(Symtab *symtab, ELFRelocation &rel, + DataExtractor &debug_data, + Section *rel_section) { + Log *log = GetLog(LLDBLog::Modules); + Symbol *symbol = symtab->FindSymbolByID(ELFRelocation::RelocSymbol32(rel)); + if (symbol) { + addr_t value = symbol->GetAddressRef().GetFileAddress(); + if (value == LLDB_INVALID_ADDRESS) { + const char *name = symbol->GetName().GetCString(); + LLDB_LOGF(log, "Debug info symbol invalid: %s", name); + return; + } + assert(llvm::isUInt<32>(value) && "Valid addresses are 32-bit"); + DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer(); + // ObjectFileELF creates a WritableDataBuffer in CreateInstance. + WritableDataBuffer *data_buffer = + llvm::cast(data_buffer_sp.get()); + uint8_t *dst = data_buffer->GetBytes() + rel_section->GetFileOffset() + + ELFRelocation::RelocOffset32(rel); + // Implicit addend is stored inline as a signed value. + int32_t addend = *reinterpret_cast(dst); + // The sum must be positive. This extra check prevents UB from overflow in + // the actual range check below. + if (addend < 0 && static_cast(std::abs(addend)) > value) { + LLDB_LOGF(log, "Debug info relocation overflow: 0x%" PRIx64, + static_cast(value) + addend); + return; + } + if (!llvm::isUInt<32>(value + addend)) { + LLDB_LOGF(log, "Debug info relocation out of range: 0x%" PRIx64, value); + return; + } + uint32_t addr = value + addend; + memcpy(dst, &addr, sizeof(uint32_t)); + } +} + unsigned ObjectFileELF::ApplyRelocations( Symtab *symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, @@ -2667,6 +2704,15 @@ if (hdr->Is32Bit()) { switch (hdr->e_machine) { + case llvm::ELF::EM_ARM: + switch (reloc_type(rel)) { + case R_ARM_ABS32: + ApplyELF32ABS32Relocation(symtab, rel, debug_data, rel_section); + break; + default: + assert(false && "unexpected relocation type"); + } + break; case llvm::ELF::EM_386: switch (reloc_type(rel)) { case R_386_32: diff --git a/lldb/test/Shell/ObjectFile/ELF/aarch32-relocations.yaml b/lldb/test/Shell/ObjectFile/ELF/aarch32-relocations.yaml new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/ObjectFile/ELF/aarch32-relocations.yaml @@ -0,0 +1,62 @@ +# RUN: yaml2obj %s -o %t +# RUN: lldb-test object-file -contents %t | FileCheck %s + +## Test that R_ARM_ABS32 relocations are resolved in .debug_info sections on aarch32. +## REL-type relocations store implicit addend as signed values inline. +## We relocate the symbol foo with 4 different addends and bar once in the .debug_info section. +## Results that exceed the 32-bit range or overflow are logged and ignored. + +# CHECK: Name: .debug_info +# CHECK: Data: ( +# +# Addends: Zero Positive Negative Overflow Out-of-range +# 00000000 04030201 D6FFFFFF D5FFFFFF FFFFFF7F +# CHECK-NEXT: 0000: 2A000000 2E030201 00000000 D5FFFFFF FFFFFF7F +# CHECK-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + - Name: .debug_info + Type: SHT_PROGBITS + Content: 0000000004030201D6FFFFFFD5FFFFFFFFFFFF7F + - Name: .rel.debug_info + Type: SHT_REL + Info: .debug_info + Relocations: + - Offset: 0x0 + Symbol: foo + Type: R_ARM_ABS32 + - Offset: 0x4 + Symbol: foo + Type: R_ARM_ABS32 + - Offset: 0x8 + Symbol: foo + Type: R_ARM_ABS32 + - Offset: 0xC + Symbol: foo + Type: R_ARM_ABS32 + - Offset: 0x10 + Symbol: bar + Type: R_ARM_ABS32 +Symbols: + - Name: .debug_info + Type: STT_SECTION + Section: .debug_info + - Name: foo + Type: STT_FUNC + Section: .debug_info + Value: 0x0000002A + - Name: bar + Type: STT_FUNC + Section: .debug_info + Value: 0xFF000000 +...