Merge "Fixed gdb support and added some ElfFile functions"
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 4c093c7..55ee18e 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -43,7 +43,7 @@
                                      size_t& oat_data_offset) {
   std::string error_msg;
   std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg));
-  CHECK(elf_file.get() != NULL) << error_msg;
+  CHECK(elf_file.get() != nullptr) << error_msg;
 
   oat_loaded_size = elf_file->GetLoadedSize();
   CHECK_NE(0U, oat_loaded_size);
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 78757ec..e4dcaa7 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -20,6 +20,7 @@
 #include "base/unix_file/fd_file.h"
 #include "buffered_output_stream.h"
 #include "driver/compiler_driver.h"
+#include "dwarf.h"
 #include "elf_utils.h"
 #include "file_output_stream.h"
 #include "globals.h"
@@ -469,9 +470,9 @@
   pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset,
                                 hash.data(), hash.size() * sizeof(Elf32_Word)));
   pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset,
-                                NULL, rodata_builder_.section_.sh_size));
+                                nullptr, rodata_builder_.section_.sh_size));
   pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset,
-                                NULL, text_builder_.section_.sh_size));
+                                nullptr, text_builder_.section_.sh_size));
   if (IncludingDebugSymbols()) {
     pieces.push_back(ElfFilePiece(".symtab", symtab_builder_.section_.sh_offset,
                                   symtab.data(), symtab.size() * sizeof(Elf32_Sym)));
@@ -547,7 +548,7 @@
   if (tag == DT_NULL) {
     return;
   }
-  dynamics_.push_back({NULL, tag, d_un});
+  dynamics_.push_back({nullptr, tag, d_un});
 }
 
 void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un,
@@ -650,7 +651,7 @@
   // Lets say the state is something like this.
   // +--------+       +--------+      +-----------+
   // | symtab |       | bucket |      |   chain   |
-  // |  NULL  |       | 1      |      | STN_UNDEF |
+  // |  nullptr  |       | 1      |      | STN_UNDEF |
   // | <sym1> |       | 4      |      | 2         |
   // | <sym2> |       |        |      | 5         |
   // | <sym3> |       |        |      | STN_UNDEF |
@@ -821,10 +822,10 @@
 
   bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
   if (generateDebugInformation) {
-    ElfRawSectionBuilder debug_info(".debug_info",   SHT_PROGBITS, 0, NULL, 0, 1, 0);
-    ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, NULL, 0, 1, 0);
-    ElfRawSectionBuilder debug_str(".debug_str",    SHT_PROGBITS, 0, NULL, 0, 1, 0);
-    ElfRawSectionBuilder debug_frame(".debug_frame",  SHT_PROGBITS, 0, NULL, 0, 4, 0);
+    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());
 
     FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
