Merge "1. Fix CFI for quick compiled code in x86 & x86_64; 2. Emit CFI in .eh_frame instead of .debug_frame."
diff --git a/compiler/compilers.cc b/compiler/compilers.cc
index bac1f12..250924a 100644
--- a/compiler/compilers.cc
+++ b/compiler/compilers.cc
@@ -39,7 +39,7 @@
                                                          const art::DexFile& dex_file);
 
 // Hack for CFI CIE initialization
-extern std::vector<uint8_t>* X86CFIInitialization();
+extern std::vector<uint8_t>* X86CFIInitialization(bool is_x86_64);
 
 void QuickCompiler::Init() const {
   ArtInitQuickCompilerContext(GetCompilerDriver());
@@ -129,10 +129,10 @@
 std::vector<uint8_t>* QuickCompiler::GetCallFrameInformationInitialization(
     const CompilerDriver& driver) const {
   if (driver.GetInstructionSet() == kX86) {
-    return X86CFIInitialization();
+    return X86CFIInitialization(false);
   }
   if (driver.GetInstructionSet() == kX86_64) {
-    return X86CFIInitialization();
+    return X86CFIInitialization(true);
   }
   return nullptr;
 }
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 3bc79ad..0a46f2e 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -394,7 +394,7 @@
    * @brief Generate the debug_frame CFI information.
    * @returns pointer to vector containing CFE information
    */
-  static std::vector<uint8_t>* ReturnCommonCallFrameInformation();
+  static std::vector<uint8_t>* ReturnCommonCallFrameInformation(bool is_x86_64);
 
   /*
    * @brief Generate the debug_frame FDE information.
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 3111025..3fa4b6e 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -1443,49 +1443,8 @@
 }
 
 
-std::vector<uint8_t>* X86CFIInitialization() {
-  return X86Mir2Lir::ReturnCommonCallFrameInformation();
-}
-
-std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation() {
-  std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
-
-  // Length of the CIE (except for this field).
-  PushWord(*cfi_info, 16);
-
-  // CIE id.
-  PushWord(*cfi_info, 0xFFFFFFFFU);
-
-  // Version: 3.
-  cfi_info->push_back(0x03);
-
-  // Augmentation: empty string.
-  cfi_info->push_back(0x0);
-
-  // Code alignment: 1.
-  cfi_info->push_back(0x01);
-
-  // Data alignment: -4.
-  cfi_info->push_back(0x7C);
-
-  // Return address register (R8).
-  cfi_info->push_back(0x08);
-
-  // Initial return PC is 4(ESP): DW_CFA_def_cfa R4 4.
-  cfi_info->push_back(0x0C);
-  cfi_info->push_back(0x04);
-  cfi_info->push_back(0x04);
-
-  // Return address location: 0(SP): DW_CFA_offset R8 1 (* -4);.
-  cfi_info->push_back(0x2 << 6 | 0x08);
-  cfi_info->push_back(0x01);
-
-  // And 2 Noops to align to 4 byte boundary.
-  cfi_info->push_back(0x0);
-  cfi_info->push_back(0x0);
-
-  DCHECK_EQ(cfi_info->size() & 3, 0U);
-  return cfi_info;
+std::vector<uint8_t>* X86CFIInitialization(bool is_x86_64) {
+  return X86Mir2Lir::ReturnCommonCallFrameInformation(is_x86_64);
 }
 
 static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
@@ -1496,6 +1455,114 @@
   }
 }
 
+static void EncodeSignedLeb128(std::vector<uint8_t>& buf, int32_t value) {
+  uint8_t buffer[12];
+  uint8_t *ptr = EncodeSignedLeb128(buffer, value);
+  for (uint8_t *p = buffer; p < ptr; p++) {
+    buf.push_back(*p);
+  }
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation(bool is_x86_64) {
+  std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+  // Length (will be filled in later in this routine).
+  PushWord(*cfi_info, 0);
+
+  // CIE id: always 0.
+  PushWord(*cfi_info, 0);
+
+  // Version: always 1.
+  cfi_info->push_back(0x01);
+
+  // Augmentation: 'zR\0'
+  cfi_info->push_back(0x7a);
+  cfi_info->push_back(0x52);
+  cfi_info->push_back(0x0);
+
+  // Code alignment: 1.
+  EncodeUnsignedLeb128(*cfi_info, 1);
+
+  // Data alignment.
+  if (is_x86_64) {
+    EncodeSignedLeb128(*cfi_info, -8);
+  } else {
+    EncodeSignedLeb128(*cfi_info, -4);
+  }
+
+  // Return address register.
+  if (is_x86_64) {
+    // R16(RIP)
+    cfi_info->push_back(0x10);
+  } else {
+    // R8(EIP)
+    cfi_info->push_back(0x08);
+  }
+
+  // Augmentation length: 1.
+  cfi_info->push_back(1);
+
+  // Augmentation data: 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
+  cfi_info->push_back(0x03);
+
+  // Initial instructions.
+  if (is_x86_64) {
+    // DW_CFA_def_cfa R7(RSP) 8.
+    cfi_info->push_back(0x0c);
+    cfi_info->push_back(0x07);
+    cfi_info->push_back(0x08);
+
+    // DW_CFA_offset R16(RIP) 1 (* -8).
+    cfi_info->push_back(0x90);
+    cfi_info->push_back(0x01);
+  } else {
+    // DW_CFA_def_cfa R4(ESP) 4.
+    cfi_info->push_back(0x0c);
+    cfi_info->push_back(0x04);
+    cfi_info->push_back(0x04);
+
+    // DW_CFA_offset R8(EIP) 1 (* -4).
+    cfi_info->push_back(0x88);
+    cfi_info->push_back(0x01);
+  }
+
+  // Padding to a multiple of 4
+  while ((cfi_info->size() & 3) != 0) {
+    // DW_CFA_nop is encoded as 0.
+    cfi_info->push_back(0);
+  }
+
+  // Set the length of the CIE inside the generated bytes.
+  uint32_t length = cfi_info->size() - 4;
+  (*cfi_info)[0] = length;
+  (*cfi_info)[1] = length >> 8;
+  (*cfi_info)[2] = length >> 16;
+  (*cfi_info)[3] = length >> 24;
+  return cfi_info;
+}
+
+static bool ARTRegIDToDWARFRegID(bool is_x86_64, int art_reg_id, int* dwarf_reg_id) {
+  if (is_x86_64) {
+    switch (art_reg_id) {
+    case 3 : *dwarf_reg_id =  3; return true; // %rbx
+    // This is the only discrepancy between ART & DWARF register numbering.
+    case 5 : *dwarf_reg_id =  6; return true; // %rbp
+    case 12: *dwarf_reg_id = 12; return true; // %r12
+    case 13: *dwarf_reg_id = 13; return true; // %r13
+    case 14: *dwarf_reg_id = 14; return true; // %r14
+    case 15: *dwarf_reg_id = 15; return true; // %r15
+    default: return false; // Should not get here
+    }
+  } else {
+    switch (art_reg_id) {
+    case 5: *dwarf_reg_id = 5; return true; // %ebp
+    case 6: *dwarf_reg_id = 6; return true; // %esi
+    case 7: *dwarf_reg_id = 7; return true; // %edi
+    default: return false; // Should not get here
+    }
+  }
+}
+
 std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
   std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
 
@@ -1505,8 +1572,7 @@
   // Length (will be filled in later in this routine).
   PushWord(*cfi_info, 0);
 
-  // CIE_pointer (can be filled in by linker); might be left at 0 if there is only
-  // one CIE for the whole debug_frame section.
+  // 'CIE_pointer' (filled in by linker).
   PushWord(*cfi_info, 0);
 
   // 'initial_location' (filled in by linker).
@@ -1515,6 +1581,9 @@
   // 'address_range' (number of bytes in the method).
   PushWord(*cfi_info, data_offset_);
 
+  // Augmentation length: 0
+  cfi_info->push_back(0);
+
   // The instructions in the FDE.
   if (stack_decrement_ != nullptr) {
     // Advance LOC to just past the stack decrement.
@@ -1525,6 +1594,30 @@
     cfi_info->push_back(0x0e);
     EncodeUnsignedLeb128(*cfi_info, frame_size_);
 
+    // Handle register spills
+    const uint32_t kSpillInstLen = (cu_->target64) ? 5 : 4;
+    const int kDataAlignmentFactor = (cu_->target64) ? -8 : -4;
+    uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
+    int offset = -(GetInstructionSetPointerSize(cu_->instruction_set) * num_core_spills_);
+    for (int reg = 0; mask; mask >>= 1, reg++) {
+      if (mask & 0x1) {
+        pc += kSpillInstLen;
+
+        // Advance LOC to pass this instruction
+        AdvanceLoc(*cfi_info, kSpillInstLen);
+
+        int dwarf_reg_id;
+        if (ARTRegIDToDWARFRegID(cu_->target64, reg, &dwarf_reg_id)) {
+          // DW_CFA_offset_extended_sf reg_no offset
+          cfi_info->push_back(0x11);
+          EncodeUnsignedLeb128(*cfi_info, dwarf_reg_id);
+          EncodeSignedLeb128(*cfi_info, offset / kDataAlignmentFactor);
+        }
+
+        offset += GetInstructionSetPointerSize(cu_->instruction_set);
+      }
+    }
+
     // We continue with that stack until the epilogue.
     if (stack_increment_ != nullptr) {
       uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
@@ -1534,10 +1627,10 @@
       // current state: DW_CFA_remember_state.
       cfi_info->push_back(0x0a);
 
-      // We have now popped the stack: DW_CFA_def_cfa_offset 4.  There is only the return
-      // PC on the stack now.
+      // We have now popped the stack: DW_CFA_def_cfa_offset 4/8.
+      // There is only the return PC on the stack now.
       cfi_info->push_back(0x0e);
-      EncodeUnsignedLeb128(*cfi_info, 4);
+      EncodeUnsignedLeb128(*cfi_info, GetInstructionSetPointerSize(cu_->instruction_set));
 
       // Everything after that is the same as before the epilogue.
       // Stack bump was followed by RET instruction.
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 4274386..1fde12e 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -106,14 +106,14 @@
   // | .strtab\0               |  (Optional)
   // | .debug_str\0            |  (Optional)
   // | .debug_info\0           |  (Optional)
-  // | .debug_frame\0          |  (Optional)
+  // | .eh_frame\0             |  (Optional)
   // | .debug_abbrev\0         |  (Optional)
   // +-------------------------+  (Optional)
   // | .debug_str              |  (Optional)
   // +-------------------------+  (Optional)
   // | .debug_info             |  (Optional)
   // +-------------------------+  (Optional)
-  // | .debug_frame            |  (Optional)
+  // | .eh_frame               |  (Optional)
   // +-------------------------+  (Optional)
   // | .debug_abbrev           |  (Optional)
   // +-------------------------+
@@ -127,7 +127,7 @@
   // | Elf32_Shdr .shstrtab    |
   // | Elf32_Shdr .debug_str   |  (Optional)
   // | Elf32_Shdr .debug_info  |  (Optional)
-  // | Elf32_Shdr .debug_frame |  (Optional)
+  // | Elf32_Shdr .eh_frame    |  (Optional)
   // | Elf32_Shdr .debug_abbrev|  (Optional)
   // +-------------------------+
 
@@ -844,14 +844,14 @@
     ElfRawSectionBuilder debug_info(".debug_info",   SHT_PROGBITS, 0, nullptr, 0, 1, 0);
     ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
     ElfRawSectionBuilder debug_str(".debug_str",    SHT_PROGBITS, 0, nullptr, 0, 1, 0);
-    ElfRawSectionBuilder debug_frame(".debug_frame",  SHT_PROGBITS, 0, nullptr, 0, 4, 0);
-    debug_frame.SetBuffer(*compiler_driver_->GetCallFrameInformation());
+    ElfRawSectionBuilder eh_frame(".eh_frame",  SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+    eh_frame.SetBuffer(*compiler_driver_->GetCallFrameInformation());
 
     FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
                          debug_abbrev.GetBuffer(), debug_str.GetBuffer());
     builder.RegisterRawSection(debug_info);
     builder.RegisterRawSection(debug_abbrev);
-    builder.RegisterRawSection(debug_frame);
+    builder.RegisterRawSection(eh_frame);
     builder.RegisterRawSection(debug_str);
   }
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 22f36f4..9da59ab 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -410,8 +410,16 @@
             int cur_offset = cfi_info->size();
             cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
 
+            // Set the 'CIE_pointer' field to cur_offset+4.
+            uint32_t CIE_pointer = cur_offset + 4;
+            uint32_t offset_to_update = cur_offset + sizeof(uint32_t);
+            (*cfi_info)[offset_to_update+0] = CIE_pointer;
+            (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+            (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+            (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+
             // Set the 'initial_location' field to address the start of the method.
-            uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t);
+            offset_to_update = cur_offset + 2*sizeof(uint32_t);
             (*cfi_info)[offset_to_update+0] = quick_code_start;
             (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
             (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 1522129..6d74b83 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1113,7 +1113,8 @@
 
 DEFINE_FUNCTION art_quick_resolution_trampoline
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    PUSH esp                      // pass SP
+    movl %esp, %edi
+    PUSH EDI                      // pass SP. do not just PUSH ESP; that messes up unwinding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass receiver
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index e5402e1..594c65f 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1033,18 +1033,13 @@
 }
 
 static bool IsFDE(FDE* frame) {
-  // TODO This seems to be the constant everyone uses (for the .debug_frame
-  // section at least), however we should investigate this further.
-  const uint32_t kDwarfCIE_id = 0xffffffff;
-  const uint32_t kReservedLengths[] = {0xffffffff, 0xfffffff0};
-  return frame->CIE_pointer != kDwarfCIE_id &&
-      frame->raw_length_ != kReservedLengths[0] && frame->raw_length_ != kReservedLengths[1];
+  return frame->CIE_pointer != 0;
 }
 
 // TODO This only works for 32-bit Elf Files.
-static bool FixupDebugFrame(uintptr_t text_start, byte* dbg_frame, size_t dbg_frame_size) {
-  FDE* last_frame = reinterpret_cast<FDE*>(dbg_frame + dbg_frame_size);
-  FDE* frame = NextFDE(reinterpret_cast<FDE*>(dbg_frame));
+static bool FixupEHFrame(uintptr_t text_start, byte* eh_frame, size_t eh_frame_size) {
+  FDE* last_frame = reinterpret_cast<FDE*>(eh_frame + eh_frame_size);
+  FDE* frame = NextFDE(reinterpret_cast<FDE*>(eh_frame));
   for (; frame < last_frame; frame = NextFDE(frame)) {
     if (!IsFDE(frame)) {
       return false;
@@ -1301,7 +1296,7 @@
 static bool FixupDebugSections(const byte* dbg_abbrev, size_t dbg_abbrev_size,
                                uintptr_t text_start,
                                byte* dbg_info, size_t dbg_info_size,
-                               byte* dbg_frame, size_t dbg_frame_size) {
+                               byte* eh_frame, size_t eh_frame_size) {
   std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(dbg_abbrev, dbg_abbrev_size));
   if (abbrev.get() == nullptr) {
     return false;
@@ -1313,7 +1308,7 @@
     return false;
   }
   return FixupDebugInfo(text_start, iter.get())
-      && FixupDebugFrame(text_start, dbg_frame, dbg_frame_size);
+      && FixupEHFrame(text_start, eh_frame, eh_frame_size);
 }
 
 void ElfFile::GdbJITSupport() {
@@ -1334,20 +1329,15 @@
   // Do we have interesting sections?
   const Elf32_Shdr* debug_info = all.FindSectionByName(".debug_info");
   const Elf32_Shdr* debug_abbrev = all.FindSectionByName(".debug_abbrev");
-  const Elf32_Shdr* debug_frame = all.FindSectionByName(".debug_frame");
+  const Elf32_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
   const Elf32_Shdr* debug_str = all.FindSectionByName(".debug_str");
   const Elf32_Shdr* strtab_sec = all.FindSectionByName(".strtab");
   const Elf32_Shdr* symtab_sec = all.FindSectionByName(".symtab");
   Elf32_Shdr* text_sec = all.FindSectionByName(".text");
-  if (debug_info == nullptr || debug_abbrev == nullptr || debug_frame == nullptr ||
+  if (debug_info == nullptr || debug_abbrev == nullptr || eh_frame == nullptr ||
       debug_str == nullptr || text_sec == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
     return;
   }
-#ifdef __LP64__
-  if (true) {
-    return;  // No ELF debug support in 64bit.
-  }
-#endif
   // We need to add in a strtab and symtab to the image.
   // all is MAP_PRIVATE so it can be written to freely.
   // We also already have strtab and symtab so we are fine there.
@@ -1364,7 +1354,7 @@
   if (!FixupDebugSections(
         all.Begin() + debug_abbrev->sh_offset, debug_abbrev->sh_size, text_sec->sh_addr,
         all.Begin() + debug_info->sh_offset, debug_info->sh_size,
-        all.Begin() + debug_frame->sh_offset, debug_frame->sh_size)) {
+        all.Begin() + eh_frame->sh_offset, eh_frame->sh_size)) {
     LOG(ERROR) << "Failed to load GDB data";
     return;
   }