summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2015-04-17 21:14:10 +0100
committerDavid Srbecky <dsrbecky@google.com>2015-04-21 19:47:42 +0100
commit527c9c71f0c6e2f9943ac028e7c050500699a44b (patch)
tree09e6794e5b184ce33ca468c972a8ef2faff7f174
parente7bee3b7d307508243f4a00b5cf8a8867fcaaff5 (diff)
downloadart-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.h4
-rw-r--r--compiler/dwarf/dwarf_constants.h22
-rw-r--r--compiler/dwarf/dwarf_test.cc10
-rw-r--r--compiler/dwarf/dwarf_test.h20
-rw-r--r--compiler/dwarf/headers.h9
-rw-r--r--compiler/elf_builder.h133
-rw-r--r--compiler/elf_writer_debug.cc83
-rw-r--r--compiler/elf_writer_debug.h16
-rw-r--r--compiler/elf_writer_quick.cc106
-rw-r--r--runtime/elf_file.cc3
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;
}