Tell GDB about Quick ART generated code

This is actually a lot of work.  To do this, we need:
.debug_info
.debug_abbrev
.debug_frame
.debug_str

These are generated into the OAT file by OatWriter and ElfWriterQuick.

Since the Quick ART runtime doesn't use dlopen to load the OAT files,
GDB can't find this information.  Use the alternate GDB JIT interface,
which can be invoked at runtime. To use this interface, an ELF image
needs to be built in memory.  Read the information from the OAT file,
fixup the addresses to point to the real locations, add a symbol table
to hold the .text symbol, and then let GDB know about the information,
which will be read from the runtime address space.

This is quite primitive now, and could be cleaned up considerably.  It
probably needs symbol table entries for the methods, and descriptions of
parameters and return types.

Currently only supported for X86.

This defaults to enabled for debug builds. Added dexoat --gen-gdb-info
and --no-gen-gdb-info flags to override.

Change-Id: I4d18b2370f6dfaa00c8cc1925f10717be3bd1a62
Signed-off-by: Mark Mendell <mark.p.mendell@intel.com>
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f6d724a..d884bc0 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -153,12 +153,14 @@
                                const uint32_t fp_spill_mask,
                                const std::vector<uint8_t>& mapping_table,
                                const std::vector<uint8_t>& vmap_table,
-                               const std::vector<uint8_t>& native_gc_map)
+                               const std::vector<uint8_t>& native_gc_map,
+                               const std::vector<uint8_t>* cfi_info)
     : CompiledCode(&driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
   mapping_table_(driver.DeduplicateMappingTable(mapping_table)),
   vmap_table_(driver.DeduplicateVMapTable(vmap_table)),
-  gc_map_(driver.DeduplicateGCMap(native_gc_map)) {
+  gc_map_(driver.DeduplicateGCMap(native_gc_map)),
+  cfi_info_(driver.DeduplicateCFIInfo(cfi_info)) {
 }
 
 CompiledMethod::CompiledMethod(CompilerDriver& driver,
@@ -169,10 +171,11 @@
                                const uint32_t fp_spill_mask)
     : CompiledCode(&driver, instruction_set, code),
       frame_size_in_bytes_(frame_size_in_bytes),
-      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
-  mapping_table_ = driver.DeduplicateMappingTable(std::vector<uint8_t>());
-  vmap_table_ = driver.DeduplicateVMapTable(std::vector<uint8_t>());
-  gc_map_ = driver.DeduplicateGCMap(std::vector<uint8_t>());
+      core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
+      mapping_table_(driver.DeduplicateMappingTable(std::vector<uint8_t>())),
+      vmap_table_(driver.DeduplicateVMapTable(std::vector<uint8_t>())),
+      gc_map_(driver.DeduplicateGCMap(std::vector<uint8_t>())),
+      cfi_info_(nullptr) {
 }
 
 // Constructs a CompiledMethod for the Portable compiler.
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 6112305..90ae6ee 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -110,7 +110,8 @@
                  const uint32_t fp_spill_mask,
                  const std::vector<uint8_t>& mapping_table,
                  const std::vector<uint8_t>& vmap_table,
-                 const std::vector<uint8_t>& native_gc_map);
+                 const std::vector<uint8_t>& native_gc_map,
+                 const std::vector<uint8_t>* cfi_info);
 
   // Constructs a CompiledMethod for the QuickJniCompiler.
   CompiledMethod(CompilerDriver& driver,
@@ -157,6 +158,10 @@
     return *gc_map_;
   }
 
+  const std::vector<uint8_t>* GetCFIInfo() const {
+    return cfi_info_;
+  }
+
  private:
   // For quick code, the size of the activation used by the code.
   const size_t frame_size_in_bytes_;
@@ -172,6 +177,8 @@
   // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers
   // are live. For portable code, the key is a dalvik PC.
   std::vector<uint8_t>* gc_map_;
+  // For quick code, a FDE entry for the debug_frame section.
+  std::vector<uint8_t>* cfi_info_;
 };
 
 }  // namespace art
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
index f37ee37..0afa665 100644
--- a/compiler/compiler_backend.cc
+++ b/compiler/compiler_backend.cc
@@ -83,6 +83,9 @@
 }
 
 
+// Hack for CFI CIE initialization
+extern std::vector<uint8_t>* X86CFIInitialization();
+
 class QuickBackend : public CompilerBackend {
  public:
   QuickBackend() : CompilerBackend(100) {}
@@ -166,11 +169,27 @@
       bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
       CHECK(set_max);
     }
-    return mir_to_lir;;
+    return mir_to_lir;
   }
 
   void InitCompilationUnit(CompilationUnit& cu) const {}
 
+  /*
+   * @brief Generate and return Dwarf CFI initialization, if supported by the
+   * backend.
+   * @param driver CompilerDriver for this compile.
+   * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+   * information.
+   * @note This is used for backtrace information in generated code.
+   */
+  std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver) const
+      OVERRIDE {
+    if (driver.GetInstructionSet() == kX86) {
+      return X86CFIInitialization();
+    }
+    return nullptr;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(QuickBackend);
 };
diff --git a/compiler/compiler_backend.h b/compiler/compiler_backend.h
index 51fb29a..b473806 100644
--- a/compiler/compiler_backend.h
+++ b/compiler/compiler_backend.h
@@ -93,6 +93,19 @@
 
   virtual ~CompilerBackend() {}
 
+  /*
+   * @brief Generate and return Dwarf CFI initialization, if supported by the
+   * backend.
+   * @param driver CompilerDriver for this compile.
+   * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+   * information.
+   * @note This is used for backtrace information in generated code.
+   */
+  virtual std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver)
+      const {
+    return nullptr;
+  }
+
  private:
   const uint64_t maximum_compilation_time_before_warning_;
 
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 3185449..b0b8d1e 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1070,10 +1070,12 @@
     DCHECK_EQ(fp_vmap_table_.size(), 0u);
     vmap_encoder.PushBackUnsigned(0u);  // Size is 0.
   }
+
+  UniquePtr<std::vector<uint8_t> > cfi_info(ReturnCallFrameInformation());
   CompiledMethod* result =
       new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
                          core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
-                         vmap_encoder.GetData(), native_gc_map_);
+                         vmap_encoder.GetData(), native_gc_map_, cfi_info.get());
   return result;
 }
 
@@ -1216,4 +1218,9 @@
   AppendLIR(load_pc_rel);
 }
 
+std::vector<uint8_t>* Mir2Lir::ReturnCallFrameInformation() {
+  // Default case is to do nothing.
+  return nullptr;
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index b74052c..8f199f8 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1089,6 +1089,11 @@
                                             bool can_assume_type_is_in_dex_cache,
                                             uint32_t type_idx, RegLocation rl_dest,
                                             RegLocation rl_src);
