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/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);