@@ -866,31 +867,6 @@
   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,
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index bf04a54..280f6d0 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -875,6 +875,8 @@
       watch_dog_enabled = false;
     } else if (option == "--gen-gdb-info") {
       generate_gdb_information = true;
+      // Debug symbols are needed for gdb information.
+      include_debug_symbols = true;
     } else if (option == "--no-gen-gdb-info") {
       generate_gdb_information = false;
     } else if (option.starts_with("-j")) {
diff --git a/runtime/dwarf.h b/runtime/dwarf.h
new file mode 100644
index 0000000..370ad95
--- /dev/null
+++ b/runtime/dwarf.h
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DWARF_H_
+#define ART_RUNTIME_DWARF_H_
+
+namespace art {
+
+// Based on the Dwarf 4 specification at dwarfstd.com and issues marked
+// for inclusion in Dwarf 5 on same. Values not specified in the Dwarf 4
+// standard might change or be removed in the future and may be different
+// than the values used currently by other implementations for the same trait,
+// use at your own risk.
+
+enum Tag {
+  DW_TAG_array_type = 0x01,
+  DW_TAG_class_type = 0x02,
+  DW_TAG_entry_point = 0x03,
+  DW_TAG_enumeration_type = 0x04,
+  DW_TAG_formal_parameter = 0x05,
+  DW_TAG_imported_declaration = 0x08,
+  DW_TAG_label = 0x0a,
+  DW_TAG_lexical_block = 0x0b,
+  DW_TAG_member = 0x0d,
+  DW_TAG_pointer_type = 0x0f,
+  DW_TAG_reference_type = 0x10,
+  DW_TAG_compile_unit = 0x11,
+  DW_TAG_string_type = 0x12,
+  DW_TAG_structure_type = 0x13,
+  DW_TAG_subroutine_type = 0x15,
+  DW_TAG_typedef = 0x16,
+  DW_TAG_union_type = 0x17,
+  DW_TAG_unspecified_parameters = 0x18,
+  DW_TAG_variant = 0x19,
+  DW_TAG_common_block = 0x1a,
+  DW_TAG_common_inclusion = 0x1b,
+  DW_TAG_inheritance = 0x1c,
+  DW_TAG_inlined_subroutine = 0x1d,
+  DW_TAG_module = 0x1e,
+  DW_TAG_ptr_to_member_type = 0x1f,
+  DW_TAG_set_type = 0x20,
+  DW_TAG_subrange_type = 0x21,
+  DW_TAG_with_stmt = 0x22,
+  DW_TAG_access_declaration = 0x23,
+  DW_TAG_base_type = 0x24,
+  DW_TAG_catch_block = 0x25,
+  DW_TAG_const_type = 0x26,
+  DW_TAG_constant = 0x27,
+  DW_TAG_enumerator = 0x28,
+  DW_TAG_file_type = 0x29,
+  DW_TAG_friend = 0x2a,
+  DW_TAG_namelist = 0x2b,
+  DW_TAG_namelist_item = 0x2c,
+  DW_TAG_packed_type = 0x2d,
+  DW_TAG_subprogram = 0x2e,
+  DW_TAG_template_type_parameter = 0x2f,
+  DW_TAG_template_value_parameter = 0x30,
+  DW_TAG_thrown_type = 0x31,
+  DW_TAG_try_block = 0x32,
+  DW_TAG_variant_part = 0x33,
+  DW_TAG_variable = 0x34,
+  DW_TAG_volatile_type = 0x35,
+  DW_TAG_dwarf_procedure = 0x36,
+  DW_TAG_restrict_type = 0x37,
+  DW_TAG_interface_type = 0x38,
+  DW_TAG_namespace = 0x39,
+  DW_TAG_imported_module = 0x3a,
+  DW_TAG_unspecified_type = 0x3b,
+  DW_TAG_partial_unit = 0x3c,
+  DW_TAG_imported_unit = 0x3d,
+  DW_TAG_condition = 0x3f,
+  DW_TAG_shared_type = 0x40,
+  DW_TAG_type_unit = 0x41,
+  DW_TAG_rvalue_reference_type = 0x42,
+  DW_TAG_template_alias = 0x43,
+#ifdef INCLUDE_DWARF5_VALUES
+  // Values to be added in Dwarf 5. Final value not yet specified. Values listed
+  // may be different than other implementations. Use with caution.
+  // TODO Update these values when Dwarf 5 is released.
+  DW_TAG_coarray_type = 0x44,
+  DW_TAG_call_site = 0x45,
+  DW_TAG_call_site_parameter = 0x46,
+  DW_TAG_generic_subrange = 0x47,
+  DW_TAG_atomic_type = 0x48,
+  DW_TAG_dynamic_type = 0x49,
+  DW_TAG_aligned_type = 0x50,
+#endif
+  DW_TAG_lo_user = 0x4080,
+  DW_TAG_hi_user = 0xffff
+};
+
+enum Children : uint8_t {
+  DW_CHILDREN_no = 0x00,
+  DW_CHILDREN_yes = 0x01
+};
+
+enum Attribute {
+  DW_AT_sibling = 0x01,
+  DW_AT_location = 0x02,
+  DW_AT_name = 0x03,
+  DW_AT_ordering = 0x09,
+  DW_AT_byte_size = 0x0b,
+  DW_AT_bit_offset = 0x0c,
+  DW_AT_bit_size = 0x0d,
+  DW_AT_stmt_list = 0x10,
+  DW_AT_low_pc = 0x11,
+  DW_AT_high_pc = 0x12,
+  DW_AT_language = 0x13,
+  DW_AT_discr = 0x15,
+  DW_AT_discr_value = 0x16,
+  DW_AT_visibility = 0x17,
+  DW_AT_import = 0x18,
+  DW_AT_string_length = 0x19,
+  DW_AT_common_reference = 0x1a,
+  DW_AT_comp_dir = 0x1b,
+  DW_AT_const_value = 0x1c,
+  DW_AT_containing_type = 0x1d,
+  DW_AT_default_value = 0x1e,
+  DW_AT_inline = 0x20,
+  DW_AT_is_optional = 0x21,
+  DW_AT_lower_bound = 0x22,
+  DW_AT_producer = 0x25,
+  DW_AT_prototyped = 0x27,
+  DW_AT_return_addr = 0x2a,
+  DW_AT_start_scope = 0x2c,
+  DW_AT_bit_stride = 0x2e,
+  DW_AT_upper_bound = 0x2f,
+  DW_AT_abstract_origin = 0x31,
+  DW_AT_accessibility = 0x32,
+  DW_AT_address_class = 0x33,
+  DW_AT_artificial = 0x34,
+  DW_AT_base_types = 0x35,
+  DW_AT_calling_convention = 0x36,
+  DW_AT_count = 0x37,
+  DW_AT_data_member_location = 0x38,
+  DW_AT_decl_column = 0x39,
+  DW_AT_decl_file = 0x3a,
+  DW_AT_decl_line = 0x3b,
+  DW_AT_declaration = 0x3c,
+  DW_AT_discr_list = 0x3d,
+  DW_AT_encoding = 0x3e,
+  DW_AT_external = 0x3f,
+  DW_AT_frame_base = 0x40,
+  DW_AT_friend = 0x41,
+  DW_AT_identifier_case = 0x42,
+  DW_AT_macro_info = 0x43,
+  DW_AT_namelist_item = 0x44,
+  DW_AT_priority = 0x45,
+  DW_AT_segment = 0x46,
+  DW_AT_specification = 0x47,
+  DW_AT_static_link = 0x48,
+  DW_AT_type = 0x49,
+  DW_AT_use_location = 0x4a,
+  DW_AT_variable_parameter = 0x4b,
+  DW_AT_virtuality = 0x4c,
+  DW_AT_vtable_elem_location = 0x4d,
+  DW_AT_allocated = 0x4e,
+  DW_AT_associated = 0x4f,
+  DW_AT_data_location = 0x50,
+  DW_AT_byte_stride = 0x51,
+  DW_AT_entry_pc = 0x52,
+  DW_AT_use_UTF8 = 0x53,
+  DW_AT_extension = 0x54,
+  DW_AT_ranges = 0x55,
+  DW_AT_trampoline = 0x56,
+  DW_AT_call_column = 0x57,
+  DW_AT_call_file = 0x58,
+  DW_AT_call_line = 0x59,
+  DW_AT_description = 0x5a,
+  DW_AT_binary_scale = 0x5b,
+  DW_AT_decimal_scale = 0x5c,
+  DW_AT_small = 0x5d,
+  DW_AT_decimal_sign = 0x5e,
+  DW_AT_digit_count = 0x5f,
+  DW_AT_picture_string = 0x60,
+  DW_AT_mutable = 0x61,
+  DW_AT_threads_scaled = 0x62,
+  DW_AT_explicit = 0x63,
+  DW_AT_object_pointer = 0x64,
+  DW_AT_endianity = 0x65,
+  DW_AT_elemental = 0x66,
+  DW_AT_pure = 0x67,
+  DW_AT_recursive = 0x68,
+  DW_AT_signature = 0x69,
+  DW_AT_main_subprogram = 0x6a,
+  DW_AT_data_bit_offset = 0x6b,
+  DW_AT_const_expr = 0x6c,
+  DW_AT_enum_class = 0x6d,
+#ifdef INCLUDE_DWARF5_VALUES
+  // Values to be added in Dwarf 5. Final value not yet specified. Values listed
+  // may be different than other implementations. Use with caution.
+  // TODO Update these values when Dwarf 5 is released.
+  DW_AT_linkage_name = 0x6e,
+  DW_AT_call_site_value = 0x6f,
+  DW_AT_call_site_data_value = 0x70,
+  DW_AT_call_site_target = 0x71,
+  DW_AT_call_site_target_clobbered = 0x72,
+  DW_AT_tail_call = 0x73,
+  DW_AT_all_tail_call_sites = 0x74,
+  DW_AT_all_call_sites = 0x75,
+  DW_AT_all_source_call_sites = 0x76,
+  DW_AT_call_site_parameter = 0x77,
+  DW_AT_tail_call = 0x78,
+  DW_AT_all_tail_call_sites = 0x79,
+  DW_AT_all_call_sites = 0x7a,
+  DW_AT_all_source_call_sites = 0x7b,
+  DW_AT_rank = 0x7c,
+  DW_AT_string_bitsize = 0x7d,
+  DW_AT_string_byte_size = 0x7e,
+  DW_AT_reference = 0x7f,
+  DW_AT_rvalue_reference = 0x80,
+  DW_AT_noreturn = 0x81,
+  DW_AT_alignment = 0x82,
+#endif
+  DW_AT_lo_user = 0x2000,
+  DW_AT_hi_user = 0xffff
+};
+
+enum Form : uint8_t {
+  DW_FORM_addr = 0x01,
+  DW_FORM_block2 = 0x03,
+  DW_FORM_block4 = 0x04,
+  DW_FORM_data2 = 0x05,
+  DW_FORM_data4 = 0x06,
+  DW_FORM_data8 = 0x07,
+  DW_FORM_string = 0x08,
+  DW_FORM_block = 0x09,
+  DW_FORM_block1 = 0x0a,
+  DW_FORM_data1 = 0x0b,
+  DW_FORM_flag = 0x0c,
+  DW_FORM_sdata = 0x0d,
+  DW_FORM_strp = 0x0e,
+  DW_FORM_udata = 0x0f,
+  DW_FORM_ref_addr = 0x10,
+  DW_FORM_ref1 = 0x11,
+  DW_FORM_ref2 = 0x12,
+  DW_FORM_ref4 = 0x13,
+  DW_FORM_ref8 = 0x14,
+  DW_FORM_ref_udata = 0x15,
+  DW_FORM_indirect = 0x16,
+  DW_FORM_sec_offset = 0x17,
+  DW_FORM_exprloc = 0x18,
+  DW_FORM_flag_present = 0x19,
+  DW_FORM_ref_sig8 = 0x20
+};
+
+enum Operation : uint16_t {
+  DW_OP_addr = 0x03,
+  DW_OP_deref = 0x06,
+  DW_OP_const1u = 0x08,
+  DW_OP_const1s = 0x09,
+  DW_OP_const2u = 0x0a,
+  DW_OP_const2s = 0x0b,
+  DW_OP_const4u = 0x0c,
+  DW_OP_const4s = 0x0d,
+  DW_OP_const8u = 0x0e,
+  DW_OP_const8s = 0x0f,
+  DW_OP_constu = 0x10,
+  DW_OP_consts = 0x11,
+  DW_OP_dup = 0x12,
+  DW_OP_drop = 0x13,
+  DW_OP_over = 0x14,
+  DW_OP_pick = 0x15,
+  DW_OP_swap = 0x16,
+  DW_OP_rot = 0x17,
+  DW_OP_xderef = 0x18,
+  DW_OP_abs = 0x19,
+  DW_OP_and = 0x1a,
+  DW_OP_div = 0x1b,
+  DW_OP_minus = 0x1c,
+  DW_OP_mod = 0x1d,
+  DW_OP_mul = 0x1e,
+  DW_OP_neg = 0x1f,
+  DW_OP_not = 0x20,
+  DW_OP_or = 0x21,
+  DW_OP_plus = 0x22,
+  DW_OP_plus_uconst = 0x23,
+  DW_OP_shl = 0x24,
+  DW_OP_shr = 0x25,
+  DW_OP_shra = 0x26,
+  DW_OP_xor = 0x27,
+  DW_OP_skip = 0x2f,
+  DW_OP_bra = 0x28,
+  DW_OP_eq = 0x29,
+  DW_OP_ge = 0x2a,
+  DW_OP_gt = 0x2b,
+  DW_OP_le = 0x2c,
+  DW_OP_lt = 0x2d,
+  DW_OP_ne = 0x2e,
+  DW_OP_lit0 = 0x30,
+  DW_OP_lit1 = 0x31,
+  DW_OP_lit2 = 0x32,
+  DW_OP_lit3 = 0x33,
+  DW_OP_lit4 = 0x34,
+  DW_OP_lit5 = 0x35,
+  DW_OP_lit6 = 0x36,
+  DW_OP_lit7 = 0x37,
+  DW_OP_lit8 = 0x38,
+  DW_OP_lit9 = 0x39,
+  DW_OP_lit10 = 0x3a,
+  DW_OP_lit11 = 0x3b,
+  DW_OP_lit12 = 0x3c,
+  DW_OP_lit13 = 0x3d,
+  DW_OP_lit14 = 0x3e,
+  DW_OP_lit15 = 0x3f,
+  DW_OP_lit16 = 0x40,
+  DW_OP_lit17 = 0x41,
+  DW_OP_lit18 = 0x42,
+  DW_OP_lit19 = 0x43,
+  DW_OP_lit20 = 0x44,
+  DW_OP_lit21 = 0x45,
+  DW_OP_lit22 = 0x46,
+  DW_OP_lit23 = 0x47,
+  DW_OP_lit24 = 0x48,
+  DW_OP_lit25 = 0x49,
+  DW_OP_lit26 = 0x4a,
+  DW_OP_lit27 = 0x4b,
+  DW_OP_lit28 = 0x4c,
+  DW_OP_lit29 = 0x4d,
+  DW_OP_lit30 = 0x4e,
+  DW_OP_lit31 = 0x4f,
+  DW_OP_reg0 = 0x50,
+  DW_OP_reg1 = 0x51,
+  DW_OP_reg2 = 0x52,
+  DW_OP_reg3 = 0x53,
+  DW_OP_reg4 = 0x54,
+  DW_OP_reg5 = 0x55,
+  DW_OP_reg6 = 0x56,
+  DW_OP_reg7 = 0x57,
+  DW_OP_reg8 = 0x58,
+  DW_OP_reg9 = 0x59,
+  DW_OP_reg10 = 0x5a,
+  DW_OP_reg11 = 0x5b,
+  DW_OP_reg12 = 0x5c,
+  DW_OP_reg13 = 0x5d,
+  DW_OP_reg14 = 0x5e,
+  DW_OP_reg15 = 0x5f,
+  DW_OP_reg16 = 0x60,
+  DW_OP_reg17 = 0x61,
+  DW_OP_reg18 = 0x62,
+  DW_OP_reg19 = 0x63,
+  DW_OP_reg20 = 0x64,
+  DW_OP_reg21 = 0x65,
+  DW_OP_reg22 = 0x66,
+  DW_OP_reg23 = 0x67,
+  DW_OP_reg24 = 0x68,
+  DW_OP_reg25 = 0x69,
+  DW_OP_reg26 = 0x6a,
+  DW_OP_reg27 = 0x6b,
+  DW_OP_reg28 = 0x6c,
+  DW_OP_reg29 = 0x6d,
+  DW_OP_reg30 = 0x6e,
+  DW_OP_reg31 = 0x6f,
+  DW_OP_breg0 = 0x50,
+  DW_OP_breg1 = 0x51,
+  DW_OP_breg2 = 0x52,
+  DW_OP_breg3 = 0x53,
+  DW_OP_breg4 = 0x54,
+  DW_OP_breg5 = 0x55,
+  DW_OP_breg6 = 0x56,
+  DW_OP_breg7 = 0x57,
+  DW_OP_breg8 = 0x58,
+  DW_OP_breg9 = 0x59,
+  DW_OP_breg10 = 0x5a,
+  DW_OP_breg11 = 0x5b,
+  DW_OP_breg12 = 0x5c,
+  DW_OP_breg13 = 0x5d,
+  DW_OP_breg14 = 0x5e,
+  DW_OP_breg15 = 0x5f,
+  DW_OP_breg16 = 0x60,
+  DW_OP_breg17 = 0x61,
+  DW_OP_breg18 = 0x62,
+  DW_OP_breg19 = 0x63,
+  DW_OP_breg20 = 0x64,
+  DW_OP_breg21 = 0x65,
+  DW_OP_breg22 = 0x66,
+  DW_OP_breg23 = 0x67,
+  DW_OP_breg24 = 0x68,
+  DW_OP_breg25 = 0x69,
+  DW_OP_breg26 = 0x6a,
+  DW_OP_breg27 = 0x6b,
+  DW_OP_breg28 = 0x6c,
+  DW_OP_breg29 = 0x6d,
+  DW_OP_breg30 = 0x6e,
+  DW_OP_breg31 = 0x6f,
+  DW_OP_regx = 0x90,
+  DW_OP_fbreg = 0x91,
+  DW_OP_bregx = 0x92,
+  DW_OP_piece = 0x93,
+  DW_OP_deref_size = 0x94,
+  DW_OP_xderef_size = 0x95,
+  DW_OP_nop = 0x96,
+  DW_OP_push_object_address = 0x97,
+  DW_OP_call2 = 0x98,
+  DW_OP_call4 = 0x99,
+  DW_OP_call_ref = 0x9a,
+  DW_OP_form_tls_address = 0x9b,
+  DW_OP_call_frame_cfa = 0x9c,
+  DW_OP_bit_piece = 0x9d,
+  DW_OP_implicit_value = 0x9e,
+  DW_OP_stack_value = 0x9f,
+#ifdef INCLUDE_DWARF5_VALUES
+  // Values to be added in Dwarf 5. Final value not yet specified. Values listed
+  // may be different than other implementations. Use with caution.
+  // TODO Update these values when Dwarf 5 is released.
+  DW_OP_entry_value = 0xa0,
+  DW_OP_const_type = 0xa1,
+  DW_OP_regval_type = 0xa2,
+  DW_OP_deref_type = 0xa3,
+  DW_OP_xderef_type = 0xa4,
+  DW_OP_convert = 0xa5,
+  DW_OP_reinterpret = 0xa6,
+#endif
+  DW_OP_lo_user = 0xe0,
+  DW_OP_hi_user = 0xff
+};
+
+enum BaseTypeEncoding : uint8_t {
+  DW_ATE_address = 0x01,
+  DW_ATE_boolean = 0x02,
+  DW_ATE_complex_float = 0x03,
+  DW_ATE_float = 0x04,
+  DW_ATE_signed = 0x05,
+  DW_ATE_signed_char = 0x06,
+  DW_ATE_unsigned = 0x07,
+  DW_ATE_unsigned_char = 0x08,
+  DW_ATE_imaginary_float = 0x09,
+  DW_ATE_packed_decimal = 0x0a,
+  DW_ATE_numeric_string = 0x0b,
+  DW_ATE_edited = 0x0c,
+  DW_ATE_signed_fixed = 0x0d,
+  DW_ATE_unsigned_fixed = 0x0e,
+  DW_ATE_decimal_float = 0x0f,
+  DW_ATE_UTF = 0x10,
+  DW_ATE_lo_user = 0x80,
+  DW_ATE_hi_user = 0xff
+};
+
+enum DecimalSign : uint8_t {
+  DW_DS_unsigned = 0x01,
+  DW_DS_leading_overpunch = 0x02,
+  DW_DS_trailing_overpunch = 0x03,
+  DW_DS_leading_separate = 0x04,
+  DW_DS_trailing_separate = 0x05
+};
+
+enum Endianity : uint8_t {
+  DW_END_default = 0x00,
+  DW_END_big = 0x01,
+  DW_END_little = 0x02,
+  DW_END_lo_user = 0x40,
+  DW_END_hi_user = 0xff
+};
+
+enum Accessibility : uint8_t {
+  DW_ACCESS_public = 0x01,
+  DW_ACCESS_protected = 0x02,
+  DW_ACCESS_private = 0x03
+};
+
+enum Visibility : uint8_t {
+  DW_VIS_local = 0x01,
+  DW_VIS_exported = 0x02,
+  DW_VIS_qualified = 0x03
+};
+
+enum Virtuality : uint8_t {
+  DW_VIRTUALITY_none = 0x00,
+  DW_VIRTUALITY_virtual = 0x01,
+  DW_VIRTUALITY_pure_virtual = 0x02
+};
+
+enum Language {
+  DW_LANG_C89 = 0x01,
+  DW_LANG_C = 0x02,
+  DW_LANG_Ada83 = 0x03,
+  DW_LANG_C_plus_plus = 0x04,
+  DW_LANG_Cobol74 = 0x05,
+  DW_LANG_Cobol85 = 0x06,
+  DW_LANG_Fortran77 = 0x07,
+  DW_LANG_Fortran90 = 0x08,
+  DW_LANG_Pascal83 = 0x09,
+  DW_LANG_Modula2 = 0x0a,
+  DW_LANG_Java = 0x0b,
+  DW_LANG_C99 = 0x0c,
+  DW_LANG_Ada95 = 0x0d,
+  DW_LANG_Fortran95 = 0x0e,
+  DW_LANG_PLI = 0x0f,
+  DW_LANG_ObjC = 0x10,
+  DW_LANG_ObjC_plus_plus = 0x11,
+  DW_LANG_UPC = 0x12,
+  DW_LANG_D = 0x13,
+  DW_LANG_Python = 0x14,
+#ifdef INCLUDE_DWARF5_VALUES
+  // Values to be added in Dwarf 5. Final value not yet specified. Values listed
+  // may be different than other implementations. Use with caution.
+  // TODO Update these values when Dwarf 5 is released.
+  DW_LANG_OpenCL = 0x15,
+  DW_LANG_Go = 0x16,
+  DW_LANG_Modula3 = 0x17,
+  DW_LANG_Haskell = 0x18,
+  DW_LANG_C_plus_plus_03 = 0x19,
+  DW_LANG_C_plus_plus_11 = 0x1a,
+  DW_LANG_OCaml = 0x1b,
+  DW_LANG_Rust = 0x1c,
+  DW_LANG_C11 = 0x1d,
+  DW_LANG_Swift = 0x1e,
+  DW_LANG_Julia = 0x1f,
+#endif
+  DW_LANG_lo_user = 0x8000,
+  DW_LANG_hi_user = 0xffff
+};
+
+enum Identifier : uint8_t {
+  DW_ID_case_sensitive = 0x00,
+  DW_ID_up_case = 0x01,
+  DW_ID_down_case = 0x02,
+  DW_ID_case_insensitive = 0x03
+};
+
+enum CallingConvention : uint8_t {
+  DW_CC_normal = 0x01,
+  DW_CC_program = 0x02,
+  DW_CC_nocall = 0x03,
+  DW_CC_lo_user = 0x40,
+  DW_CC_hi_user = 0xff
+};
+
+enum Inline : uint8_t {
+  DW_INL_not_inlined = 0x00,
+  DW_INL_inlined = 0x01,
+  DW_INL_declared_not_inlined = 0x02,
+  DW_INL_declared_inlined = 0x03
+};
+
+enum ArrayOrdering : uint8_t {
+  DW_ORD_row_major = 0x00,
+  DW_ORD_col_major = 0x01
+};
+
+enum DiscriminantList : uint8_t {
+  DW_DSC_label = 0x00,
+  DW_DSC_range = 0x01
+};
+
+enum LineNumberOpcode : uint8_t {
+  DW_LNS_copy = 0x01,
+  DW_LNS_advance_pc = 0x02,
+  DW_LNS_advance_line = 0x03,
+  DW_LNS_set_file = 0x04,
+  DW_LNS_set_column = 0x05,
+  DW_LNS_negate_stmt = 0x06,
+  DW_LNS_set_basic_block = 0x07,
+  DW_LNS_const_add_pc = 0x08,
+  DW_LNS_fixed_advance_pc = 0x09,
+  DW_LNS_set_prologue_end = 0x0a,
+  DW_LNS_set_epilogue_begin = 0x0b,
+  DW_LNS_set_isa = 0x0c
+};
+
+enum LineNumberExtendedOpcode : uint8_t {
+  DW_LNE_end_sequence = 0x01,
+  DW_LNE_set_address = 0x02,
+  DW_LNE_define_file = 0x03,
+  DW_LNE_set_discriminator = 0x04,
+  DW_LNE_lo_user = 0x80,
+  DW_LNE_hi_user = 0xff
+};
+
+#ifdef INCLUDE_DWARF5_VALUES
+enum LineNumberFormat : uint8_t {
+  // Values to be added in Dwarf 5. Final value not yet specified. Values listed
+  // may be different than other implementations. Use with caution.
+  // TODO Update these values when Dwarf 5 is released.
+  //
+  DW_LNF_path = 0x1,
+  DW_LNF_include_index = 0x2,
+  DW_LNF_timestamp = 0x3,
+  DW_LNF_size = 0x4,
+  DW_LNF_MD5 = 0x5,
+  DW_LNF_lo_user = 0x2000,
+  DW_LNF_hi_user = 0x3fff
+};
+#endif
+
+enum MacroInfo : uint8_t {
+  DW_MACINFO_define = 0x01,
+  DW_MACINFO_undef = 0x02,
+  DW_MACINFO_start_file = 0x03,
+  DW_MACINFO_end_file = 0x04,
+  DW_MACINFO_vendor_ext = 0xff
+};
+
+#ifdef INCLUDE_DWARF5_VALUES
+enum Macro : uint8_t {
+  // Values to be added in Dwarf 5. Final value not yet specified. Values listed
+  // may be different than other implementations. Use with caution.
+  // TODO Update these values when Dwarf 5 is released.
+  DW_MACRO_define = 0x01,
+  DW_MACRO_undef = 0x02,
+  DW_MACRO_start_file = 0x03,
+  DW_MACRO_end_file = 0x04,
+  DW_MACRO_define_indirect = 0x05,
+  DW_MACRO_undef_indirect = 0x06,
+  DW_MACRO_transparent_include = 0x07,
+  DW_MACRO_define_indirectx = 0x0b,
+  DW_MACRO_undef_indirectx = 0x0c,
+  DW_MACRO_lo_user = 0xe0,
+  DW_MACRO_hi_user = 0xff
+};
+#endif
+
+const uint32_t CIE_ID_32 = 0xffffffff;
+const uint64_t CIE_ID_64 = 0xffffffffffffffff;
+
+enum CallFrameInstruction : uint8_t {
+  DW_CFA_advance_loc = 0x40,
+  DW_CFA_offset = 0x80,
+  DW_CFA_restore = 0xc0,
+  DW_CFA_nop = 0x00,
+  DW_CFA_set_loc = 0x01,
+  DW_CFA_advance_loc1 = 0x02,
+  DW_CFA_advance_loc2 = 0x03,
+  DW_CFA_advance_loc4 = 0x04,
+  DW_CFA_offset_extended = 0x05,
+  DW_CFA_restore_extended = 0x06,
+  DW_CFA_undefined = 0x07,
+  DW_CFA_same_value = 0x08,
+  DW_CFA_register = 0x09,
+  DW_CFA_remember_state = 0x0a,
+  DW_CFA_restore_state = 0x0b,
+  DW_CFA_def_cfa = 0x0c,
+  DW_CFA_def_cfa_register = 0x0d,
+  DW_CFA_def_cfa_offset = 0x0e,
+  DW_CFA_def_cfa_expression = 0x0f,
+  DW_CFA_expression = 0x10,
+  DW_CFA_offset_extended_sf = 0x11,
+  DW_CFA_def_cfa_sf = 0x12,
+  DW_CFA_def_cfa_offset_sf = 0x13,
+  DW_CFA_val_offset = 0x14,
+  DW_CFA_val_offset_sf = 0x15,
+  DW_CFA_val_expression = 0x16,
+  DW_CFA_lo_user = 0x1c,
+  DW_CFA_hi_user = 0x3f
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DWARF_H_
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 0df8211..bb33978 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -22,6 +22,8 @@
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "base/stl_util.h"
+#include "dwarf.h"
+#include "leb128.h"
 #include "utils.h"
 #include "instruction_set.h"
 
@@ -108,43 +110,51 @@
   : file_(file),
     writable_(writable),
     program_header_only_(program_header_only),
-    header_(NULL),
-    base_address_(NULL),
-    program_headers_start_(NULL),
-    section_headers_start_(NULL),
-    dynamic_program_header_(NULL),
-    dynamic_section_start_(NULL),
-    symtab_section_start_(NULL),
-    dynsym_section_start_(NULL),
-    strtab_section_start_(NULL),
-    dynstr_section_start_(NULL),
-    hash_section_start_(NULL),
-    symtab_symbol_table_(NULL),
-    dynsym_symbol_table_(NULL),
-    jit_elf_image_(NULL),
-    jit_gdb_entry_(NULL) {
-  CHECK(file != NULL);
+    header_(nullptr),
+    base_address_(nullptr),
+    program_headers_start_(nullptr),
+    section_headers_start_(nullptr),
+    dynamic_program_header_(nullptr),
+    dynamic_section_start_(nullptr),
+    symtab_section_start_(nullptr),
+    dynsym_section_start_(nullptr),
+    strtab_section_start_(nullptr),
+    dynstr_section_start_(nullptr),
+    hash_section_start_(nullptr),
+    symtab_symbol_table_(nullptr),
+    dynsym_symbol_table_(nullptr),
+    jit_elf_image_(nullptr),
+    jit_gdb_entry_(nullptr) {
+  CHECK(file != nullptr);
 }
 
 ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only,
                        std::string* error_msg) {
   std::unique_ptr<ElfFile> elf_file(new ElfFile(file, writable, program_header_only));
-  if (!elf_file->Setup(error_msg)) {
-    return nullptr;
-  }
-  return elf_file.release();
-}
-
-bool ElfFile::Setup(std::string* error_msg) {
   int prot;
   int flags;
-  if (writable_) {
+  if (writable) {
     prot = PROT_READ | PROT_WRITE;
     flags = MAP_SHARED;
   } else {
     prot = PROT_READ;
     flags = MAP_PRIVATE;
   }
+  if (!elf_file->Setup(prot, flags, error_msg)) {
+    return nullptr;
+  }
+  return elf_file.release();
+}
+
+ElfFile* ElfFile::Open(File* file, int prot, int flags, std::string* error_msg) {
+  std::unique_ptr<ElfFile> elf_file(new ElfFile(file, (prot & PROT_WRITE) == PROT_WRITE, false));
+  if (!elf_file->Setup(prot, flags, error_msg)) {
+    return nullptr;
+  }
+  return elf_file.release();
+}
+
+bool ElfFile::Setup(int prot, int flags, std::string* error_msg) {
   int64_t temp_file_length = file_->GetLength();
   if (temp_file_length < 0) {
     errno = -temp_file_length;
@@ -201,7 +211,7 @@
 
     // Find .dynamic section info from program header
     dynamic_program_header_ = FindProgamHeaderByType(PT_DYNAMIC);
-    if (dynamic_program_header_ == NULL) {
+    if (dynamic_program_header_ == nullptr) {
       *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
                                 file_->GetPath().c_str());
       return false;
@@ -263,14 +273,14 @@
 }
 
 bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
-  if (map == NULL) {
+  if (map == nullptr) {
     // MemMap::Open should have already set an error.
     DCHECK(!error_msg->empty());
     return false;
   }
   map_.reset(map);
-  CHECK(map_.get() != NULL) << file_->GetPath();
-  CHECK(map_->Begin() != NULL) << file_->GetPath();
+  CHECK(map_.get() != nullptr) << file_->GetPath();
+  CHECK(map_->Begin() != nullptr) << file_->GetPath();
 
   header_ = reinterpret_cast<Elf32_Ehdr*>(map_->Begin());
   if ((ELFMAG0 != header_->e_ident[EI_MAG0])
@@ -397,27 +407,27 @@
 
 
 Elf32_Ehdr& ElfFile::GetHeader() const {
-  CHECK(header_ != NULL);
+  CHECK(header_ != nullptr);
   return *header_;
 }
 
 byte* ElfFile::GetProgramHeadersStart() const {
-  CHECK(program_headers_start_ != NULL);
+  CHECK(program_headers_start_ != nullptr);
   return program_headers_start_;
 }
 
 byte* ElfFile::GetSectionHeadersStart() const {
-  CHECK(section_headers_start_ != NULL);
+  CHECK(section_headers_start_ != nullptr);
   return section_headers_start_;
 }
 
 Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const {
-  CHECK(dynamic_program_header_ != NULL);
+  CHECK(dynamic_program_header_ != nullptr);
   return *dynamic_program_header_;
 }
 
 Elf32_Dyn* ElfFile::GetDynamicSectionStart() const {
-  CHECK(dynamic_section_start_ != NULL);
+  CHECK(dynamic_section_start_ != nullptr);
   return dynamic_section_start_;
 }
 
@@ -435,10 +445,10 @@
     }
     default: {
       LOG(FATAL) << section_type;
-      symbol_section_start = NULL;
+      symbol_section_start = nullptr;
     }
   }
-  CHECK(symbol_section_start != NULL);
+  CHECK(symbol_section_start != nullptr);
   return symbol_section_start;
 }
 
@@ -456,17 +466,17 @@
     }
     default: {
       LOG(FATAL) << section_type;
-      string_section_start = NULL;
+      string_section_start = nullptr;
     }
   }
-  CHECK(string_section_start != NULL);
+  CHECK(string_section_start != nullptr);
   return string_section_start;
 }
 
 const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   if (i == 0) {
-    return NULL;
+    return nullptr;
   }
   const char* string_section_start = GetStringSectionStart(section_type);
   const char* string = string_section_start + i;
@@ -474,7 +484,7 @@
 }
 
 Elf32_Word* ElfFile::GetHashSectionStart() const {
-  CHECK(hash_section_start_ != NULL);
+  CHECK(hash_section_start_ != nullptr);
   return hash_section_start_;
 }
 
@@ -516,7 +526,7 @@
       return &program_header;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 Elf32_Word ElfFile::GetSectionHeaderNum() const {
@@ -543,7 +553,7 @@
       return &section_header;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 // from bionic
@@ -565,6 +575,15 @@
 }
 
 const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+  const Elf32_Sym* sym = FindDynamicSymbol(symbol_name);
+  if (sym != nullptr) {
+    return base_address_ + sym->st_value;
+  } else {
+    return nullptr;
+  }
+}
+
+const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const {
   Elf32_Word hash = elfhash(symbol_name.c_str());
   Elf32_Word bucket_index = hash % GetHashBucketNum();
   Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index);