+    /*
+     * @brief Generate the debug_frame FDE information if possible.
+     * @returns pointer to vector containg CFE information, or NULL.
+     */
+    virtual std::vector<uint8_t>* ReturnCallFrameInformation();
 
     /**
      * @brief Used to insert marker that can be used to associate MIR with LIR.
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 0613cdf..399001c 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -198,7 +198,7 @@
   LockTemp(rX86_ARG2);
 
   /* Build frame, return address already on stack */
-  OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
+  stack_decrement_ = OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
 
   /*
    * We can safely skip the stack overflow check if we're
@@ -246,7 +246,7 @@
   NewLIR0(kPseudoMethodExit);
   UnSpillCoreRegs();
   /* Remove frame except for return address */
-  OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
+  stack_increment_ = OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
   NewLIR0(kX86Ret);
 }
 
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 421d51e..c97d0e6 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -302,6 +302,18 @@
      */
     void InstallLiteralPools();
 
+    /*
+     * @brief Generate the debug_frame CFI information.
+     * @returns pointer to vector containing CFE information
+     */
+    static std::vector<uint8_t>* ReturnCommonCallFrameInformation();
+
+    /*
+     * @brief Generate the debug_frame FDE information.
+     * @returns pointer to vector containing CFE information
+     */
+    std::vector<uint8_t>* ReturnCallFrameInformation();
+
   private:
     void EmitPrefix(const X86EncodingMap* entry);
     void EmitOpcode(const X86EncodingMap* entry);
@@ -549,6 +561,12 @@
 
     // Instructions needing patching with PC relative code addresses.
     GrowableArray<LIR*> call_method_insns_;
+
+    // Prologue decrement of stack pointer.
+    LIR* stack_decrement_;
+
+    // Epilogue increment of stack pointer.
+    LIR* stack_increment_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index eea7191..7bb866d 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -539,7 +539,8 @@
     : Mir2Lir(cu, mir_graph, arena),
       method_address_insns_(arena, 100, kGrowableArrayMisc),
       class_type_address_insns_(arena, 100, kGrowableArrayMisc),
-      call_method_insns_(arena, 100, kGrowableArrayMisc) {
+      call_method_insns_(arena, 100, kGrowableArrayMisc),
+      stack_decrement_(nullptr), stack_increment_(nullptr) {
   store_method_addr_used_ = false;
   for (int i = 0; i < kX86Last; i++) {
     if (X86Mir2Lir::EncodingMap[i].opcode != i) {
@@ -1118,4 +1119,166 @@
   return true;
 }
 
+/*
+ * @brief Enter a 32 bit quantity into the FDE buffer
+ * @param buf FDE buffer.
+ * @param data Data value.
+ */
+static void PushWord(std::vector<uint8_t>&buf, int data) {
+  buf.push_back(data & 0xff);
+  buf.push_back((data >> 8) & 0xff);
+  buf.push_back((data >> 16) & 0xff);
+  buf.push_back((data >> 24) & 0xff);
+}
+
+/*
+ * @brief Enter an 'advance LOC' into the FDE buffer
+ * @param buf FDE buffer.
+ * @param increment Amount by which to increase the current location.
+ */
+static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) {
+  if (increment < 64) {
+    // Encoding in opcode.
+    buf.push_back(0x1 << 6 | increment);
+  } else if (increment < 256) {
+    // Single byte delta.
+    buf.push_back(0x02);
+    buf.push_back(increment);
+  } else if (increment < 256 * 256) {
+    // Two byte delta.
+    buf.push_back(0x03);
+    buf.push_back(increment & 0xff);
+    buf.push_back((increment >> 8) & 0xff);
+  } else {
+    // Four byte delta.
+    buf.push_back(0x04);
+    PushWord(buf, increment);
+  }
+}
+
+
+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;
+}
+
+static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
+  uint8_t buffer[12];
+  uint8_t *ptr = EncodeUnsignedLeb128(buffer, value);
+  for (uint8_t *p = buffer; p < ptr; p++) {
+    buf.push_back(*p);
+  }
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
+  std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+  // Generate the FDE for the method.
+  DCHECK_NE(data_offset_, 0U);
+
+  // 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.
+  PushWord(*cfi_info, 0);
+
+  // 'initial_location' (filled in by linker).
+  PushWord(*cfi_info, 0);
+
+  // 'address_range' (number of bytes in the method).
+  PushWord(*cfi_info, data_offset_);
+
+  // The instructions in the FDE.
+  if (stack_decrement_ != nullptr) {
+    // Advance LOC to just past the stack decrement.
+    uint32_t pc = NEXT_LIR(stack_decrement_)->offset;
+    AdvanceLoc(*cfi_info, pc);
+
+    // Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size.
+    cfi_info->push_back(0x0e);
+    EncodeUnsignedLeb128(*cfi_info, frame_size_);
+
+    // We continue with that stack until the epilogue.
+    if (stack_increment_ != nullptr) {
+      uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
+      AdvanceLoc(*cfi_info, new_pc - pc);
+
+      // We probably have code snippets after the epilogue, so save the
+      // 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.
+      cfi_info->push_back(0x0e);
+      EncodeUnsignedLeb128(*cfi_info, 4);
+
+      // Everything after that is the same as before the epilogue.
+      // Stack bump was followed by RET instruction.
+      LIR *post_ret_insn = NEXT_LIR(NEXT_LIR(stack_increment_));
+      if (post_ret_insn != nullptr) {
+        pc = new_pc;
+        new_pc = post_ret_insn->offset;
+        AdvanceLoc(*cfi_info, new_pc - pc);
+        // Restore the state: DW_CFA_restore_state.
+        cfi_info->push_back(0x0b);
+      }
+    }
+  }
+
+  // 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 FDE 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;
+}
+
 }  // namespace art
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 931055b..708cce6 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -31,6 +31,7 @@
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
 #include "dex/quick/dex_file_method_inliner.h"
+#include "driver/compiler_options.h"
 #include "jni_internal.h"
 #include "object_utils.h"
 #include "runtime.h"
@@ -323,10 +324,12 @@
       compiler_enable_auto_elf_loading_(NULL),
       compiler_get_method_code_addr_(NULL),
       support_boot_image_fixup_(instruction_set != kMips),
+      cfi_info_(nullptr),
       dedupe_code_("dedupe code"),
       dedupe_mapping_table_("dedupe mapping table"),
       dedupe_vmap_table_("dedupe vmap table"),
