diff options
author | David Srbecky <dsrbecky@google.com> | 2015-04-17 21:14:10 +0100 |
---|---|---|
committer | David Srbecky <dsrbecky@google.com> | 2015-04-21 19:47:42 +0100 |
commit | 527c9c71f0c6e2f9943ac028e7c050500699a44b (patch) | |
tree | 09e6794e5b184ce33ca468c972a8ef2faff7f174 | |
parent | e7bee3b7d307508243f4a00b5cf8a8867fcaaff5 (diff) | |
download | art-527c9c71f0c6e2f9943ac028e7c050500699a44b.zip art-527c9c71f0c6e2f9943ac028e7c050500699a44b.tar.gz art-527c9c71f0c6e2f9943ac028e7c050500699a44b.tar.bz2 |
Generate .eh_frame_hdr section and PT_GNU_EH_FRAME segment.
Fixes issue 20125400 - ART: Need .eh_frame_hdr and PT_GNU_EH_FRAME
for libunwind.
.eh_frame_hdr serves two purposes. Firstly, it can optionally contain
binary search table for fast eh_frame lookup. This is important for
C++ exception handling, but we do not need it so we omit it.
Secondly, it contains a relative .eh_frame pointer which makes it
easier for run-time code to locate the .eh_frame section.
libunwind seems to rely on this relative pointer.
Bug: 20125400
Change-Id: I7c1e3f68d914f70781404c508395831a3296a7da
-rw-r--r-- | compiler/cfi_test.h | 4 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_constants.h | 22 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_test.cc | 10 | ||||
-rw-r--r-- | compiler/dwarf/dwarf_test.h | 20 | ||||
-rw-r--r-- | compiler/dwarf/headers.h | 9 | ||||
-rw-r--r-- | compiler/elf_builder.h | 133 | ||||
-rw-r--r-- | compiler/elf_writer_debug.cc | 83 | ||||
-rw-r--r-- | compiler/elf_writer_debug.h | 16 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 106 | ||||
-rw-r--r-- | runtime/elf_file.cc | 3 |
10 files changed, 278 insertions, 128 deletions
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h index cdb1b9e..f7501d2 100644 --- a/compiler/cfi_test.h +++ b/compiler/cfi_test.h @@ -22,6 +22,7 @@ #include <sstream> #include "arch/instruction_set.h" +#include "dwarf/dwarf_constants.h" #include "dwarf/dwarf_test.h" #include "dwarf/headers.h" #include "disassembler/disassembler.h" @@ -45,7 +46,8 @@ class CFITest : public dwarf::DwarfTest { // Pretty-print CFI opcodes. constexpr bool is64bit = false; dwarf::DebugFrameOpCodeWriter<> initial_opcodes; - dwarf::WriteEhFrameCIE(is64bit, dwarf::Reg(8), initial_opcodes, &eh_frame_data_); + dwarf::WriteEhFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8), + initial_opcodes, &eh_frame_data_); std::vector<uintptr_t> eh_frame_patches; dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi, &eh_frame_data_, &eh_frame_patches); diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/dwarf/dwarf_constants.h index 8e39ca7..61a44cd 100644 --- a/compiler/dwarf/dwarf_constants.h +++ b/compiler/dwarf/dwarf_constants.h @@ -658,6 +658,28 @@ enum CallFrameInstruction : uint8_t { DW_CFA_hi_user = 0x3f }; +enum ExceptionHeaderValueFormat : uint8_t { + DW_EH_PE_native = 0x00, + DW_EH_PE_uleb128 = 0x01, + 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, + DW_EH_PE_omit = 0xFF, +}; + +enum ExceptionHeaderValueApplication : uint8_t { + DW_EH_PE_absptr = 0x00, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, +}; + } // namespace dwarf } // namespace art diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc index 98f691a..edba00a 100644 --- a/compiler/dwarf/dwarf_test.cc +++ b/compiler/dwarf/dwarf_test.cc @@ -16,6 +16,7 @@ #include "dwarf_test.h" +#include "dwarf/dwarf_constants.h" #include "dwarf/debug_frame_opcode_writer.h" #include "dwarf/debug_info_entry_writer.h" #include "dwarf/debug_line_opcode_writer.h" @@ -119,7 +120,8 @@ TEST_F(DwarfTest, DebugFrame) { DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)"); DebugFrameOpCodeWriter<> initial_opcodes; - WriteEhFrameCIE(is64bit, Reg(is64bit ? 16 : 8), initial_opcodes, &eh_frame_data_); + WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8), + initial_opcodes, &eh_frame_data_); std::vector<uintptr_t> eh_frame_patches; std::vector<uintptr_t> expected_patches { 28 }; // NOLINT WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(), @@ -132,7 +134,8 @@ TEST_F(DwarfTest, DebugFrame) { TEST_F(DwarfTest, DebugFrame64) { constexpr bool is64bit = true; DebugFrameOpCodeWriter<> initial_opcodes; - WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_); + WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16), + initial_opcodes, &eh_frame_data_); DebugFrameOpCodeWriter<> opcodes; std::vector<uintptr_t> eh_frame_patches; std::vector<uintptr_t> expected_patches { 32 }; // NOLINT @@ -170,7 +173,8 @@ TEST_F(DwarfTest, x86_64_RegisterMapping) { DW_CHECK_NEXT("DW_CFA_offset: r14 (r14)"); DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)"); DebugFrameOpCodeWriter<> initial_opcodes; - WriteEhFrameCIE(is64bit, Reg(16), initial_opcodes, &eh_frame_data_); + WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16), + initial_opcodes, &eh_frame_data_); std::vector<uintptr_t> eh_frame_patches; WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000, opcodes.data(), &eh_frame_data_, &eh_frame_patches); diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h index dd5e0c2..cbe700a 100644 --- a/compiler/dwarf/dwarf_test.h +++ b/compiler/dwarf/dwarf_test.h @@ -100,30 +100,30 @@ class DwarfTest : public CommonRuntimeTest { Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr> builder( &code, file.GetFile(), isa, 0, 0, 0, 0, 0, 0, false, false); typedef ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> Section; + Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + Section eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0); if (!debug_info_data_.empty()) { - Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0); debug_info.SetBuffer(debug_info_data_); - builder.RegisterRawSection(debug_info); + builder.RegisterRawSection(&debug_info); } if (!debug_abbrev_data_.empty()) { - Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); debug_abbrev.SetBuffer(debug_abbrev_data_); - builder.RegisterRawSection(debug_abbrev); + builder.RegisterRawSection(&debug_abbrev); } if (!debug_str_data_.empty()) { - Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); debug_str.SetBuffer(debug_str_data_); - builder.RegisterRawSection(debug_str); + builder.RegisterRawSection(&debug_str); } if (!debug_line_data_.empty()) { - Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0); debug_line.SetBuffer(debug_line_data_); - builder.RegisterRawSection(debug_line); + builder.RegisterRawSection(&debug_line); } if (!eh_frame_data_.empty()) { - Section eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0); eh_frame.SetBuffer(eh_frame_data_); - builder.RegisterRawSection(eh_frame); + builder.RegisterRawSection(&eh_frame); } builder.Init(); builder.Write(); diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h index 760f53c..9f64766 100644 --- a/compiler/dwarf/headers.h +++ b/compiler/dwarf/headers.h @@ -22,6 +22,7 @@ #include "dwarf/debug_frame_opcode_writer.h" #include "dwarf/debug_info_entry_writer.h" #include "dwarf/debug_line_opcode_writer.h" +#include "dwarf/dwarf_constants.h" #include "dwarf/register.h" #include "dwarf/writer.h" @@ -36,7 +37,9 @@ namespace dwarf { // Write common information entry (CIE) to .eh_frame section. template<typename Allocator> -void WriteEhFrameCIE(bool is64bit, Reg return_address_register, +void WriteEhFrameCIE(bool is64bit, + ExceptionHeaderValueApplication address_type, + Reg return_address_register, const DebugFrameOpCodeWriter<Allocator>& opcodes, std::vector<uint8_t>* eh_frame) { Writer<> writer(eh_frame); @@ -50,9 +53,9 @@ void WriteEhFrameCIE(bool is64bit, Reg return_address_register, writer.PushUleb128(return_address_register.num()); // ubyte in DWARF2. writer.PushUleb128(1); // z: Augmentation data size. if (is64bit) { - writer.PushUint8(0x04); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8). + writer.PushUint8(address_type | DW_EH_PE_udata8); // R: Pointer encoding. } else { - writer.PushUint8(0x03); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4). + writer.PushUint8(address_type | DW_EH_PE_udata4); // R: Pointer encoding. } writer.PushData(opcodes.data()); writer.Pad(is64bit ? 8 : 4); diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 124ed03..323c933 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -584,11 +584,12 @@ class ElfBuilder FINAL { // | Elf_Ehdr | // +-------------------------+ // | Elf_Phdr PHDR | - // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .rodata + // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .eh_frame .eh_frame_hdr .rodata // | Elf_Phdr LOAD R X | .text // | Elf_Phdr LOAD RW | .bss (Optional) // | Elf_Phdr LOAD RW | .dynamic // | Elf_Phdr DYNAMIC | .dynamic + // | Elf_Phdr EH_FRAME R | .eh_frame_hdr // +-------------------------+ // | .dynsym | // | Elf_Sym STN_UNDEF | @@ -615,6 +616,10 @@ class ElfBuilder FINAL { // | ... | // | Elf_Word chain[c - 1] | // +-------------------------+ + // | .eh_frame | (Optional) + // +-------------------------+ + // | .eh_frame_hdr | (Optional) + // +-------------------------+ // | .rodata | // | oatdata..oatexec-4 | // +-------------------------+ @@ -648,22 +653,21 @@ class ElfBuilder FINAL { // | .shstrtab\0 | // | .symtab\0 | (Optional) // | .strtab\0 | (Optional) - // | .debug_str\0 | (Optional) - // | .debug_info\0 | (Optional) // | .eh_frame\0 | (Optional) - // | .debug_line\0 | (Optional) + // | .eh_frame_hdr\0 | (Optional) + // | .debug_info\0 | (Optional) // | .debug_abbrev\0 | (Optional) + // | .debug_str\0 | (Optional) + // | .debug_line\0 | (Optional) // +-------------------------+ (Optional) // | .debug_info | (Optional) // +-------------------------+ (Optional) // | .debug_abbrev | (Optional) // +-------------------------+ (Optional) - // | .eh_frame | (Optional) + // | .debug_str | (Optional) // +-------------------------+ (Optional) // | .debug_line | (Optional) // +-------------------------+ (Optional) - // | .debug_str | (Optional) - // +-------------------------+ (Optional) // | Elf_Shdr NULL | // | Elf_Shdr .dynsym | // | Elf_Shdr .dynstr | @@ -673,11 +677,12 @@ class ElfBuilder FINAL { // | Elf_Shdr .bss | (Optional) // | Elf_Shdr .dynamic | // | Elf_Shdr .shstrtab | + // | Elf_Shdr .eh_frame | (Optional) + // | Elf_Shdr .eh_frame_hdr | (Optional) // | Elf_Shdr .debug_info | (Optional) // | Elf_Shdr .debug_abbrev | (Optional) - // | Elf_Shdr .eh_frame | (Optional) - // | Elf_Shdr .debug_line | (Optional) // | Elf_Shdr .debug_str | (Optional) + // | Elf_Shdr .debug_line | (Optional) // +-------------------------+ if (fatal_error_) { @@ -718,6 +723,9 @@ class ElfBuilder FINAL { program_headers_[PH_DYNAMIC].p_type = PT_DYNAMIC; program_headers_[PH_DYNAMIC].p_flags = PF_R | PF_W; + program_headers_[PH_EH_FRAME_HDR].p_type = PT_NULL; + program_headers_[PH_EH_FRAME_HDR].p_flags = PF_R; + // Get the dynstr string. dynstr_ = dynsym_builder_.GenerateStrtab(); @@ -828,10 +836,37 @@ class ElfBuilder FINAL { hash_builder_.GetSection()->sh_size = hash_.size() * sizeof(Elf_Word); hash_builder_.GetSection()->sh_link = hash_builder_.GetLink(); + // Get the layout of the extra sections with SHF_ALLOC flag. + // This will deal with .eh_frame and .eh_frame_hdr. + // .eh_frame contains relative pointers to .text which we + // want to fixup between the calls to Init() and Write(). + // Therefore we handle those sections here as opposed to Write(). + // It also has the nice side effect of including .eh_frame + // with the rest of LOAD_R segment. It must come before .rodata + // because .rodata and .text must be next to each other. + Elf_Shdr* prev = hash_builder_.GetSection(); + for (auto* it : other_builders_) { + if ((it->GetSection()->sh_flags & SHF_ALLOC) != 0) { + it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev); + it->GetSection()->sh_addr = it->GetSection()->sh_offset; + it->GetSection()->sh_size = it->GetBuffer()->size(); + it->GetSection()->sh_link = it->GetLink(); + prev = it->GetSection(); + } + } + // If the sections exist, check that they have been handled. + const auto* eh_frame = FindRawSection(".eh_frame"); + if (eh_frame != nullptr) { + DCHECK_NE(eh_frame->GetSection()->sh_offset, 0u); + } + const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr"); + if (eh_frame_hdr != nullptr) { + DCHECK_NE(eh_frame_hdr->GetSection()->sh_offset, 0u); + } + // Get the layout of the rodata section. rodata_builder_.GetSection()->sh_offset = - NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(), - *hash_builder_.GetSection()); + NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(), *prev); rodata_builder_.GetSection()->sh_addr = rodata_builder_.GetSection()->sh_offset; rodata_builder_.GetSection()->sh_size = rodata_builder_.GetSize(); rodata_builder_.GetSection()->sh_link = rodata_builder_.GetLink(); @@ -909,9 +944,7 @@ class ElfBuilder FINAL { } // Setup all the other sections. - for (ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> *builder = other_builders_.data(), - *end = builder + other_builders_.size(); - builder != end; ++builder) { + for (auto* builder : other_builders_) { section_ptrs_.push_back(builder->GetSection()); AssignSectionStr(builder, &shstrtab_); builder->SetSectionIndex(section_index_); @@ -958,20 +991,22 @@ class ElfBuilder FINAL { } } - // Get the layout of the extra sections. (This will deal with the debug - // sections if they are there) - for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) { - it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev); - it->GetSection()->sh_addr = 0; - it->GetSection()->sh_size = it->GetBuffer()->size(); - it->GetSection()->sh_link = it->GetLink(); - - // We postpone adding an ElfFilePiece to keep the order in "pieces." - - prev = it->GetSection(); - if (debug_logging_) { - LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset - << " size=" << it->GetSection()->sh_size; + // Get the layout of the extra sections without SHF_ALLOC flag. + // (This will deal with the debug sections if they are there) + for (auto* it : other_builders_) { + if ((it->GetSection()->sh_flags & SHF_ALLOC) == 0) { + it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev); + it->GetSection()->sh_addr = 0; + it->GetSection()->sh_size = it->GetBuffer()->size(); + it->GetSection()->sh_link = it->GetLink(); + + // We postpone adding an ElfFilePiece to keep the order in "pieces." + + prev = it->GetSection(); + if (debug_logging_) { + LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset + << " size=" << it->GetSection()->sh_size; + } } } @@ -1044,6 +1079,26 @@ class ElfBuilder FINAL { program_headers_[PH_DYNAMIC].p_memsz = dynamic_builder_.GetSection()->sh_size; program_headers_[PH_DYNAMIC].p_align = dynamic_builder_.GetSection()->sh_addralign; + const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr"); + if (eh_frame_hdr != nullptr) { + const auto* eh_frame = FindRawSection(".eh_frame"); + // Check layout: + // 1) eh_frame is before eh_frame_hdr. + // 2) There's no gap. + CHECK(eh_frame != nullptr); + CHECK_LE(eh_frame->GetSection()->sh_offset, eh_frame_hdr->GetSection()->sh_offset); + CHECK_EQ(eh_frame->GetSection()->sh_offset + eh_frame->GetSection()->sh_size, + eh_frame_hdr->GetSection()->sh_offset); + + program_headers_[PH_EH_FRAME_HDR].p_type = PT_GNU_EH_FRAME; + program_headers_[PH_EH_FRAME_HDR].p_offset = eh_frame_hdr->GetSection()->sh_offset; + program_headers_[PH_EH_FRAME_HDR].p_vaddr = eh_frame_hdr->GetSection()->sh_addr; + program_headers_[PH_EH_FRAME_HDR].p_paddr = eh_frame_hdr->GetSection()->sh_addr; + program_headers_[PH_EH_FRAME_HDR].p_filesz = eh_frame_hdr->GetSection()->sh_size; + program_headers_[PH_EH_FRAME_HDR].p_memsz = eh_frame_hdr->GetSection()->sh_size; + program_headers_[PH_EH_FRAME_HDR].p_align = eh_frame_hdr->GetSection()->sh_addralign; + } + // Finish setup of the Ehdr values. elf_header_.e_phoff = PHDR_OFFSET; elf_header_.e_shoff = sections_offset; @@ -1108,7 +1163,7 @@ class ElfBuilder FINAL { } // Postponed debug info. - for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) { + for (auto* it : other_builders_) { pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(it->GetName(), it->GetSection()->sh_offset, it->GetBuffer()->data(), it->GetBuffer()->size())); @@ -1125,12 +1180,21 @@ class ElfBuilder FINAL { return true; } - // Adds the given raw section to the builder. This will copy it. The caller - // is responsible for deallocating their copy. - void RegisterRawSection(ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> bld) { + // Adds the given raw section to the builder. It does not take ownership. + void RegisterRawSection(ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* bld) { other_builders_.push_back(bld); } + const ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>* + FindRawSection(const char* name) { + for (const auto* other_builder : other_builders_) { + if (other_builder->GetName() == name) { + return other_builder; + } + } + return nullptr; + } + private: void SetISA(InstructionSet isa) { switch (isa) { @@ -1282,7 +1346,8 @@ class ElfBuilder FINAL { PH_LOAD_RW_BSS = 3, PH_LOAD_RW_DYNAMIC = 4, PH_DYNAMIC = 5, - PH_NUM = 6, + PH_EH_FRAME_HDR = 6, + PH_NUM = 7, }; static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM; Elf_Phdr program_headers_[PH_NUM]; @@ -1306,7 +1371,7 @@ class ElfBuilder FINAL { ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> hash_builder_; ElfDynamicBuilder<Elf_Word, Elf_Sword, Elf_Dyn, Elf_Shdr> dynamic_builder_; ElfSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> shstrtab_builder_; - std::vector<ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>> other_builders_; + std::vector<ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr>*> other_builders_; DISALLOW_COPY_AND_ASSIGN(ElfBuilder); }; diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index 39233ce..cf0adae 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -28,7 +28,9 @@ namespace art { namespace dwarf { -static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) { +static void WriteEhFrameCIE(InstructionSet isa, + ExceptionHeaderValueApplication addr_type, + std::vector<uint8_t>* eh_frame) { // Scratch registers should be marked as undefined. This tells the // debugger that its value in the previous frame is not recoverable. bool is64bit = Is64BitInstructionSet(isa); @@ -53,8 +55,8 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) opcodes.SameValue(Reg::ArmFp(reg)); } } - auto return_address_reg = Reg::ArmCore(14); // R14(LR). - WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame); + auto return_reg = Reg::ArmCore(14); // R14(LR). + WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); return; } case kArm64: { @@ -76,8 +78,8 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) opcodes.SameValue(Reg::Arm64Fp(reg)); } } - auto return_address_reg = Reg::Arm64Core(30); // R30(LR). - WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame); + auto return_reg = Reg::Arm64Core(30); // R30(LR). + WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); return; } case kMips: @@ -92,8 +94,8 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) opcodes.SameValue(Reg::MipsCore(reg)); } } - auto return_address_reg = Reg::MipsCore(31); // R31(RA). - WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame); + auto return_reg = Reg::MipsCore(31); // R31(RA). + WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); return; } case kX86: { @@ -114,8 +116,8 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) for (int reg = 0; reg < 8; reg++) { opcodes.Undefined(Reg::X86Fp(reg)); } - auto return_address_reg = Reg::X86Core(8); // R8(EIP). - WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame); + auto return_reg = Reg::X86Core(8); // R8(EIP). + WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); return; } case kX86_64: { @@ -140,8 +142,8 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) opcodes.SameValue(Reg::X86_64Fp(reg)); } } - auto return_address_reg = Reg::X86_64Core(16); // R16(RIP). - WriteEhFrameCIE(is64bit, return_address_reg, opcodes, eh_frame); + auto return_reg = Reg::X86_64Core(16); // R16(RIP). + WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame); return; } case kNone: @@ -152,22 +154,37 @@ static void WriteEhFrameCIE(InstructionSet isa, std::vector<uint8_t>* eh_frame) } void WriteEhFrame(const CompilerDriver* compiler, - OatWriter* oat_writer, - uint32_t text_section_offset, - std::vector<uint8_t>* eh_frame) { + const OatWriter* oat_writer, + ExceptionHeaderValueApplication address_type, + std::vector<uint8_t>* eh_frame, + std::vector<uintptr_t>* eh_frame_patches, + std::vector<uint8_t>* eh_frame_hdr) { const auto& method_infos = oat_writer->GetMethodDebugInfo(); const InstructionSet isa = compiler->GetInstructionSet(); + + // Write .eh_frame section. size_t cie_offset = eh_frame->size(); - auto* eh_frame_patches = oat_writer->GetAbsolutePatchLocationsFor(".eh_frame"); - WriteEhFrameCIE(isa, eh_frame); + WriteEhFrameCIE(isa, address_type, eh_frame); for (const OatWriter::DebugInfo& mi : method_infos) { const SwapVector<uint8_t>* opcodes = mi.compiled_method_->GetCFIInfo(); if (opcodes != nullptr) { WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset, - text_section_offset + mi.low_pc_, mi.high_pc_ - mi.low_pc_, + mi.low_pc_, mi.high_pc_ - mi.low_pc_, opcodes, eh_frame, eh_frame_patches); } } + + // Write .eh_frame_hdr section. + Writer<> header(eh_frame_hdr); + header.PushUint8(1); // Version. + header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); // Encoding of .eh_frame pointer. + header.PushUint8(DW_EH_PE_omit); // Encoding of binary search table size. + header.PushUint8(DW_EH_PE_omit); // Encoding of binary search table addresses. + // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section, and need to encode + // relative to this location as libunwind doesn't honor datarel for eh_frame_hdr correctly. + header.PushInt32(-static_cast<int32_t>(eh_frame->size() + 4U)); + // Omit binary search table size (number of entries). + // Omit binary search table. } /* @@ -175,17 +192,20 @@ void WriteEhFrame(const CompilerDriver* compiler, * @param oat_writer The Oat file Writer. * @param eh_frame Call Frame Information. * @param debug_info Compilation unit information. + * @param debug_info_patches Address locations to be patched. * @param debug_abbrev Abbreviations used to generate dbg_info. * @param debug_str Debug strings. * @param debug_line Line number table. + * @param debug_line_patches Address locations to be patched. */ void WriteDebugSections(const CompilerDriver* compiler, - OatWriter* oat_writer, - uint32_t text_section_offset, + const OatWriter* oat_writer, std::vector<uint8_t>* debug_info, + std::vector<uintptr_t>* debug_info_patches, std::vector<uint8_t>* debug_abbrev, std::vector<uint8_t>* debug_str, - std::vector<uint8_t>* debug_line) { + std::vector<uint8_t>* debug_line, + std::vector<uintptr_t>* debug_line_patches) { const std::vector<OatWriter::DebugInfo>& method_infos = oat_writer->GetMethodDebugInfo(); const InstructionSet isa = compiler->GetInstructionSet(); @@ -229,8 +249,8 @@ void WriteDebugSections(const CompilerDriver* compiler, info.StartTag(DW_TAG_compile_unit, DW_CHILDREN_yes); info.WriteStrp(DW_AT_producer, "Android dex2oat", debug_str); info.WriteData1(DW_AT_language, DW_LANG_Java); - info.WriteAddr(DW_AT_low_pc, cunit_low_pc + text_section_offset); - info.WriteAddr(DW_AT_high_pc, cunit_high_pc + text_section_offset); + info.WriteAddr(DW_AT_low_pc, cunit_low_pc); + info.WriteAddr(DW_AT_high_pc, cunit_high_pc); info.WriteData4(DW_AT_stmt_list, debug_line->size()); for (auto method_info : compilation_unit) { std::string method_name = PrettyMethod(method_info->dex_method_index_, @@ -240,12 +260,11 @@ void WriteDebugSections(const CompilerDriver* compiler, } info.StartTag(DW_TAG_subprogram, DW_CHILDREN_no); info.WriteStrp(DW_AT_name, method_name.data(), debug_str); - info.WriteAddr(DW_AT_low_pc, method_info->low_pc_ + text_section_offset); - info.WriteAddr(DW_AT_high_pc, method_info->high_pc_ + text_section_offset); + info.WriteAddr(DW_AT_low_pc, method_info->low_pc_); + info.WriteAddr(DW_AT_high_pc, method_info->high_pc_); info.EndTag(); // DW_TAG_subprogram } info.EndTag(); // DW_TAG_compile_unit - auto* debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info"); WriteDebugInfoCU(debug_abbrev_offset, info, debug_info, debug_info_patches); // Write .debug_line section. @@ -272,7 +291,7 @@ void WriteDebugSections(const CompilerDriver* compiler, break; } DebugLineOpCodeWriter<> opcodes(false /* 32bit */, code_factor_bits_); - opcodes.SetAddress(text_section_offset + cunit_low_pc); + opcodes.SetAddress(cunit_low_pc); if (dwarf_isa != -1) { opcodes.SetISA(dwarf_isa); } @@ -343,7 +362,6 @@ void WriteDebugSections(const CompilerDriver* compiler, // Generate mapping opcodes from PC to Java lines. const DefaultSrcMap& dex2line_map = debug_info_callbacks.dex2line_; - uint32_t low_pc = text_section_offset + mi->low_pc_; if (file_index != 0 && !dex2line_map.empty()) { bool first = true; for (SrcMapElem pc2dex : mi->compiled_method_->GetSrcMappingTable()) { @@ -359,24 +377,23 @@ void WriteDebugSections(const CompilerDriver* compiler, int first_line = dex2line_map.front().to_; // Prologue is not a sensible place for a breakpoint. opcodes.NegateStmt(); - opcodes.AddRow(low_pc, first_line); + opcodes.AddRow(mi->low_pc_, first_line); opcodes.NegateStmt(); opcodes.SetPrologueEnd(); } - opcodes.AddRow(low_pc + pc, line); + opcodes.AddRow(mi->low_pc_ + pc, line); } else if (line != opcodes.CurrentLine()) { - opcodes.AddRow(low_pc + pc, line); + opcodes.AddRow(mi->low_pc_ + pc, line); } } } } else { // line 0 - instruction cannot be attributed to any source line. - opcodes.AddRow(low_pc, 0); + opcodes.AddRow(mi->low_pc_, 0); } } - opcodes.AdvancePC(text_section_offset + cunit_high_pc); + opcodes.AdvancePC(cunit_high_pc); opcodes.EndSequence(); - auto* debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line"); WriteDebugLineTable(directories, files, opcodes, debug_line, debug_line_patches); } } diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h index 2c03b98..5bf4841 100644 --- a/compiler/elf_writer_debug.h +++ b/compiler/elf_writer_debug.h @@ -19,23 +19,27 @@ #include <vector> +#include "dwarf/dwarf_constants.h" #include "oat_writer.h" namespace art { namespace dwarf { void WriteEhFrame(const CompilerDriver* compiler, - OatWriter* oat_writer, - uint32_t text_section_offset, - std::vector<uint8_t>* eh_frame); + const OatWriter* oat_writer, + ExceptionHeaderValueApplication address_type, + std::vector<uint8_t>* eh_frame, + std::vector<uintptr_t>* eh_frame_patches, + std::vector<uint8_t>* eh_frame_hdr); void WriteDebugSections(const CompilerDriver* compiler, - OatWriter* oat_writer, - uint32_t text_section_offset, + const OatWriter* oat_writer, std::vector<uint8_t>* debug_info, + std::vector<uintptr_t>* debug_info_patches, std::vector<uint8_t>* debug_abbrev, std::vector<uint8_t>* debug_str, - std::vector<uint8_t>* debug_line); + std::vector<uint8_t>* debug_line, + std::vector<uintptr_t>* debug_line_patches); } // namespace dwarf } // namespace art diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 429cd85..44c14a0 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -70,8 +70,7 @@ class OatWriterWrapper FINAL : public CodeOutput { template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr> -static void WriteDebugSymbols(const CompilerDriver* compiler_driver, - ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, +static void WriteDebugSymbols(ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder, OatWriter* oat_writer); @@ -109,6 +108,19 @@ void ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, Elf_Sym, Elf_Ehdr, buffer->push_back(0); // End of sections. } +template<typename AddressType, bool SubtractPatchLocation = false> +static void PatchAddresses(const std::vector<uintptr_t>* patch_locations, + AddressType delta, std::vector<uint8_t>* buffer) { + // Addresses in .debug_* sections are unaligned. + typedef __attribute__((__aligned__(1))) AddressType UnalignedAddressType; + if (patch_locations != nullptr) { + for (uintptr_t patch_location : *patch_locations) { + *reinterpret_cast<UnalignedAddressType*>(buffer->data() + patch_location) += + delta - (SubtractPatchLocation ? patch_location : 0); + } + } +} + template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Dyn, typename Elf_Sym, typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr> @@ -141,33 +153,77 @@ bool ElfWriterQuick<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(), debug)); - if (!builder->Init()) { - return false; - } + InstructionSet isa = compiler_driver_->GetInstructionSet(); + int alignment = GetInstructionSetPointerSize(isa); + typedef ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> RawSection; + RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, alignment, 0); + RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0); + RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, 1, 0); + // Do not add to .oat_patches since we will make the addresses relative. + std::vector<uintptr_t> eh_frame_patches; if (compiler_driver_->GetCompilerOptions().GetIncludeCFI() && !oat_writer->GetMethodDebugInfo().empty()) { - ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> eh_frame( - ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0); dwarf::WriteEhFrame(compiler_driver_, oat_writer, - builder->GetTextBuilder().GetSection()->sh_addr, - eh_frame.GetBuffer()); - builder->RegisterRawSection(eh_frame); + dwarf::DW_EH_PE_pcrel, + eh_frame.GetBuffer(), &eh_frame_patches, + eh_frame_hdr.GetBuffer()); + builder->RegisterRawSection(&eh_frame); + builder->RegisterRawSection(&eh_frame_hdr); } + // Must be done after .eh_frame is created since it is used in the Elf layout. + if (!builder->Init()) { + return false; + } + + std::vector<uintptr_t>* debug_info_patches = nullptr; + std::vector<uintptr_t>* debug_line_patches = nullptr; if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols() && !oat_writer->GetMethodDebugInfo().empty()) { - WriteDebugSymbols(compiler_driver_, builder.get(), oat_writer); + // Add methods to .symtab. + WriteDebugSymbols(builder.get(), oat_writer); + // Generate DWARF .debug_* sections. + debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info"); + debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line"); + dwarf::WriteDebugSections(compiler_driver_, oat_writer, + debug_info.GetBuffer(), debug_info_patches, + debug_abbrev.GetBuffer(), + debug_str.GetBuffer(), + debug_line.GetBuffer(), debug_line_patches); + builder->RegisterRawSection(&debug_info); + builder->RegisterRawSection(&debug_abbrev); + builder->RegisterRawSection(&debug_str); + builder->RegisterRawSection(&debug_line); } if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() || // ElfWriter::Fixup will be called regardless and it needs to be able // to patch debug sections so we have to include patches for them. compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) { - ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> oat_patches( - ".oat_patches", SHT_OAT_PATCH, 0, NULL, 0, 1, 0); EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer()); - builder->RegisterRawSection(oat_patches); + builder->RegisterRawSection(&oat_patches); + } + + // We know where .text and .eh_frame will be located, so patch the addresses. + Elf_Addr text_addr = builder->GetTextBuilder().GetSection()->sh_addr; + // TODO: Simplify once we use Elf64 - we can use Elf_Addr instead of branching. + if (Is64BitInstructionSet(compiler_driver_->GetInstructionSet())) { + // relative_address = (text_addr + address) - (eh_frame_addr + patch_location); + PatchAddresses<uint64_t, true>(&eh_frame_patches, + text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer()); + PatchAddresses<uint64_t>(debug_info_patches, text_addr, debug_info.GetBuffer()); + PatchAddresses<uint64_t>(debug_line_patches, text_addr, debug_line.GetBuffer()); + } else { + // relative_address = (text_addr + address) - (eh_frame_addr + patch_location); + PatchAddresses<uint32_t, true>(&eh_frame_patches, + text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer()); + PatchAddresses<uint32_t>(debug_info_patches, text_addr, debug_info.GetBuffer()); + PatchAddresses<uint32_t>(debug_line_patches, text_addr, debug_line.GetBuffer()); } return builder->Write(); @@ -178,8 +234,7 @@ template <typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Phdr, typename Elf_Shdr> // Do not inline to avoid Clang stack frame problems. b/18738594 NO_INLINE -static void WriteDebugSymbols(const CompilerDriver* compiler_driver, - ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, +static void WriteDebugSymbols(ElfBuilder<Elf_Word, Elf_Sword, Elf_Addr, Elf_Dyn, Elf_Sym, Elf_Ehdr, Elf_Phdr, Elf_Shdr>* builder, OatWriter* oat_writer) { const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetMethodDebugInfo(); @@ -214,25 +269,6 @@ static void WriteDebugSymbols(const CompilerDriver* compiler_driver, 0, STB_LOCAL, STT_NOTYPE); } } - - typedef ElfRawSectionBuilder<Elf_Word, Elf_Sword, Elf_Shdr> Section; - Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - - dwarf::WriteDebugSections(compiler_driver, - oat_writer, - builder->GetTextBuilder().GetSection()->sh_addr, - debug_info.GetBuffer(), - debug_abbrev.GetBuffer(), - debug_str.GetBuffer(), - debug_line.GetBuffer()); - - builder->RegisterRawSection(debug_info); - builder->RegisterRawSection(debug_abbrev); - builder->RegisterRawSection(debug_str); - builder->RegisterRawSection(debug_line); } // Explicit instantiations diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index f2b013f..37e391d 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1606,9 +1606,6 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, if (base_address_delta == 0) { return true; } - if (!ApplyOatPatchesTo(".eh_frame", base_address_delta)) { - return false; - } if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) { return false; } |