diff --git a/src/bloaty.h b/src/bloaty.h index d1c1a5a..942d1c3 100644 --- a/src/bloaty.h +++ b/src/bloaty.h @@ -314,8 +314,8 @@ inline void ReadDWARFCompileUnits(const dwarf::File& file, const DualMap& map, } void ReadDWARFInlines(const dwarf::File& file, RangeSink* sink, bool include_line); -void ReadEhFrame(std::string_view contents, RangeSink* sink); -void ReadEhFrameHdr(std::string_view contents, RangeSink* sink); +void ReadEhFrame(std::string_view contents, RangeSink* sink, bool is_64bit); +void ReadEhFrameHdr(std::string_view contents, RangeSink* sink, bool is_64bit); // Demangle C++ symbols according to the Itanium ABI. The |source| argument // controls what demangling mode we are using. diff --git a/src/dwarf_constants.h b/src/dwarf_constants.h index 7e6fc04..8237d61 100644 --- a/src/dwarf_constants.h +++ b/src/dwarf_constants.h @@ -674,10 +674,15 @@ enum PointerEncoding { DW_EH_PE_udata2 = 0x02, DW_EH_PE_udata4 = 0x03, DW_EH_PE_udata8 = 0x04, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0A, - DW_EH_PE_sdata4 = 0x0B, - DW_EH_PE_sdata8 = 0x0C, + + // This acts as a flag. + DW_EH_PE_signed = 0x08, + + DW_EH_PE_sabsptr = DW_EH_PE_absptr | DW_EH_PE_signed, + DW_EH_PE_sleb128 = DW_EH_PE_uleb128 | DW_EH_PE_signed, + DW_EH_PE_sdata2 = DW_EH_PE_udata2 | DW_EH_PE_signed, + DW_EH_PE_sdata4 = DW_EH_PE_udata4 | DW_EH_PE_signed, + DW_EH_PE_sdata8 = DW_EH_PE_udata8 | DW_EH_PE_signed, DW_EH_PE_FORMAT_MASK = 0x0f, DW_EH_PE_pcrel = 0x10, diff --git a/src/eh_frame.cc b/src/eh_frame.cc index d9dc6d2..3b52055 100644 --- a/src/eh_frame.cc +++ b/src/eh_frame.cc @@ -41,6 +41,13 @@ uint64_t ReadEncodedPointer(uint8_t encoding, bool is_64bit, string_view* data, value = ReadFixed(data); } break; + case DW_EH_PE_sabsptr: + if (is_64bit) { + value = ReadFixed(data); + } else { + value = ReadFixed(data); + } + break; case DW_EH_PE_uleb128: value = dwarf::ReadLEB128(data); break; @@ -124,7 +131,7 @@ uint64_t ReadEncodedPointer(uint8_t encoding, bool is_64bit, string_view* data, // https://github.com/llvm-mirror/libunwind/blob/master/src/DwarfParser.hpp // * libgcc // https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2-fde.c -void ReadEhFrame(string_view data, RangeSink* sink) { +void ReadEhFrame(string_view data, RangeSink* sink, bool is_64bit) { string_view remaining = data; struct CIEInfo { @@ -187,7 +194,7 @@ void ReadEhFrame(string_view data, RangeSink* sink) { case 'P': { uint8_t encoding = ReadFixed(&entry); cie_info.personality_function = - ReadEncodedPointer(encoding, true, &entry, nullptr, sink); + ReadEncodedPointer(encoding, is_64bit, &entry, nullptr, sink); break; } default: @@ -201,14 +208,13 @@ void ReadEhFrame(string_view data, RangeSink* sink) { THROW("Couldn't find CIE for FDE"); } const CIEInfo& cie_info = iter->second; - // TODO(haberman): don't hard-code 64-bit. - uint64_t address = ReadEncodedPointer(cie_info.fde_encoding, true, &entry, + uint64_t address = ReadEncodedPointer(cie_info.fde_encoding, is_64bit, &entry, nullptr, sink); // TODO(haberman); Technically the FDE addresses could span a // function/compilation unit? They can certainly span inlines. /* uint64_t length = - ReadEncodedPointer(cie_info.fde_encoding & 0xf, true, &entry, sink); + ReadEncodedPointer(cie_info.fde_encoding & 0xf, is_64bit, &entry, sink); (void)length; if (cie_info.has_augmentation_length) { @@ -217,7 +223,7 @@ void ReadEhFrame(string_view data, RangeSink* sink) { } uint64_t lsda = - ReadEncodedPointer(cie_info.lsda_encoding, true, &entry, sink); + ReadEncodedPointer(cie_info.lsda_encoding, is_64bit, &entry, sink); if (lsda) { } */ @@ -229,7 +235,7 @@ void ReadEhFrame(string_view data, RangeSink* sink) { // See documentation here: // http://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html#EHFRAME -void ReadEhFrameHdr(string_view data, RangeSink* sink) { +void ReadEhFrameHdr(string_view data, RangeSink* sink, bool is_64bit) { const char* base = data.data(); uint8_t version = ReadFixed(&data); uint8_t eh_frame_ptr_enc = ReadFixed(&data); @@ -240,12 +246,11 @@ void ReadEhFrameHdr(string_view data, RangeSink* sink) { THROWF("Unknown eh_frame_hdr version: $0", version); } - // TODO(haberman): don't hard-code 64-bit. uint64_t eh_frame_ptr = - ReadEncodedPointer(eh_frame_ptr_enc, true, &data, base, sink); + ReadEncodedPointer(eh_frame_ptr_enc, is_64bit, &data, base, sink); (void)eh_frame_ptr; uint64_t fde_count = - ReadEncodedPointer(fde_count_enc, true, &data, base, sink); + ReadEncodedPointer(fde_count_enc, is_64bit, &data, base, sink); if (table_enc == DW_EH_PE_omit) { return; @@ -254,8 +259,8 @@ void ReadEhFrameHdr(string_view data, RangeSink* sink) { for (uint64_t i = 0; i < fde_count; i++) { string_view entry_data = data; uint64_t initial_location = - ReadEncodedPointer(table_enc, true, &data, base, sink); - uint64_t fde_addr = ReadEncodedPointer(table_enc, true, &data, base, sink); + ReadEncodedPointer(table_enc, is_64bit, &data, base, sink); + uint64_t fde_addr = ReadEncodedPointer(table_enc, is_64bit, &data, base, sink); entry_data.remove_suffix(data.size()); sink->AddFileRangeForVMAddr("dwarf_fde_table", initial_location, entry_data); diff --git a/src/elf.cc b/src/elf.cc index a6870ce..08ae4fd 100644 --- a/src/elf.cc +++ b/src/elf.cc @@ -1022,9 +1022,9 @@ static void ReadELFTables(const InputFile& file, RangeSink* sink) { // fde entries from there). But these section names should be // standard enough that this approach works also. if (section.GetName() == ".eh_frame") { - ReadEhFrame(section.contents(), sink); + ReadEhFrame(section.contents(), sink, elf.is_64bit()); } else if (section.GetName() == ".eh_frame_hdr") { - ReadEhFrameHdr(section.contents(), sink); + ReadEhFrameHdr(section.contents(), sink, elf.is_64bit()); } } }); diff --git a/tests/elf/sections/eh-frame-signed.test b/tests/elf/sections/eh-frame-signed.test new file mode 100644 index 0000000..00be2b4 --- /dev/null +++ b/tests/elf/sections/eh-frame-signed.test @@ -0,0 +1,53 @@ +# RUN: %yaml2obj %s -o %t.o +# RUN: %bloaty -d symbols %t.o | %FileCheck %s + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + Size: 0x100 + - Name: .eh_frame + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + AddressAlign: 4 + # CIE Details: + # 10000000 # Length (16 bytes) + # 00000000 # CIE ID (0) + # 01 # Version (1) + # 7A5200 # Augmentation String: "zR" + # 01 # Code Alignment Factor (1) + # 7C # Data Alignment Factor (-4) + # 08 # Return Address Register (8) + # 01 # Augmentation Data Length (1) + # 08 # Augmentation Data (FDE Encoding: DW_EH_PE_signed = 0x08) + # 000000 # Padding (DW_CFA_nop) + # FDE Details: + # 0C000000 # Length (12 bytes) + # 18000000 # CIE Pointer (offset 24 backwards from here -> points to CIE at 0) + # 00100000 # PC Begin (0x1000, encoded as DW_EH_PE_signed 32-bit) + # 00010000 # PC Range (0x100, assuming same encoding) + Content: 1000000000000000017A5200017C0801080000000C000000180000000010000000010000 + +Symbols: + - Name: foo + Type: STT_FUNC + Section: .text + Value: 0x1000 + Size: 0x100 + +# CHECK: FILE SIZE VM SIZE +# CHECK-NEXT: -------------- -------------- +# CHECK-NEXT: 41.7% 277 87.7% 256 foo +# CHECK-NEXT: 36.1% 240 0.0% 0 [ELF Section Headers] +# CHECK-NEXT: 7.8% 52 0.0% 0 [ELF Header] +# CHECK-NEXT: 6.5% 43 0.0% 0 [section .shstrtab] +# CHECK-NEXT: 5.4% 36 12.3% 36 [section .eh_frame] +# CHECK-NEXT: 2.4% 16 0.0% 0 [section .symtab] +# CHECK-NEXT: 100.0% 664 100.0% 292 TOTAL