-      dedupe_gc_map_("dedupe gc map") {
+      dedupe_gc_map_("dedupe gc map"),
+      dedupe_cfi_info_("dedupe cfi info") {
   DCHECK(compiler_options_ != nullptr);
   DCHECK(verification_results_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
@@ -341,6 +344,11 @@
   if (!image_) {
     CHECK(image_classes_.get() == NULL);
   }
+
+  // Are we generating CFI information?
+  if (compiler_options->GetGenerateGDBInformation()) {
+    cfi_info_.reset(compiler_backend_->GetCallFrameInformationInitialization(*this));
+  }
 }
 
 std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t>& code) {
@@ -359,6 +367,13 @@
   return dedupe_gc_map_.Add(Thread::Current(), code);
 }
 
+std::vector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info) {
+  if (cfi_info == nullptr) {
+    return nullptr;
+  }
+  return dedupe_cfi_info_.Add(Thread::Current(), *cfi_info);
+}
+
 CompilerDriver::~CompilerDriver() {
   Thread* self = Thread::Current();
   {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 5a5fc36..6ccbf0f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -493,6 +493,15 @@
   std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
   std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
   std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
+  std::vector<uint8_t>* DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info);
+
+  /*
+   * @brief return the pointer to the Call Frame Information.
+   * @return pointer to call frame information for this compilation.
+   */
+  std::vector<uint8_t>* GetCallFrameInformation() const {
+    return cfi_info_.get();
+  }
 
  private:
   // Compute constant code and method pointers when possible
@@ -625,6 +634,9 @@
 
   bool support_boot_image_fixup_;
 
+  // Call Frame Information, which might be generated to help stack tracebacks.
+  UniquePtr<std::vector<uint8_t> > cfi_info_;
+
   // DeDuplication data structures, these own the corresponding byte arrays.
   class DedupeHashFunc {
    public:
@@ -663,6 +675,7 @@
   DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_;
   DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_;
   DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_;
+  DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9f6745b..39738ab 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -43,7 +43,8 @@
     large_method_threshold_(kDefaultLargeMethodThreshold),
     small_method_threshold_(kDefaultSmallMethodThreshold),
     tiny_method_threshold_(kDefaultTinyMethodThreshold),
-    num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold)
+    num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
+    generate_gdb_information_(false)
 #ifdef ART_SEA_IR_MODE
     , sea_ir_mode_(false)
 #endif
@@ -54,7 +55,8 @@
                   size_t large_method_threshold,
                   size_t small_method_threshold,
                   size_t tiny_method_threshold,
-                  size_t num_dex_methods_threshold
+                  size_t num_dex_methods_threshold,
+                  bool generate_gdb_information
 #ifdef ART_SEA_IR_MODE
                   , bool sea_ir_mode
 #endif
@@ -64,7 +66,8 @@
     large_method_threshold_(large_method_threshold),
     small_method_threshold_(small_method_threshold),
     tiny_method_threshold_(tiny_method_threshold),
-    num_dex_methods_threshold_(num_dex_methods_threshold)
+    num_dex_methods_threshold_(num_dex_methods_threshold),
+    generate_gdb_information_(generate_gdb_information)
 #ifdef ART_SEA_IR_MODE
     , sea_ir_mode_(sea_ir_mode)
 #endif
@@ -118,6 +121,10 @@
   bool GetSeaIrMode();
 #endif
 
+  bool GetGenerateGDBInformation() const {
+    return generate_gdb_information_;
+  }
+
  private:
   CompilerFilter compiler_filter_;
   size_t huge_method_threshold_;
@@ -125,6 +132,7 @@
   size_t small_method_threshold_;
   size_t tiny_method_threshold_;
   size_t num_dex_methods_threshold_;
+  bool generate_gdb_information_;
 
 #ifdef ART_SEA_IR_MODE
   bool sea_ir_mode_;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 4b416a0..4b823ef 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -98,6 +98,7 @@
   // | .rodata\0               |
   // | .text\0                 |
   // | .shstrtab\0             |
+  // | .debug_frame\0          |
   // +-------------------------+
   // | Elf32_Shdr NULL         |
   // | Elf32_Shdr .dynsym      |
@@ -107,6 +108,9 @@
   // | Elf32_Shdr .rodata      |
   // | Elf32_Shdr .dynamic     |
   // | Elf32_Shdr .shstrtab    |
+  // | Elf32_Shdr .debug_info  |  (Optional)
+  // | Elf32_Shdr .debug_abbrev|  (Optional)
+  // | Elf32_Shdr .debug_frame |  (Optional)
   // +-------------------------+
 
   // phase 1: computing offsets
@@ -259,6 +263,18 @@
   uint32_t shstrtab_shstrtab_offset = shstrtab.size();
   shstrtab += ".shstrtab";
   shstrtab += '\0';
+  uint32_t shstrtab_debug_info_offset = shstrtab.size();
+  shstrtab += ".debug_info";
+  shstrtab += '\0';
+  uint32_t shstrtab_debug_abbrev_offset = shstrtab.size();
+  shstrtab += ".debug_abbrev";
+  shstrtab += '\0';
+  uint32_t shstrtab_debug_str_offset = shstrtab.size();
+  shstrtab += ".debug_str";
+  shstrtab += '\0';
+  uint32_t shstrtab_debug_frame_offset = shstrtab.size();
+  shstrtab += ".debug_frame";
+  shstrtab += '\0';
   uint32_t shstrtab_size = shstrtab.size();
   expected_offset += shstrtab_size;
   if (debug) {
@@ -266,6 +282,52 @@
     LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size;
   }
 
+  // Create debug informatin, if we have it.
+  bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
+  std::vector<uint8_t> dbg_info;
+  std::vector<uint8_t> dbg_abbrev;
+  std::vector<uint8_t> dbg_str;
+  if (generateDebugInformation) {
+    FillInCFIInformation(oat_writer, &dbg_info, &dbg_abbrev, &dbg_str);
+  }
+
+  uint32_t shdbg_info_alignment = 1;
+  uint32_t shdbg_info_offset = expected_offset;
+  uint32_t shdbg_info_size = dbg_info.size();
+  expected_offset += shdbg_info_size;
+  if (debug) {
+    LOG(INFO) << "shdbg_info_offset=" << shdbg_info_offset << std::hex << " " << shdbg_info_offset;
+    LOG(INFO) << "shdbg_info_size=" << shdbg_info_size << std::hex << " " << shdbg_info_size;
+  }
+
+  uint32_t shdbg_abbrev_alignment = 1;
+  uint32_t shdbg_abbrev_offset = expected_offset;
+  uint32_t shdbg_abbrev_size = dbg_abbrev.size();
+  expected_offset += shdbg_abbrev_size;
+  if (debug) {
+    LOG(INFO) << "shdbg_abbrev_offset=" << shdbg_abbrev_offset << std::hex << " " << shdbg_abbrev_offset;
+    LOG(INFO) << "shdbg_abbrev_size=" << shdbg_abbrev_size << std::hex << " " << shdbg_abbrev_size;
+  }
+
+  uint32_t shdbg_frm_alignment = 4;
+  uint32_t shdbg_frm_offset = expected_offset = RoundUp(expected_offset, shdbg_frm_alignment);
+  uint32_t shdbg_frm_size =
+    generateDebugInformation ? compiler_driver_->GetCallFrameInformation()->size() : 0;
+  expected_offset += shdbg_frm_size;
+  if (debug) {
+    LOG(INFO) << "shdbg_frm_offset=" << shdbg_frm_offset << std::hex << " " << shdbg_frm_offset;
+    LOG(INFO) << "shdbg_frm_size=" << shdbg_frm_size << std::hex << " " << shdbg_frm_size;
+  }
+
+  uint32_t shdbg_str_alignment = 1;
+  uint32_t shdbg_str_offset = expected_offset;
+  uint32_t shdbg_str_size = dbg_str.size();
+  expected_offset += shdbg_str_size;
+  if (debug) {
+    LOG(INFO) << "shdbg_str_offset=" << shdbg_str_offset << std::hex << " " << shdbg_str_offset;
+    LOG(INFO) << "shdbg_str_size=" << shdbg_str_size << std::hex << " " << shdbg_str_size;
+  }
+
   // section headers (after all sections)
   uint32_t shdr_alignment = sizeof(Elf32_Word);
   uint32_t shdr_offset = expected_offset = RoundUp(expected_offset, shdr_alignment);
@@ -277,7 +339,11 @@
   const uint8_t SH_TEXT     = 5;
   const uint8_t SH_DYNAMIC  = 6;
   const uint8_t SH_SHSTRTAB = 7;
-  const uint8_t SH_NUM      = 8;
+  const uint8_t SH_DBG_INFO = 8;
+  const uint8_t SH_DBG_ABRV = 9;
+  const uint8_t SH_DBG_FRM  = 10;
+  const uint8_t SH_DBG_STR  = 11;
+  const uint8_t SH_NUM      = generateDebugInformation ? 12 : 8;
   uint32_t shdr_size = sizeof(Elf32_Shdr) * SH_NUM;
   expected_offset += shdr_size;
   if (debug) {
@@ -554,6 +620,52 @@
   section_headers[SH_SHSTRTAB].sh_addralign = shstrtab_alignment;
   section_headers[SH_SHSTRTAB].sh_entsize   = 0;
 
+  if (generateDebugInformation) {
+    section_headers[SH_DBG_INFO].sh_name      = shstrtab_debug_info_offset;
+    section_headers[SH_DBG_INFO].sh_type      = SHT_PROGBITS;
+    section_headers[SH_DBG_INFO].sh_flags     = 0;
+    section_headers[SH_DBG_INFO].sh_addr      = 0;
+    section_headers[SH_DBG_INFO].sh_offset    = shdbg_info_offset;
+    section_headers[SH_DBG_INFO].sh_size      = shdbg_info_size;
+    section_headers[SH_DBG_INFO].sh_link      = 0;
+    section_headers[SH_DBG_INFO].sh_info      = 0;
+    section_headers[SH_DBG_INFO].sh_addralign = shdbg_info_alignment;
+    section_headers[SH_DBG_INFO].sh_entsize   = 0;
+
+    section_headers[SH_DBG_ABRV].sh_name      = shstrtab_debug_abbrev_offset;
+    section_headers[SH_DBG_ABRV].sh_type      = SHT_PROGBITS;
+    section_headers[SH_DBG_ABRV].sh_flags     = 0;
+    section_headers[SH_DBG_ABRV].sh_addr      = 0;
+    section_headers[SH_DBG_ABRV].sh_offset    = shdbg_abbrev_offset;
+    section_headers[SH_DBG_ABRV].sh_size      = shdbg_abbrev_size;
+    section_headers[SH_DBG_ABRV].sh_link      = 0;
+    section_headers[SH_DBG_ABRV].sh_info      = 0;
+    section_headers[SH_DBG_ABRV].sh_addralign = shdbg_abbrev_alignment;
+    section_headers[SH_DBG_ABRV].sh_entsize   = 0;
+
+    section_headers[SH_DBG_FRM].sh_name      = shstrtab_debug_frame_offset;
+    section_headers[SH_DBG_FRM].sh_type      = SHT_PROGBITS;
+    section_headers[SH_DBG_FRM].sh_flags     = 0;
+    section_headers[SH_DBG_FRM].sh_addr      = 0;
+    section_headers[SH_DBG_FRM].sh_offset    = shdbg_frm_offset;
+    section_headers[SH_DBG_FRM].sh_size      = shdbg_frm_size;
+    section_headers[SH_DBG_FRM].sh_link      = 0;
+    section_headers[SH_DBG_FRM].sh_info      = 0;
+    section_headers[SH_DBG_FRM].sh_addralign = shdbg_frm_alignment;
+    section_headers[SH_DBG_FRM].sh_entsize   = 0;
+
+    section_headers[SH_DBG_STR].sh_name      = shstrtab_debug_str_offset;
+    section_headers[SH_DBG_STR].sh_type      = SHT_PROGBITS;
+    section_headers[SH_DBG_STR].sh_flags     = 0;
+    section_headers[SH_DBG_STR].sh_addr      = 0;
+    section_headers[SH_DBG_STR].sh_offset    = shdbg_str_offset;
+    section_headers[SH_DBG_STR].sh_size      = shdbg_str_size;
+    section_headers[SH_DBG_STR].sh_link      = 0;
+    section_headers[SH_DBG_STR].sh_info      = 0;
+    section_headers[SH_DBG_STR].sh_addralign = shdbg_str_alignment;
+    section_headers[SH_DBG_STR].sh_entsize   = 0;
+  }
+
   // phase 3: writing file
 
   // Elf32_Ehdr
@@ -646,8 +758,62 @@
     return false;
   }
 
+  if (generateDebugInformation) {
+    // .debug_info
+    DCHECK_LE(shstrtab_offset + shstrtab_size, shdbg_info_offset);
+    if (static_cast<off_t>(shdbg_info_offset) != lseek(elf_file_->Fd(), shdbg_info_offset, SEEK_SET)) {
+      PLOG(ERROR) << "Failed to seek to .shdbg_info offset " << shdbg_info_offset
+                  << " for " << elf_file_->GetPath();
+      return false;
+    }
+    if (!elf_file_->WriteFully(&dbg_info[0], shdbg_info_size)) {
+      PLOG(ERROR) << "Failed to write .debug_info for " << elf_file_->GetPath();
+      return false;
+    }
+
+    // .debug_abbrev
+    DCHECK_LE(shdbg_info_offset + shdbg_info_size, shdbg_abbrev_offset);
+    if (static_cast<off_t>(shdbg_abbrev_offset) != lseek(elf_file_->Fd(), shdbg_abbrev_offset, SEEK_SET)) {
+      PLOG(ERROR) << "Failed to seek to .shdbg_abbrev offset " << shdbg_abbrev_offset
+                  << " for " << elf_file_->GetPath();
+      return false;
+    }
+    if (!elf_file_->WriteFully(&dbg_abbrev[0], shdbg_abbrev_size)) {
+      PLOG(ERROR) << "Failed to write .debug_abbrev for " << elf_file_->GetPath();
+      return false;
+    }
+
+    // .debug_frame
+    DCHECK_LE(shdbg_abbrev_offset + shdbg_abbrev_size, shdbg_frm_offset);
+    if (static_cast<off_t>(shdbg_frm_offset) != lseek(elf_file_->Fd(), shdbg_frm_offset, SEEK_SET)) {
+      PLOG(ERROR) << "Failed to seek to .shdbg_frm offset " << shdbg_frm_offset
+                  << " for " << elf_file_->GetPath();
+      return false;
+    }
+    if (!elf_file_->WriteFully(&((*compiler_driver_->GetCallFrameInformation())[0]), shdbg_frm_size)) {
+      PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
+      return false;
+    }
+
+    // .debug_str
+    DCHECK_LE(shdbg_frm_offset + shdbg_frm_size, shdbg_str_offset);
+    if (static_cast<off_t>(shdbg_str_offset) != lseek(elf_file_->Fd(), shdbg_str_offset, SEEK_SET)) {
+      PLOG(ERROR) << "Failed to seek to .shdbg_str offset " << shdbg_str_offset
+                  << " for " << elf_file_->GetPath();
+      return false;
+    }
+    if (!elf_file_->WriteFully(&dbg_str[0], shdbg_str_size)) {
+      PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
+      return false;
+    }
+  }
+
   // section headers (after all sections)
-  DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+  if (generateDebugInformation) {
+    DCHECK_LE(shdbg_str_offset + shdbg_str_size, shdr_offset);
+  } else {
+    DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+  }
   if (static_cast<off_t>(shdr_offset) != lseek(elf_file_->Fd(), shdr_offset, SEEK_SET)) {
     PLOG(ERROR) << "Failed to seek to ELF section headers offset " << shdr_offset
                 << " for " << elf_file_->GetPath();
@@ -660,6 +826,164 @@
 
   VLOG(compiler) << "ELF file written successfully: " << elf_file_->GetPath();
   return true;
+}  // NOLINT(readability/fn_size)
+
+static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) {
+  (*buf)[offset+0] = data;
+  (*buf)[offset+1] = data >> 8;
+  (*buf)[offset+2] = data >> 16;
+  (*buf)[offset+3] = data >> 24;
+}
+
+static void PushWord(std::vector<uint8_t>*buf, int data) {
+  buf->push_back(data & 0xff);
+  buf->push_back((data >> 8) & 0xff);
+  buf->push_back((data >> 16) & 0xff);
+  buf->push_back((data >> 24) & 0xff);
+}
+
+static void PushHalf(std::vector<uint8_t>*buf, int data) {
+  buf->push_back(data & 0xff);
+  buf->push_back((data >> 8) & 0xff);
+}
+
+// DWARF constants needed to generate CFI information.
+enum {
+  // Tag encodings.
+  DW_TAG_compile_unit = 0x11,
+  DW_TAG_subprogram = 0X2e,
+
+  // Attribute encodings.
+  DW_AT_name = 0x03,
+  DW_AT_low_pc = 0x11,
+  DW_AT_high_pc = 0x12,
+  DW_AT_language = 0x13,
+
+  // Constant encoding.
+  DW_CHILDREN_no = 0x00,
+  DW_CHILDREN_yes = 0x01,
+
+  // Attribute form encodings.
+  DW_FORM_addr = 0x01,
+  DW_FORM_data1 = 0x0b,
+  DW_FORM_strp = 0x0e,
+
+  // Language encoding.
+  DW_LANG_Java = 0x000b
+};
+
+void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
+                                          std::vector<uint8_t>* dbg_info,
+                                          std::vector<uint8_t>* dbg_abbrev,
+                                          std::vector<uint8_t>* dbg_str) {
+  // Create the debug_abbrev section with boilerplate information.
+  // We only care about low_pc and high_pc right now for the compilation
+  // unit and methods.
+
+  // Tag 1: Compilation unit: DW_TAG_compile_unit.
+  dbg_abbrev->push_back(1);
+  dbg_abbrev->push_back(DW_TAG_compile_unit);
+
+  // There are children (the methods).
+  dbg_abbrev->push_back(DW_CHILDREN_yes);
+
+  // DW_LANG_Java DW_FORM_data1.
+  dbg_abbrev->push_back(DW_AT_language);
+  dbg_abbrev->push_back(DW_FORM_data1);
+
+  // DW_AT_low_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_low_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // DW_AT_high_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_high_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // End of DW_TAG_compile_unit.
+  PushHalf(dbg_abbrev, 0);
+
+  // Tag 2: Compilation unit: DW_TAG_subprogram.
+  dbg_abbrev->push_back(2);
+  dbg_abbrev->push_back(DW_TAG_subprogram);
+
+  // There are no children.
+  dbg_abbrev->push_back(DW_CHILDREN_no);
+
+  // Name of the method.
+  dbg_abbrev->push_back(DW_AT_name);
+  dbg_abbrev->push_back(DW_FORM_strp);
+
+  // DW_AT_low_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_low_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // DW_AT_high_pc DW_FORM_addr.
+  dbg_abbrev->push_back(DW_AT_high_pc);
+  dbg_abbrev->push_back(DW_FORM_addr);
+
+  // End of DW_TAG_subprogram.
+  PushHalf(dbg_abbrev, 0);
+
+  // Start the debug_info section with the header information
+  // 'unit_length' will be filled in later.
+  PushWord(dbg_info, 0);
+
+  // 'version' - 3.
+  PushHalf(dbg_info, 3);
+
+  // Offset into .debug_abbrev section (always 0).
+  PushWord(dbg_info, 0);
+
+  // Address size: 4.
+  dbg_info->push_back(4);
+
+  // Start the description for the compilation unit.
+  // This uses tag 1.
+  dbg_info->push_back(1);
+
+  // The language is Java.
+  dbg_info->push_back(DW_LANG_Java);
+
+  // Leave space for low_pc and high_pc.
+  int low_pc_offset = dbg_info->size();
+  PushWord(dbg_info, 0);
+  PushWord(dbg_info, 0);
+
+  // Walk through the information in the method table, and enter into dbg_info.
+  const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
+  uint32_t low_pc = 0xFFFFFFFFU;
+  uint32_t high_pc = 0;
+
+  for (uint32_t i = 0; i < dbg.size(); i++) {
+    const OatWriter::DebugInfo& info = dbg[i];
+    if (info.low_pc_ < low_pc) {
+      low_pc = info.low_pc_;
+    }
+    if (info.high_pc_ > high_pc) {
+      high_pc = info.high_pc_;
+    }
+
+    // Start a new TAG: subroutine (2).
+    dbg_info->push_back(2);
+
+    // Enter the name into the string table (and NUL terminate).
+    uint32_t str_offset = dbg_str->size();
+    dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
+    dbg_str->push_back('\0');
+
+    // Enter name, low_pc, high_pc.
+    PushWord(dbg_info, str_offset);
+    PushWord(dbg_info, info.low_pc_);
+    PushWord(dbg_info, info.high_pc_);
+  }
+
+  // One byte terminator
+  dbg_info->push_back(0);
+
+  // We have now walked all the methods.  Fill in lengths and low/high PCs.
+  UpdateWord(dbg_info, 0, dbg_info->size() - 4);
+  UpdateWord(dbg_info, low_pc_offset, low_pc);
+  UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
 }
 
 }  // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index 25b0495..dec75dc 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -45,6 +45,16 @@
     : ElfWriter(driver, elf_file) {}
   ~ElfWriterQuick() {}
 
