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
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 @@
     // 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 @@
   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 @@
   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, 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 @@
   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 @@
                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 @@
 
 // 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 @@
   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 @@
     // | 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 @@
     // |         ...             |
     // | Elf_Word chain[c - 1]   |
     // +-------------------------+
+    // | .eh_frame               |  (Optional)
+    // +-------------------------+
+    // | .eh_frame_hdr           |  (Optional)
+    // +-------------------------+
     // | .rodata                 |
     // | oatdata..oatexec-4      |
     // +-------------------------+
@@ -648,22 +653,21 @@
     // | .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 @@
     // | 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 @@
     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 @@
     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 @@
     }
 
     // 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 @@
       }
     }
 
-    // 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();
+    // 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."
+        // 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;
+        prev = it->GetSection();
+        if (debug_logging_) {
+          LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset
+                    << " size=" << it->GetSection()->sh_size;
+        }
       }
     }
 
@@ -1044,6 +1079,26 @@
     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 @@
     }
 
     // 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 @@
     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 @@
     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 @@
   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 @@
           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 @@
           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 @@
           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 @@
       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 @@
           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 @@
 }
 
 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 @@
  * @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 @@
     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 @@
       }
       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 @@
         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 @@
 
       // 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 @@
                 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 @@
 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 @@
   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 @@
           compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
           debug));
 
+  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()) {
+    dwarf::WriteEhFrame(compiler_driver_, oat_writer,
+                        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;
   }
 
-  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);
-  }
-
+  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 @@
           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 @@
                         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