@@ -572,11 +591,11 @@
     Elf32_Sym& symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
     const char* name = GetString(SHT_DYNSYM, symbol.st_name);
     if (symbol_name == name) {
-      return base_address_ + symbol.st_value;
+      return &symbol;
     }
     symbol_and_chain_index = GetHashChain(symbol_and_chain_index);
   }
-  return NULL;
+  return nullptr;
 }
 
 bool ElfFile::IsSymbolSectionType(Elf32_Word section_type) {
@@ -606,7 +625,7 @@
     }
     default: {
       LOG(FATAL) << section_type;
-      return NULL;
+      return nullptr;
     }
   }
 }
@@ -618,12 +637,12 @@
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
 
   SymbolTable** symbol_table = GetSymbolTable(section_type);
-  if (*symbol_table != NULL || build_map) {
-    if (*symbol_table == NULL) {
+  if (*symbol_table != nullptr || build_map) {
+    if (*symbol_table == nullptr) {
       DCHECK(build_map);
       *symbol_table = new SymbolTable;
       Elf32_Shdr* symbol_section = FindSectionByType(section_type);
-      CHECK(symbol_section != NULL) << file_->GetPath();
+      CHECK(symbol_section != nullptr) << file_->GetPath();
       Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
       for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
         Elf32_Sym& symbol = GetSymbol(section_type, i);
@@ -632,7 +651,7 @@
           continue;
         }
         const char* name = GetString(string_section, symbol.st_name);
-        if (name == NULL) {
+        if (name == nullptr) {
           continue;
         }
         std::pair<SymbolTable::iterator, bool> result =
@@ -647,36 +666,36 @@
         }
       }
     }
-    CHECK(*symbol_table != NULL);
+    CHECK(*symbol_table != nullptr);
     SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
     if (it == (*symbol_table)->end()) {
-      return NULL;
+      return nullptr;
     }
     return it->second;
   }
 
   // Fall back to linear search
   Elf32_Shdr* symbol_section = FindSectionByType(section_type);