+  /*
+   * @brief Generate the DWARF debug_info and debug_abbrev sections
+   * @param oat_writer The Oat file Writer.
+   * @param dbg_info Compilation unit information.
+   * @param dbg_abbrev Abbreviations used to generate dbg_info.
+   * @param dbg_str Debug strings.
+   */
+  void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info,
+                            std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
 };
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 970d2e3..a400bdd 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -378,6 +378,27 @@
       uint32_t thumb_offset = compiled_method->CodeDelta();
       quick_code_offset = offset + sizeof(code_size) + thumb_offset;
 
+      std::vector<uint8_t>* cfi_info = compiler_driver_->GetCallFrameInformation();
+      if (cfi_info != nullptr) {
+      // Copy in the FDE, if present
+      const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo();
+        if (fde != nullptr) {
+          // Copy the information into cfi_info and then fix the address in the new copy.
+          int cur_offset = cfi_info->size();
+          cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
+
+          // Set the 'initial_location' field to address the start of the method.
+          uint32_t new_value = quick_code_offset - oat_header_->GetExecutableOffset();
+          uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t);
+          (*cfi_info)[offset_to_update+0] = new_value;
+          (*cfi_info)[offset_to_update+1] = new_value >> 8;
+          (*cfi_info)[offset_to_update+2] = new_value >> 16;
+          (*cfi_info)[offset_to_update+3] = new_value >> 24;
+          method_info_.push_back(DebugInfo(PrettyMethod(class_def_method_index, dex_file, false),
+                                           new_value, new_value + code_size));
+        }
+      }
+
       // Deduplicate code arrays
       SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter =
           code_offsets_.find(quick_code);
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index f12c84d..3d4b48a 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -82,6 +82,19 @@
 
   ~OatWriter();
 
