libelffile: move to DWARF3 when writing .debug_frame.

zR augmentation in .debug_frame isn't recognized by llvm-dwarfdump.
This leads to below test failure after compiler update:
  DwarfTest.DebugFrame
  DwarfTest.x86_64_RegisterMapping

So switch to DWARF3, which supports 64-bit format without using zR
augmentation.

Bug: 192012848
Test: run art-test
Change-Id: Ib37c0bba7a293ae7b04c8cc0e9e09c045bcc0287
diff --git a/compiler/debug/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc
index 8897e45..8fdc7ca 100644
--- a/compiler/debug/dwarf/dwarf_test.cc
+++ b/compiler/debug/dwarf/dwarf_test.cc
@@ -131,7 +131,7 @@
   CheckObjdumpOutput(is64bit, "-debug-frame");
 }
 
-TEST_F(DwarfTest, DISABLED_DebugFrame64) {
+TEST_F(DwarfTest, DebugFrame64) {
   constexpr bool is64bit = true;
   DebugFrameOpCodeWriter<> initial_opcodes;
   WriteCIE(is64bit, Reg(16), initial_opcodes, &debug_frame_data_);
@@ -143,7 +143,7 @@
            0x0200000000000000,
            ArrayRef<const uint8_t>(*opcodes.data()),
            &debug_frame_data_);
-  DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
+  DW_CHECK("FDE cie=00000000 pc=100000000000000...300000000000000");
 
   CheckObjdumpOutput(is64bit, "-debug-frame");
 }
@@ -158,7 +158,7 @@
     opcodes.RelOffset(Reg::X86_64Core(i), 0);
   }
   DW_CHECK("FDE");
-  DW_CHECK_NEXT("DWARF32");
+  DW_CHECK_NEXT("DWARF64");
   DW_CHECK_NEXT("DW_CFA_nop:");  // TODO: Why is a nop here.
   DW_CHECK_NEXT("DW_CFA_offset: RAX 0");
   DW_CHECK_NEXT("DW_CFA_offset: RCX 0");
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 765a81d..d0ca6db 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -215,8 +215,8 @@
     reader.VisitDebugFrame([&](const Reader::CIE* cie ATTRIBUTE_UNUSED) {
       num_cies++;
     }, [&](const Reader::FDE* fde, const Reader::CIE* cie ATTRIBUTE_UNUSED) {
-      DCHECK_EQ(fde->sym_addr, method_info.code_address);
-      DCHECK_EQ(fde->sym_size, method_info.code_size);
+      DCHECK_EQ(fde->sym_addr(), method_info.code_address);
+      DCHECK_EQ(fde->sym_size(), method_info.code_size);
       num_fdes++;
     });
     DCHECK_EQ(num_syms, 1u);
@@ -308,8 +308,8 @@
         }
       }, [&](const Reader::FDE* fde, const Reader::CIE* cie ATTRIBUTE_UNUSED) {
         DCHECK(copied_cie);
-        DCHECK_EQ(fde->cie_pointer, 0);
-        if (!is_removed_symbol(fde->sym_addr)) {
+        DCHECK_EQ(fde->cie_pointer(), 0);
+        if (!is_removed_symbol(fde->sym_addr())) {
           debug_frame->WriteFully(fde->data(), fde->size());
         }
       });
diff --git a/libelffile/dwarf/headers.h b/libelffile/dwarf/headers.h
index d77012f..b48d089 100644
--- a/libelffile/dwarf/headers.h
+++ b/libelffile/dwarf/headers.h
@@ -46,22 +46,26 @@
 
   Writer<> writer(buffer);
   size_t cie_header_start_ = writer.data()->size();
-  writer.PushUint32(0);  // Length placeholder.
-  writer.PushUint32(0xFFFFFFFF);  // CIE id.
-  writer.PushUint8(1);   // Version.
-  writer.PushString("zR");
+  if (is64bit) {
+    writer.PushUint32(0xFFFFFFFF);
+    writer.PushUint64(0);  // Length placeholder.
+    writer.PushUint64(0xFFFFFFFFFFFFFFFFull);  // CIE id.
+  } else {
+    writer.PushUint32(0);  // Length placeholder.
+    writer.PushUint32(0xFFFFFFFF);  // CIE id.
+  }
+  writer.PushUint8(3);   // Version.
+  writer.PushString("");  // Augmentation.
   writer.PushUleb128(DebugFrameOpCodeWriter<Vector>::kCodeAlignmentFactor);
   writer.PushSleb128(DebugFrameOpCodeWriter<Vector>::kDataAlignmentFactor);
   writer.PushUleb128(return_address_register.num());  // ubyte in DWARF2.
-  writer.PushUleb128(1);  // z: Augmentation data size.
-  if (is64bit) {
-    writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata8);  // R: Pointer encoding.
-  } else {
-    writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata4);  // R: Pointer encoding.
-  }
   writer.PushData(opcodes.data());
   writer.Pad(is64bit ? 8 : 4);
-  writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
+  if (is64bit) {
+    writer.UpdateUint64(cie_header_start_ + 4, writer.data()->size() - cie_header_start_ - 12);
+  } else {
+    writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
+  }
 }
 
 // Write frame description entry (FDE) to .debug_frame or .eh_frame section.