-  CHECK(symbol_section != NULL) << file_->GetPath();
+  CHECK(symbol_section != nullptr) << file_->GetPath();
   Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
   for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
     Elf32_Sym& symbol = GetSymbol(section_type, i);
     const char* name = GetString(string_section, symbol.st_name);
-    if (name == NULL) {
+    if (name == nullptr) {
       continue;
     }
     if (symbol_name == name) {
       return &symbol;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 Elf32_Addr ElfFile::FindSymbolAddress(Elf32_Word section_type,
                                       const std::string& symbol_name,
                                       bool build_map) {
   Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
-  if (symbol == NULL) {
+  if (symbol == nullptr) {
     return 0;
   }
   return symbol->st_value;
@@ -688,7 +707,7 @@
   CHECK_EQ(static_cast<Elf32_Word>(SHT_STRTAB), string_section.sh_type) << file_->GetPath();
   CHECK_LT(i, string_section.sh_size) << file_->GetPath();
   if (i == 0) {
-    return NULL;
+    return nullptr;
   }
   byte* strings = Begin() + string_section.sh_offset;
   byte* string = strings + i;
@@ -846,7 +865,7 @@
       std::string reservation_name("ElfFile reservation for ");
       reservation_name += file_->GetPath();
       std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
-                                                     NULL, GetLoadedSize(), PROT_NONE, false,
+                                                     nullptr, GetLoadedSize(), PROT_NONE, false,
                                                      error_msg));
       if (reserve.get() == nullptr) {
         *error_msg = StringPrintf("Failed to allocate %s: %s",
@@ -970,29 +989,323 @@
   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;
+
+Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const {
+  CHECK(!program_header_only_);
+  Elf32_Shdr& shstrtab_sec = GetSectionNameStringSection();
+  for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf32_Shdr& shdr = GetSectionHeader(i);
+    const char* sec_name = GetString(shstrtab_sec, shdr.sh_name);
+    if (sec_name == nullptr) {
+      continue;
+    }
+    if (name == sec_name) {
+      return &shdr;
+    }
+  }
+  return nullptr;
 }
 
-static void IncrementUint32(byte *p, uint32_t increment) {
-  uint32_t *u = reinterpret_cast<uint32_t *>(p);
-  *u += increment;
+struct PACKED(1) FDE {
+  uint32_t raw_length_;
+  uint32_t GetLength() {
+    return raw_length_ + sizeof(raw_length_);
+  }
+  uint32_t CIE_pointer;
+  uint32_t initial_location;
+  uint32_t address_range;
+  uint8_t instructions[0];
+};
+
+static FDE* NextFDE(FDE* frame) {
+  byte* fde_bytes = reinterpret_cast<byte*>(frame);
+  fde_bytes += frame->GetLength();
+  return reinterpret_cast<FDE*>(fde_bytes);
 }
 
-static void RoundAndClear(byte *image, uint32_t& offset, int pwr2) {
-  uint32_t mask = pwr2 - 1;
-  while (offset & mask) {
-    image[offset++] = 0;
+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];
+}
+
+// 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));
+  for (; frame < last_frame; frame = NextFDE(frame)) {
+    if (!IsFDE(frame)) {
+      return false;
+    }
+    frame->initial_location += text_start;
+  }
+  return true;
+}
+
+struct PACKED(1) DebugInfoHeader {
+  uint32_t unit_length;  // TODO 32-bit specific size
+  uint16_t version;
+  uint32_t debug_abbrev_offset;  // TODO 32-bit specific size
+  uint8_t  address_size;
+};
+
+// Returns -1 if it is variable length, which we will just disallow for now.
+static int32_t FormLength(uint32_t att) {
+  switch (att) {
+    case DW_FORM_data1:
+    case DW_FORM_flag:
+    case DW_FORM_flag_present:
+    case DW_FORM_ref1:
+      return 1;
+
+    case DW_FORM_data2:
+    case DW_FORM_ref2:
+      return 2;
+
+    case DW_FORM_addr:        // TODO 32-bit only
+    case DW_FORM_ref_addr:    // TODO 32-bit only
+    case DW_FORM_sec_offset:  // TODO 32-bit only
+    case DW_FORM_strp:        // TODO 32-bit only
+    case DW_FORM_data4:
+    case DW_FORM_ref4:
+      return 4;
+
+    case DW_FORM_data8:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_sig8:
+      return 8;
+
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+    case DW_FORM_exprloc:
+    case DW_FORM_indirect:
+    case DW_FORM_ref_udata:
+    case DW_FORM_sdata:
+    case DW_FORM_string:
+    case DW_FORM_udata:
+    default:
+      return -1;
   }
 }
 
-// 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
+class DebugTag {
+ public:
+  const uint32_t index_;
+  ~DebugTag() {}
+  // Creates a new tag and moves data pointer up to the start of the next one.
+  // nullptr means error.
+  static DebugTag* Create(const byte** data_pointer) {
+    const byte* data = *data_pointer;
+    uint32_t index = DecodeUnsignedLeb128(&data);
+    std::unique_ptr<DebugTag> tag(new DebugTag(index));
+    tag->size_ = static_cast<uint32_t>(
+        reinterpret_cast<uintptr_t>(data) - reinterpret_cast<uintptr_t>(*data_pointer));
+    // skip the abbrev
+    tag->tag_ = DecodeUnsignedLeb128(&data);
+    tag->has_child_ = (*data == 0);
+    data++;
+    while (true) {
+      uint32_t attr = DecodeUnsignedLeb128(&data);
+      uint32_t form = DecodeUnsignedLeb128(&data);
+      if (attr == 0 && form == 0) {
+        break;
+      } else if (attr == 0 || form == 0) {
+        // Bad abbrev.
+        return nullptr;
+      }
+      int32_t size = FormLength(form);
+      if (size == -1) {
+        return nullptr;
+      }
+      tag->AddAttribute(attr, static_cast<uint32_t>(size));
+    }
+    *data_pointer = data;
+    return tag.release();
+  }
+
+  uint32_t GetSize() const {
+    return size_;
+  }
+
+  bool HasChild() {
+    return has_child_;
+  }
+
+  uint32_t GetTagNumber() {
+    return tag_;
+  }
+
+  // Gets the offset of a particular attribute in this tag structure.
+  // Interpretation of the data is left to the consumer. 0 is returned if the
+  // tag does not contain the attribute.
+  uint32_t GetOffsetOf(uint32_t dwarf_attribute) const {
+    auto it = off_map_.find(dwarf_attribute);
+    if (it == off_map_.end()) {
+      return 0;
+    } else {
+      return it->second;
+    }
+  }
+
+  // Gets the size of attribute
+  uint32_t GetAttrSize(uint32_t dwarf_attribute) const {
+    auto it = size_map_.find(dwarf_attribute);
+    if (it == size_map_.end()) {
+      return 0;
+    } else {
+      return it->second;
+    }
+  }
+
+ private:
+  explicit DebugTag(uint32_t index) : index_(index) {}
+  void AddAttribute(uint32_t type, uint32_t attr_size) {
+    off_map_.insert(std::pair<uint32_t, uint32_t>(type, size_));
+    size_map_.insert(std::pair<uint32_t, uint32_t>(type, attr_size));
+    size_ += attr_size;
+  }
+  std::map<uint32_t, uint32_t> off_map_;
+  std::map<uint32_t, uint32_t> size_map_;
+  uint32_t size_;
+  uint32_t tag_;
+  bool has_child_;
+};
+
+class DebugAbbrev {
+ public:
+  ~DebugAbbrev() {}
+  static DebugAbbrev* Create(const byte* dbg_abbrev, size_t dbg_abbrev_size) {
+    std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev);
+    const byte* last = dbg_abbrev + dbg_abbrev_size;
+    while (dbg_abbrev < last) {
+      std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
+      if (tag.get() == nullptr) {
+        return nullptr;
+      } else {
+        abbrev->tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, abbrev->tag_list_.size()));
+        abbrev->tag_list_.push_back(std::move(tag));
+      }
+    }
+    return abbrev.release();
+  }
+
+  DebugTag* ReadTag(const byte* entry) {
+    uint32_t tag_num = DecodeUnsignedLeb128(&entry);
+    auto it = tags_.find(tag_num);
+    if (it == tags_.end()) {
+      return nullptr;
+    } else {
+      CHECK_GT(tag_list_.size(), it->second);
+      return tag_list_.at(it->second).get();
+    }
+  }
+
+ private:
+  DebugAbbrev() {}
+  std::map<uint32_t, uint32_t> tags_;
+  std::vector<std::unique_ptr<DebugTag>> tag_list_;
+};
+
+class DebugInfoIterator {
+ public:
+  static DebugInfoIterator* Create(DebugInfoHeader* header, size_t frame_size,
+                                   DebugAbbrev* abbrev) {
+    std::unique_ptr<DebugInfoIterator> iter(new DebugInfoIterator(header, frame_size, abbrev));
+    if (iter->GetCurrentTag() == nullptr) {
+      return nullptr;
+    } else {
+      return iter.release();
+    }
+  }
+  ~DebugInfoIterator() {}
+
+  // Moves to the next DIE. Returns false if at last entry.
+  // TODO Handle variable length attributes.
+  bool next() {
+    if (current_entry_ == nullptr || current_tag_ == nullptr) {
+      return false;
+    }
+    current_entry_ += current_tag_->GetSize();
+    if (current_entry_ >= last_entry_) {
+      current_entry_ = nullptr;
+      return false;
+    }
+    current_tag_ = abbrev_->ReadTag(current_entry_);
+    if (current_tag_ == nullptr) {
+      current_entry_ = nullptr;
+      return false;
+    } else {
+      return true;
+    }
+  }
+
+  const DebugTag* GetCurrentTag() {
+    return const_cast<DebugTag*>(current_tag_);
+  }
+  byte* GetPointerToField(uint8_t dwarf_field) {
+    if (current_tag_ == nullptr || current_entry_ == nullptr || current_entry_ >= last_entry_) {
+      return nullptr;
+    }
+    uint32_t off = current_tag_->GetOffsetOf(dwarf_field);
+    if (off == 0) {
+      // tag does not have that field.
+      return nullptr;
+    } else {
+      DCHECK_LT(off, current_tag_->GetSize());
+      return current_entry_ + off;
+    }
+  }
+
+ private:
+  DebugInfoIterator(DebugInfoHeader* header, size_t frame_size, DebugAbbrev* abbrev)
+      : abbrev_(abbrev),
+        last_entry_(reinterpret_cast<byte*>(header) + frame_size),
+        current_entry_(reinterpret_cast<byte*>(header) + sizeof(DebugInfoHeader)),
+        current_tag_(abbrev_->ReadTag(current_entry_)) {}
+  DebugAbbrev* abbrev_;
+  byte* last_entry_;
+  byte* current_entry_;
+  DebugTag* current_tag_;
+};
+
+static bool FixupDebugInfo(uint32_t text_start, DebugInfoIterator* iter) {
+  do {
+    if (iter->GetCurrentTag()->GetAttrSize(DW_AT_low_pc) != sizeof(int32_t) ||
+        iter->GetCurrentTag()->GetAttrSize(DW_AT_high_pc) != sizeof(int32_t)) {
+      return false;
+    }
+    uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_low_pc));
+    uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_high_pc));
+    if (PC_low != nullptr && PC_high != nullptr) {
+      *PC_low  += text_start;
+      *PC_high += text_start;
+    }
+  } while (iter->next());
+  return true;
+}
+
+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) {
+  std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(dbg_abbrev, dbg_abbrev_size));
+  if (abbrev.get() == nullptr) {
+    return false;
+  }
+  std::unique_ptr<DebugInfoIterator> iter(
+      DebugInfoIterator::Create(reinterpret_cast<DebugInfoHeader*>(dbg_info),
+                                dbg_info_size, abbrev.get()));
+  if (iter.get() == nullptr) {
+    return false;
+  }
+  return FixupDebugInfo(text_start, iter.get())
+      && FixupDebugFrame(text_start, dbg_frame, dbg_frame_size);
+}
 
 void ElfFile::GdbJITSupport() {
   // We only get here if we only are mapping the program header.
@@ -1000,18 +1313,25 @@
 
   // Well, we need the whole file to do this.
   std::string error_msg;
-  std::unique_ptr<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) {
+  // Make it MAP_PRIVATE so we can just give it to gdb if all the necessary
+  // sections are there.
+  std::unique_ptr<ElfFile> all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
+                                        MAP_PRIVATE, &error_msg));
+  if (all_ptr.get() == nullptr) {
     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")) {
+  ElfFile& all = *all_ptr;
+
+  // 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* 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 ||
+      debug_str == nullptr || text_sec == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
     return;
   }
 #ifdef __LP64__