+  struct DebugInfo {
+    DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc)
+      : method_name_(method_name), low_pc_(low_pc), high_pc_(high_pc) {
+    }
+    std::string method_name_;
+    uint32_t    low_pc_;
+    uint32_t    high_pc_;
+  };
+
+  const std::vector<DebugInfo>& GetCFIMethodInfo() const {
+    return method_info_;
+  }
+
  private:
   size_t InitOatHeader();
   size_t InitOatDexFiles(size_t offset);
@@ -205,6 +218,8 @@
     DISALLOW_COPY_AND_ASSIGN(OatClass);
   };
 
+  std::vector<DebugInfo> method_info_;
+
   const CompilerDriver* const compiler_driver_;
 
   // note OatFile does not take ownership of the DexFiles
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 0e54021..041a66b 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -760,6 +760,7 @@
   bool dump_passes = false;
   bool dump_slow_timing = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
+  bool generate_gdb_information = kIsDebugBuild;
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
@@ -797,6 +798,10 @@
       watch_dog_enabled = true;
     } else if (option == "--no-watch-dog") {
       watch_dog_enabled = false;
+    } else if (option == "--gen-gdb-info") {
+      generate_gdb_information = true;
+    } else if (option == "--no-gen-gdb-info") {
+      generate_gdb_information = false;
     } else if (option.starts_with("-j")) {
       const char* thread_count_str = option.substr(strlen("-j")).data();
       if (!ParseInt(thread_count_str, &thread_count)) {
@@ -1042,7 +1047,8 @@
                                    large_method_threshold,
                                    small_method_threshold,
                                    tiny_method_threshold,
-                                   num_dex_methods_threshold
+                                   num_dex_methods_threshold,
+                                   generate_gdb_information
 #ifdef ART_SEA_IR_MODE
                                    , compiler_options.sea_ir_ = true;
 #endif
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 3a17e41..c646b86 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -22,6 +22,83 @@
 
 namespace art {
 
+// -------------------------------------------------------------------
+// Binary GDB JIT Interface as described in
+//   http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html
+extern "C" {
+  typedef enum {
+    JIT_NOACTION = 0,
+    JIT_REGISTER_FN,
+    JIT_UNREGISTER_FN
+  } JITAction;
+
+  struct JITCodeEntry {
+    JITCodeEntry* next_;
+    JITCodeEntry* prev_;
+    const byte *symfile_addr_;
+    uint64_t symfile_size_;
+  };
+
+  struct JITDescriptor {
+    uint32_t version_;
+    uint32_t action_flag_;
+    JITCodeEntry* relevant_entry_;
+    JITCodeEntry* first_entry_;
+  };
+
+  // GDB will place breakpoint into this function.
+  // To prevent GCC from inlining or removing it we place noinline attribute
+  // and inline assembler statement inside.
+  void __attribute__((noinline)) __jit_debug_register_code() {
+    __asm__("");
+  }
+
+  // GDB will inspect contents of this descriptor.
+  // Static initialization is necessary to prevent GDB from seeing
+  // uninitialized descriptor.
+  JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr };
+}
+
+
+static JITCodeEntry* CreateCodeEntry(const byte *symfile_addr,
+                                     uintptr_t symfile_size) {
+  JITCodeEntry* entry = new JITCodeEntry;
+  entry->symfile_addr_ = symfile_addr;
+  entry->symfile_size_ = symfile_size;
+  entry->prev_ = nullptr;
+
+  // TODO: Do we need a lock here?
+  entry->next_ = __jit_debug_descriptor.first_entry_;
+  if (entry->next_ != nullptr) {
+    entry->next_->prev_ = entry;
+  }
+  __jit_debug_descriptor.first_entry_ = entry;
+  __jit_debug_descriptor.relevant_entry_ = entry;
+
+  __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
+  __jit_debug_register_code();
+  return entry;
+}
+
+
+static void UnregisterCodeEntry(JITCodeEntry* entry) {
+  // TODO: Do we need a lock here?
+  if (entry->prev_ != nullptr) {
+    entry->prev_->next_ = entry->next_;
+  } else {
+    __jit_debug_descriptor.first_entry_ = entry->next_;
+  }
+
+  if (entry->next_ != nullptr) {
+    entry->next_->prev_ = entry->prev_;
+  }
+
+  __jit_debug_descriptor.relevant_entry_ = entry;
+  __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
+  __jit_debug_register_code();
+  delete entry;
+}
+
 ElfFile::ElfFile(File* file, bool writable, bool program_header_only)
   : file_(file),
     writable_(writable),
@@ -38,7 +115,9 @@
     dynstr_section_start_(NULL),
     hash_section_start_(NULL),
     symtab_symbol_table_(NULL),
-    dynsym_symbol_table_(NULL) {
+    dynsym_symbol_table_(NULL),
+    jit_elf_image_(NULL),
+    jit_gdb_entry_(NULL) {
   CHECK(file != NULL);
 }
 
@@ -172,6 +251,10 @@
   STLDeleteElements(&segments_);
   delete symtab_symbol_table_;
   delete dynsym_symbol_table_;
+  delete jit_elf_image_;
+  if (jit_gdb_entry_) {
+    UnregisterCodeEntry(jit_gdb_entry_);
+  }
 }
 
 bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
@@ -830,6 +913,11 @@
     }
   }
 