@@ -74,20 +78,27 @@
               /*inout*/ std::vector<uint8_t>* buffer) {
   Writer<> writer(buffer);
   size_t fde_header_start = writer.data()->size();
-  writer.PushUint32(0);  // Length placeholder.
-  writer.PushUint32(cie_pointer);
   // Relocate code_address if it has absolute value.
   if (is64bit) {
+    writer.PushUint32(0xFFFFFFFF);
+    writer.PushUint64(0);  // Length placeholder.
+    writer.PushUint64(cie_pointer);
     writer.PushUint64(code_address);
     writer.PushUint64(code_size);
   } else {
+    writer.PushUint32(0);  // Length placeholder.
+    writer.PushUint32(cie_pointer);
     writer.PushUint32(code_address);
     writer.PushUint32(code_size);
   }
   writer.PushUleb128(0);  // Augmentation data size.
   writer.PushData(opcodes.data(), opcodes.size());
   writer.Pad(is64bit ? 8 : 4);
-  writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4);
+  if (is64bit) {
+    writer.UpdateUint64(fde_header_start + 4, writer.data()->size() - fde_header_start - 12);
+  } else {
+    writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4);
+  }
 }
 
 // Write compilation unit (CU) to .debug_info section.
diff --git a/libelffile/elf/elf_debug_reader.h b/libelffile/elf/elf_debug_reader.h
index 266c638..54aade7 100644
--- a/libelffile/elf/elf_debug_reader.h
+++ b/libelffile/elf/elf_debug_reader.h
@@ -43,11 +43,41 @@
 
   // Call Frame Information.
   struct CFI {
-    uint32_t length;  // Length excluding the size of this field.
-    int32_t cie_pointer;  // Offset in the section or -1 for CIE.
-
     const uint8_t* data() const { return reinterpret_cast<const uint8_t*>(this); }
-    size_t size() const { return sizeof(uint32_t) + length; }
+    const uint32_t* data_u32() const { return reinterpret_cast<const uint32_t*>(this); }
+    uint32_t* data_u32() { return reinterpret_cast<uint32_t*>(this); }
+
+    bool is_64bit() const {
+      return data_u32()[0] == 0xFFFFFFFF;
+    }
+
+    size_t size() const {
+      const uint32_t* s = data_u32();
+      if (is_64bit()) {
+        return 12 + (static_cast<uint64_t>(s[2]) << 32) + s[1];
+      }
+      return 4 + s[0];
+    }
+
+    // Offset in the section or -1 for CIE.
+    int64_t cie_pointer() const {
+      const uint32_t* s = data_u32();
+      if (is_64bit()) {
+        return static_cast<int64_t>((static_cast<uint64_t>(s[4]) << 32) + s[3]);
+      }
+      return static_cast<int32_t>(s[1]);
+    }
+
+    void set_cie_pointer(uint64_t cie_pointer) {
+      uint32_t* s = data_u32();
+      if (is_64bit()) {
+        s[3] = cie_pointer & 0xFFFFFFFF;
+        s[4] = cie_pointer >> 32;
+      } else {
+        s[1] = static_cast<uint32_t>(cie_pointer);
+      }
+    }
+
   } PACKED(1);
 
   // Common Information Entry.
@@ -56,8 +86,21 @@
 
   // Frame Description Entry.
   struct FDE : public CFI {
-    Elf_Addr sym_addr;
-    Elf_Addr sym_size;
+    Elf_Addr sym_addr() const {
+      const uint32_t* s = this->data_u32();
+      if (this->is_64bit()) {
+        return (static_cast<uint64_t>(s[6]) << 32) + s[5];
+      }
+      return s[2];
+    }
+
+    Elf_Addr sym_size() const {
+      const uint32_t* s = this->data_u32();
+      if (this->is_64bit()) {
+        return (static_cast<uint64_t>(s[8]) << 32) + s[7];
+      }
+      return s[3];
+    }
   } PACKED(1);
 
   explicit ElfDebugReader(ArrayRef<const uint8_t> file) : file_(file) {
@@ -157,11 +200,11 @@
       for (size_t offset = 0; offset < debug_frame->sh_size;) {
         const CFI* entry = Read<CFI>(debug_frame->sh_offset + offset);
         DCHECK_LE(entry->size(), debug_frame->sh_size - offset);
-        if (entry->cie_pointer == -1) {
+        if (entry->cie_pointer() == -1) {
           visit_cie(Read<CIE>(debug_frame->sh_offset + offset));
         } else {
           const FDE* fde = Read<FDE>(debug_frame->sh_offset + offset);
-          visit_fde(fde, Read<CIE>(debug_frame->sh_offset + fde->cie_pointer));
+          visit_fde(fde, Read<CIE>(debug_frame->sh_offset + fde->cie_pointer()));
         }
         offset += entry->size();
       }
diff --git a/tools/create_minidebuginfo/create_minidebuginfo.cc b/tools/create_minidebuginfo/create_minidebuginfo.cc
index 506661a..14cd6a8 100644
--- a/tools/create_minidebuginfo/create_minidebuginfo.cc
+++ b/tools/create_minidebuginfo/create_minidebuginfo.cc
@@ -122,7 +122,7 @@
       const FDE* fde = entry.first;
       const CIE* cie = entry.second;
       FDE new_header = *fde;
-      new_header.cie_pointer = new_cie_offset[cie];
+      new_header.set_cie_pointer(new_cie_offset[cie]);
       debug_frame->WriteFully(&new_header, sizeof(FDE));
       debug_frame->WriteFully(fde->data() + sizeof(FDE), fde->size() - sizeof(FDE));
     }