diff options
-rw-r--r-- | compiler/elf_writer.cc | 2 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 42 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 2 | ||||
-rw-r--r-- | runtime/dwarf.h | 662 | ||||
-rw-r--r-- | runtime/elf_file.cc | 712 | ||||
-rw-r--r-- | runtime/elf_file.h | 16 |
6 files changed, 1101 insertions, 335 deletions
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 @@ void ElfWriter::GetOatElfInformation(File* file, 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 @@ bool ElfWriterQuick::ElfBuilder::Write() { 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 @@ void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Wor 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 @@ std::vector<Elf32_Word> ElfWriterQuick::ElfSymtabBuilder::GenerateHashContents() // 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 ElfWriterQuick::Write(OatWriter* oat_writer, 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 @@ static void PushHalf(std::vector<uint8_t>*buf, int data) { 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 @@ static int dex2oat(int argc, char** argv) { 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 @@ ElfFile::ElfFile(File* file, bool writable, bool program_header_only) : 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 @@ bool ElfFile::Setup(std::string* error_msg) { // 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 @@ ElfFile::~ElfFile() { } 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 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { 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 @@ Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const { } 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 @@ const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const { } 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 @@ const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const { } Elf32_Word* ElfFile::GetHashSectionStart() const { - CHECK(hash_section_start_ != NULL); + CHECK(hash_section_start_ != nullptr); return hash_section_start_; } @@ -516,7 +526,7 @@ Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const { return &program_header; } } - return NULL; + return nullptr; } Elf32_Word ElfFile::GetSectionHeaderNum() const { @@ -543,7 +553,7 @@ Elf32_Shdr* ElfFile::FindSectionByType(Elf32_Word type) const { return §ion_header; } } - return NULL; + return nullptr; } // from bionic @@ -565,6 +575,15 @@ Elf32_Shdr& ElfFile::GetSectionNameStringSection() const { } 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 @@ const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) co 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 @@ ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) { } default: { LOG(FATAL) << section_type; - return NULL; + return nullptr; } } } @@ -618,12 +637,12 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, 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 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, 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 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, } } } - 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 @@ const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const { 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 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { 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 @@ bool ElfFile::ValidPointer(const byte* start) const { 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; } -// 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 +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; + } +} + +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 @@ void ElfFile::GdbJITSupport() { // 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 @@ void ElfFile::GdbJITSupport() { 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); - - // 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 = §ion_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); - } - - // 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); - } + text_sec->sh_type = SHT_NOBITS; + text_sec->sh_offset = 0; + + 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; } - // 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 @@ extern "C" { 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 @@ class ElfFile { 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 @@ class ElfFile { 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 @@ class ElfFile { 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 @@ class ElfFile { // 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 |