+  // Use GDB JIT support to do stack backtrace, etc.
+  if (executable) {
+    GdbJITSupport();
+  }
+
   return true;
 }
 
@@ -843,4 +931,269 @@
   return false;
 }
 
+static bool check_section_name(ElfFile& file, int section_num, const char *name) {
+  Elf32_Shdr& section_header = file.GetSectionHeader(section_num);
+  const char *section_name = file.GetString(SHT_SYMTAB, section_header.sh_name);
+  return strcmp(name, section_name) == 0;
+}
+
+static void IncrementUint32(byte *p, uint32_t increment) {
+  uint32_t *u = reinterpret_cast<uint32_t *>(p);
+  *u += increment;
+}
+
+static void RoundAndClear(byte *image, uint32_t& offset, int pwr2) {
+  uint32_t mask = pwr2 - 1;
+  while (offset & mask) {
+    image[offset++] = 0;
+  }
+}
+
+// Simple macro to bump a point to a section header to the next one.
+#define BUMP_SHENT(sp) \
+  sp = reinterpret_cast<Elf32_Shdr *> (\
+      reinterpret_cast<byte*>(sp) + elf_hdr.e_shentsize);\
+  offset += elf_hdr.e_shentsize
+
+void ElfFile::GdbJITSupport() {
+  // We only get here if we only are mapping the program header.
+  DCHECK(program_header_only_);
+
+  // Well, we need the whole file to do this.
+  std::string error_msg;
+  UniquePtr<ElfFile> ptr(Open(const_cast<File*>(file_), false, false, &error_msg));
+  ElfFile& all = *ptr;
+
+  // Do we have interesting sections?
+  // Is this an OAT file with interesting sections?
+  if (all.GetSectionHeaderNum() != kExpectedSectionsInOATFile) {
+    return;
+  }
+  if (!check_section_name(all, 8, ".debug_info") ||
+      !check_section_name(all, 9, ".debug_abbrev") ||
+      !check_section_name(all, 10, ".debug_frame") ||
+      !check_section_name(all, 11, ".debug_str")) {
+    return;
+  }
+
+  // Okay, we are good enough.  Fake up an ELF image and tell GDB about it.
+  // We need some extra space for the debug and string sections, the ELF header, and the
+  // section header.
+  uint32_t needed_size = KB;
+
+  for (Elf32_Word i = 1; i < all.GetSectionHeaderNum(); i++) {
+    Elf32_Shdr& section_header = all.GetSectionHeader(i);
+    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+      // Debug section: we need it.
+      needed_size += section_header.sh_size;
+    } else if (section_header.sh_type == SHT_STRTAB &&
+                strcmp(".shstrtab",
+                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+      // We also need the shared string table.
+      needed_size += section_header.sh_size;
+
+      // We also need the extra strings .symtab\0.strtab\0
+      needed_size += 16;
+    }
+  }
+
+  // Start creating our image.
+  jit_elf_image_ = new byte[needed_size];
+
+  // Create the Elf Header by copying the old one
+  Elf32_Ehdr& elf_hdr =
+    *reinterpret_cast<Elf32_Ehdr*>(jit_elf_image_);
+
+  elf_hdr = all.GetHeader();
+  elf_hdr.e_entry = 0;
+  elf_hdr.e_phoff = 0;
+  elf_hdr.e_phnum = 0;
+  elf_hdr.e_phentsize = 0;
+  elf_hdr.e_type = ET_EXEC;
+
+  uint32_t offset = sizeof(Elf32_Ehdr);
+
+  // Copy the debug sections and string table.
+  uint32_t debug_offsets[kExpectedSectionsInOATFile];
+  memset(debug_offsets, '\0', sizeof debug_offsets);
+  Elf32_Shdr *text_header = nullptr;
+  int extra_shstrtab_entries = -1;
+  int text_section_index = -1;
+  int section_index = 1;
+  for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
+    Elf32_Shdr& section_header = all.GetSectionHeader(i);
+    // Round up to multiple of 4, ensuring zero fill.
+    RoundAndClear(jit_elf_image_, offset, 4);
+    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+      // Debug section: we need it.  Unfortunately, it wasn't mapped in.
+      debug_offsets[i] = offset;
+      // Read it from the file.
+      lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
+      read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
+      offset += section_header.sh_size;
+      section_index++;
+      offset += 16;
+    } else if (section_header.sh_type == SHT_STRTAB &&
+                strcmp(".shstrtab",
+                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+      // We also need the shared string table.
+      debug_offsets[i] = offset;
+      // Read it from the file.
+      lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
+      read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
+      offset += section_header.sh_size;
+      // We also need the extra strings .symtab\0.strtab\0
+      extra_shstrtab_entries = section_header.sh_size;
+      memcpy(jit_elf_image_+offset, ".symtab\0.strtab\0", 16);
+      offset += 16;
+      section_index++;
+    } else if (section_header.sh_flags & SHF_EXECINSTR) {
+      DCHECK(strcmp(".text", all.GetString(SHT_SYMTAB,
+                                           section_header.sh_name)) == 0);
+      text_header = &section_header;
+      text_section_index = section_index++;
+    }
+  }
+  DCHECK(text_header != nullptr);
+  DCHECK_NE(extra_shstrtab_entries, -1);
+
+  // We now need to update the addresses for debug_info and debug_frame to get to the
+  // correct offset within the .text section.
+  uint32_t text_start_addr = 0;
+  for (uint32_t i = 0; i < segments_.size(); i++) {
+    if (segments_[i]->GetProtect() & PROT_EXEC) {
+      // We found the .text section.
+      text_start_addr = reinterpret_cast<uint32_t>(segments_[i]->Begin());
+      break;
+    }
+  }
+  DCHECK_NE(text_start_addr, 0U);
+
+  byte *p = jit_elf_image_+debug_offsets[8];
+  byte *end = p + all.GetSectionHeader(8).sh_size;
+
+  // For debug_info; patch compilation using low_pc @ offset 13, high_pc at offset 17.
+  IncrementUint32(p + 13, text_start_addr);
+  IncrementUint32(p + 17, text_start_addr);
+
+  // Now fix the low_pc, high_pc for each method address.
+  // First method starts at offset 0x15, each subsequent method is 1+3*4 bytes further.
+  for (p += 0x15; p < end; p += 1 /* attr# */ + 3 * sizeof(uint32_t) /* addresses */) {
+    IncrementUint32(p + 1 + sizeof(uint32_t), text_start_addr);
+    IncrementUint32(p + 1 + 2 * sizeof(uint32_t), text_start_addr);
+  }
+
+  // Now we have to handle the debug_frame method start addresses
+  p = jit_elf_image_+debug_offsets[10];
+  end = p + all.GetSectionHeader(10).sh_size;
+
+  // Skip past the CIE.
+  p += *reinterpret_cast<uint32_t *>(p) + 4;
+
+  // And walk the FDEs.
+  for (; p < end; p += *reinterpret_cast<uint32_t *>(p) + sizeof(uint32_t)) {
+    IncrementUint32(p + 2 * sizeof(uint32_t), text_start_addr);
+  }
+
+  // Create the data for the symbol table.
+  const int kSymbtabAlignment = 16;
+  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+  uint32_t symtab_offset = offset;
+
+  // First entry is empty.
+  memset(jit_elf_image_+offset, 0, sizeof(Elf32_Sym));
+  offset += sizeof(Elf32_Sym);
+
+  // Symbol 1 is the real .text section.
+  Elf32_Sym& sym_ent = *reinterpret_cast<Elf32_Sym*>(jit_elf_image_+offset);
+  sym_ent.st_name = 1; /* .text */
+  sym_ent.st_value = text_start_addr;
+  sym_ent.st_size = text_header->sh_size;
+  SetBindingAndType(&sym_ent, STB_LOCAL, STT_SECTION);
+  sym_ent.st_other = 0;
+  sym_ent.st_shndx = text_section_index;
+  offset += sizeof(Elf32_Sym);
+
+  // Create the data for the string table.
+  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+  const int kTextStringSize = 7;
+  uint32_t strtab_offset = offset;
+  memcpy(jit_elf_image_+offset, "\0.text", kTextStringSize);
+  offset += kTextStringSize;
+
+  // Create the section header table.
+  // Round up to multiple of kSymbtabAlignment, ensuring zero fill.
+  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
+  elf_hdr.e_shoff = offset;
+  Elf32_Shdr *sp =
+    reinterpret_cast<Elf32_Shdr *>(jit_elf_image_ + offset);
+
+  // Copy the first empty index.
+  *sp = all.GetSectionHeader(0);
+  BUMP_SHENT(sp);
+
+  elf_hdr.e_shnum = 1;
+  for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
+    Elf32_Shdr& section_header = all.GetSectionHeader(i);
+    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
+      // Debug section: we need it.
+      *sp = section_header;
+      sp->sh_offset = debug_offsets[i];
+      sp->sh_addr = 0;
+      elf_hdr.e_shnum++;
+      BUMP_SHENT(sp);
+    } else if (section_header.sh_type == SHT_STRTAB &&
+                strcmp(".shstrtab",
+                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
+      // We also need the shared string table.
+      *sp = section_header;
+      sp->sh_offset = debug_offsets[i];
+      sp->sh_size += 16; /* sizeof ".symtab\0.strtab\0" */
+      sp->sh_addr = 0;
+      elf_hdr.e_shstrndx = elf_hdr.e_shnum;
+      elf_hdr.e_shnum++;
+      BUMP_SHENT(sp);
+    }
+  }
+
+  // Add a .text section for the matching code section.
+  *sp = *text_header;
+  sp->sh_type = SHT_NOBITS;
+  sp->sh_offset = 0;
+  sp->sh_addr = text_start_addr;
+  elf_hdr.e_shnum++;
+  BUMP_SHENT(sp);
+
+  // .symtab section:  Need an empty index and the .text entry
+  sp->sh_name = extra_shstrtab_entries;
+  sp->sh_type = SHT_SYMTAB;
+  sp->sh_flags = 0;
+  sp->sh_addr = 0;
+  sp->sh_offset = symtab_offset;
+  sp->sh_size = 2 * sizeof(Elf32_Sym);
+  sp->sh_link = elf_hdr.e_shnum + 1;  // Link to .strtab section.
+  sp->sh_info = 0;
+  sp->sh_addralign = 16;
+  sp->sh_entsize = sizeof(Elf32_Sym);
+  elf_hdr.e_shnum++;
+  BUMP_SHENT(sp);
+
+  // .strtab section:  Enough for .text\0.
+  sp->sh_name = extra_shstrtab_entries + 8;
+  sp->sh_type = SHT_STRTAB;
+  sp->sh_flags = 0;
+  sp->sh_addr = 0;
+  sp->sh_offset = strtab_offset;
+  sp->sh_size = kTextStringSize;
+  sp->sh_link = 0;
+  sp->sh_info = 0;
+  sp->sh_addralign = 16;
+  sp->sh_entsize = 0;
+  elf_hdr.e_shnum++;
+  BUMP_SHENT(sp);
+
+  // We now have enough information to tell GDB about our file.
+  jit_gdb_entry_ = CreateCodeEntry(jit_elf_image_, offset);
+}
+
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 8a0a5f8..d2a044e 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -29,6 +29,12 @@
 
 namespace art {
 
+// Interface to GDB JIT for backtrace information.
+extern "C" {
+  struct JITCodeEntry;
+}
+
+
 // Used for compile time and runtime for ElfFile access. Because of
 // the need for use at runtime, cannot directly use LLVM classes such as
 // ELFObjectFile.
@@ -171,6 +177,13 @@
 
   SymbolTable* symtab_symbol_table_;
   SymbolTable* dynsym_symbol_table_;
+
+  // Support for GDB JIT
+  byte* jit_elf_image_;
+  JITCodeEntry* jit_gdb_entry_;
+  void GdbJITSupport();
+  // Is this an OAT file with debug information in it?
+  static constexpr uint32_t kExpectedSectionsInOATFile = 12;
 };
 
 }  // namespace art