Fixed gdb support and added some ElfFile functions

Fixed gdb support so that it would continue working even when debug
symbols or other sections are included in the elf file. Also made it
actually read parts of the DWARF information so it should work even if
there are minor changes to how and where DWARF information is written
out.

Added a dwarf.h file with the dwarf constants.

Added a FindSectionByName function, a FindDynamicSymbol function, and
the ability to specify the mmap protection and flags directly if we are
mapping in the whole file.

Modified elf_writer_quick.cc to use the dwarf constants from dwarf.h.

Change-Id: I09e15c425fab252b331a2e4719863552e8b6b137
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