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