@@ -1019,227 +1339,29 @@
     return;  // No ELF debug support in 64bit.
   }
 #endif
-  // This is not needed if we have no .text segment.
-  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 = PointerToLowMemUInt32(segments_[i]->Begin());
-      break;
-    }
-  }
-  if (text_start_addr == 0U) {
-    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();
+  // 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.
+  Elf32_Ehdr& 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);
+  text_sec->sh_type = SHT_NOBITS;
+  text_sec->sh_offset = 0;
 
-  // 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.
-  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);
+  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)) {
+    LOG(ERROR) << "Failed to load GDB data";
+    return;
   }
 
-  // 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);
+  jit_gdb_entry_ = CreateCodeEntry(all.Begin(), all.Size());
+  gdb_file_mapping_.reset(all_ptr.release());
 }
 
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 6650acd..496690b 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -41,6 +41,9 @@
 class ElfFile {
  public:
   static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg);
+  // Open with specific mmap flags, Always maps in the whole file, not just the
+  // program header sections.
+  static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
   ~ElfFile();
 
   // Load segments into memory based on PT_LOAD program headers
@@ -70,17 +73,19 @@
   Elf32_Word GetSectionHeaderNum() const;
   Elf32_Shdr& GetSectionHeader(Elf32_Word) const;
   Elf32_Shdr* FindSectionByType(Elf32_Word type) const;
+  Elf32_Shdr* FindSectionByName(const std::string& name) const;
 
   Elf32_Shdr& GetSectionNameStringSection() const;
 
   // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
   const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
+  const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
 
   static bool IsSymbolSectionType(Elf32_Word section_type);
   Elf32_Word GetSymbolNum(Elf32_Shdr&) const;
   Elf32_Sym& GetSymbol(Elf32_Word section_type, Elf32_Word i) const;
 
-  // Find symbol in specified table, returning NULL if it is not found.
+  // Find symbol in specified table, returning nullptr if it is not found.
   //
   // If build_map is true, builds a map to speed repeated access. The
   // map does not included untyped symbol values (aka STT_NOTYPE)
@@ -98,11 +103,11 @@
                                const std::string& symbol_name,
                                bool build_map);
 
-  // Lookup a string given string section and offset. Returns NULL for
+  // Lookup a string given string section and offset. Returns nullptr for
   // special 0 offset.
   const char* GetString(Elf32_Shdr&, Elf32_Word) const;
 
-  // Lookup a string by section type. Returns NULL for special 0 offset.
+  // Lookup a string by section type. Returns nullptr for special 0 offset.
   const char* GetString(Elf32_Word section_type, Elf32_Word) const;
 
   Elf32_Word GetDynamicNum() const;
@@ -125,7 +130,7 @@
  private:
   ElfFile(File* file, bool writable, bool program_header_only);
 
-  bool Setup(std::string* error_msg);
+  bool Setup(int prot, int flags, std::string* error_msg);
 
   bool SetMap(MemMap* map, std::string* error_msg);
 
@@ -181,9 +186,8 @@
   // Support for GDB JIT
   byte* jit_elf_image_;
   JITCodeEntry* jit_gdb_entry_;
+  std::unique_ptr<ElfFile> gdb_file_mapping_;
   void GdbJITSupport();
-  // Is this an OAT file with debug information in it?
-  static constexpr uint32_t kExpectedSectionsInOATFile = 12;
 };
 
 }  // namespace art