From 5389aa19033153c09556d1362a8b8a56abccb8f5 Mon Sep 17 00:00:00 2001 From: Vladimir Chtchetkine Date: Tue, 16 Feb 2010 10:38:35 -0800 Subject: Merge memory checking from sandbox Change-id: Ibce845d0 --- elff/dwarf.h | 1055 ++++++++++++++++++++++++++++++++++++++++++++ elff/dwarf_cu.cc | 758 +++++++++++++++++++++++++++++++ elff/dwarf_cu.h | 513 +++++++++++++++++++++ elff/dwarf_defs.h | 1000 +++++++++++++++++++++++++++++++++++++++++ elff/dwarf_die.cc | 269 +++++++++++ elff/dwarf_die.h | 202 +++++++++ elff/dwarf_utils.cc | 313 +++++++++++++ elff/dwarf_utils.h | 63 +++ elff/elf.h | 299 +++++++++++++ elff/elf_alloc.cc | 62 +++ elff/elf_alloc.h | 160 +++++++ elff/elf_defs.h | 135 ++++++ elff/elf_file.cc | 539 ++++++++++++++++++++++ elff/elf_file.h | 621 ++++++++++++++++++++++++++ elff/elf_mapped_section.cc | 95 ++++ elff/elf_mapped_section.h | 88 ++++ elff/elff-common.h | 59 +++ elff/elff_api.cc | 84 ++++ elff/elff_api.h | 173 ++++++++ 19 files changed, 6488 insertions(+) create mode 100644 elff/dwarf.h create mode 100644 elff/dwarf_cu.cc create mode 100644 elff/dwarf_cu.h create mode 100644 elff/dwarf_defs.h create mode 100644 elff/dwarf_die.cc create mode 100644 elff/dwarf_die.h create mode 100644 elff/dwarf_utils.cc create mode 100644 elff/dwarf_utils.h create mode 100644 elff/elf.h create mode 100644 elff/elf_alloc.cc create mode 100644 elff/elf_alloc.h create mode 100644 elff/elf_defs.h create mode 100644 elff/elf_file.cc create mode 100644 elff/elf_file.h create mode 100644 elff/elf_mapped_section.cc create mode 100644 elff/elf_mapped_section.h create mode 100644 elff/elff-common.h create mode 100644 elff/elff_api.cc create mode 100644 elff/elff_api.h (limited to 'elff') diff --git a/elff/dwarf.h b/elff/dwarf.h new file mode 100644 index 0000000..31ef714 --- /dev/null +++ b/elff/dwarf.h @@ -0,0 +1,1055 @@ +/* + Copyright (C) 2000,2001,2003,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2002,2007 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2007-2009 David Anderson. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, + Mountain View, CA 94043, or: + + http://www.sgi.com + + For further information regarding this notice, see: + + http://oss.sgi.com/projects/GenInfo/NoticeExplan + +*/ + + +#ifndef __DWARF_H +#define __DWARF_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + dwarf.h DWARF debugging information values + $Revision: 1.41 $ $Date: 2006/04/17 00:09:56 $ + + The comment "DWARF3" appears where there are + new entries from DWARF3 as of 2004, "DWARF3f" + where there are new entries as of the November 2005 + public review document and other comments apply + where extension entries appear. + + Extensions part of DWARF4 are marked DWARF4. + + A few extension names have omitted the 'vendor id' + (See chapter 7, "Vendor Extensibility"). Please + always use a 'vendor id' string in extension names. + + Vendors should use a vendor string in names and + whereever possible avoid duplicating values used by + other vendor extensions + +*/ + + +#define DW_TAG_array_type 0x01 +#define DW_TAG_class_type 0x02 +#define DW_TAG_entry_point 0x03 +#define DW_TAG_enumeration_type 0x04 +#define DW_TAG_formal_parameter 0x05 +#define DW_TAG_imported_declaration 0x08 +#define DW_TAG_label 0x0a +#define DW_TAG_lexical_block 0x0b +#define DW_TAG_member 0x0d +#define DW_TAG_pointer_type 0x0f +#define DW_TAG_reference_type 0x10 +#define DW_TAG_compile_unit 0x11 +#define DW_TAG_string_type 0x12 +#define DW_TAG_structure_type 0x13 +#define DW_TAG_subroutine_type 0x15 +#define DW_TAG_typedef 0x16 +#define DW_TAG_union_type 0x17 +#define DW_TAG_unspecified_parameters 0x18 +#define DW_TAG_variant 0x19 +#define DW_TAG_common_block 0x1a +#define DW_TAG_common_inclusion 0x1b +#define DW_TAG_inheritance 0x1c +#define DW_TAG_inlined_subroutine 0x1d +#define DW_TAG_module 0x1e +#define DW_TAG_ptr_to_member_type 0x1f +#define DW_TAG_set_type 0x20 +#define DW_TAG_subrange_type 0x21 +#define DW_TAG_with_stmt 0x22 +#define DW_TAG_access_declaration 0x23 +#define DW_TAG_base_type 0x24 +#define DW_TAG_catch_block 0x25 +#define DW_TAG_const_type 0x26 +#define DW_TAG_constant 0x27 +#define DW_TAG_enumerator 0x28 +#define DW_TAG_file_type 0x29 +#define DW_TAG_friend 0x2a +#define DW_TAG_namelist 0x2b + /* Early releases of this header had the following + misspelled with a trailing 's' */ +#define DW_TAG_namelist_item 0x2c /* DWARF3/2 spelling */ +#define DW_TAG_namelist_items 0x2c /* SGI misspelling/typo */ +#define DW_TAG_packed_type 0x2d +#define DW_TAG_subprogram 0x2e + /* The DWARF2 document had two spellings of the following + two TAGs, DWARF3 specifies the longer spelling. */ +#define DW_TAG_template_type_parameter 0x2f /* DWARF3/2 spelling*/ +#define DW_TAG_template_type_param 0x2f /* DWARF2 spelling*/ +#define DW_TAG_template_value_parameter 0x30 /* DWARF3/2 spelling*/ +#define DW_TAG_template_value_param 0x30 /* DWARF2 spelling*/ +#define DW_TAG_thrown_type 0x31 +#define DW_TAG_try_block 0x32 +#define DW_TAG_variant_part 0x33 +#define DW_TAG_variable 0x34 +#define DW_TAG_volatile_type 0x35 +#define DW_TAG_dwarf_procedure 0x36 /* DWARF3 */ +#define DW_TAG_restrict_type 0x37 /* DWARF3 */ +#define DW_TAG_interface_type 0x38 /* DWARF3 */ +#define DW_TAG_namespace 0x39 /* DWARF3 */ +#define DW_TAG_imported_module 0x3a /* DWARF3 */ +#define DW_TAG_unspecified_type 0x3b /* DWARF3 */ +#define DW_TAG_partial_unit 0x3c /* DWARF3 */ +#define DW_TAG_imported_unit 0x3d /* DWARF3 */ + /* Do not use DW_TAG_mutable_type */ +#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */ +#define DW_TAG_condition 0x3f /* DWARF3f */ +#define DW_TAG_shared_type 0x40 /* DWARF3f */ +#define DW_TAG_type_unit 0x41 /* DWARF4 */ +#define DW_TAG_rvalue_reference_type 0x42 /* DWARF4 */ +#define DW_TAG_template_alias 0x43 /* DWARF4 */ +#define DW_TAG_lo_user 0x4080 + +#define DW_TAG_MIPS_loop 0x4081 + +/* HP extensions: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz */ +#define DW_TAG_HP_array_descriptor 0x4090 /* HP */ + +/* GNU extensions. The first 3 missing the GNU_. */ +#define DW_TAG_format_label 0x4101 /* GNU. Fortran. */ +#define DW_TAG_function_template 0x4102 /* GNU. For C++ */ +#define DW_TAG_class_template 0x4103 /* GNU. For C++ */ +#define DW_TAG_GNU_BINCL 0x4104 /* GNU */ +#define DW_TAG_GNU_EINCL 0x4105 /* GNU */ + +/* ALTIUM extensions */ + /* DSP-C/Starcore __circ qualifier */ +#define DW_TAG_ALTIUM_circ_type 0x5101 /* ALTIUM */ + /* Starcore __mwa_circ qualifier */ +#define DW_TAG_ALTIUM_mwa_circ_type 0x5102 /* ALTIUM */ + /* Starcore __rev_carry qualifier */ +#define DW_TAG_ALTIUM_rev_carry_type 0x5103 /* ALTIUM */ + /* M16 __rom qualifier */ +#define DW_TAG_ALTIUM_rom 0x5111 /* ALTIUM */ + +/* The following 3 are extensions to support UPC */ +#define DW_TAG_upc_shared_type 0x8765 /* UPC */ +#define DW_TAG_upc_strict_type 0x8766 /* UPC */ +#define DW_TAG_upc_relaxed_type 0x8767 /* UPC */ + +/* PGI (STMicroelectronics) extensions. */ +#define DW_TAG_PGI_kanji_type 0xa000 /* PGI */ +#define DW_TAG_PGI_interface_block 0xa020 /* PGI */ +/* The following are SUN extensions */ +#define DW_TAG_SUN_function_template 0x4201 /* SUN */ +#define DW_TAG_SUN_class_template 0x4202 /* SUN */ +#define DW_TAG_SUN_struct_template 0x4203 /* SUN */ +#define DW_TAG_SUN_union_template 0x4204 /* SUN */ +#define DW_TAG_SUN_indirect_inheritance 0x4205 /* SUN */ +#define DW_TAG_SUN_codeflags 0x4206 /* SUN */ +#define DW_TAG_SUN_memop_info 0x4207 /* SUN */ +#define DW_TAG_SUN_omp_child_func 0x4208 /* SUN */ +#define DW_TAG_SUN_rtti_descriptor 0x4209 /* SUN */ +#define DW_TAG_SUN_dtor_info 0x420a /* SUN */ +#define DW_TAG_SUN_dtor 0x420b /* SUN */ +#define DW_TAG_SUN_f90_interface 0x420c /* SUN */ +#define DW_TAG_SUN_fortran_vax_structure 0x420d /* SUN */ +#define DW_TAG_SUN_hi 0x42ff /* SUN */ + + +#define DW_TAG_hi_user 0xffff + +#define DW_children_no 0 +#define DW_children_yes 1 + + + +#define DW_FORM_addr 0x01 +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_data8 0x07 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 +#define DW_FORM_sec_offset 0x17 /* DWARF4 */ +#define DW_FORM_exprloc 0x18 /* DWARF4 */ +#define DW_FORM_flag_present 0x19 /* DWARF4 */ +#define DW_FORM_ref_sig8 0x20 /* DWARF4 */ + +#define DW_AT_sibling 0x01 +#define DW_AT_location 0x02 +#define DW_AT_name 0x03 +#define DW_AT_ordering 0x09 +#define DW_AT_subscr_data 0x0a +#define DW_AT_byte_size 0x0b +#define DW_AT_bit_offset 0x0c +#define DW_AT_bit_size 0x0d +#define DW_AT_element_list 0x0f +#define DW_AT_stmt_list 0x10 +#define DW_AT_low_pc 0x11 +#define DW_AT_high_pc 0x12 +#define DW_AT_language 0x13 +#define DW_AT_member 0x14 +#define DW_AT_discr 0x15 +#define DW_AT_discr_value 0x16 +#define DW_AT_visibility 0x17 +#define DW_AT_import 0x18 +#define DW_AT_string_length 0x19 +#define DW_AT_common_reference 0x1a +#define DW_AT_comp_dir 0x1b +#define DW_AT_const_value 0x1c +#define DW_AT_containing_type 0x1d +#define DW_AT_default_value 0x1e +#define DW_AT_inline 0x20 +#define DW_AT_is_optional 0x21 +#define DW_AT_lower_bound 0x22 +#define DW_AT_producer 0x25 +#define DW_AT_prototyped 0x27 +#define DW_AT_return_addr 0x2a +#define DW_AT_start_scope 0x2c +#define DW_AT_bit_stride 0x2e /* DWARF3 name */ +#define DW_AT_stride_size 0x2e /* DWARF2 name */ +#define DW_AT_upper_bound 0x2f +#define DW_AT_abstract_origin 0x31 +#define DW_AT_accessibility 0x32 +#define DW_AT_address_class 0x33 +#define DW_AT_artificial 0x34 +#define DW_AT_base_types 0x35 +#define DW_AT_calling_convention 0x36 +#define DW_AT_count 0x37 +#define DW_AT_data_member_location 0x38 +#define DW_AT_decl_column 0x39 +#define DW_AT_decl_file 0x3a +#define DW_AT_decl_line 0x3b +#define DW_AT_declaration 0x3c +#define DW_AT_discr_list 0x3d +#define DW_AT_encoding 0x3e +#define DW_AT_external 0x3f +#define DW_AT_frame_base 0x40 +#define DW_AT_friend 0x41 +#define DW_AT_identifier_case 0x42 +#define DW_AT_macro_info 0x43 +#define DW_AT_namelist_item 0x44 +#define DW_AT_priority 0x45 +#define DW_AT_segment 0x46 +#define DW_AT_specification 0x47 +#define DW_AT_static_link 0x48 +#define DW_AT_type 0x49 +#define DW_AT_use_location 0x4a +#define DW_AT_variable_parameter 0x4b +#define DW_AT_virtuality 0x4c +#define DW_AT_vtable_elem_location 0x4d +#define DW_AT_allocated 0x4e /* DWARF3 */ +#define DW_AT_associated 0x4f /* DWARF3 */ +#define DW_AT_data_location 0x50 /* DWARF3 */ +#define DW_AT_byte_stride 0x51 /* DWARF3f */ +#define DW_AT_stride 0x51 /* DWARF3 (do not use) */ +#define DW_AT_entry_pc 0x52 /* DWARF3 */ +#define DW_AT_use_UTF8 0x53 /* DWARF3 */ +#define DW_AT_extension 0x54 /* DWARF3 */ +#define DW_AT_ranges 0x55 /* DWARF3 */ +#define DW_AT_trampoline 0x56 /* DWARF3 */ +#define DW_AT_call_column 0x57 /* DWARF3 */ +#define DW_AT_call_file 0x58 /* DWARF3 */ +#define DW_AT_call_line 0x59 /* DWARF3 */ +#define DW_AT_description 0x5a /* DWARF3 */ +#define DW_AT_binary_scale 0x5b /* DWARF3f */ +#define DW_AT_decimal_scale 0x5c /* DWARF3f */ +#define DW_AT_small 0x5d /* DWARF3f */ +#define DW_AT_decimal_sign 0x5e /* DWARF3f */ +#define DW_AT_digit_count 0x5f /* DWARF3f */ +#define DW_AT_picture_string 0x60 /* DWARF3f */ +#define DW_AT_mutable 0x61 /* DWARF3f */ +#define DW_AT_threads_scaled 0x62 /* DWARF3f */ +#define DW_AT_explicit 0x63 /* DWARF3f */ +#define DW_AT_object_pointer 0x64 /* DWARF3f */ +#define DW_AT_endianity 0x65 /* DWARF3f */ +#define DW_AT_elemental 0x66 /* DWARF3f */ +#define DW_AT_pure 0x67 /* DWARF3f */ +#define DW_AT_recursive 0x68 /* DWARF3f */ +#define DW_AT_signature 0x69 /* DWARF4 */ +#define DW_AT_main_subprogram 0x6a /* DWARF4 */ +#define DW_AT_data_bit_offset 0x6b /* DWARF4 */ +#define DW_AT_const_expr 0x6c /* DWARF4 */ +#define DW_AT_enum_class 0x6d /* DWARF4 */ +#define DW_AT_linkage_name 0x6e /* DWARF4 */ + +/* In extensions, we attempt to include the vendor extension + in the name even when the vendor leaves it out. */ + +/* HP extensions. */ +#define DW_AT_HP_block_index 0x2000 /* HP */ + +/* Follows extension so dwarfdump prints the most-likely-useful name. */ +#define DW_AT_lo_user 0x2000 + +#define DW_AT_MIPS_fde 0x2001 /* MIPS/SGI */ +#define DW_AT_MIPS_loop_begin 0x2002 /* MIPS/SGI */ +#define DW_AT_MIPS_tail_loop_begin 0x2003 /* MIPS/SGI */ +#define DW_AT_MIPS_epilog_begin 0x2004 /* MIPS/SGI */ +#define DW_AT_MIPS_loop_unroll_factor 0x2005 /* MIPS/SGI */ +#define DW_AT_MIPS_software_pipeline_depth 0x2006 /* MIPS/SGI */ +#define DW_AT_MIPS_linkage_name 0x2007 /* MIPS/SGI, GNU, and others.*/ +#define DW_AT_MIPS_stride 0x2008 /* MIPS/SGI */ +#define DW_AT_MIPS_abstract_name 0x2009 /* MIPS/SGI */ +#define DW_AT_MIPS_clone_origin 0x200a /* MIPS/SGI */ +#define DW_AT_MIPS_has_inlines 0x200b /* MIPS/SGI */ +#define DW_AT_MIPS_stride_byte 0x200c /* MIPS/SGI */ +#define DW_AT_MIPS_stride_elem 0x200d /* MIPS/SGI */ +#define DW_AT_MIPS_ptr_dopetype 0x200e /* MIPS/SGI */ +#define DW_AT_MIPS_allocatable_dopetype 0x200f /* MIPS/SGI */ +#define DW_AT_MIPS_assumed_shape_dopetype 0x2010 /* MIPS/SGI */ +#define DW_AT_MIPS_assumed_size 0x2011 /* MIPS/SGI */ + +/* HP extensions. */ +#define DW_AT_HP_unmodifiable 0x2001 /* conflict: MIPS */ +#define DW_AT_HP_actuals_stmt_list 0x2010 /* conflict: MIPS */ +#define DW_AT_HP_proc_per_section 0x2011 /* conflict: MIPS */ +#define DW_AT_HP_raw_data_ptr 0x2012 /* HP */ +#define DW_AT_HP_pass_by_reference 0x2013 /* HP */ +#define DW_AT_HP_opt_level 0x2014 /* HP */ +#define DW_AT_HP_prof_version_id 0x2015 /* HP */ +#define DW_AT_HP_opt_flags 0x2016 /* HP */ +#define DW_AT_HP_cold_region_low_pc 0x2017 /* HP */ +#define DW_AT_HP_cold_region_high_pc 0x2018 /* HP */ +#define DW_AT_HP_all_variables_modifiable 0x2019 /* HP */ +#define DW_AT_HP_linkage_name 0x201a /* HP */ +#define DW_AT_HP_prof_flags 0x201b /* HP */ + +#define DW_AT_CPQ_discontig_ranges 0x2001 /* COMPAQ/HP */ +#define DW_AT_CPQ_semantic_events 0x2002 /* COMPAQ/HP */ +#define DW_AT_CPQ_split_lifetimes_var 0x2003 /* COMPAQ/HP */ +#define DW_AT_CPQ_split_lifetimes_rtn 0x2004 /* COMPAQ/HP */ +#define DW_AT_CPQ_prologue_length 0x2005 /* COMPAQ/HP */ + +#define DW_AT_INTEL_other_endian 0x2026 /* Intel, 1 if byte swapped. */ + +/* GNU extensions. */ +#define DW_AT_sf_names 0x2101 /* GNU */ +#define DW_AT_src_info 0x2102 /* GNU */ +#define DW_AT_mac_info 0x2103 /* GNU */ +#define DW_AT_src_coords 0x2104 /* GNU */ +#define DW_AT_body_begin 0x2105 /* GNU */ +#define DW_AT_body_end 0x2106 /* GNU */ +#define DW_AT_GNU_vector 0x2107 /* GNU */ + +/* ALTIUM extension: ALTIUM Compliant location lists (flag) */ +#define DW_AT_ALTIUM_loclist 0x2300 /* ALTIUM */ + +/* Sun extensions */ +#define DW_AT_SUN_template 0x2201 /* SUN */ +#define DW_AT_VMS_rtnbeg_pd_address 0x2201 /* VMS */ +#define DW_AT_SUN_alignment 0x2202 /* SUN */ +#define DW_AT_SUN_vtable 0x2203 /* SUN */ +#define DW_AT_SUN_count_guarantee 0x2204 /* SUN */ +#define DW_AT_SUN_command_line 0x2205 /* SUN */ +#define DW_AT_SUN_vbase 0x2206 /* SUN */ +#define DW_AT_SUN_compile_options 0x2207 /* SUN */ +#define DW_AT_SUN_language 0x2208 /* SUN */ +#define DW_AT_SUN_browser_file 0x2209 /* SUN */ +#define DW_AT_SUN_vtable_abi 0x2210 /* SUN */ +#define DW_AT_SUN_func_offsets 0x2211 /* SUN */ +#define DW_AT_SUN_cf_kind 0x2212 /* SUN */ +#define DW_AT_SUN_vtable_index 0x2213 /* SUN */ +#define DW_AT_SUN_omp_tpriv_addr 0x2214 /* SUN */ +#define DW_AT_SUN_omp_child_func 0x2215 /* SUN */ +#define DW_AT_SUN_func_offset 0x2216 /* SUN */ +#define DW_AT_SUN_memop_type_ref 0x2217 /* SUN */ +#define DW_AT_SUN_profile_id 0x2218 /* SUN */ +#define DW_AT_SUN_memop_signature 0x2219 /* SUN */ +#define DW_AT_SUN_obj_dir 0x2220 /* SUN */ +#define DW_AT_SUN_obj_file 0x2221 /* SUN */ +#define DW_AT_SUN_original_name 0x2222 /* SUN */ +#define DW_AT_SUN_hwcprof_signature 0x2223 /* SUN */ +#define DW_AT_SUN_amd64_parmdump 0x2224 /* SUN */ +#define DW_AT_SUN_part_link_name 0x2225 /* SUN */ +#define DW_AT_SUN_link_name 0x2226 /* SUN */ +#define DW_AT_SUN_pass_with_const 0x2227 /* SUN */ +#define DW_AT_SUN_return_with_const 0x2228 /* SUN */ +#define DW_AT_SUN_import_by_name 0x2229 /* SUN */ +#define DW_AT_SUN_f90_pointer 0x222a /* SUN */ +#define DW_AT_SUN_pass_by_ref 0x222b /* SUN */ +#define DW_AT_SUN_f90_allocatable 0x222c /* SUN */ +#define DW_AT_SUN_f90_assumed_shape_array 0x222d /* SUN */ +#define DW_AT_SUN_c_vla 0x222e /* SUN */ +#define DW_AT_SUN_return_value_ptr 0x2230 /* SUN */ +#define DW_AT_SUN_dtor_start 0x2231 /* SUN */ +#define DW_AT_SUN_dtor_length 0x2232 /* SUN */ +#define DW_AT_SUN_dtor_state_initial 0x2233 /* SUN */ +#define DW_AT_SUN_dtor_state_final 0x2234 /* SUN */ +#define DW_AT_SUN_dtor_state_deltas 0x2235 /* SUN */ +#define DW_AT_SUN_import_by_lname 0x2236 /* SUN */ +#define DW_AT_SUN_f90_use_only 0x2237 /* SUN */ +#define DW_AT_SUN_namelist_spec 0x2238 /* SUN */ +#define DW_AT_SUN_is_omp_child_func 0x2239 /* SUN */ +#define DW_AT_SUN_fortran_main_alias 0x223a /* SUN */ +#define DW_AT_SUN_fortran_based 0x223b /* SUN */ + +/* UPC extension */ +#define DW_AT_upc_threads_scaled 0x3210 /* UPC */ + +/* PGI (STMicroelectronics) extensions. */ +#define DW_AT_PGI_lbase 0x3a00 /* PGI. Block, constant, reference. This attribute is an ASTPLAB extension used to describe the array local base. */ +#define DW_AT_PGI_soffset 0x3a01 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the section offset, or the offset to the first element in the dimension. */ +#define DW_AT_PGI_lstride 0x3a02 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the linear stride or the distance between elements in the dimension. */ + +/* Apple Extensions for closures */ +#define DW_AT_APPLE_closure 0x3fe4 /* Apple */ +/* Apple Extensions for Objective-C runtime info */ +#define DW_AT_APPLE_major_runtime_vers 0x3fe5 /* Apple */ +#define DW_AT_APPLE_runtime_class 0x3fe6 /* Apple */ + + +#define DW_AT_hi_user 0x3fff + +#define DW_OP_addr 0x03 +#define DW_OP_deref 0x06 +#define DW_OP_const1u 0x08 +#define DW_OP_const1s 0x09 +#define DW_OP_const2u 0x0a +#define DW_OP_const2s 0x0b +#define DW_OP_const4u 0x0c +#define DW_OP_const4s 0x0d +#define DW_OP_const8u 0x0e +#define DW_OP_const8s 0x0f +#define DW_OP_constu 0x10 +#define DW_OP_consts 0x11 +#define DW_OP_dup 0x12 +#define DW_OP_drop 0x13 +#define DW_OP_over 0x14 +#define DW_OP_pick 0x15 +#define DW_OP_swap 0x16 +#define DW_OP_rot 0x17 +#define DW_OP_xderef 0x18 +#define DW_OP_abs 0x19 +#define DW_OP_and 0x1a +#define DW_OP_div 0x1b +#define DW_OP_minus 0x1c +#define DW_OP_mod 0x1d +#define DW_OP_mul 0x1e +#define DW_OP_neg 0x1f +#define DW_OP_not 0x20 +#define DW_OP_or 0x21 +#define DW_OP_plus 0x22 +#define DW_OP_plus_uconst 0x23 +#define DW_OP_shl 0x24 +#define DW_OP_shr 0x25 +#define DW_OP_shra 0x26 +#define DW_OP_xor 0x27 +#define DW_OP_bra 0x28 +#define DW_OP_eq 0x29 +#define DW_OP_ge 0x2a +#define DW_OP_gt 0x2b +#define DW_OP_le 0x2c +#define DW_OP_lt 0x2d +#define DW_OP_ne 0x2e +#define DW_OP_skip 0x2f +#define DW_OP_lit0 0x30 +#define DW_OP_lit1 0x31 +#define DW_OP_lit2 0x32 +#define DW_OP_lit3 0x33 +#define DW_OP_lit4 0x34 +#define DW_OP_lit5 0x35 +#define DW_OP_lit6 0x36 +#define DW_OP_lit7 0x37 +#define DW_OP_lit8 0x38 +#define DW_OP_lit9 0x39 +#define DW_OP_lit10 0x3a +#define DW_OP_lit11 0x3b +#define DW_OP_lit12 0x3c +#define DW_OP_lit13 0x3d +#define DW_OP_lit14 0x3e +#define DW_OP_lit15 0x3f +#define DW_OP_lit16 0x40 +#define DW_OP_lit17 0x41 +#define DW_OP_lit18 0x42 +#define DW_OP_lit19 0x43 +#define DW_OP_lit20 0x44 +#define DW_OP_lit21 0x45 +#define DW_OP_lit22 0x46 +#define DW_OP_lit23 0x47 +#define DW_OP_lit24 0x48 +#define DW_OP_lit25 0x49 +#define DW_OP_lit26 0x4a +#define DW_OP_lit27 0x4b +#define DW_OP_lit28 0x4c +#define DW_OP_lit29 0x4d +#define DW_OP_lit30 0x4e +#define DW_OP_lit31 0x4f +#define DW_OP_reg0 0x50 +#define DW_OP_reg1 0x51 +#define DW_OP_reg2 0x52 +#define DW_OP_reg3 0x53 +#define DW_OP_reg4 0x54 +#define DW_OP_reg5 0x55 +#define DW_OP_reg6 0x56 +#define DW_OP_reg7 0x57 +#define DW_OP_reg8 0x58 +#define DW_OP_reg9 0x59 +#define DW_OP_reg10 0x5a +#define DW_OP_reg11 0x5b +#define DW_OP_reg12 0x5c +#define DW_OP_reg13 0x5d +#define DW_OP_reg14 0x5e +#define DW_OP_reg15 0x5f +#define DW_OP_reg16 0x60 +#define DW_OP_reg17 0x61 +#define DW_OP_reg18 0x62 +#define DW_OP_reg19 0x63 +#define DW_OP_reg20 0x64 +#define DW_OP_reg21 0x65 +#define DW_OP_reg22 0x66 +#define DW_OP_reg23 0x67 +#define DW_OP_reg24 0x68 +#define DW_OP_reg25 0x69 +#define DW_OP_reg26 0x6a +#define DW_OP_reg27 0x6b +#define DW_OP_reg28 0x6c +#define DW_OP_reg29 0x6d +#define DW_OP_reg30 0x6e +#define DW_OP_reg31 0x6f +#define DW_OP_breg0 0x70 +#define DW_OP_breg1 0x71 +#define DW_OP_breg2 0x72 +#define DW_OP_breg3 0x73 +#define DW_OP_breg4 0x74 +#define DW_OP_breg5 0x75 +#define DW_OP_breg6 0x76 +#define DW_OP_breg7 0x77 +#define DW_OP_breg8 0x78 +#define DW_OP_breg9 0x79 +#define DW_OP_breg10 0x7a +#define DW_OP_breg11 0x7b +#define DW_OP_breg12 0x7c +#define DW_OP_breg13 0x7d +#define DW_OP_breg14 0x7e +#define DW_OP_breg15 0x7f +#define DW_OP_breg16 0x80 +#define DW_OP_breg17 0x81 +#define DW_OP_breg18 0x82 +#define DW_OP_breg19 0x83 +#define DW_OP_breg20 0x84 +#define DW_OP_breg21 0x85 +#define DW_OP_breg22 0x86 +#define DW_OP_breg23 0x87 +#define DW_OP_breg24 0x88 +#define DW_OP_breg25 0x89 +#define DW_OP_breg26 0x8a +#define DW_OP_breg27 0x8b +#define DW_OP_breg28 0x8c +#define DW_OP_breg29 0x8d +#define DW_OP_breg30 0x8e +#define DW_OP_breg31 0x8f +#define DW_OP_regx 0x90 +#define DW_OP_fbreg 0x91 +#define DW_OP_bregx 0x92 +#define DW_OP_piece 0x93 +#define DW_OP_deref_size 0x94 +#define DW_OP_xderef_size 0x95 +#define DW_OP_nop 0x96 +#define DW_OP_push_object_address 0x97 /* DWARF3 */ +#define DW_OP_call2 0x98 /* DWARF3 */ +#define DW_OP_call4 0x99 /* DWARF3 */ +#define DW_OP_call_ref 0x9a /* DWARF3 */ +#define DW_OP_form_tls_address 0x9b /* DWARF3f */ +#define DW_OP_call_frame_cfa 0x9c /* DWARF3f */ +#define DW_OP_bit_piece 0x9d /* DWARF3f */ +#define DW_OP_implicit_value 0x9e /* DWARF4 */ +#define DW_OP_stack_value 0x9f /* DWARF4 */ + + + /* GNU extensions. */ +#define DW_OP_GNU_push_tls_address 0xe0 /* GNU */ + +/* Follows extension so dwarfdump prints the most-likely-useful name. */ +#define DW_OP_lo_user 0xe0 + + /* HP extensions. */ +#define DW_OP_HP_unknown 0xe0 /* HP conflict: GNU */ +#define DW_OP_HP_is_value 0xe1 /* HP */ +#define DW_OP_HP_fltconst4 0xe2 /* HP */ +#define DW_OP_HP_fltconst8 0xe3 /* HP */ +#define DW_OP_HP_mod_range 0xe4 /* HP */ +#define DW_OP_HP_unmod_range 0xe5 /* HP */ +#define DW_OP_HP_tls 0xe6 /* HP */ + +#define DW_OP_INTEL_bit_piece 0xe8 /* Intel: made obsolete by DW_OP_bit_piece above. */ + + + /* Apple extension. */ +#define DW_OP_APPLE_uninit 0xf0 /* Apple */ + +#define DW_OP_hi_user 0xff + +#define DW_ATE_address 0x1 +#define DW_ATE_boolean 0x2 +#define DW_ATE_complex_float 0x3 +#define DW_ATE_float 0x4 +#define DW_ATE_signed 0x5 +#define DW_ATE_signed_char 0x6 +#define DW_ATE_unsigned 0x7 +#define DW_ATE_unsigned_char 0x8 +#define DW_ATE_imaginary_float 0x9 /* DWARF3 */ +#define DW_ATE_packed_decimal 0xa /* DWARF3f */ +#define DW_ATE_numeric_string 0xb /* DWARF3f */ +#define DW_ATE_edited 0xc /* DWARF3f */ +#define DW_ATE_signed_fixed 0xd /* DWARF3f */ +#define DW_ATE_unsigned_fixed 0xe /* DWARF3f */ +#define DW_ATE_decimal_float 0xf /* DWARF3f */ + + +/* ALTIUM extensions. x80, x81 */ +#define DW_ATE_ALTIUM_fract 0x80 /* ALTIUM __fract type */ + +/* Follows extension so dwarfdump prints the most-likely-useful name. */ +#define DW_ATE_lo_user 0x80 + +/* Shown here to help dwarfdump build script. */ +#define DW_ATE_ALTIUM_accum 0x81 /* ALTIUM __accum type */ + +/* HP Floating point extensions. */ +#define DW_ATE_HP_float80 0x80 /* (80 bit). HP */ + + +#define DW_ATE_HP_complex_float80 0x81 /* Complex (80 bit). HP */ +#define DW_ATE_HP_float128 0x82 /* (128 bit). HP */ +#define DW_ATE_HP_complex_float128 0x83 /* Complex (128 bit). HP */ +#define DW_ATE_HP_floathpintel 0x84 /* (82 bit IA64). HP */ +#define DW_ATE_HP_imaginary_float80 0x85 /* HP */ +#define DW_ATE_HP_imaginary_float128 0x86 /* HP */ + +/* Sun extensions */ +#define DW_ATE_SUN_interval_float 0x91 +#define DW_ATE_SUN_imaginary_float 0x92 /* Obsolete: See DW_ATE_imaginary_float */ + +#define DW_ATE_hi_user 0xff + + +/* Decimal Sign codes. */ +#define DW_DS_unsigned 0x01 /* DWARF3f */ +#define DW_DS_leading_overpunch 0x02 /* DWARF3f */ +#define DW_DS_trailing_overpunch 0x03 /* DWARF3f */ +#define DW_DS_leading_separate 0x04 /* DWARF3f */ + +#define DW_DS_trailing_separate 0x05 /* DWARF3f */ + +/* Endian code name. */ +#define DW_END_default 0x00 /* DWARF3f */ +#define DW_END_big 0x01 /* DWARF3f */ +#define DW_END_little 0x02 /* DWARF3f */ + +#define DW_END_lo_user 0x40 /* DWARF3f */ +#define DW_END_hi_user 0xff /* DWARF3f */ + +/* For use with DW_TAG_SUN_codeflags + * If DW_TAG_SUN_codeflags is accepted as a dwarf standard, then + * standard dwarf ATCF entries start at 0x01 + */ +#define DW_ATCF_lo_user 0x40 /* SUN */ +#define DW_ATCF_SUN_mop_bitfield 0x41 /* SUN */ +#define DW_ATCF_SUN_mop_spill 0x42 /* SUN */ +#define DW_ATCF_SUN_mop_scopy 0x43 /* SUN */ +#define DW_ATCF_SUN_func_start 0x44 /* SUN */ +#define DW_ATCF_SUN_end_ctors 0x45 /* SUN */ +#define DW_ATCF_SUN_branch_target 0x46 /* SUN */ +#define DW_ATCF_SUN_mop_stack_probe 0x47 /* SUN */ +#define DW_ATCF_SUN_func_epilog 0x48 /* SUN */ +#define DW_ATCF_hi_user 0xff /* SUN */ + +/* Accessibility code name. */ +#define DW_ACCESS_public 0x01 +#define DW_ACCESS_protected 0x02 +#define DW_ACCESS_private 0x03 + +/* Visibility code name. */ +#define DW_VIS_local 0x01 +#define DW_VIS_exported 0x02 +#define DW_VIS_qualified 0x03 + +/* Virtuality code name. */ +#define DW_VIRTUALITY_none 0x00 +#define DW_VIRTUALITY_virtual 0x01 +#define DW_VIRTUALITY_pure_virtual 0x02 + +#define DW_LANG_C89 0x0001 +#define DW_LANG_C 0x0002 +#define DW_LANG_Ada83 0x0003 +#define DW_LANG_C_plus_plus 0x0004 +#define DW_LANG_Cobol74 0x0005 +#define DW_LANG_Cobol85 0x0006 +#define DW_LANG_Fortran77 0x0007 +#define DW_LANG_Fortran90 0x0008 +#define DW_LANG_Pascal83 0x0009 +#define DW_LANG_Modula2 0x000a +#define DW_LANG_Java 0x000b /* DWARF3 */ +#define DW_LANG_C99 0x000c /* DWARF3 */ +#define DW_LANG_Ada95 0x000d /* DWARF3 */ +#define DW_LANG_Fortran95 0x000e /* DWARF3 */ +#define DW_LANG_PLI 0x000f /* DWARF3 */ +#define DW_LANG_ObjC 0x0010 /* DWARF3f */ +#define DW_LANG_ObjC_plus_plus 0x0011 /* DWARF3f */ +#define DW_LANG_UPC 0x0012 /* DWARF3f */ +#define DW_LANG_D 0x0013 /* DWARF3f */ +#define DW_LANG_Python 0x0014 /* DWARF4 */ +#define DW_LANG_lo_user 0x8000 +#define DW_LANG_Mips_Assembler 0x8001 /* MIPS */ +#define DW_LANG_Upc 0x8765 /* UPC, use + DW_LANG_UPC instead. */ +/* ALTIUM extension */ +#define DW_LANG_ALTIUM_Assembler 0x9101 /* ALTIUM */ + +/* Sun extensions */ +#define DW_LANG_SUN_Assembler 0x9001 /* SUN */ + +#define DW_LANG_hi_user 0xffff + +/* Identifier case name. */ +#define DW_ID_case_sensitive 0x00 +#define DW_ID_up_case 0x01 +#define DW_ID_down_case 0x02 +#define DW_ID_case_insensitive 0x03 + +/* Calling Convention Name. */ +#define DW_CC_normal 0x01 +#define DW_CC_program 0x02 +#define DW_CC_nocall 0x03 +#define DW_CC_lo_user 0x40 + +/* ALTIUM extensions. */ +/* Function is an interrupt handler, return address on system stack. */ +#define DW_CC_ALTIUM_interrupt 0x65 /* ALTIUM*/ + +/* Near function model, return address on system stack. */ +#define DW_CC_ALTIUM_near_system_stack 0x66 /*ALTIUM */ + +/* Near function model, return address on user stack. */ +#define DW_CC_ALTIUM_near_user_stack 0x67 /* ALTIUM */ + +/* Huge function model, return address on user stack. */ +#define DW_CC_ALTIUM_huge_user_stack 0x68 /* ALTIUM */ + + +#define DW_CC_hi_user 0xff + +/* Inline Code Name. */ +#define DW_INL_not_inlined 0x00 +#define DW_INL_inlined 0x01 +#define DW_INL_declared_not_inlined 0x02 +#define DW_INL_declared_inlined 0x03 + +/* Ordering Name. */ +#define DW_ORD_row_major 0x00 +#define DW_ORD_col_major 0x01 + +/* Discriminant Descriptor Name. */ +#define DW_DSC_label 0x00 +#define DW_DSC_range 0x01 + +/* Line number standard opcode name. */ +#define DW_LNS_copy 0x01 +#define DW_LNS_advance_pc 0x02 +#define DW_LNS_advance_line 0x03 +#define DW_LNS_set_file 0x04 +#define DW_LNS_set_column 0x05 +#define DW_LNS_negate_stmt 0x06 +#define DW_LNS_set_basic_block 0x07 +#define DW_LNS_const_add_pc 0x08 +#define DW_LNS_fixed_advance_pc 0x09 +#define DW_LNS_set_prologue_end 0x0a /* DWARF3 */ +#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */ +#define DW_LNS_set_isa 0x0c /* DWARF3 */ + +/* Line number extended opcode name. */ +#define DW_LNE_end_sequence 0x01 +#define DW_LNE_set_address 0x02 +#define DW_LNE_define_file 0x03 +#define DW_LNE_set_discriminator 0x04 /* DWARF4 */ + +/* HP extensions. */ +#define DW_LNE_HP_negate_is_UV_update 0x11 /* 17 HP */ +#define DW_LNE_HP_push_context 0x12 /* 18 HP */ +#define DW_LNE_HP_pop_context 0x13 /* 19 HP */ +#define DW_LNE_HP_set_file_line_column 0x14 /* 20 HP */ +#define DW_LNE_HP_set_routine_name 0x15 /* 21 HP */ +#define DW_LNE_HP_set_sequence 0x16 /* 22 HP */ +#define DW_LNE_HP_negate_post_semantics 0x17 /* 23 HP */ +#define DW_LNE_HP_negate_function_exit 0x18 /* 24 HP */ +#define DW_LNE_HP_negate_front_end_logical 0x19 /* 25 HP */ +#define DW_LNE_HP_define_proc 0x20 /* 32 HP */ + +#define DW_LNE_lo_user 0x80 /* DWARF3 */ +#define DW_LNE_hi_user 0xff /* DWARF3 */ + +/* Macro information. */ +#define DW_MACINFO_define 0x01 +#define DW_MACINFO_undef 0x02 +#define DW_MACINFO_start_file 0x03 +#define DW_MACINFO_end_file 0x04 +#define DW_MACINFO_vendor_ext 0xff + +/* CFA operator compaction (a space saving measure, see + the DWARF standard) means DW_CFA_extended and DW_CFA_nop + have the same value here. */ +#define DW_CFA_advance_loc 0x40 +#define DW_CFA_offset 0x80 +#define DW_CFA_restore 0xc0 +#define DW_CFA_extended 0 + +#define DW_CFA_nop 0x00 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offset_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_def_cfa_expression 0x0f /* DWARF3 */ +#define DW_CFA_expression 0x10 /* DWARF3 */ +#define DW_CFA_offset_extended_sf 0x11 /* DWARF3 */ +#define DW_CFA_def_cfa_sf 0x12 /* DWARF3 */ +#define DW_CFA_def_cfa_offset_sf 0x13 /* DWARF3 */ +#define DW_CFA_val_offset 0x14 /* DWARF3f */ +#define DW_CFA_val_offset_sf 0x15 /* DWARF3f */ +#define DW_CFA_val_expression 0x16 /* DWARF3f */ + +#define DW_CFA_lo_user 0x1c +#define DW_CFA_low_user 0x1c /* Incorrect spelling, do not use. */ + +/* SGI/MIPS extension. */ +#define DW_CFA_MIPS_advance_loc8 0x1d /* MIPS */ + +/* GNU extensions. */ +#define DW_CFA_GNU_window_save 0x2d /* GNU */ +#define DW_CFA_GNU_args_size 0x2e /* GNU */ +#define DW_CFA_GNU_negative_offset_extended 0x2f /* GNU */ + +#define DW_CFA_high_user 0x3f + +/* GNU exception header encoding. See the Generic + Elf Specification of the Linux Standard Base (LSB). + http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html + The upper 4 bits indicate how the value is to be applied. + The lower 4 bits indicate the format of the data. +*/ +#define DW_EH_PE_absptr 0x00 /* GNU */ +#define DW_EH_PE_uleb128 0x01 /* GNU */ +#define DW_EH_PE_udata2 0x02 /* GNU */ +#define DW_EH_PE_udata4 0x03 /* GNU */ +#define DW_EH_PE_udata8 0x04 /* GNU */ +#define DW_EH_PE_sleb128 0x09 /* GNU */ +#define DW_EH_PE_sdata2 0x0A /* GNU */ +#define DW_EH_PE_sdata4 0x0B /* GNU */ +#define DW_EH_PE_sdata8 0x0C /* GNU */ + +#define DW_EH_PE_pcrel 0x10 /* GNU */ +#define DW_EH_PE_textrel 0x20 /* GNU */ +#define DW_EH_PE_datarel 0x30 /* GNU */ +#define DW_EH_PE_funcrel 0x40 /* GNU */ +#define DW_EH_PE_aligned 0x50 /* GNU */ + +#define DW_EH_PE_omit 0xff /* GNU. Means no value present. */ + + +/* Mapping from machine registers and pseudo-regs into the .debug_frame table. + DW_FRAME entries are machine specific. These describe + MIPS/SGI R3000, R4K, R4400 and all later MIPS/SGI IRIX machines. + They describe a mapping from hardware register number to + the number used in the table to identify that register. + + The CFA (Canonical Frame Address) described in DWARF is called + the Virtual Frame Pointer on MIPS/SGI machines. + + The DW_FRAME* names here are MIPS/SGI specfic. + Libdwarf interfaces defined in 2008 make the FRAME definitions + here (and the fixed table sizes they imply) obsolete. + They are left here for compatibility. + +*/ +/* Column used for CFA. Assumes reg 0 never appears as + a register in DWARF info. */ +#define DW_FRAME_CFA_COL 0 + +#define DW_FRAME_REG1 1 /* integer reg 1 */ +#define DW_FRAME_REG2 2 /* integer reg 2 */ +#define DW_FRAME_REG3 3 /* integer reg 3 */ +#define DW_FRAME_REG4 4 /* integer reg 4 */ +#define DW_FRAME_REG5 5 /* integer reg 5 */ +#define DW_FRAME_REG6 6 /* integer reg 6 */ +#define DW_FRAME_REG7 7 /* integer reg 7 */ +#define DW_FRAME_REG8 8 /* integer reg 8 */ +#define DW_FRAME_REG9 9 /* integer reg 9 */ +#define DW_FRAME_REG10 10 /* integer reg 10 */ +#define DW_FRAME_REG11 11 /* integer reg 11 */ +#define DW_FRAME_REG12 12 /* integer reg 12 */ +#define DW_FRAME_REG13 13 /* integer reg 13 */ +#define DW_FRAME_REG14 14 /* integer reg 14 */ +#define DW_FRAME_REG15 15 /* integer reg 15 */ +#define DW_FRAME_REG16 16 /* integer reg 16 */ +#define DW_FRAME_REG17 17 /* integer reg 17 */ +#define DW_FRAME_REG18 18 /* integer reg 18 */ +#define DW_FRAME_REG19 19 /* integer reg 19 */ +#define DW_FRAME_REG20 20 /* integer reg 20 */ +#define DW_FRAME_REG21 21 /* integer reg 21 */ +#define DW_FRAME_REG22 22 /* integer reg 22 */ +#define DW_FRAME_REG23 23 /* integer reg 23 */ +#define DW_FRAME_REG24 24 /* integer reg 24 */ +#define DW_FRAME_REG25 25 /* integer reg 25 */ +#define DW_FRAME_REG26 26 /* integer reg 26 */ +#define DW_FRAME_REG27 27 /* integer reg 27 */ +#define DW_FRAME_REG28 28 /* integer reg 28 */ +#define DW_FRAME_REG29 29 /* integer reg 29 */ +#define DW_FRAME_REG30 30 /* integer reg 30 */ +#define DW_FRAME_REG31 31 /* integer reg 31, aka ra */ + + /* MIPS1, 2 have only some of these 64-bit registers. + ** MIPS1 save/restore takes 2 instructions per 64-bit reg, and + ** in that case, the register is considered stored after the second + ** swc1. + */ +#define DW_FRAME_FREG0 32 /* 64-bit floating point reg 0 */ +#define DW_FRAME_FREG1 33 /* 64-bit floating point reg 1 */ +#define DW_FRAME_FREG2 34 /* 64-bit floating point reg 2 */ +#define DW_FRAME_FREG3 35 /* 64-bit floating point reg 3 */ +#define DW_FRAME_FREG4 36 /* 64-bit floating point reg 4 */ +#define DW_FRAME_FREG5 37 /* 64-bit floating point reg 5 */ +#define DW_FRAME_FREG6 38 /* 64-bit floating point reg 6 */ +#define DW_FRAME_FREG7 39 /* 64-bit floating point reg 7 */ +#define DW_FRAME_FREG8 40 /* 64-bit floating point reg 8 */ +#define DW_FRAME_FREG9 41 /* 64-bit floating point reg 9 */ +#define DW_FRAME_FREG10 42 /* 64-bit floating point reg 10 */ +#define DW_FRAME_FREG11 43 /* 64-bit floating point reg 11 */ +#define DW_FRAME_FREG12 44 /* 64-bit floating point reg 12 */ +#define DW_FRAME_FREG13 45 /* 64-bit floating point reg 13 */ +#define DW_FRAME_FREG14 46 /* 64-bit floating point reg 14 */ +#define DW_FRAME_FREG15 47 /* 64-bit floating point reg 15 */ +#define DW_FRAME_FREG16 48 /* 64-bit floating point reg 16 */ +#define DW_FRAME_FREG17 49 /* 64-bit floating point reg 17 */ +#define DW_FRAME_FREG18 50 /* 64-bit floating point reg 18 */ +#define DW_FRAME_FREG19 51 /* 64-bit floating point reg 19 */ +#define DW_FRAME_FREG20 52 /* 64-bit floating point reg 20 */ +#define DW_FRAME_FREG21 53 /* 64-bit floating point reg 21 */ +#define DW_FRAME_FREG22 54 /* 64-bit floating point reg 22 */ +#define DW_FRAME_FREG23 55 /* 64-bit floating point reg 23 */ +#define DW_FRAME_FREG24 56 /* 64-bit floating point reg 24 */ +#define DW_FRAME_FREG25 57 /* 64-bit floating point reg 25 */ +#define DW_FRAME_FREG26 58 /* 64-bit floating point reg 26 */ +#define DW_FRAME_FREG27 59 /* 64-bit floating point reg 27 */ +#define DW_FRAME_FREG28 60 /* 64-bit floating point reg 28 */ +#define DW_FRAME_FREG29 61 /* 64-bit floating point reg 29 */ +#define DW_FRAME_FREG30 62 /* 64-bit floating point reg 30 */ +#define DW_FRAME_FREG31 63 /* 64-bit floating point reg 31 */ + +/* ***IMPORTANT NOTE, TARGET DEPENDENCY **** + The following 4 #defines are dependent on + the target cpu(s) that you apply libdwarf to. + Ensure that DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL + do not conflict with the range [0-DW_FRAME_STATIC_LINK]. + The value 63 works for MIPS cpus at least up to the R16000. + + For a cpu with more than 63 real registers + DW_FRAME_HIGHEST_NORMAL_REGISTER + must be increased for things to work properly! + Also ensure that DW_FRAME_UNDEFINED_VAL DW_FRAME_SAME_VAL + are not in the range [0-DW_FRAME_STATIC_LINK] + + Having DW_FRAME_HIGHEST_NORMAL_REGISTER be higher than + is strictly needed is safe. + +*/ + +#ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER +#define DW_FRAME_HIGHEST_NORMAL_REGISTER 63 +#endif +/* This is the number of columns in the Frame Table. + This constant should + be kept in sync with DW_REG_TABLE_SIZE defined in libdwarf.h + It must also be large enough to be beyond the highest + compiler-defined-register (meaning DW_FRAME_RA_COL DW_FRAME_STATIC_LINK + in the MIPS/IRIX case */ +#ifndef DW_FRAME_LAST_REG_NUM +#define DW_FRAME_LAST_REG_NUM (DW_FRAME_HIGHEST_NORMAL_REGISTER + 3) +#endif + + +/* Column recording ra (return addrress from a function call). + This is common to many architectures, but as a 'simple register' + is not necessarily adequate for all architectures. + For MIPS/IRIX this register number is actually recorded on disk + in the .debug_frame section. + */ +#define DW_FRAME_RA_COL (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1) + +/* Column recording static link applicable to up-level + addressing, as in IRIX mp code, pascal, etc. + This is common to many architectures but + is not necessarily adequate for all architectures. + For MIPS/IRIX this register number is actually recorded on disk + in the .debug_frame section. +*/ +#define DW_FRAME_STATIC_LINK (DW_FRAME_HIGHEST_NORMAL_REGISTER + 2) + + + +/* + DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL are + never on disk, just generated by libdwarf. See libdwarf.h + for their values. +*/ + + + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +#ifdef __cplusplus +} +#endif +#endif /* __DWARF_H */ diff --git a/elff/dwarf_cu.cc b/elff/dwarf_cu.cc new file mode 100644 index 0000000..8e7da98 --- /dev/null +++ b/elff/dwarf_cu.cc @@ -0,0 +1,758 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of a class DwarfCU, that encapsulates a compilation + * unit in the .debug_info section of the mapped ELF file. + */ + +#include "string.h" +#include "stdio.h" +#include "elf_file.h" +#include "dwarf_cu.h" +#include "dwarf_utils.h" + +DwarfCU::DwarfCU(ElfFile* elf) + : elf_file_(elf), + cu_die_(NULL), + prev_cu_(NULL) { +} + +DwarfCU::~DwarfCU() { + if (cu_die_ != NULL) { + delete cu_die_; + } + abbrs_.empty(); +} + +DwarfCU* DwarfCU::create_instance(ElfFile* elf, const void* hdr) { + DwarfCU* ret; + + /* 64-bit DWARF CU has first 4 bytes in its header set to 0xFFFFFFFF. */ + if (*reinterpret_cast(hdr) == 0xFFFFFFFF) { + ret = new(elf) DwarfCUImpl + (elf, reinterpret_cast(hdr)); + } else { + ret = new(elf) DwarfCUImpl + (elf, reinterpret_cast(hdr)); + } + assert(ret != NULL); + if (ret == NULL) { + _set_errno(ENOMEM); + } + return ret; +} + +const Elf_Byte* DwarfCU::process_attrib(const Elf_Byte* prop, + Dwarf_Form form, + Dwarf_Value* attr_value) const { + assert(form != 0); + Dwarf_Value tmp_val; + Dwarf_Value leb128; + + attr_value->type = DWARF_VALUE_UNKNOWN; + attr_value->encoded_size = 0; + attr_value->u64 = 0; + + switch (form) { + /* Property is a block of data, contained in .debug_info section. Block + * size is encoded with 1 byte value, and block data immediately follows + * block size. */ + case DW_FORM_block1: + attr_value->type = DWARF_VALUE_BLOCK; + attr_value->block.block_size = *prop; + attr_value->block.block_ptr = prop + 1; + attr_value->encoded_size = + static_cast(attr_value->block.block_size + 1); + break; + + /* Property is a block of data, contained in .debug_info section. Block + * size is encoded with 2 bytes value, and block data immediately follows + * block size. */ + case DW_FORM_block2: + attr_value->type = DWARF_VALUE_BLOCK; + attr_value->block.block_size = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->block.block_ptr = prop + 2; + attr_value->encoded_size = + static_cast(attr_value->block.block_size + 2); + break; + + /* Property is a block of data, contained in .debug_info section. Block + * size is encoded with 4 bytes value, and block data immediately follows + * block size. */ + case DW_FORM_block4: + attr_value->type = DWARF_VALUE_BLOCK; + attr_value->block.block_size = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->block.block_ptr = prop + 4; + attr_value->encoded_size = + static_cast(attr_value->block.block_size + 4); + break; + + /* Property is a block of data, contained in .debug_info section. Block + * size is encoded with unsigned LEB128 value, and block data immediately + * follows block size. */ + case DW_FORM_block: + reinterpret_cast(prop)->process_unsigned(&leb128); + attr_value->type = DWARF_VALUE_BLOCK; + attr_value->block.block_size = leb128.u32; + attr_value->block.block_ptr = prop + leb128.encoded_size; + attr_value->encoded_size = + static_cast(attr_value->block.block_size + + leb128.encoded_size); + break; + + /* Property is unsigned 1 byte value. */ + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + attr_value->type = DWARF_VALUE_U8; + attr_value->u8 = *prop; + attr_value->encoded_size = 1; + break; + + /* Property is unsigned 2 bytes value. */ + case DW_FORM_data2: + case DW_FORM_ref2: + attr_value->type = DWARF_VALUE_U16; + attr_value->u16 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 2; + break; + + /* Property is unsigned 4 bytes value. */ + case DW_FORM_data4: + case DW_FORM_ref4: + attr_value->type = DWARF_VALUE_U32; + attr_value->u32 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 4; + break; + + /* Property is unsigned 8 bytes value. */ + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + attr_value->type = DWARF_VALUE_U64; + attr_value->u64 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 8; + break; + + /* Property is signed LEB128 value. */ + case DW_FORM_sdata: + reinterpret_cast(prop)->process_signed(attr_value); + break; + + /* Property is unsigned LEB128 value. */ + case DW_FORM_ref_udata: + case DW_FORM_udata: + reinterpret_cast(prop)->process_unsigned(attr_value); + break; + + /* Property is a string contained directly in .debug_info section. */ + case DW_FORM_string: + attr_value->type = DWARF_VALUE_STR; + attr_value->str = reinterpret_cast(prop); + attr_value->encoded_size = strlen(attr_value->str) + 1; + break; + + /* Property is an offset of a string contained in .debug_str section. + * We will process the reference here, converting it into the actual + * string value. */ + case DW_FORM_strp: + attr_value->type = DWARF_VALUE_STR; + if (elf_file_->is_DWARF_64()) { + Elf_Xword str_offset = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->str = elf_file_->get_debug_str(str_offset); + attr_value->encoded_size = 8; + } else { + Elf_Word str_offset = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->str = elf_file_->get_debug_str(str_offset); + attr_value->encoded_size = 4; + } + break; + + /* Property is an address. */ + case DW_FORM_addr: + if (addr_sizeof_ == 4) { + attr_value->type = DWARF_VALUE_PTR32; + attr_value->u32 = + elf_file_->pull_val(reinterpret_cast(prop)); + } else { + attr_value->type = DWARF_VALUE_PTR64; + attr_value->u64 = + elf_file_->pull_val(reinterpret_cast(prop)); + } + attr_value->encoded_size = addr_sizeof_; + break; + + /* Reference from the beginning of .debug_info section. */ + case DW_FORM_ref_addr: + /* DWARF3+ requires that encoding size of this property must be 4 bytes + * in 32-bit DWARF, and 8 bytes in 64-bit DWARF, while DWARF2- requires + * encoding size to be equal to CU's pointer size. */ + if (is_DWARF3_or_higher()) { + if (elf_file_->is_DWARF_64()) { + attr_value->type = DWARF_VALUE_U64; + attr_value->u64 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 4; + } else { + attr_value->type = DWARF_VALUE_U32; + attr_value->u32 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 8; + } + } else { + if (addr_sizeof_ == 4) { + attr_value->type = DWARF_VALUE_U32; + attr_value->u32 = + elf_file_->pull_val(reinterpret_cast(prop)); + } else { + attr_value->type = DWARF_VALUE_U64; + attr_value->u64 = + elf_file_->pull_val(reinterpret_cast(prop)); + } + attr_value->encoded_size = addr_sizeof_; + } + break; + + /* Reference to a section, other than .debug_info, or .debug_str */ + case DW_FORM_sec_offset: + if (elf_file_->is_DWARF_64()) { + attr_value->type = DWARF_VALUE_U64; + attr_value->u64 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 4; + } else { + attr_value->type = DWARF_VALUE_U32; + attr_value->u32 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 8; + } + break; + + /* This is a replacement for DW_FORM_flag, which doesn't consume memory + * in .debug_info section, and only by the fact of its existence it is + * equal to DW_FORM_flag with value set to 1. */ + case DW_FORM_flag_present: + attr_value->type = DWARF_VALUE_U8; + attr_value->u8 = 1; + attr_value->encoded_size = 0; + break; + + /* Encodes the actual form to be used. */ + case DW_FORM_indirect: + // Starts with ULEB128 + prop = reinterpret_cast + (reinterpret_cast + (prop)->process_unsigned(&tmp_val)); + /* ULEB128 encodes the actual form to be used to process this entry. */ + process_attrib(prop, tmp_val.u16, attr_value); + attr_value->encoded_size += tmp_val.encoded_size; + break; + + /* This form is defined for DWARF4, and has no documentation whatsoever. */ + case DW_FORM_exprloc: + default: + attr_value->type = DWARF_VALUE_U32; + attr_value->u32 = + elf_file_->pull_val(reinterpret_cast(prop)); + attr_value->encoded_size = 4; + break; + } + + return prop + attr_value->encoded_size; +} + +void DwarfCU::dump() const { + printf("\n\n>>>>>>>>>>>>>>> CU %p (version %u, address size %u)\n", + cu_die_->die(), static_cast(version_), + static_cast(addr_sizeof_)); + printf(">>>>> Build dir path: %s\n", comp_dir_path()); + printf(">>>>> Build file path: %s\n", rel_cu_path()); + if (cu_die_ != NULL) { + cu_die_->dump(false); + } +} + +//============================================================================= +// DwarfCUImpl implementation +//============================================================================= + +template +DwarfCUImpl::DwarfCUImpl(ElfFile* elf, + const Dwarf_CUHdr* hdr) + : DwarfCU(elf), + cu_header_(hdr) { + /* Cache CU's DIE abbreviation descriptor in the array. This MUST be done + * BEFORE first call to array's cache_to() method. */ + const Dwarf_Abbr_DIE* cu_abbr_die = reinterpret_cast + (INC_CPTR(elf->get_debug_abbrev_data(), + elf->pull_val(hdr->abbrev_offset))); + abbrs_.add(cu_abbr_die); + + cu_size_ = elf->pull_val(hdr->size_hdr.size); + version_ = elf->pull_val(hdr->version); + addr_sizeof_ = hdr->address_size; + memset(&stmtl_header_, 0, sizeof(stmtl_header_)); +} + +template +bool DwarfCUImpl::parse( + const DwarfParseContext* parse_context, + const void** next_cu_die) { + /* Start parsing with the DIE for this CU. */ + if (process_DIE(parse_context, get_DIE(), NULL) == NULL) { + return false; + } + + /* CU area size (thus, next CU header offset) in .debug_info section equals + * to CU size, plus number of bytes, required to encode CU size in CU header + * (4 for 32-bit CU, and 12 for 64-bit CU. */ + *next_cu_die = + INC_CPTR(cu_header_, cu_size_ + ELFF_FIELD_OFFSET(Dwarf_CUHdr, version)); + + return true; +} + +template +const Elf_Byte* DwarfCUImpl::process_DIE( + const DwarfParseContext* parse_context, + const Dwarf_DIE* die, + DIEObject* parent_obj) { + while (is_attrib_ptr_valid(die) && !die->is_separator()) { + Dwarf_AbbrNum abbr_num; + Dwarf_Tag die_tag; + Elf_Word sibling_off = 0; + + /* Get DIE's abbreviation number, and advance to DIE's properties. */ + const Elf_Byte* die_attr = die->process(&abbr_num); + + /* Get abbreviation for the current DIE. */ + const Dwarf_Abbr_DIE* die_abbr = abbrs_.cache_to(abbr_num); + if (die_abbr == NULL) { + return NULL; + } + + /* Get base DIE properties, and advance to the DIE's + * attribute descriptors. */ + const Dwarf_Abbr_AT* at_abbr = die_abbr->process(NULL, &die_tag); + + /* Instantiate DIE object for this DIE, and get list of properties, + * that should be collected while processing that DIE. */ + DIEObject* die_obj = + create_die_object(parse_context, die, parent_obj, die_tag); + if (die_obj == NULL && errno != 0) { + return NULL; + } + + if (die_obj != NULL) { + if (parent_obj != NULL) { + /* Update list of parent's children. */ + die_obj->link_sibling(parent_obj->last_child()); + parent_obj->link_child(die_obj); + } else { + /* NULL parent object is allowed only for CU DIE itself. */ + assert(cu_die_ == NULL && die_tag == DW_TAG_compile_unit); + if (cu_die_ == NULL && die_tag != DW_TAG_compile_unit) { + _set_errno(EINVAL); + return NULL; + } + cu_die_ = die_obj; + /* This CU DIE object will be used as a parent for all DIE + * objects, created in this method. */ + parent_obj = cu_die_; + } + } + + // Loop through all DIE properties. + while (elf_file_->is_valid_abbr_ptr(at_abbr, sizeof(Dwarf_Abbr_AT)) && + !at_abbr->is_separator()) { + Dwarf_At at_value; + Dwarf_Form at_form; + Dwarf_Value attr_value; + + // Obtain next property value. + at_abbr = at_abbr->process(&at_value, &at_form); + die_attr = process_attrib(die_attr, at_form, &attr_value); + + if (at_value == DW_AT_sibling) { + /* DW_AT_sibling means that next DIE is a child of the one that's + * being currently processed. We need to cache value of this property + * in order to correctly calculate next sibling of this DIE after + * child's DIE has been processed. */ + assert(sibling_off == 0); + sibling_off = attr_value.u32; + } + } + + /* Next DIE immediately follows last property for the current DIE. */ + die = reinterpret_cast(die_attr); + if (sibling_off != 0) { + // Process child DIE. + process_DIE(parse_context, die, die_obj != NULL ? die_obj : parent_obj); + // Next sibling DIE offset is relative to this CU's header beginning. + die = INC_CPTR_T(Dwarf_DIE, cu_header_, sibling_off); + } + } + + return INC_CPTR_T(Elf_Byte, die, 1); +} + +template +DIEObject* DwarfCUImpl::create_die_object( + const DwarfParseContext* parse_context, + const Dwarf_DIE* die, + DIEObject* parent, + Dwarf_Tag tag) { + DIEObject* ret = NULL; + + /* We will always create a DIE object for CU DIE. */ + if (tag == DW_TAG_compile_unit || collect_die(parse_context, tag)) { + ret = new(elf_file_) DIEObject(die, this, parent); + assert(ret != NULL); + if (ret == NULL) { + _set_errno(ENOMEM); + } + } else { + _set_errno(0); + } + return ret; +} + +template +bool DwarfCUImpl::init_stmtl() { + if (stmtl_header_.unit_length != 0) { + return true; + } + + assert(cu_die_ != NULL); + if (cu_die_ == NULL) { + _set_errno(EINVAL); + return false; + } + + DIEAttrib stmtl; + if (!cu_die()->get_attrib(DW_AT_stmt_list, &stmtl)) { + _set_errno(EINVAL); + return false; + } + + const void* stmtl_start = + INC_CPTR(elf_file()->get_debug_line_data(), stmtl.value()->u32); + if (*reinterpret_cast(stmtl_start) == 0xFFFFFFFF) { + cache_stmtl(reinterpret_cast(stmtl_start)); + } else { + cache_stmtl(reinterpret_cast(stmtl_start)); + } + + return true; +} + +template +bool DwarfCUImpl::get_pc_address_file_info( + Elf_Xword address, + Dwarf_AddressInfo* info) { + /* Make sure STMTL header is cached. */ + if (!init_stmtl()) { + return false; + } + /* Flags address match, that should trigger return next time + * source line gets adjusted. */ + bool found = false; + /* Create new state machine. */ + DwarfStateMachine state(stmtl_header_.default_is_stmt != 0); + + /* Start the "Line Number Program" */ + const Elf_Byte* go = stmtl_header_.start; + while (go < stmtl_header_.end) { + const Elf_Byte op = *go; + go++; + + if (op == 0) { + /* This is an extended opcode. */ + Dwarf_Value op_size; + + /* First ULEB128 contains opcode size, (excluding ULEB128 itself). */ + go = reinterpret_cast + (reinterpret_cast(go)->process_unsigned(&op_size)); + /* Next is the extended opcode. */ + const Elf_Byte* ex_op_ptr = go; + switch (*ex_op_ptr) { + case DW_LNE_end_sequence: + state.end_sequence_ = true; + state.reset(stmtl_header_.default_is_stmt != 0); + found = false; + break; + + case DW_LNE_set_address: { + Elf_Xword prev_address = state.address_; + if (is_CU_address_64()) { + state.address_ = + elf_file()->pull_val(reinterpret_cast(ex_op_ptr + 1)); + } else { + state.address_ = + elf_file()->pull_val(reinterpret_cast(ex_op_ptr + 1)); + } + if (prev_address != 0 && + address >= prev_address && address < state.address_) { + return set_source_info(&state, info); + } else if (address == state.address_) { + found = true; + } + break; + } + + case DW_LNE_define_file: { + /* Parameters start with the directly encoded zero-terminated + * file name. */ + state.set_file_info_ = INC_CPTR_T(Dwarf_STMTL_FileDesc, ex_op_ptr, 1); + assert(state.set_file_info_ != NULL); + if (state.set_file_info_ != NULL) { + ex_op_ptr = reinterpret_cast(state.set_file_info_->process(NULL)); + } + break; + } + + case DW_LNE_set_discriminator: { + Dwarf_Value discr_val; + /* One parameter: discriminator's ULEB128 value. */ + reinterpret_cast(ex_op_ptr + 1)->process_unsigned(&discr_val); + state.discriminator_ = discr_val.u32; + break; + } + + default: + assert(0); + return false; + } + go += op_size.u32; + } else if (op < stmtl_header_.opcode_base) { + /* This is a standard opcode. */ + switch (op) { + case DW_LNS_copy: + /* No parameters. */ + state.basic_block_ = false; + state.prologue_end_ = false; + state.epilogue_begin_ = false; + break; + + case DW_LNS_advance_pc: { + /* One parameter: ULEB128 value to add to the current address value + * in the state machine. */ + Dwarf_Value addr_add; + go = reinterpret_cast + (reinterpret_cast(go)->process_unsigned(&addr_add)); + Elf_Xword prev_address = state.address_; + state.address_ += addr_add.u64; + if (prev_address != 0 && + address >= prev_address && address < state.address_) { + return set_source_info(&state, info); + } else if (address == state.address_) { + found = true; + } + break; + } + + case DW_LNS_advance_line: { + /* One parameter: signed LEB128 value to add to the current line + * number in the state machine. */ + Dwarf_Value line_add; + go = reinterpret_cast + (reinterpret_cast(go)->process_signed(&line_add)); + state.line_ += line_add.s32; + if (found) { + return set_source_info(&state, info); + } + break; + } + + case DW_LNS_set_file: { + /* One parameter: ULEB128 value encoding current file number. */ + Dwarf_Value file_num; + go = reinterpret_cast + (reinterpret_cast(go)->process_unsigned(&file_num)); + state.file_ = file_num.u32; + /* This operation should discard previously saved file information. */ + state.set_file_info_ = NULL; + break; + } + + case DW_LNS_set_column: { + /* One parameter: ULEB128 value encoding current column number. */ + Dwarf_Value column_num; + go = reinterpret_cast + (reinterpret_cast(go)->process_unsigned(&column_num)); + state.column_ = column_num.u32; + break; + } + + case DW_LNS_negate_stmt: + /* No parameters. */ + state.is_stmt_ = !state.is_stmt_; + break; + + case DW_LNS_set_basic_block: + /* No parameters. */ + state.basic_block_ = true; + break; + + case DW_LNS_const_add_pc: { + Elf_Xword prev_address = state.address_; + /* No parameters. This operation does the same thing, as special + * opcode 255 would do to the current address. */ + Elf_Word adjusted = + static_cast(255) - stmtl_header_.opcode_base; + state.address_ += (adjusted / stmtl_header_.line_range) * + stmtl_header_.min_instruction_len; + if (prev_address != 0 && + address >= prev_address && address < state.address_) { + return set_source_info(&state, info); + } else if (address == state.address_) { + found = true; + } + break; + } + + case DW_LNS_fixed_advance_pc: { + Elf_Xword prev_address = state.address_; + /* One parameter: directly encoded 16-bit value to add to the + * current address. */ + state.address_ += + elf_file()->pull_val(reinterpret_cast(go)); + if (prev_address != 0 && + address >= prev_address && address < state.address_) { + return set_source_info(&state, info); + } else if (address == state.address_) { + found = true; + } + go += sizeof(Elf_Half); + break; + } + + case DW_LNS_set_prologue_end: + /* No parameters. */ + state.prologue_end_ = true; + break; + + case DW_LNS_set_epilogue_begin: + /* No parameters. */ + state.epilogue_begin_ = true; + break; + + case DW_LNS_set_isa: { + /* One parameter: ISA value encoded as ULEB128. */ + Dwarf_Value isa_val; + go = reinterpret_cast + (reinterpret_cast(go)->process_unsigned(&isa_val)); + state.isa_ = isa_val.u32; + break; + } + + default: + /* Unknown opcode. Just skip it. */ + for (Elf_Byte uleb = 0; + uleb < stmtl_header_.standard_opcode_lengths[op - 1]; uleb++) { + Dwarf_Value tmp; + go = reinterpret_cast + (reinterpret_cast(go)->process_unsigned(&tmp)); + } + break; + } + } else { + Elf_Xword prev_address = state.address_; + /* This is a special opcode. */ + const Elf_Word adjusted = op - stmtl_header_.opcode_base; + /* Advance address. */ + state.address_ += (adjusted / stmtl_header_.line_range) * + stmtl_header_.min_instruction_len; + if (prev_address != 0 && + address >= prev_address && address < state.address_) { + return set_source_info(&state, info); + } + /* Advance line. */ + state.line_ += stmtl_header_.line_base + + (adjusted % stmtl_header_.line_range); + if (state.address_ == address) { + return set_source_info(&state, info); + } + /* Do the woodoo. */ + state.basic_block_ = false; + state.prologue_end_ = false; + state.epilogue_begin_ = false; + } + } + + return false; +} + +template +const Dwarf_STMTL_FileDesc* DwarfCUImpl::get_stmt_file_info( + Elf_Word index) { + /* Index must be 1-based. */ + if (index == 0) { + return NULL; + } + + const Dwarf_STMTL_FileDesc* cur_desc = stmtl_header_.file_infos; + while (index != 1 && !cur_desc->is_last_entry()) { + cur_desc = cur_desc->process(NULL); + index--; + } + assert(!cur_desc->is_last_entry()); + return cur_desc->is_last_entry() ? NULL : cur_desc; +} + +template +const char* DwarfCUImpl::get_stmt_dir_name( + Elf_Word dir_index) { + if (dir_index == 0) { + /* Requested is current compilation directory. */ + return comp_dir_path(); + } + if (dir_index > stmtl_header_.inc_dir_num) { + return NULL; + } + + const char* cur_dir = stmtl_header_.include_directories; + while (dir_index != 1) { + cur_dir += strlen(cur_dir) + 1; + dir_index--; + } + return cur_dir; +} + +template +bool DwarfCUImpl::set_source_info( + const DwarfStateMachine* state, + Dwarf_AddressInfo* info) { + info->line_number = state->line_; + const Dwarf_STMTL_FileDesc* file_info = state->set_file_info_; + if (file_info == NULL) { + file_info = get_stmt_file_info(state->file_); + if (file_info == NULL) { + info->file_name = rel_cu_path(); + info->dir_name = comp_dir_path(); + return true; + } + } + info->file_name = file_info->get_file_name(); + const Elf_Word dir_index = file_info->get_dir_index(); + info->dir_name = get_stmt_dir_name(dir_index); + return true; +} + diff --git a/elff/dwarf_cu.h b/elff/dwarf_cu.h new file mode 100644 index 0000000..a8f0578 --- /dev/null +++ b/elff/dwarf_cu.h @@ -0,0 +1,513 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declaration of a class DwarfCU, that encapsulates a compilation + * unit in the .debug_info section of the mapped ELF file. + */ + +#ifndef ELFF_DWARF_CU_H_ +#define ELFF_DWARF_CU_H_ + +#include "dwarf_defs.h" +#include "dwarf_die.h" + +/* Address information descriptor. */ +typedef struct Dwarf_AddressInfo { + /* Routine DIE containing the address. */ + const DIEObject* die_obj; + + /* Source file name for the address. */ + const char* file_name; + + /* Source file directory path for the address. */ + const char* dir_name; + + /* Source file line number for the address. */ + Elf_Word line_number; +} Dwarf_AddressInfo; + +/* STMTL header cached by compilation unit. This header is contained in + * the .debug_line section of the ELF file. */ +typedef struct Dwarf_STMTL_Hdr { + /* The size in bytes of the line number information for this compilation + * unit, not including the unit_length field itself. */ + Elf_Xword unit_length; + + /* A version number. This number is specific to the line number information + * and is independent of the DWARF version number. */ + Elf_Half version; + + /* The number of bytes following the header_length field to the beginning of + * the first byte of the line number program itself. In the 32-bit DWARF + * format, this is a 4-byte unsigned length; in the 64-bit DWARF format, + * this field is an 8-byte unsigned length. */ + Elf_Xword header_length; + + /* The size in bytes of the smallest target machine instruction. Line number + * program opcodes that alter the address register first multiply their + * operands by this value. */ + Elf_Byte min_instruction_len; + + /* The initial value of the is_stmt register. */ + Elf_Byte default_is_stmt; + + /* This parameter affects the meaning of the special opcodes. */ + Elf_Sbyte line_base; + + /* This parameter affects the meaning of the special opcodes. */ + Elf_Byte line_range; + + /* The number assigned to the first special opcode. */ + Elf_Byte opcode_base; + + /* Points to standard_opcode_lengths array in the actual STMTL header in + * the mapped .debug_line section. */ + const Elf_Byte* standard_opcode_lengths; + + /* Pointer to the beginning of the list of include directories in the mapped + * .debug_line section. */ + const char* include_directories; + + /* Number of include directories in the list that begins with + * include_directories. */ + Elf_Word inc_dir_num; + + /* Pointer to the beginning of the list of file information in the mapped + * .debug_line section. Each entry in this list begins with zero-terminated + * file name, followed by ULEB128 encoding directory index for the file, + * followed by ULEB128 encoding last modification time, followed by ULEB128 + * encoding length of file in bytes. */ + const Dwarf_STMTL_FileDesc* file_infos; + + /* Start of the "Line Number Program" in the mapped .debug_line section. */ + const Elf_Byte* start; + + /* End of the "Line Number Program" in the mapped .debug_line section. */ + const Elf_Byte* end; +} Dwarf_STMTL_Hdr; + +/* Encapsulates architecture-independent functionality of a + * compilation unit. + */ +class DwarfCU : public DwarfAllocBase { +friend class ElfFile; + public: + /* Constructs DwarfCU instance. + * Param: + * elf - Instance of ElfFile containing this compilation unit. + */ + explicit DwarfCU(ElfFile* elf); + + /* Destructs DwarfCU instance. */ + virtual ~DwarfCU(); + + /* Creates DwarfCUImpl instance, depending on DWARF format. + * Param: + * elf - Instance of ElfFile containing this compilation unit. + * hdr - Pointer to compilation unit header inside mapped .debug_info + * section of the ELF file. Actual data addressed by this pointer + * must be Dwarf32_CUHdr for 32 bit DWARFs, or Dwarf64_CUHdr for + * 64 bit DWARFs. + * Return: + * Created DwarfCUImpl instance (typecasted back to DwarfCU) on success, + * or NULL on failure. + */ + static DwarfCU* create_instance(ElfFile* elf, const void* hdr); + + /* Process a DIE attribute. + * Param: + * attr - Attribute list inside the mapped .debug_info section of the ELF + * file. + * form - Attribute's form, definig representation of attribute value in the + * mapped .debug_info section of the ELF file. + * attr_value - Upon return contains attribute value. + * Return: + * Pointer to the next DIE attribute inside the mapped .debug_info section + * of the ELF file. + */ + const Elf_Byte* process_attrib(const Elf_Byte* attr, + Dwarf_Form form, + Dwarf_Value* attr_value) const; + + /* Dumps this compilation unit to the stdout. */ + void dump() const; + + /* Gets instance of ElfFile containing this compilation unit. */ + ElfFile* elf_file() const { + return elf_file_; + } + + /* Gets DIE object for this CU. */ + DIEObject* cu_die() const { + return cu_die_; + } + + /* Gets byte size of the pointer type for this compilation unit. */ + Elf_Byte addr_sizeof() const { + return addr_sizeof_; + } + + /* Gets full path to the compilation directory (DW_AT_comp_dir attribute). + * Return: + * Full path to the compilation directory (DW_AT_comp_dir attribute), + * or NULL, if that attribute was missing in CU's attribute list. + */ + const char* comp_dir_path() const { + DIEAttrib attr; + return cu_die()->get_attrib(DW_AT_comp_dir, &attr) ? attr.value()->str : + NULL; + } + + /* Gets relative (from the compilation directory) path to the compiled file. + * (DW_AT_name attribute). + * Return: + * Relative path to the compiled file (DW_AT_name attribute), or NULL, if + * that attribute was missing in CU's attribute list. + */ + const char* rel_cu_path() const { + DIEAttrib attr; + return cu_die()->get_attrib(DW_AT_name, &attr) ? attr.value()->str : + NULL; + } + + /* Gets next compilation unit in the list. NULL indicates the last CU. */ + DwarfCU* prev_cu() const { + return prev_cu_; + } + + /* Links this CU to the list of prevoiusly discovered CUs. */ + void set_prev_cu(DwarfCU* prev) { + prev_cu_ = prev; + } + + /* Checks if DWARF version for this CU is higher than 2. */ + bool is_DWARF3_or_higher() const { + return version_ >= 3; + } + + /* Gets DIE abbreviation for given abbreviation number. + * See DwarfAbbrDieArray::get() */ + const Dwarf_Abbr_DIE* get_die_abbr(Dwarf_AbbrNum num) const { + return abbrs_.get(num); + } + + /* Gets DIE object containing given address. + * DIE address ranges may overlap (for instance, address range for an inlined + * routine will be contained within the address range of a routine where it + * was inlined). This method will return a DIE object that is a "leaf" in + * that inlining tree. I.e the returned DIE object represents the last DIE + * in the branch of all DIEs containing given address. + * Param: + * address - Address to get a DIE for. NOTE: for the sake of simplicity we + * explicitly use 64-bit type for an address. + * Return: + * Leaf DIE containing given address, or NULL if this CU doesn't contain + * the given address. + */ + DIEObject* get_leaf_die_for_address(Elf_Xword address) const { + return cu_die_->get_leaf_for_address(address); + } + + /* Checks if this CU contains 64, or 32-bit addresses. */ + bool is_CU_address_64() const { + return addr_sizeof_ == 8; + } + bool is_CU_address_32() const { + return addr_sizeof_ == 4; + } + +//============================================================================= +// DWARF format dependent methods +//============================================================================= + + public: + /* Parses this compilation unit in .debug_info section, collecting children + * DIEs of this compilation unit. + * Param: + * parse_context - Parsing context that lists tags for DIEs that should be + * collected during parsing. NULL passed in this parameter indicates DIEs + * for all tags should be collected. + * next_cu_die - Upon successful return contains pointer to the next + * compilation unit descriptor inside mapped .debug_info section of + * the ELF file. + * Return: + * true on success, false on failure. + */ + virtual bool parse(const DwarfParseContext* parse_context, + const void** next_cu_die) = 0; + + /* Gets a DIE object referenced by an offset from the beginning of + * this CU in the mapped .debug_info section. + */ + virtual DIEObject* get_referenced_die_object(Elf_Word ref) const = 0; + + /* Gets a reference to a DIE object (offset of the DIE from the + * beginning of this CU in the mapped .debug_info section. + */ + virtual Elf_Word get_die_reference(const Dwarf_DIE* die) const = 0; + + /* Gets PC address information. + * Param: + * address - PC address to get information for. + * info - Upon success contains information about routine that belongs to + * this compilation unit, containing the given address. + * Return: + * true on success, or false if this CU doesn't contain the given address. + */ + virtual bool get_pc_address_file_info(Elf_Xword address, + Dwarf_AddressInfo* info) = 0; + + /* Gets file descriptor in the mapped .debug_line section of ELF file for a + * given index in the file descriptor list. + * Param: + * index - 1-based index of file descriptor in the file descriptor list. + * Return: + * File descriptor for the given index, or NULL if index was too big. + * NOTE: pointer returned from this method addressed mapped section of + * ELF file. + */ + virtual const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index) = 0; + + /* Gets directory name by an index in the mapped .debug_line section of + * ELF file. + * Param: + * dir_index - Index of the directory in the file descriptor list. If this + * parameter is zero, compilation directory (DW_AT_comp_dir) for this CU + * will be returned. + * Return: + * Directory name for the given index, or NULL if index was too big. + * NOTE: pointer returned from this method addressed mapped section of + * ELF file. + */ + virtual const char* get_stmt_dir_name(Elf_Word dir_index) = 0; + + protected: + /* DIE abbreviation descriptors, cached for this compilation unit. */ + DwarfAbbrDieArray abbrs_; + + /* Instance of an ELF file that contains this compilation unit. */ + ElfFile* elf_file_; + + /* DIE object for this CU. */ + DIEObject* cu_die_; + + /* Next compilation unit in the list (previous in the order they've been + * discovered during ELF file parsing). + */ + DwarfCU* prev_cu_; + + /* DWARF version for this CU. */ + Elf_Half version_; + + /* Byte size of the pointer type for this compilation unit. */ + Elf_Byte addr_sizeof_; +}; + +/* Encapsulates architecture-dependent functionality of a compilation unit. + * Template param: + * Dwarf_CUHdr - type compilation unit header in the mapped .debug_info + * section of ELF file. Must be: + * - Dwarf32_CUHdr for 32-bit DWARF, or + * - Dwarf64_CUHdr for 64-bit DWARF. + * Dwarf_Off - type for an offset field in DWARF data format. Must be: + * - Dwarf32_Off for 32-bit DWARF, or + * - Dwarf64_Off for 64-bit DWARF. + */ +template +class DwarfCUImpl : public DwarfCU { + public: + /* Constructs DwarfCU instance. + * Param: + * elf - Instance of ElfFile containing this compilation unit. + * hdr - Pointer to compilation unit header inside mapped .debug_info + * section of the ELF file. + */ + DwarfCUImpl(ElfFile* elf, const Dwarf_CUHdr* hdr); + + /* Destructs DwarfCU instance. */ + ~DwarfCUImpl() { + } + + /* Parses this compilation unit in .debug_info section, collecting children + * DIEs of this compilation unit. This is an implementation of DwarfCU's + * abstract metod. + * See DwarfCU::parse(). + */ + bool parse(const DwarfParseContext* parse_context, + const void** next_cu_die); + + /* Gets PC address information. + * This is an implementation of DwarfCU's abstract metod. + * See DwarfCU::get_pc_address_file_info(). + */ + bool get_pc_address_file_info(Elf_Xword address, Dwarf_AddressInfo* info); + + /* Gets file descriptor in the mapped .debug_line section of ELF file for a + * given index in the file descriptor list. + * This is an implementation of DwarfCU's abstract metod. + * See DwarfCU::get_stmt_file_info(). + */ + const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index); + + /* Gets directory name by an index in the mapped .debug_line section of + * ELF file. + * This is an implementation of DwarfCU's abstract metod. + * See DwarfCU::get_stmt_dir_name(). + */ + const char* get_stmt_dir_name(Elf_Word dir_index); + + /* Gets a DIE object referenced by an offset from the beginning of + * this CU. This is an implementation of DwarfCU's abstract metod. + */ + DIEObject* get_referenced_die_object(Elf_Word ref) const { + const Dwarf_DIE* die = get_referenced_die(ref); + return cu_die_->find_die_object(die); + } + + /* Gets a reference to a DIE object (offset of the DIE from the + * beginning of this CU in the mapped .debug_info section. + * This is an implementation of DwarfCU's abstract metod. + */ + Elf_Word get_die_reference(const Dwarf_DIE* die) const { + return static_cast(diff_ptr(cu_header_, die)); + } + + protected: + /* Process a child DIE (and all its children) in this compilation unit. + * Param: + * parse_context - See DwarfCU::parse(). + * die - DIE descriptor of the child to process in this method. + * parent_obj - Parent object of the child to process in this method. + * NOTE: this parameter can be NULL only for a DIE that represents this + * compilation unit itself. + * Return: + * Pointer to the end of child's attribute list in the mapped .debug_info + * section on success, or NULL on failure. Usually, pointer returned from + * this method is simply discarded, since parent calculates address of the + * next sibling's DIE based on DW_AT_sibling attribute of the DIE preceding + * child's DIE. + */ + const Elf_Byte* process_DIE(const DwarfParseContext* parse_context, + const Dwarf_DIE* die, + DIEObject* parent_obj); + + /* Creates a DIE object for the given DIE. + * Param: + * parse_context See DwarfCU::parse(). + * die - DIE to create an object for. + * parent - Parent DIE object for the one that's being created in this + * method. + * tag - Tag of the DIE object that's being created in this method. + * Return: + * Created DIE object. This method may returns NULL in two cases: + * - We're not interested in this DIE (decided by looking at 'tag' + * parameter. In this case errno should be set to zero. + * - Memory allocation has failed. In this case errno should be + * set to ENOMEM. + */ + DIEObject* create_die_object(const DwarfParseContext* parse_context, + const Dwarf_DIE* die, + DIEObject* parent, + Dwarf_Tag tag); + + /* Initializes (caches) STMT lines header for this CU. */ + bool init_stmtl(); + + /* Saves current source file information, collected in the state machine by + * the "Line Number Program". + * Param: + * state - State machine collected "Line Number Program" results. + * info - Upon success contains source file information, copied over from + * the state machine. + * Return: + * true on success, or false on failure. + */ + bool set_source_info(const DwarfStateMachine* state, + Dwarf_AddressInfo* info); + + /* Gets pointer to the DIE descriptor for this CU. */ + const Dwarf_DIE* get_DIE() const { + /* CU's DIE descriptor immediately follows CU header. */ + return INC_CPTR_T(Dwarf_DIE, cu_header_, sizeof(Dwarf_CUHdr)); + } + + /* Caches STMTL header from .debug_line section to stmtl_header_. + * Template param: + * Dwarf_STMTL_Hdr - Dwarf_STMTL_Hdr32, or Dwarf_STMTL_Hdr64, depending + * on the header type. + * Param: + * stmtl_hdr - STMTL header in the mapped .debug_line section to cache. + */ + template + void cache_stmtl(const Dwarf_STMTL_Hdr* stmtl_hdr) { + stmtl_header_.unit_length = elf_file()->pull_val(stmtl_hdr->unit_length.size); + stmtl_header_.version = elf_file()->pull_val(stmtl_hdr->version); + stmtl_header_.header_length = elf_file()->pull_val(stmtl_hdr->header_length); + stmtl_header_.min_instruction_len = stmtl_hdr->min_instruction_len; + stmtl_header_.default_is_stmt = stmtl_hdr->default_is_stmt; + stmtl_header_.line_base = stmtl_hdr->line_base; + stmtl_header_.line_range = stmtl_hdr->line_range; + stmtl_header_.opcode_base = stmtl_hdr->opcode_base; + stmtl_header_.standard_opcode_lengths = &stmtl_hdr->standard_opcode_lengths; + stmtl_header_.start = INC_CPTR_T(Elf_Byte, &stmtl_hdr->min_instruction_len, + stmtl_header_.header_length); + stmtl_header_.end = INC_CPTR_T(Elf_Byte, &stmtl_hdr->version, + stmtl_header_.unit_length); + stmtl_header_.include_directories = + INC_CPTR_T(char, stmtl_header_.standard_opcode_lengths, + stmtl_header_.opcode_base - 1); + const char* dir = stmtl_header_.include_directories; + while (*dir != '\0') { + dir += strlen(dir) + 1; + stmtl_header_.inc_dir_num++; + } + stmtl_header_.file_infos = INC_CPTR_T(Dwarf_STMTL_FileDesc, dir, 1); + } + + /* Gets a DIE referenced by an offset from the beginning of this CU + * in the mapped .debug_info section. + */ + const Dwarf_DIE* get_referenced_die(Elf_Word ref) const { + return INC_CPTR_T(Dwarf_DIE, cu_header_, ref); + } + + /* Checks if pointer to the DIE attribute is contained within the CU's area + * of the mapped .debug_info section. + * Param: + * ptr - Pointer to the DIE attribute to check. + * Return: + * true, if pointer to the DIE attribute is contained within the CU's area + * of the mapped .debug_info section, or false if attribute pointer goes + * beyond CU's area of the mapped .debug_info section. + */ + bool is_attrib_ptr_valid(const void* ptr) const { + return diff_ptr(cu_header_, ptr) < cu_size_; + } + + protected: + /* Pointer to this compilation unit header inside the mapped .debug_info + * section of the ELF file. + */ + const Dwarf_CUHdr* cu_header_; + + /* Size of this compilation unit area in the mapped .debug_info section. + * This value has been cached off the CU header in order to avoid + * endianness conversions. + */ + Dwarf_Off cu_size_; + + /* STMT lines header, cached off mapped .debug_line section. */ + Dwarf_STMTL_Hdr stmtl_header_; +}; + +#endif // ELFF_DWARF_CU_H_ diff --git a/elff/dwarf_defs.h b/elff/dwarf_defs.h new file mode 100644 index 0000000..567df6a --- /dev/null +++ b/elff/dwarf_defs.h @@ -0,0 +1,1000 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declarations of types, constants and structures + * describing DWARF format. + */ + +#ifndef ELFF_DWARF_DEFS_H_ +#define ELFF_DWARF_DEFS_H_ + +#include "dwarf.h" +#include "elf_defs.h" + +/* DWARF structures are packed to 1 byte. */ +#define ELFF_PACKED __attribute__ ((packed)) + +/* + * Helper types for misc. DWARF variables. + */ + +/* Type for DWARF abbreviation number. */ +typedef uint32_t Dwarf_AbbrNum; + +/* Type for DWARF tag ID. */ +typedef uint16_t Dwarf_Tag; + +/* Type for DWARF attribute ID. */ +typedef uint16_t Dwarf_At; + +/* Type for DWARF form ID. */ +typedef uint16_t Dwarf_Form; + +/* Type for offset in 32-bit DWARF. */ +typedef uint32_t Dwarf32_Off; + +/* Type for offset in 64-bit DWARF. */ +typedef uint64_t Dwarf64_Off; + +/* Enumerates types of values, obtained during DWARF attribute decoding. */ +typedef enum DwarfValueType { + /* Undefined */ + DWARF_VALUE_UNKNOWN = 1, + + /* uint8_t */ + DWARF_VALUE_U8, + + /* int8_t */ + DWARF_VALUE_S8, + + /* uint16_t */ + DWARF_VALUE_U16, + + /* int16_t */ + DWARF_VALUE_S16, + + /* uint32_t */ + DWARF_VALUE_U32, + + /* int32_t */ + DWARF_VALUE_S32, + + /* uint64_t */ + DWARF_VALUE_U64, + + /* int64_t */ + DWARF_VALUE_S64, + + /* const char* */ + DWARF_VALUE_STR, + + /* 32-bit address */ + DWARF_VALUE_PTR32, + + /* 64-bit address */ + DWARF_VALUE_PTR64, + + /* Dwarf_Block */ + DWARF_VALUE_BLOCK, +} DwarfValueType; + +/* Describes block of data, stored directly in the mapped .debug_info + * section. This type is used to represent an attribute encoded with + * DW_FORM_block# form. + */ +typedef struct Dwarf_Block { + /* Pointer to the block data inside mapped .debug_info section. */ + const void* block_ptr; + + /* Byte size of the block data. */ + Elf_Word block_size; +} Dwarf_Block; + +/* Describes a value, obtained from the mapped .debug_info section + * during DWARF attribute decoding. + */ +typedef struct Dwarf_Value { + /* Unites all possible data types for the value. + * See DwarfValueType for the list of types. + */ + union { + Elf_Byte u8; + Elf_Sbyte s8; + Elf_Half u16; + Elf_Shalf s16; + Elf_Word u32; + Elf_Sword s32; + Elf_Xword u64; + Elf_Sxword s64; + Elf_Word ptr32; + Elf_Xword ptr64; + const char* str; + Dwarf_Block block; + }; + + /* Value type (defines which variable in the union abowe + * contains the value). + */ + DwarfValueType type; + + /* Number of bytes that encode this value in .debug_info section + * of ELF file. + */ + Elf_Word encoded_size; +} Dwarf_Value; + +/* DWARF's LEB128 data type. LEB128 is defined as: + * Variable Length Data. "Little Endian Base 128" (LEB128) numbers. LEB128 is + * a scheme for encoding integers densely that exploits the assumption that + * most integers are small in magnitude. (This encoding is equally suitable + * whether the target machine architecture represents data in big-endian or + * littleendian order. It is "little endian" only in the sense that it avoids + * using space to represent the "big" end of an unsigned integer, when the big + * end is all zeroes or sign extension bits). + * + * Unsigned LEB128 numbers are encoded as follows: start at the low order end + * of an unsigned integer and chop it into 7-bit chunks. Place each chunk into + * the low order 7 bits of a byte. Typically, several of the high order bytes + * will be zero; discard them. Emit the remaining bytes in a stream, starting + * with the low order byte; set the high order bit on each byte except the last + * emitted byte. The high bit of zero on the last byte indicates to the decoder + * that it has encountered the last byte. The integer zero is a special case, + * consisting of a single zero byte. + * + * The encoding for signed LEB128 numbers is similar, except that the criterion + * for discarding high order bytes is not whether they are zero, but whether + * they consist entirely of sign extension bits. Consider the 32-bit integer + * -2. The three high level bytes of the number are sign extension, thus LEB128 + * would represent it as a single byte containing the low order 7 bits, with + * the high order bit cleared to indicate the end of the byte stream. Note that + * there is nothing within the LEB128 representation that indicates whether an + * encoded number is signed or unsigned. The decoder must know what type of + * number to expect. + * + * NOTE: It's assumed that LEB128 will not contain encodings for integers, + * larger than 64 bit. +*/ +typedef struct ELFF_PACKED Dwarf_Leb128 { + /* Beginning of the LEB128 block. */ + Elf_Byte val; + + /* Pulls actual value, encoded with this LEB128 block. + * Param: + * value - Upon return will contain value, encoded with this LEB128 block. + * sign - If true, the caller expects the LEB128 to contain a signed + * integer, otherwise, caller expects an unsigned integer value to be + * encoded with this LEB128 block. + */ + void get_common(Dwarf_Value* value, bool sign) const { + value->u64 = 0; + /* Integer zero is a special case. */ + if (val == 0) { + value->type = sign ? DWARF_VALUE_S32 : DWARF_VALUE_U32; + value->encoded_size = 1; + return; + } + + /* We've got to reconstruct the integer. */ + value->type = DWARF_VALUE_UNKNOWN; + value->encoded_size = 0; + + /* Byte by byte loop though the LEB128, reconstructing the integer from + * 7-bits chunks. Byte with 8-th bit set to zero indicates the end + * of the LEB128 block. For signed integers, 7-th bit of the last LEB128 + * byte controls the sign. If 7-th bit of the last LEB128 byte is set, + * the integer is negative. If 7-th bit of the last LEB128 byte is not + * set, the integer is positive. + */ + const Elf_Byte* cur = &val; + Elf_Word shift = 0; + while ((*cur & 0x80) != 0) { + value->u64 |= (static_cast(*cur) & 0x7F) << shift; + shift += 7; + value->encoded_size++; + cur++; + } + value->u64 |= (static_cast(*cur) & 0x7F) << shift; + value->encoded_size++; + + /* LEB128 format doesn't carry any info of the sizeof of the integer it + * represents. We well guess it, judging by the highest bit set in the + * reconstucted integer. + */ + if ((value->u64 & 0xFFFFFFFF00000000LL) == 0) { + /* 32-bit integer. */ + if (sign) { + value->type = DWARF_VALUE_S32; + if (((*cur) & 0x40) != 0) { + // Value is negative. + value->u64 |= - (1 << (shift + 7)); + } else if ((value->u32 & 0x80000000) != 0) { + // Make sure we don't report negative value in this case. + value->type = DWARF_VALUE_S64; + } + } else { + value->type = DWARF_VALUE_U32; + } + } else { + /* 64-bit integer. */ + if (sign) { + value->type = DWARF_VALUE_S64; + if (((*cur) & 0x40) != 0) { + // Value is negative. + value->u64 |= - (1 << (shift + 7)); + } + } else { + value->type = DWARF_VALUE_U64; + } + } + } + + /* Pulls actual unsigned value, encoded with this LEB128 block. + * See get_common() for more info. + * Param: + * value - Upon return will contain unsigned value, encoded with + * this LEB128 block. + */ + void get_unsigned(Dwarf_Value* value) const { + get_common(value, false); + } + + /* Pulls actual signed value, encoded with this LEB128 block. + * See get_common() for more info. + * Param: + * value - Upon return will contain signed value, encoded with + * this LEB128 block. + */ + void get_signed(Dwarf_Value* value) const { + get_common(value, true); + } + + /* Pulls LEB128 value, advancing past this LEB128 block. + * See get_common() for more info. + * Return: + * Pointer to the byte past this LEB128 block. + */ + const void* process(Dwarf_Value* value, bool sign) const { + get_common(value, sign); + return INC_CPTR(&val, value->encoded_size); + } + + /* Pulls LEB128 unsigned value, advancing past this LEB128 block. + * See process() for more info. + */ + const void* process_unsigned(Dwarf_Value* value) const { + return process(value, false); + } + + /* Pulls LEB128 signed value, advancing past this LEB128 block. + * See process() for more info. + */ + const void* process_signed(Dwarf_Value* value) const { + return process(value, true); + } +} Dwarf_Leb128; + +/* DIE attribute descriptor in the .debug_abbrev section. + * Attribute descriptor contains two LEB128 values. First one provides + * attribute ID (one of DW_AT_XXX values), and the second one provides + * format (one of DW_FORMAT_XXX values), in which attribute value is + * encoded in the .debug_info section of the ELF file. + */ +typedef struct ELFF_PACKED Dwarf_Abbr_AT { + /* Attribute ID (DW_AT_XXX). + * Attribute format (DW_FORMAT_XXX) follows immediately. + */ + Dwarf_Leb128 at; + + /* Checks if this is a separator descriptor. + * Zero is an invalid attribute ID, indicating the end of attribute + * list for the current DIE. + */ + bool is_separator() const { + return at.val == 0; + } + + /* Pulls attribute data, advancing past this descriptor. + * Param: + * at_value - Upon return contains attribute value of this descriptor. + * form - Upon return contains form value of this descriptor. + * Return: + * Pointer to the byte past this descriptor block (usually, next + * attribute decriptor). + */ + const Dwarf_Abbr_AT* process(Dwarf_At* at_value, Dwarf_Form* form) const { + if (is_separator()) { + /* Size of separator descriptor is always 2 bytes. */ + *at_value = 0; + *form = 0; + return INC_CPTR_T(Dwarf_Abbr_AT, &at.val, 2); + } + + Dwarf_Value val; + + /* Process attribute ID. */ + const Dwarf_Leb128* next = + reinterpret_cast(at.process_unsigned(&val)); + *at_value = val.u16; + + /* Follow with processing the form. */ + next = reinterpret_cast(next->process_unsigned(&val)); + *form = val.u16; + return reinterpret_cast(next); + } +} Dwarf_Abbr_AT; + +/* DIE abbreviation descriptor in the .debug_abbrev section. + * DIE abbreviation descriptor contains three parameters. The first one is a + * LEB128 value, that encodes 1 - based abbreviation descriptor number. + * Abbreviation descriptor numbers seems to be always in sequential order, and + * are counted on per-compilation unit basis. I.e. abbreviation number for the + * first DIE abbreviation descriptor of each compilation unit is always 1. + * + * Besides abbreviation number, DIE abbreviation descriptor contains two more + * values. The first one (after abbr_num) is a LEB128 value containing DIE's + * tag value, and the second one is one byte flag specifying whether or not + * the DIE contains any cildren. + * + * This descriptor is immediately followed by a list of attribute descriptors + * (see Dwarf_Abbr_AT) for the DIE represented by this abbreviation descriptor. + */ +typedef struct ELFF_PACKED Dwarf_Abbr_DIE { + /* 1 - based abbreviation number for the DIE. */ + Dwarf_Leb128 abbr_num; + + /* Gets abbreviation number for this descriptor. */ + Dwarf_AbbrNum get_abbr_num() const { + Dwarf_Value val; + abbr_num.get_unsigned(&val); + return val.u16; + } + + /* Gets DIE tag for this descriptor. */ + Dwarf_Tag get_tag() const { + Dwarf_Tag tag; + process(NULL, &tag); + return tag; + } + + /* Pulls DIE abbreviation descriptor data, advancing past this descriptor. + * Param: + * abbr_index - Upon return contains abbreviation number for this + * descriptor. This parameter can be NULL, if the caller is not interested + * in this value. + * tag - Upon return contains tag of the DIE for this descriptor. This + * parameter can be NULL, if the caller is not interested in this value. + * form - Upon return contains form of the DIE for this descriptor. + * Return: + * Pointer to the list of attribute descriptors for the DIE. + */ + const Dwarf_Abbr_AT* process(Dwarf_AbbrNum* abbr_index, + Dwarf_Tag* tag) const { + Dwarf_Value val; + const Dwarf_Leb128* next = + reinterpret_cast(abbr_num.process_unsigned(&val)); + if (abbr_index != NULL) { + *abbr_index = val.u32; + } + + /* Next one is a "tag". */ + next = reinterpret_cast(next->process_unsigned(&val)); + if (tag != NULL) { + *tag = val.u16; + } + + /* Next one is a "has children" one byte flag. We're not interested in it, + * so jump to the list of attribute descriptors that immediately follows + * this DIE descriptor. */ + return INC_CPTR_T(Dwarf_Abbr_AT, next, 1); + } +} Dwarf_Abbr_DIE; + +/* DIE descriptor in the .debug_info section. + * DIE descriptor contains one LEB128-encoded value, containing DIE's + * abbreviation descriptor number in the .debug_abbrev section. + * + * DIE descriptor is immediately followed by the list of DIE attribute values, + * format of wich is defined by the list of attribute descriptors in the + * .debug_abbrev section, that immediately follow the DIE attribute descriptor, + * addressed by this descriptor's abbr_num LEB128. + */ +typedef struct ELFF_PACKED Dwarf_DIE { + /* 1 - based index of DIE abbreviation descriptor (Dwarf_Abbr_DIE) for this + * DIE in the .debug_abbrev section. + * + * NOTE: DIE abbreviation descriptor indexes are tied to the compilation + * unit. In other words, each compilation unit restarts counting DIE + * abbreviation descriptors from 1. + * + * NOTE: Zero is invalid value for this field, indicating that this DIE is a + * separator (usually it ends a list of "child" DIEs) + */ + Dwarf_Leb128 abbr_num; + + /* Checks if this is a separator DIE. */ + bool is_separator() const { + return abbr_num.val == 0; + } + + /* Gets (1 - based) abbreviation number for this DIE. */ + Dwarf_AbbrNum get_abbr_num() const { + Dwarf_Value val; + abbr_num.get_unsigned(&val); + return val.u16; + } + + /* Pulls DIE information, advancing past this descriptor to DIE attributes. + * Param: + * abbr_num - Upon return contains abbreviation number for this DIE. This + * parameter can be NULL, if the caller is not interested in this value. + * Return: + * Pointer to the byte past this descriptor (the list of DIE attributes). + */ + const Elf_Byte* process(Dwarf_AbbrNum* abbr_number) const { + if (is_separator()) { + if (abbr_number != NULL) { + *abbr_number = 0; + } + // Size of a separator DIE is 1 byte. + return INC_CPTR_T(Elf_Byte, &abbr_num.val, 1); + } + Dwarf_Value val; + const void* ret = abbr_num.process_unsigned(&val); + if (abbr_number != NULL) { + *abbr_number = val.u32; + } + return reinterpret_cast(ret); + } +} Dwarf_DIE; + +/* + * Variable size headers. + * When encoding size value in DWARF, the first 32 bits of a "size" header + * define header type. If first 32 bits of the header contain 0xFFFFFFFF + * value, this is 64-bit size header with the following 64 bits encoding + * the size. Otherwise, if first 32 bits are not 0xFFFFFFFF, they contain + * 32-bit size value. + */ + +/* Size header for 32-bit DWARF. */ +typedef struct ELFF_PACKED Dwarf32_SizeHdr { + /* Size value. */ + Elf_Word size; +} Dwarf32_SizeHdr; + +/* Size header for 64-bit DWARF. */ +typedef struct ELFF_PACKED Dwarf64_SizeHdr { + /* Size selector. For 64-bit DWARF this field is set to 0xFFFFFFFF */ + Elf_Word size_selector; + + /* Actual size value. */ + Elf_Xword size; +} Dwarf64_SizeHdr; + +/* Compilation unit header in the .debug_info section. + * Template param: + * Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr + * for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF. + * Elf_Off - Type for abbrev_offset field. Must be Elf_Word for for 32-bit + * DWARF, or Elf_Xword for 64-bit DWARF. + */ +template +struct ELFF_PACKED Dwarf_CUHdr { + /* Size of the compilation unit data in .debug_info section. */ + Dwarf_SizeHdr size_hdr; + + /* Compilation unit's DWARF version stamp. */ + Elf_Half version; + + /* Relative (to the beginning of .debug_abbrev section data) offset of the + * beginning of abbreviation sequence for this compilation unit. + */ + Elf_Off abbrev_offset; + + /* Pointer size for this compilation unit (should be 4, or 8). */ + Elf_Byte address_size; +}; +/* Compilation unit header in the .debug_info section for 32-bit DWARF. */ +typedef Dwarf_CUHdr Dwarf32_CUHdr; +/* Compilation unit header in the .debug_info section for 64-bit DWARF. */ +typedef Dwarf_CUHdr Dwarf64_CUHdr; + +/* CU STMTL header in the .debug_line section. + * Template param: + * Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr + * for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF. + * Elf_Size - Type for header_length field. Must be Elf_Word for for 32-bit + * DWARF, or Elf_Xword for 64-bit DWARF. + */ +template +struct ELFF_PACKED Dwarf_STMTLHdr { + /* The size in bytes of the line number information for this compilation + * unit, not including the unit_length field itself. */ + Dwarf_SizeHdr unit_length; + + /* A version number. This number is specific to the line number information + * and is independent of the DWARF version number. */ + Elf_Half version; + + /* The number of bytes following the header_length field to the beginning of + * the first byte of the line number program itself. In the 32-bit DWARF + * format, this is a 4-byte unsigned length; in the 64-bit DWARF format, + * this field is an 8-byte unsigned length. */ + Elf_Size header_length; + + /* The size in bytes of the smallest target machine instruction. Line number + * program opcodes that alter the address register first multiply their + * operands by this value. */ + Elf_Byte min_instruction_len; + + /* The initial value of the is_stmt register. */ + Elf_Byte default_is_stmt; + + /* This parameter affects the meaning of the special opcodes. */ + Elf_Sbyte line_base; + + /* This parameter affects the meaning of the special opcodes. */ + Elf_Byte line_range; + + /* The number assigned to the first special opcode. */ + Elf_Byte opcode_base; + + /* This is first opcode in an array specifying the number of LEB128 operands + * for each of the standard opcodes. The first element of the array + * corresponds to the opcode whose value is 1, and the last element + * corresponds to the opcode whose value is opcode_base - 1. By increasing + * opcode_base, and adding elements to this array, new standard opcodes can + * be added, while allowing consumers who do not know about these new opcodes + * to be able to skip them. NOTE: this array points to the mapped + * .debug_line section. */ + Elf_Byte standard_opcode_lengths; +}; +/* CU STMTL header in the .debug_line section for 32-bit DWARF. */ +typedef Dwarf_STMTLHdr Dwarf32_STMTLHdr; +/* CU STMTL header in the .debug_line section for 64-bit DWARF. */ +typedef Dwarf_STMTLHdr Dwarf64_STMTLHdr; + +/* Source file descriptor in the .debug_line section. + * Descriptor begins with zero-terminated file name, followed by an ULEB128, + * encoding directory index in the list of included directories, followed by + * an ULEB12, encoding file modification time, followed by an ULEB12, encoding + * file size. + */ +typedef struct ELFF_PACKED Dwarf_STMTL_FileDesc { + /* Zero-terminated file name. */ + char file_name[1]; + + /* Checks of this descriptor ends the list. */ + bool is_last_entry() const { + return file_name[0] == '\0'; + } + + /* Gets file name. */ + const char* get_file_name() const { + return file_name; + } + + /* Processes this descriptor, advancing to the next one. + * Param: + * dir_index - Upon return contains index of the parent directory in the + * list of included directories. Can be NULL if caller is not interested + * in this value. + * Return: + * Pointer to the next source file descriptor in the list. + */ + const Dwarf_STMTL_FileDesc* process(Elf_Word* dir_index) const { + if (is_last_entry()) { + return this; + } + + /* First parameter: include directory index. */ + Dwarf_Value tmp; + const Dwarf_Leb128* leb = + INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1); + leb = reinterpret_cast(leb->process_unsigned(&tmp)); + if (dir_index != NULL) { + *dir_index = tmp.u32; + } + /* Process file time. */ + leb = reinterpret_cast(leb->process_unsigned(&tmp)); + /* Process file size. */ + return reinterpret_cast(leb->process_unsigned(&tmp)); + } + + /* Gets directory index for this descriptor. */ + Elf_Word get_dir_index() const { + assert(!is_last_entry()); + if (is_last_entry()) { + return 0; + } + /* Get directory index. */ + Dwarf_Value ret; + const Dwarf_Leb128* leb = + INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1); + leb->process_unsigned(&ret); + return ret.u32; + } +} Dwarf_STMTL_FileDesc; + +/* Encapsulates a DIE attribute, collected during ELF file parsing. + */ +class DIEAttrib { + public: + /* Constructs DIEAttrib intance. */ + DIEAttrib() + : at_(0), + form_(0) { + value_.type = DWARF_VALUE_UNKNOWN; + } + + /* Destructs DIEAttrib intance. */ + ~DIEAttrib() { + } + + /* Gets DWARF attribute ID (DW_AT_Xxx) for this property. */ + Dwarf_At at() const { + return at_; + } + + /* Gets DWARF form ID (DW_FORM_Xxx) for this property. */ + Dwarf_Form form() const { + return form_; + } + + /* Gets value of this property. */ + const Dwarf_Value* value() const { + return &value_; + } + + /* Value of this property. */ + Dwarf_Value value_; + + /* DWARF attribute ID (DW_AT_Xxx) for this property. */ + Dwarf_At at_; + + /* DWARF form ID (DW_FORM_Xxx) for this property. */ + Dwarf_Form form_; +}; + +/* Parse tag context. + * This structure is used as an ELF file parsing parameter, limiting collected + * DIEs by the list of tags. + */ +typedef struct DwarfParseContext { + /* Zero-terminated list of tags to collect DIEs for. If this field is NULL, + * DIEs for all tags will be collected during the parsing. */ + const Dwarf_Tag* tags; +} DwarfParseContext; + +/* Checks if a DIE with the given tag should be collected during the parsing. + * Param: + * parse_context - Parse context to check the tag against. This parameter can + * be NULL, indicating that all tags should be collected. + * tag - Tag to check. + * Return: + * true if a DIE with the given tag should be collected during the parsing, + * or false, if the DIE should not be collected. + */ +static inline bool +collect_die(const DwarfParseContext* parse_context, Dwarf_Tag tag) { + if (parse_context == NULL || parse_context->tags == NULL) { + return true; + } + for (const Dwarf_Tag* tags = parse_context->tags; *tags != 0; tags++) { + if (*tags == tag) { + return true; + } + } + return false; +} + +/* Encapsulates an array of Dwarf_Abbr_DIE pointers, cached for a compilation + * unit. Although Dwarf_Abbr_DIE descriptors in the .debug_abbrev section of + * the ELF file seems to be always in sequential order, DIE descriptors may + * reference them randomly. So, to provide better performance, we will cache + * all Dwarf_Abbr_DIE pointers, that were found for each DIE. Since all of the + * Dwarf_Abbr_DIE are sequential, an array is the best way to cache them. + * + * NOTE: Objects of this class are instantiated one per each CU, as all DIE + * abbreviation numberation is restarted from 1 for each new CU. + */ +class DwarfAbbrDieArray { + public: + /* Constructs DwarfAbbrDieArray instance. + * Most of the CUs don't have too many unique Dwarf_Abbr_DIEs, so, in order + * to decrease the amount of memory allocation calls, we will preallocate + * a relatively small array for them along with the instance of this class, + * hopping, that all Dwarf_Abbr_DIEs for the CU will fit into it. + */ + DwarfAbbrDieArray() + : count_(0), + array_size_(ELFF_ARRAY_SIZE(small_array_)), + array_(&small_array_[0]) { + } + + /* Destructs DwarfAbbrDieArray instance. */ + ~DwarfAbbrDieArray() { + if (array_ != &small_array_[0]) { + delete[] array_; + } + } + + /* Adds new entry to the array + * Param: + * abbr - New entry to add. + * num - Abbreviation number for the adding entry. + * NOTE: before adding, this method will verify that descriptor for the + * given abbreviation number has not been cached yet. + * NOTE: due to the nature of this array, entries MUST be added strictly + * in sequential order. + * Return: + * true on success, false on failure. + */ + bool add(const Dwarf_Abbr_DIE* abbr, Dwarf_AbbrNum num) { + assert(num != 0); + if (num == 0) { + // Zero is illegal DIE abbreviation number. + _set_errno(EINVAL); + return false; + } + + if (num <= count_) { + // Already cached. + return true; + } + + // Enforce strict sequential order. + assert(num == (count_ + 1)); + if (num != (count_ + 1)) { + _set_errno(EINVAL); + return false; + } + + if (num >= array_size_) { + /* Expand the array. Make it 64 entries bigger than adding entry number. + * NOTE: that we don't check for an overflow here, since we secured + * ourselves from that by enforcing strict sequential order. So, an + * overflow may happen iff number of entries cached in this array is + * close to 4G, which is a) totally unreasonable, and b) we would die + * long before this amount of entries is cached. + */ + Dwarf_AbbrNum new_size = num + 64; + + // Reallocate. + const Dwarf_Abbr_DIE** new_array = new const Dwarf_Abbr_DIE*[new_size]; + assert(new_array != NULL); + if (new_array == NULL) { + _set_errno(ENOMEM); + return false; + } + memcpy(new_array, array_, count_ * sizeof(const Dwarf_Abbr_DIE*)); + if (array_ != &small_array_[0]) { + delete[] array_; + } + array_ = new_array; + array_size_ = new_size; + } + + // Abbreviation numbers are 1-based. + array_[num - 1] = abbr; + count_++; + return true; + } + + /* Adds new entry to the array + * Param: + * abbr - New entry to add. + * Return: + * true on success, false on failure. + */ + bool add(const Dwarf_Abbr_DIE* abbr) { + return add(abbr, abbr->get_abbr_num()); + } + + /* Gets an entry from the array + * Param: + * num - 1-based index of an entry to get. + * Return: + * Entry on success, or NULL if num exceeds the number of entries + * contained in the array. + */ + const Dwarf_Abbr_DIE* get(Dwarf_AbbrNum num) const { + assert(num != 0 && num <= count_); + if (num != 0 && num <= count_) { + return array_[num - 1]; + } else { + _set_errno(EINVAL); + return NULL; + } + } + + /* Caches Dwarf_Abbr_DIEs into this array up to the requested number. + * NOTE: This method cannot be called on an empty array. Usually, first + * entry is inserted into this array when CU object is initialized. + * Param: + * num - Entry number to cache entries up to. + * Return: + * Last cached entry (actually, an entry for the 'num' index). + */ + const Dwarf_Abbr_DIE* cache_to(Dwarf_AbbrNum num) { + /* Last cached DIE abbreviation. We always should have cached at least one + * abbreviation for the CU DIE itself, added via "add" method when CU + * object was initialized. */ + const Dwarf_Abbr_DIE* cur_abbr = get(count_); + assert(cur_abbr != NULL); + if (cur_abbr == NULL) { + return NULL; + } + + /* Starting with the last cached DIE abbreviation, loop through the + * remaining DIE abbreviations in the .debug_abbrev section of the + * mapped ELF file, caching them until we reach the requested + * abbreviation descriptor number. Normally, the very next DIE + * abbreviation will stop the loop. */ + while (num > count_) { + Dwarf_AbbrNum abbr_num; + Dwarf_Tag tmp2; + Dwarf_Form tmp3; + Dwarf_At tmp4; + + /* Process all AT abbreviations for the current DIE entry, reaching next + * DIE abbreviation. */ + const Dwarf_Abbr_AT* abbr_at = cur_abbr->process(&abbr_num, &tmp2); + while (!abbr_at->is_separator()) { + abbr_at = abbr_at->process(&tmp4, &tmp3); + } + + // Next DIE abbreviation is right after the separator AT abbreviation. + cur_abbr = reinterpret_cast + (abbr_at->process(&tmp4, &tmp3)); + if (!add(cur_abbr)) { + return NULL; + } + } + + return array_[num - 1]; + } + + /* Empties array and frees allocations. */ + void empty() { + if (array_ != &small_array_[0]) { + delete[] array_; + array_ = &small_array_[0]; + array_size_ = sizeof(small_array_) / sizeof(small_array_[0]); + } + count_ = 0; + } + + protected: + /* Array, preallocated in anticipation of relatively small number of + * DIE abbreviations in compilation unit. */ + const Dwarf_Abbr_DIE* small_array_[64]; + + /* Array of Dwarf_Abbr_DIE pointers, cached for a compilation unit. */ + const Dwarf_Abbr_DIE** array_; + + /* Current size of the array. */ + Dwarf_AbbrNum array_size_; + + /* Number of entries, cached in the array. */ + Dwarf_AbbrNum count_; +}; + +/* Encapsulates a state machine for the "Line Number Program", that is run + * on data conained in the mapped .debug_line section. + */ +class DwarfStateMachine { + public: + /* Constructs DwarfStateMachine instance. + * Param: + * set_is_stmt - Matches value of default_is_stmt field in the STMTL header. + * see Dwarf_STMTL_HdrXX. + */ + explicit DwarfStateMachine(bool set_is_stmt) + : address_(0), + file_(1), + line_(1), + column_(0), + discriminator_(0), + is_stmt_(set_is_stmt), + basic_block_(false), + end_sequence_(false), + prologue_end_(false), + epilogue_begin_(false), + isa_(0), + set_file_info_(NULL) { + } + + /* Destructs DwarfStateMachine instance. */ + ~DwarfStateMachine() { + } + + /* Resets the state to default. + * Param: + * set_is_stmt - Matches value of default_is_stmt field in the STMTL header. + * see Dwarf_STMTL_HdrXX. + */ + void reset(bool set_is_stmt) { + address_ = 0; + file_ = 1; + line_ = 1; + column_ = 0; + discriminator_ = 0; + is_stmt_ = set_is_stmt; + basic_block_ = false; + end_sequence_ = false; + prologue_end_ = false; + epilogue_begin_ = false; + isa_ = 0; + set_file_info_ = NULL; + } + + /* + * Machine state. + */ + + /* Current address (current PC value). */ + Elf_Xword address_; + + /* Current index of source file descriptor. */ + Elf_Word file_; + + /* Current line in the current source file. */ + Elf_Word line_; + + /* Current column. */ + Elf_Word column_; + + /* Current discriminator value. */ + Elf_Word discriminator_; + + /* Current STMT flag. */ + bool is_stmt_; + + /* Current basic block flag. */ + bool basic_block_; + + /* Current end of sequence flag. */ + bool end_sequence_; + + /* Current end of prologue flag. */ + bool prologue_end_; + + /* Current epilogue begin flag. */ + bool epilogue_begin_; + + /* Current ISA value. */ + Elf_Word isa_; + + /* Current value for explicitly set current source file descriptor. + * If not NULL, this descriptor has priority over the descriptor, addressed + * by the file_ member of this class. */ + const Dwarf_STMTL_FileDesc* set_file_info_; +}; + +/* Checks if given tag belongs to a routine. */ +static inline bool +dwarf_tag_is_routine(Dwarf_Tag tag) { + return tag == DW_TAG_inlined_subroutine || + tag == DW_TAG_subprogram || + tag == DW_AT_main_subprogram; +} + +/* Checks if given tag belongs to a compilation unit. */ +static inline bool +dwarf_tag_is_cu(Dwarf_Tag tag) { + return tag == DW_TAG_compile_unit || + tag == DW_TAG_partial_unit; +} + +#endif // ELFF_DWARF_DEFS_H_ diff --git a/elff/dwarf_die.cc b/elff/dwarf_die.cc new file mode 100644 index 0000000..2085e31 --- /dev/null +++ b/elff/dwarf_die.cc @@ -0,0 +1,269 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementations of classes defined for a variety of DWARF objects. + */ + +#include "stdio.h" +#include "dwarf_die.h" +#include "dwarf_cu.h" +#include "dwarf_utils.h" +#include "elf_file.h" + +DIEObject::~DIEObject() { + /* Delete all children of this object. */ + DIEObject* to_del = last_child(); + while (to_del != NULL) { + DIEObject* next = to_del->prev_sibling(); + delete to_del; + to_del = next; + } +} + +ElfFile* DIEObject::elf_file() const { + return parent_cu()->elf_file(); +} + +Dwarf_Tag DIEObject::get_tag() const { + Dwarf_Tag tag; + return advance(NULL, &tag) != NULL ? tag : 0; +} + +const char* DIEObject::get_name() const { + DIEAttrib die_attr; + /* Start with the obvious. */ + if (get_attrib(DW_AT_name, &die_attr)) { + return die_attr.value()->str; + } + + /* Lets see if there is a reference to the abstract origin, or specification, + * and use its name as the name for this DIE. */ + if (get_attrib(DW_AT_abstract_origin, &die_attr) || + get_attrib(DW_AT_specification, &die_attr)) { + DIEObject* org_die_obj = + parent_cu()->get_referenced_die_object(die_attr.value()->u32); + if (org_die_obj != NULL) { + return org_die_obj->get_name(); + } + } + + /* Lets see if there is a reference to the type DIE, and use + * its name as the name for this DIE. */ + if (get_attrib(DW_AT_type, &die_attr)) { + DIEObject* org_die_obj = + parent_cu()->get_referenced_die_object(die_attr.value()->u32); + if (org_die_obj != NULL) { + return org_die_obj->get_name(); + } + } + + /* Can't figure the name for this DIE. */ + return NULL; +} + +bool DIEObject::get_attrib(Dwarf_At at_id, DIEAttrib* attr) const { + const Dwarf_Abbr_AT* at_abbr; + + /* Advance to DIE attributes. */ + const Elf_Byte* die_attr = advance(&at_abbr, NULL); + if (die_attr == NULL) { + _set_errno(EINVAL); + return false; + } + + /* Loop through all DIE attributes, looking for the one that's being + * requested. */ + while (!at_abbr->is_separator()) { + at_abbr = at_abbr->process(&attr->at_, &attr->form_); + die_attr = parent_cu()->process_attrib(die_attr, attr->form_, &attr->value_); + if (at_id == attr->at()) { + return true; + } + } + + _set_errno(EINVAL); + + return false; +} + +DIEObject* DIEObject::get_leaf_for_address(Elf_Xword address) { + const bool contains = parent_cu()->is_CU_address_64() ? + contains_address(address) : + contains_address(address); + if (!contains && !is_cu_die()) { + /* For CU DIEs address range may be zero size, even though its child DIEs + * occupie some address space. So, if CU DIE's address range doesn't + * contain the given address, we still want to go and check the children. + */ + _set_errno(EINVAL); + return NULL; + } + + /* This DIE contains given address (or may contain it, if this is a CU DIE). + * Lets iterate through child DIEs to find the leaf (last DIE) that contains + * this address. */ + DIEObject* child = last_child(); + while (child != NULL) { + DIEObject* leaf = child->get_leaf_for_address(address); + if (leaf != NULL) { + return leaf; + } + child = child->prev_sibling(); + } + /* No child DIE contains this address. This DIE is the leaf. */ + return contains || !is_cu_die() ? this : NULL; +} + +template +bool DIEObject::contains_address(Elf_Xword address) { + DIEAttrib die_ranges; + /* DIE can contain either list of ranges (f.i. DIEs that represent a routine + * that is inlined in multiple places will contain list of address ranges + * where that routine is inlined), or a pair "low PC, and high PC" describing + * contiguos address space where routine has been placed by compiler. */ + if (get_attrib(DW_AT_ranges, &die_ranges)) { + /* Iterate through this DIE's ranges list, looking for the one that + * contains the given address. */ + AddrType low; + AddrType high; + Elf_Word range_off = die_ranges.value()->u32; + while (elf_file()->get_range(range_off, &low, &high) && + (low != 0 || high != 0)) { + if (address >= low && address < high) { + return true; + } + range_off += sizeof(AddrType) * 2; + } + return false; + } else { + /* This DIE doesn't have ranges. Lets see if it has low_pc and high_pc + * attributes. */ + DIEAttrib low_pc; + DIEAttrib high_pc; + if (!get_attrib(DW_AT_low_pc, &low_pc) || + !get_attrib(DW_AT_high_pc, &high_pc) || + address < low_pc.value()->u64 || + address >= high_pc.value()->u64) { + return false; + } + return true; + } +} + +DIEObject* DIEObject::find_die_object(const Dwarf_DIE* die_to_find) { + if (die_to_find == die()) { + return this; + } + + /* First we will iterate through the list of children, since chances to + * find requested DIE decrease as we go deeper into DIE tree. */ + DIEObject* iter = last_child(); + while (iter != NULL) { + if (iter->die() == die_to_find) { + return iter; + } + iter = iter->prev_sibling(); + }; + + /* DIE has not been found among the children. Lets go deeper now. */ + iter = last_child(); + while (iter != NULL) { + DIEObject* ret = iter->find_die_object(die_to_find); + if (ret != NULL) { + return ret; + } + iter = iter->prev_sibling(); + } + + _set_errno(EINVAL); + return NULL; +} + +void DIEObject::dump(bool only_this) const { + const Dwarf_Abbr_AT* at_abbr; + Dwarf_Tag tag; + + const Elf_Byte* die_attr = advance(&at_abbr, &tag); + if (die_attr != NULL) { + printf("\n********** DIE[%p(%04X)] %s: %s **********\n", + die_, parent_cu()->get_die_reference(die_), dwarf_tag_name(tag), + get_name()); + + /* Dump this DIE attributes. */ + while (!at_abbr->is_separator()) { + DIEAttrib attr; + at_abbr = at_abbr->process(&attr.at_, &attr.form_); + die_attr = parent_cu()->process_attrib(die_attr, attr.form(), &attr.value_); + dump_attrib(attr.at(), attr.form(), attr.value()); + if (attr.at() == DW_AT_ranges) { + /* Dump all ranges for this DIE. */ + Elf_Word off = attr.value()->u32; + if (parent_cu()->is_CU_address_64()) { + Elf_Xword low, high; + while (elf_file()->get_range(off, &low, &high) && + (low != 0 || high != 0)) { + printf(" %08I64X - %08I64X\n", + low, high); + off += 16; + } + } else { + Elf_Word low, high; + while (elf_file()->get_range(off, &low, &high) && + (low != 0 || high != 0)) { + printf(" %08X - %08X\n", + low, high); + off += 8; + } + } + } + } + } + + if (only_this) { + if (parent_die_ != NULL && !parent_die_->is_cu_die()) { + printf("\n-----------> CHILD OF:\n"); + parent_die_->dump(true); + } + } else { + /* Dump this DIE's children. */ + if (last_child() != NULL) { + last_child()->dump(false); + } + + /* Dump this DIE's siblings. */ + if (prev_sibling() != NULL) { + prev_sibling()->dump(false); + } + } +} + +const Elf_Byte* DIEObject::advance(const Dwarf_Abbr_AT** at_abbr, + Dwarf_Tag* tag) const { + Dwarf_AbbrNum abbr_num; + Dwarf_Tag die_tag; + + const Elf_Byte* die_attr = die()->process(&abbr_num); + const Dwarf_Abbr_DIE* abbr = parent_cu()->get_die_abbr(abbr_num); + if (abbr == NULL) { + return NULL; + } + + const Dwarf_Abbr_AT* attrib_abbr = abbr->process(NULL, &die_tag); + if (at_abbr != NULL) { + *at_abbr = attrib_abbr; + } + if (tag != NULL) { + *tag = die_tag; + } + return die_attr; +} diff --git a/elff/dwarf_die.h b/elff/dwarf_die.h new file mode 100644 index 0000000..21dea37 --- /dev/null +++ b/elff/dwarf_die.h @@ -0,0 +1,202 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declarations of classes defined for a variety of DWARF objects. + */ + +#ifndef ELFF_DWARF_DIE_H_ +#define ELFF_DWARF_DIE_H_ + +#include "dwarf_defs.h" +#include "elf_alloc.h" + +class ElfFile; +class DwarfCU; + +/* Encapsulates an object that wraps up a DIE, cached during + * ELF file parsing. + */ +class DIEObject : public DwarfAllocBase { + public: + /* Constructs DIEObject intance. + * Param: + * die - DIE represented with this instance. + * parent_cu - Compilation unit this DIE belongs to. + * parent_die - Parent DIE object for this DIE. This parameter can be NULL + * only for compilation unit DIEs. + */ + DIEObject(const Dwarf_DIE* die, DwarfCU* parent_cu, DIEObject* parent_die) + : die_(die), + parent_cu_(parent_cu), + parent_die_(parent_die), + prev_sibling_(NULL), + last_child_(NULL) { + } + + /* Destructs DIEObject intance. */ + ~DIEObject(); + + /* Gets ELF file this DIE belongs to. */ + ElfFile* elf_file() const; + + /* Gets DWARF tag (DW_TAG_Xxx) for the DIE represented with this instance. */ + Dwarf_Tag get_tag() const; + + /* Gets the best name for this DIE. + * Some DIEs (such as inline routine DIEs) may have no DW_AT_name property, + * but may reference to another DIE that may contain DIE name. This method + * tries its best to get DIE name by iterating through different methods of + * naming the DIE. + * Return: + * Name for this DIE, or NULL if it was not possible to find a relevant DIE + * with DW_AT_name property. + */ + const char* get_name() const; + + /* Gets DIE's attribute by its ID. + * Param: + * at_id - ID (DW_AT_Xxx) of the attribute to get. + * attr - Upon successful return contains requested attribute information. + * Return: + * true on success, or false if attribute for the given ID doesn't exist + * in the DIE's attribute list. + */ + bool get_attrib(Dwarf_At at, DIEAttrib* attr) const; + + /* Gets the leaf DIE object containing given address. + * See DwarfCU::get_leaf_die_for_address() for method details. + * See DIEObject::contains_address() for implementation details. + */ + DIEObject* get_leaf_for_address(Elf_Xword address); + + /* Finds a DIE object for the given die in the branch starting with + * this DIE object. + */ + DIEObject* find_die_object(const Dwarf_DIE* die_to_find); + + /* Dumps this object to stdout. + * Param: + * only_this - If true, only this object will be dumped. If this parameter + * is false, all the childs and siblings of this object will be dumped + * along with this object. + */ + void dump(bool only_this) const; + + protected: + /* Checks if this DIE object containing given address. + * Template param: + * AddrType - Type of compilation unin address (4, or 8 bytes), defined by + * address_size field of the CU header. Must be Elf_Xword for 8 bytes + * address, or Elf_Word for 4 bytes address. + * Param: + * address - Address ti check. + * Return: + * True, if this DIE address ranges (including low_pc, high_pc attributes) + * contain given address, or false otherwise. + */ + template + bool contains_address(Elf_Xword address); + + /* Advances to the DIE's property list. + * Param: + * at_abbr - Upon successful return contains a pointer to the beginning of + * DIE attribute abbreviation list. This parameter can be NULL, if the + * caller is not interested in attribute abbreviation list for this DIE. + * tag - Upon successful return contains DIE's tag. This parameter can be + * NULL, if the caller is not interested in the tag value for this DIE. + * Return: + * Pointer to the beginning of the DIE attribute list in mapped .debug_info + * section on success, or NULL on failure. + */ + const Elf_Byte* advance(const Dwarf_Abbr_AT** at_abbr, Dwarf_Tag* tag) const; + + public: + /* Gets DIE represented with this instance. */ + const Dwarf_DIE* die() const { + return die_; + } + + /* Gets compilation unit this DIE belongs to. */ + DwarfCU* parent_cu() const { + return parent_cu_; + } + + /* Gets parent DIE object for this die. */ + DIEObject* parent_die() const { + return parent_die_; + } + + /* Gets last child object in the list of this DIE's childs. NOTE: for better + * performace the list is created in reverse order (relatively to the order, + * in which children DIEs have been discovered). + */ + DIEObject* last_child() const { + return last_child_; + } + + /* Links next child to the list of this DIE childs. */ + void link_child(DIEObject* child) { + last_child_ = child; + } + + /* Gets previous sibling of this DIE in the parent's DIE object list. */ + DIEObject* prev_sibling() const { + return prev_sibling_; + } + + /* Links next sibling to the list of this DIE siblings. */ + void link_sibling(DIEObject* sibl) { + prev_sibling_ = sibl; + } + + /* Checks if this DIE object represents a CU DIE. + * We relay here on the fact that only CU DIE objects have no parent + * DIE objects. + */ + bool is_cu_die() const { + return parent_die_ == NULL; + } + + /* Gets this DIE level in the branch. + * DIE level defines DIE's distance from the CU DIE in the branch this DIE + * belongs to. In other words, DIE level defines how many parent DIEs exist + * between this DIE, and the CU DIE. For instance, the CU DIE has level 0, + * a subroutine a() in this compilation unit has level 1, a soubroutine b(), + * that has been inlined into subroutine a() will have level 2, a try/catch + * block in the inlined subroutine b() will have level 3, and so on. + */ + Elf_Word get_level() const { + return parent_die_ != NULL ? parent_die_->get_level() + 1 : 0; + } + + protected: + /* DIE that is represented with this instance. */ + const Dwarf_DIE* die_; + + /* Compilation unit this DIE belongs to. */ + DwarfCU* parent_cu_; + + /* Parent DIE object for this die. */ + DIEObject* parent_die_; + + /* Last child object in the list of this DIE's childs. NOTE: for better + * performace the list is created in reverse order (relatively to the order, + * in which children DIEs have been discovered). + */ + DIEObject* last_child_; + + /* Previous sibling of this DIE in the parent's DIE object list. */ + DIEObject* prev_sibling_; +}; + +#endif // ELFF_DWARF_DIE_H_ diff --git a/elff/dwarf_utils.cc b/elff/dwarf_utils.cc new file mode 100644 index 0000000..56c05a3 --- /dev/null +++ b/elff/dwarf_utils.cc @@ -0,0 +1,313 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of misc. DWARF utility routines. + */ + +#include "stdio.h" +#include "dwarf_utils.h" + +/* "Stringifies" the parameter. */ +#define DWARF_NAMEFY(val) case val: return "" #val "" + +/* "Stringifies" two parameters. */ +#define DWARF_NAMEFY2(val1, val2) case val1: return "" #val1 " | " #val2 "" + +const char* +dwarf_at_name(Dwarf_At at) { + switch (at) { + DWARF_NAMEFY(DW_AT_sibling); + DWARF_NAMEFY(DW_AT_location); + DWARF_NAMEFY(DW_AT_name); + DWARF_NAMEFY(DW_AT_ordering); + DWARF_NAMEFY(DW_AT_subscr_data); + DWARF_NAMEFY(DW_AT_byte_size); + DWARF_NAMEFY(DW_AT_bit_offset); + DWARF_NAMEFY(DW_AT_bit_size); + DWARF_NAMEFY(DW_AT_element_list); + DWARF_NAMEFY(DW_AT_stmt_list); + DWARF_NAMEFY(DW_AT_low_pc); + DWARF_NAMEFY(DW_AT_high_pc); + DWARF_NAMEFY(DW_AT_language); + DWARF_NAMEFY(DW_AT_member); + DWARF_NAMEFY(DW_AT_discr); + DWARF_NAMEFY(DW_AT_discr_value); + DWARF_NAMEFY(DW_AT_visibility); + DWARF_NAMEFY(DW_AT_import); + DWARF_NAMEFY(DW_AT_string_length); + DWARF_NAMEFY(DW_AT_common_reference); + DWARF_NAMEFY(DW_AT_comp_dir); + DWARF_NAMEFY(DW_AT_const_value); + DWARF_NAMEFY(DW_AT_containing_type); + DWARF_NAMEFY(DW_AT_default_value); + DWARF_NAMEFY(DW_AT_inline); + DWARF_NAMEFY(DW_AT_is_optional); + DWARF_NAMEFY(DW_AT_lower_bound); + DWARF_NAMEFY(DW_AT_producer); + DWARF_NAMEFY(DW_AT_prototyped); + DWARF_NAMEFY(DW_AT_return_addr); + DWARF_NAMEFY(DW_AT_start_scope); + DWARF_NAMEFY2(DW_AT_bit_stride, DW_AT_stride_size); + DWARF_NAMEFY(DW_AT_upper_bound); + DWARF_NAMEFY(DW_AT_abstract_origin); + DWARF_NAMEFY(DW_AT_accessibility); + DWARF_NAMEFY(DW_AT_address_class); + DWARF_NAMEFY(DW_AT_artificial); + DWARF_NAMEFY(DW_AT_base_types); + DWARF_NAMEFY(DW_AT_calling_convention); + DWARF_NAMEFY(DW_AT_count); + DWARF_NAMEFY(DW_AT_data_member_location); + DWARF_NAMEFY(DW_AT_decl_column); + DWARF_NAMEFY(DW_AT_decl_file); + DWARF_NAMEFY(DW_AT_decl_line); + DWARF_NAMEFY(DW_AT_declaration); + DWARF_NAMEFY(DW_AT_discr_list); + DWARF_NAMEFY(DW_AT_encoding); + DWARF_NAMEFY(DW_AT_external); + DWARF_NAMEFY(DW_AT_frame_base); + DWARF_NAMEFY(DW_AT_friend); + DWARF_NAMEFY(DW_AT_identifier_case); + DWARF_NAMEFY(DW_AT_macro_info); + DWARF_NAMEFY(DW_AT_namelist_item); + DWARF_NAMEFY(DW_AT_priority); + DWARF_NAMEFY(DW_AT_segment); + DWARF_NAMEFY(DW_AT_specification); + DWARF_NAMEFY(DW_AT_static_link); + DWARF_NAMEFY(DW_AT_type); + DWARF_NAMEFY(DW_AT_use_location); + DWARF_NAMEFY(DW_AT_variable_parameter); + DWARF_NAMEFY(DW_AT_virtuality); + DWARF_NAMEFY(DW_AT_vtable_elem_location); + DWARF_NAMEFY(DW_AT_allocated); + DWARF_NAMEFY(DW_AT_associated); + DWARF_NAMEFY(DW_AT_data_location); + DWARF_NAMEFY2(DW_AT_byte_stride, DW_AT_stride); + DWARF_NAMEFY(DW_AT_entry_pc); + DWARF_NAMEFY(DW_AT_use_UTF8); + DWARF_NAMEFY(DW_AT_extension); + DWARF_NAMEFY(DW_AT_ranges); + DWARF_NAMEFY(DW_AT_trampoline); + DWARF_NAMEFY(DW_AT_call_column); + DWARF_NAMEFY(DW_AT_call_file); + DWARF_NAMEFY(DW_AT_call_line); + DWARF_NAMEFY(DW_AT_description); + DWARF_NAMEFY(DW_AT_binary_scale); + DWARF_NAMEFY(DW_AT_decimal_scale); + DWARF_NAMEFY(DW_AT_small); + DWARF_NAMEFY(DW_AT_decimal_sign); + DWARF_NAMEFY(DW_AT_digit_count); + DWARF_NAMEFY(DW_AT_picture_string); + DWARF_NAMEFY(DW_AT_mutable); + DWARF_NAMEFY(DW_AT_threads_scaled); + DWARF_NAMEFY(DW_AT_explicit); + DWARF_NAMEFY(DW_AT_object_pointer); + DWARF_NAMEFY(DW_AT_endianity); + DWARF_NAMEFY(DW_AT_elemental); + DWARF_NAMEFY(DW_AT_pure); + DWARF_NAMEFY(DW_AT_recursive); + DWARF_NAMEFY(DW_AT_signature); + DWARF_NAMEFY(DW_AT_main_subprogram); + DWARF_NAMEFY(DW_AT_data_bit_offset); + DWARF_NAMEFY(DW_AT_const_expr); + DWARF_NAMEFY(DW_AT_enum_class); + DWARF_NAMEFY(DW_AT_linkage_name); + default: + return "DW_AT_Unknown"; + } +} + +const char* +dwarf_form_name(Dwarf_Form form) { + switch (form) { + DWARF_NAMEFY(DW_FORM_addr); + DWARF_NAMEFY(DW_FORM_block2); + DWARF_NAMEFY(DW_FORM_block4); + DWARF_NAMEFY(DW_FORM_data2); + DWARF_NAMEFY(DW_FORM_data4); + DWARF_NAMEFY(DW_FORM_data8); + DWARF_NAMEFY(DW_FORM_string); + DWARF_NAMEFY(DW_FORM_block); + DWARF_NAMEFY(DW_FORM_block1); + DWARF_NAMEFY(DW_FORM_data1); + DWARF_NAMEFY(DW_FORM_flag); + DWARF_NAMEFY(DW_FORM_sdata); + DWARF_NAMEFY(DW_FORM_strp); + DWARF_NAMEFY(DW_FORM_udata); + DWARF_NAMEFY(DW_FORM_ref_addr); + DWARF_NAMEFY(DW_FORM_ref1); + DWARF_NAMEFY(DW_FORM_ref2); + DWARF_NAMEFY(DW_FORM_ref4); + DWARF_NAMEFY(DW_FORM_ref8); + DWARF_NAMEFY(DW_FORM_ref_udata); + DWARF_NAMEFY(DW_FORM_indirect); + DWARF_NAMEFY(DW_FORM_sec_offset); + DWARF_NAMEFY(DW_FORM_exprloc); + DWARF_NAMEFY(DW_FORM_flag_present); + DWARF_NAMEFY(DW_FORM_ref_sig8); + default: + return "DW_FORM_Unknown"; + } +} + +const char* +dwarf_tag_name(Dwarf_Tag tag) { + switch (tag) { + DWARF_NAMEFY(DW_TAG_array_type); + DWARF_NAMEFY(DW_TAG_class_type); + DWARF_NAMEFY(DW_TAG_entry_point); + DWARF_NAMEFY(DW_TAG_enumeration_type); + DWARF_NAMEFY(DW_TAG_formal_parameter); + DWARF_NAMEFY(DW_TAG_imported_declaration); + DWARF_NAMEFY(DW_TAG_label); + DWARF_NAMEFY(DW_TAG_lexical_block); + DWARF_NAMEFY(DW_TAG_member); + DWARF_NAMEFY(DW_TAG_pointer_type); + DWARF_NAMEFY(DW_TAG_reference_type); + DWARF_NAMEFY(DW_TAG_compile_unit); + DWARF_NAMEFY(DW_TAG_string_type); + DWARF_NAMEFY(DW_TAG_structure_type); + DWARF_NAMEFY(DW_TAG_subroutine_type); + DWARF_NAMEFY(DW_TAG_typedef); + DWARF_NAMEFY(DW_TAG_union_type); + DWARF_NAMEFY(DW_TAG_unspecified_parameters); + DWARF_NAMEFY(DW_TAG_variant); + DWARF_NAMEFY(DW_TAG_common_block); + DWARF_NAMEFY(DW_TAG_common_inclusion); + DWARF_NAMEFY(DW_TAG_inheritance); + DWARF_NAMEFY(DW_TAG_inlined_subroutine); + DWARF_NAMEFY(DW_TAG_module); + DWARF_NAMEFY(DW_TAG_ptr_to_member_type); + DWARF_NAMEFY(DW_TAG_set_type); + DWARF_NAMEFY(DW_TAG_subrange_type); + DWARF_NAMEFY(DW_TAG_with_stmt); + DWARF_NAMEFY(DW_TAG_access_declaration); + DWARF_NAMEFY(DW_TAG_base_type); + DWARF_NAMEFY(DW_TAG_catch_block); + DWARF_NAMEFY(DW_TAG_const_type); + DWARF_NAMEFY(DW_TAG_constant); + DWARF_NAMEFY(DW_TAG_enumerator); + DWARF_NAMEFY(DW_TAG_file_type); + DWARF_NAMEFY(DW_TAG_friend); + DWARF_NAMEFY(DW_TAG_namelist); + DWARF_NAMEFY2(DW_TAG_namelist_item, DW_TAG_namelist_items); + DWARF_NAMEFY(DW_TAG_packed_type); + DWARF_NAMEFY(DW_TAG_subprogram); + DWARF_NAMEFY2(DW_TAG_template_type_parameter, DW_TAG_template_type_param); + DWARF_NAMEFY2(DW_TAG_template_value_parameter, + DW_TAG_template_value_param); + DWARF_NAMEFY(DW_TAG_thrown_type); + DWARF_NAMEFY(DW_TAG_try_block); + DWARF_NAMEFY(DW_TAG_variant_part); + DWARF_NAMEFY(DW_TAG_variable); + DWARF_NAMEFY(DW_TAG_volatile_type); + DWARF_NAMEFY(DW_TAG_dwarf_procedure); + DWARF_NAMEFY(DW_TAG_restrict_type); + DWARF_NAMEFY(DW_TAG_interface_type); + DWARF_NAMEFY(DW_TAG_namespace); + DWARF_NAMEFY(DW_TAG_imported_module); + DWARF_NAMEFY(DW_TAG_unspecified_type); + DWARF_NAMEFY(DW_TAG_partial_unit); + DWARF_NAMEFY(DW_TAG_imported_unit); + DWARF_NAMEFY(DW_TAG_mutable_type); + DWARF_NAMEFY(DW_TAG_condition); + DWARF_NAMEFY(DW_TAG_shared_type); + DWARF_NAMEFY(DW_TAG_type_unit); + DWARF_NAMEFY(DW_TAG_rvalue_reference_type); + DWARF_NAMEFY(DW_TAG_template_alias); + default: + return "DW_TAG_Unknown"; + } +} + +void +dump_attrib(Dwarf_At at, Dwarf_Form form, const Dwarf_Value* val) { + if (form != 0) { + printf(" +++ Attribute: %s [%s]\n", + dwarf_at_name(at), dwarf_form_name(form)); + } else { + printf(" +++ Attribute: %s\n", dwarf_at_name(at)); + } + dump_value(val); +} + +void +dump_value(const Dwarf_Value* attr_value) { + printf(" Data[%03u]: (", attr_value->encoded_size); + switch (attr_value->type) { + case DWARF_VALUE_U8: + printf("BYTE) = %u (x%02X)\n", (Elf_Word)attr_value->u8, + (Elf_Word)attr_value->u8); + break; + + case DWARF_VALUE_S8: + printf("SBYTE) = %d (x%02X)\n", (Elf_Sword)attr_value->s8, + (Elf_Sword)attr_value->s8); + break; + + case DWARF_VALUE_U16: + printf("WORD) = %u (x%04X)\n", (Elf_Word)attr_value->u16, + (Elf_Word)attr_value->u16); + break; + + case DWARF_VALUE_S16: + printf("SWORD) = %d (x%04X)\n", (Elf_Sword)attr_value->s16, + (Elf_Sword)attr_value->s16); + break; + + case DWARF_VALUE_U32: + printf("DWORD) = %u (x%08X)\n", attr_value->u32, + attr_value->u32); + break; + + case DWARF_VALUE_S32: + printf("SDWORD) = %d (x%08X)\n", attr_value->s32, + attr_value->s32); + break; + + case DWARF_VALUE_U64: + printf("XWORD) = %I64u (x%I64X)\n", attr_value->u64, + attr_value->u64); + break; + + case DWARF_VALUE_S64: + printf("SXWORD) = %I64d (x%I64X)\n", attr_value->s64, + attr_value->s64); + break; + + case DWARF_VALUE_STR: + printf("STRING) = %s\n", attr_value->str); + break; + + case DWARF_VALUE_PTR32: + printf("PTR32) = x%08X\n", attr_value->ptr32); + break; + + case DWARF_VALUE_PTR64: + printf("PTR64) = x%08I64X\n", attr_value->ptr64); + break; + + case DWARF_VALUE_BLOCK: + printf("BLOCK) = [%I64u]:", attr_value->block.block_size); + for (Elf_Xword i = 0; i < attr_value->block.block_size; i++) { + Elf_Byte prnt = *((const Elf_Byte*)attr_value->block.block_ptr + i); + printf(" x%02X", prnt); + } + printf("\n"); + break; + + case DWARF_VALUE_UNKNOWN: + default: + printf("UNKNOWN)"); + break; + } +} diff --git a/elff/dwarf_utils.h b/elff/dwarf_utils.h new file mode 100644 index 0000000..fc007d1 --- /dev/null +++ b/elff/dwarf_utils.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declarations of misc. DWARF utility routines. + */ + +#ifndef ELFF_DWARF_UTILS_ +#define ELFF_DWARF_UTILS_ + +#include "dwarf_defs.h" + +/* Gets DWARF attribute name string (DW_AT_Xxx) for a given attribute ID. + * Param: + * at - DWARF attribute ID to get name string for. + * Return: + * Attribute name string. Note that this routine returns "DW_AT_Unknown", + * if DWARF attribute value passed to this routine has not been recognized. + */ +const char* dwarf_at_name(Dwarf_At at); + +/* Gets DWARF form name string (DW_FORM_Xxx) for a given form. + * Param: + * form - DWARF form to get name string for. + * Return: + * Form name string. Note that this routine returns "DW_FORM_Unknown", if + * DWARF form value passed to this routine has not been recognized. + */ +const char* dwarf_form_name(Dwarf_Form form); + +/* Gets DWARF tag name string (DW_TAG_Xxx) for a given tag. + * Param: + * tag - DWARF tag to get name string for. + * Return: + * Tag name string. Note that this routine returns "DW_TAG_Unknown", if DWARF + * tag value passed to this routine has not been recognized. + */ +const char* dwarf_tag_name(Dwarf_Tag tag); + +/* Dumps DWARF attribute to stdout. + * Param: + * at - Attribute ID (DW_AT_Xxx) + * form - Attribute form (DW_FORM_Xxx) + * val - Attribute value. + */ +void dump_attrib(Dwarf_At at, Dwarf_Form form, const Dwarf_Value* val); + +/* Dumps DWARF attribute value to stdout. + * Param: + * val - Attribute value. + */ +void dump_value(const Dwarf_Value* val); + +#endif // ELFF_DWARF_UTILS_ diff --git a/elff/elf.h b/elff/elf.h new file mode 100644 index 0000000..de92ba6 --- /dev/null +++ b/elff/elf.h @@ -0,0 +1,299 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declarations of types, constants and structures + * describing ELF file format. + */ + +#ifndef ELFF_ELH_H_ +#define ELFF_ELH_H_ + +extern "C" { +#include "qemu-common.h" +} +#include "elff-common.h" + +//============================================================================= +// ELF file definitions +//============================================================================= + +#ifdef WIN32 +typedef HANDLE ELF_FILE_HANDLE; +#define INVALID_ELF_FILE_HANDLE INVALID_HANDLE_VALUE +#define close_elf_file_handle CloseHandle +#else // WIN32 +typedef int ELF_FILE_HANDLE; +#define INVALID_ELF_FILE_HANDLE -1 +#define close_elf_file_handle close +#endif // WIN32 + +/* Checks if ELF file handle is valid. */ +static inline bool +elfhandle_is_valid(ELF_FILE_HANDLE handle) { + return handle != INVALID_ELF_FILE_HANDLE; +} + +/* + * ELF format documentation uses Elf##_Xxx notation for data types, where + * ## stands for CPU architecture (32, or 64 bit), and Xxx stands for a + * specific type. For the sake of compliance, we will follow doc's notation + * when defining types used in ELF file descriptors. However, for the sake of + * code simplicity, we will drop CPU architecture index from the types that + * have equal sizes on both, 32 and 64 bit architectures. + */ + +/* + * Architecture independent types. + */ + +typedef uint8_t Elf_Byte; +typedef int8_t Elf_Sbyte; + +typedef uint16_t Elf_Half; +typedef int16_t Elf_Shalf; + +typedef uint32_t Elf_Word; +typedef int32_t Elf_Sword; + +typedef uint64_t Elf_Xword; +typedef int64_t Elf_Sxword; + +/* + * Architecture dependent types. + */ + +/* 32-bit ELF address. */ +typedef uint32_t Elf32_Addr; +/* 32-bit ELF offset. */ +typedef uint32_t Elf32_Off; + +/* 64-bit ELF address. */ +typedef uint64_t Elf64_Addr; +/* 64-bit ELF offset. */ +typedef uint64_t Elf64_Off; + +//============================================================================= +// ELF file header +//============================================================================= + +/* Byte size of the fixed portion of ELF header. */ +#define EI_NIDENT 16 + +/* Common (architecture independent portion of) ELF file header, + * that starts at offset 0 in ELF file. + */ +typedef struct Elf_CommonHdr { + union { + struct { + /* ei_mag0 - ei_mag3 contain ELF header signature. See ELFMAGx bellow. */ + Elf_Byte ei_mag0; + Elf_Byte ei_mag1; + Elf_Byte ei_mag2; + Elf_Byte ei_mag3; + + /* File class (32, or 64 bits). See ELFCLASSxxx bellow. */ + Elf_Byte ei_class; + + /* Data encoding (endianness). See ELFDATAxxx bellow. */ + Elf_Byte ei_data; + + /* ELF header version number. */ + Elf_Byte ei_version; + } ei_info; + unsigned char e_ident[EI_NIDENT]; + }; + + /* File type (executable, shared object, etc.) */ + Elf_Half e_type; + + /* Processor type. */ + Elf_Half e_machine; + + /* File version. */ + Elf_Word e_version; +} Elf_CommonHdr; + + +/* ELF header signature. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +/* + * Possible ei_class values. + */ + +/* Invalid. */ +#define ELFCLASSNONE 0 +/* It's 32-bit ELF file. */ +#define ELFCLASS32 1 +/* It's 64-bit ELF file. */ +#define ELFCLASS64 2 + +/* + * Possible ei_data values. + */ + +/* Invalid. */ +#define ELFDATANONE 0 +/* ELF data is formatted in little-endian. */ +#define ELFDATA2LSB 1 +/* ELF data is formatted in big-endian. */ +#define ELFDATA2MSB 2 + +/* Tempated (architecture dependent) ELF file header. + * Template param: + * Elf_Addr - Actual type for address encoding (Elf32_Addr, or Elf64_Addr). + * Elf_Off - Actual type for offset encoding (Elf32_Off, or Elf64_Off). + */ +template +struct Elf_FHdr { + /* Common header. */ + Elf_CommonHdr common; + + /* Module entry point. */ + Elf_Addr e_entry; + + /* Programm header table offset (in bytes) from the beginning of the file. + * Zero if there is no programm header in this file. + */ + Elf_Off e_phoff; + + /* Section header table offset (in bytes) from the beginning of the file. + * Zero if there is no section header in this file. + */ + Elf_Off e_shoff; + + /* Processor-specific flags. */ + Elf_Word e_flags; + + /* This header size in bytes. */ + Elf_Half e_ehsize; + + /* Byte size of an entry in programm header table. All entries + * in the table are the same size. + */ + Elf_Half e_phentsize; + + /* Number of entries in programm header table. */ + Elf_Half e_phnum; + + /* Byte size of an entry in section header table. All entries + * in the table are the same size. + */ + Elf_Half e_shentsize; + + /* Number of entries in section header table. */ + Elf_Half e_shnum; + + /* Zero-based index of an entry for name string table section in the section + * header table. If no such section exists in the file this field contains + * SHN_UNDEF value. + */ + Elf_Half e_shstrndx; +}; +/* 32-bit ELF header. */ +typedef Elf_FHdr Elf32_FHdr; +/* 64-bit ELF header. */ +typedef Elf_FHdr Elf64_FHdr; + +//============================================================================= +// ELF section header +//============================================================================= + +/* Templated (architecture dependent) section header for ELF file. + * Template param: + * Elf_Addr - Actual type for address encoding (Elf32_Addr, or Elf64_Addr). + * Elf_Off - Actual type for offset encoding (Elf32_Off, or Elf64_Off). + */ +template +struct Elf_SHdr { + /* Index (byte offset) of section name in the name string table section. */ + Elf_Word sh_name; + + /* Section type and semantics. */ + Elf_Word sh_type; + + /* Section flags and attributes. */ + Elf_Word sh_flags; + + /* Section address in the memory image of the process. */ + Elf_Addr sh_addr; + + /* Byte offset from the beginning of the ELF file to the first + * byte in the section. + */ + Elf_Off sh_offset; + + /* Section size in bytes. */ + Elf_Word sh_size; + + /* Section header table index link. Depends on section type. */ + Elf_Word sh_link; + + /* Extra section information, depending on the section type. */ + Elf_Word sh_info; + + /* Address alignment constrains. 0 and 1 means that section has no + * alignment constrains. + */ + Elf_Word sh_addralign; + + /* Entry size for sections that hold some kind of a table. */ + Elf_Word sh_entsize; +}; +/* 32-bit section header. */ +typedef Elf_SHdr Elf32_SHdr; +/* 64-bit section header. */ +typedef Elf_SHdr Elf64_SHdr; + +/* + * Special section indices + */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_LOOS 0xff20 +#define SHN_HIOS 0xff3f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xffff + +/* + * Values for sh_type + */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_NUM 19 + +#endif // ELFF_ELH_H_ diff --git a/elff/elf_alloc.cc b/elff/elf_alloc.cc new file mode 100644 index 0000000..10d740b --- /dev/null +++ b/elff/elf_alloc.cc @@ -0,0 +1,62 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of class ElfAllocator, that implements memory + * allocations for DWARF objects. + */ + +#include "elf_alloc.h" +#include "elf_file.h" + +ElfAllocator::ElfAllocator() + : current_chunk_(NULL) { +} + +ElfAllocator::~ElfAllocator() { + ElfAllocatorChunk* chunk_to_free = current_chunk_; + while (chunk_to_free != NULL) { + ElfAllocatorChunk* next_chunk = chunk_to_free->prev; + free(chunk_to_free); + chunk_to_free = next_chunk; + } +} + +void* ElfAllocator::alloc(size_t size) { + /* Lets keep everyting properly aligned. */ + size = (size + ELFALLOC_ALIGNMENT_MASK) & ~ELFALLOC_ALIGNMENT_MASK; + + if (current_chunk_ == NULL || current_chunk_->remains < size) { + /* Allocate new chunk. */ + ElfAllocatorChunk* new_chunk = + reinterpret_cast(malloc(ELF_ALLOC_CHUNK_SIZE)); + assert(new_chunk != NULL); + if (new_chunk == NULL) { + _set_errno(ENOMEM); + return NULL; + } + new_chunk->size = ELF_ALLOC_CHUNK_SIZE; + new_chunk->avail = INC_PTR(new_chunk, sizeof(ElfAllocatorChunk)); + new_chunk->remains = new_chunk->size - sizeof(ElfAllocatorChunk); + new_chunk->prev = current_chunk_; + current_chunk_ = new_chunk; + } + + void* ret = current_chunk_->avail; + current_chunk_->remains -= size; + current_chunk_->avail = INC_PTR(current_chunk_->avail, size); + return ret; +} + +void* DwarfAllocBase::operator new(size_t size, const ElfFile* elf) { + return elf->allocator()->alloc(size); +} diff --git a/elff/elf_alloc.h b/elff/elf_alloc.h new file mode 100644 index 0000000..d76dcdb --- /dev/null +++ b/elff/elf_alloc.h @@ -0,0 +1,160 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declaration of class ElfAllocator, that implements memory + * allocations for DWARF objects. + */ + +#ifndef ELFF_ELF_ALLOC_H_ +#define ELFF_ELF_ALLOC_H_ + +extern "C" { +#include "qemu-common.h" +} +#include "elff-common.h" + +class ElfFile; + +/* Alignment mask for blocks, allocated with this allocator. */ +#define ELFALLOC_ALIGNMENT_MASK 3 + +/* Chunk size. Even on relatively small ELF files, there are a lot of DWARF + * info, which makes our parsing pretty hungry on memory. On average, memory + * consumption on cached DWARF objects may easily reach 640K, which makes + * choosing 32K as chunk size pretty reasonable. + */ +#define ELF_ALLOC_CHUNK_SIZE (32 * 1024) + +/* Describes a chunk of memory, allocated by ElfAllocator. + * NOTE: this header's sizeof must be always aligned accordingly to the + * ELFALLOC_ALIGNMENT_MASK value, so we can produce properly aligned blocks + * without having to adjust alignment of the blocks, returned from alloc() + * method. + */ +typedef struct ElfAllocatorChunk { + /* Previous chunk in the chain of chunks allocated by ElfAllocator instance. + * For better allocation performance, ElfAllocator keeps its list of + * allocated chunks in reverse order (relatively to the chunk allocation + * sequence). So this field in each chunk references the chunk, allocated + * just prior this one. This field contains NULL for the first allocated + * chunk. + */ + ElfAllocatorChunk* prev; + + /* Address of the next available block in this chunk. */ + void* avail; + + /* Chunk size. */ + size_t size; + + /* Number of bytes that remain available in this chunk. */ + size_t remains; +} ElfAllocatorChunk; + +/* Encapsulates memory allocator for DWARF-related objects. + * Due to the implementation of ELF/DWARF framework in this library, data, + * collected during ELF/DWARF parsing stays in memory for as long, as instance + * of ElfFile that's being parsed is alive. To save performance on the numerous + * memory allocations (and then, deallocations) we will use this simple memory + * allocator that will grab memory from the heap in large chunks and then will + * provide DWARF objects with blocks of the required size inside those chunks. + * This will be much faster than going to the heap all the time, and since we + * will use overwritten operators new/delete for the DWARF objects that use + * this allocator, this is going to be pretty flexible and reliable solution + * for DWARF object allocation implementation. See DwarfAllocBase for more + * details. + * + * Instance (always one) of this class is created by ElfFile object when it is + * initializing. + */ +class ElfAllocator { + public: + /* Constructs ElfAllocator instance. */ + ElfAllocator(); + + /* Destructs ElfAllocator instance. */ + ~ElfAllocator(); + + /* Allocates requested number of bytes for a DWARF object. + * Param: + * size - Number of bytes to allocate. Value passed in this parameter + * will be rounded up accordingly to ELFALLOC_ALIGNMENT_MASK value, + * simplifying alignment adjustments for the allocated blocks. + * Return: + * Address of allocated block of the requested size on success, + * or NULL on failure. + */ + void* alloc(size_t size); + + protected: + /* Current chunk to allocate memory from. NOTE: chunks are listed here + * in reverse order (relatively to the chunk allocation sequence). + */ + ElfAllocatorChunk* current_chunk_; +}; + +/* Base class for all WDARF objects that will use ElfAllocator class for + * instance allocations. NOTE: it's required, that all classes that use + * ElfAllocator are derived from this one, as it provides compilation-time + * protection from mistakenly using "traditional" operator 'new' for object + * instantiation. + */ +class DwarfAllocBase { + public: + /* Constructs DwarfAllocBase instance. */ + DwarfAllocBase() { + } + + /* Destructs DwarfAllocBase instance. */ + virtual ~DwarfAllocBase() { + } + + /* Main operator new. + * Implements allocation of objects of derived classes from elf's "chunked" + * allocator, instantiated in ElfFile object (see ElfAllocator class). + * Param: + * size - Number of bytes to allocate for an instance of the derived class. + * elf - ELF file instance that owns the allocating object. + * Return: + * Pointer to the allocated memory on success, or NULL on failure. + */ + void* operator new(size_t size, const ElfFile* elf); + + /* Overwitten operator delete. + * Since deleting for chunk-allocated objects is a "no-op", we don't do + * anything in this operator. We, however, are obliged to implement this + * operator in order to compliment overwritten operator 'new'. + */ + void operator delete(void* ptr) { + } + + /* Overwitten operator delete. + * Since deleting for chunk-allocated objects is a "no-op", we don't do + * anything in this operator. We, however, are obliged to implement this + * operator in order to compliment overwritten operator 'new'. + */ + void operator delete[](void* ptr) { + } + + private: + /* Default operator new. + * We override it making 'private' in order to cause a compiler error on + * attempts to instantiate objects of derived classes using this version + * of operator 'new'. + */ + void* operator new(size_t size) { + return NULL; + } +}; + +#endif // ELFF_ELF_ALLOC_H_ diff --git a/elff/elf_defs.h b/elff/elf_defs.h new file mode 100644 index 0000000..39fd1b1 --- /dev/null +++ b/elff/elf_defs.h @@ -0,0 +1,135 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains some helpful macros, and inline routines. + */ + +#ifndef ELFF_ELF_DEFS_H_ +#define ELFF_ELF_DEFS_H_ + +#include "elf.h" + +//============================================================================= +// Macros. +//============================================================================= + +/* Increments a pointer by n bytes. + * Param: + * p - Pointer to increment. + * n - Number of bytes to increment the pointer with. + */ +#define INC_PTR(p, n) (reinterpret_cast(p) + (n)) + +/* Increments a constant pointer by n bytes. + * Param: + * p - Pointer to increment. + * n - Number of bytes to increment the pointer with. + */ +#define INC_CPTR(p, n) (reinterpret_cast(p) + (n)) + +/* Increments a pointer of a given type by n bytes. + * Param: + * T - Pointer type + * p - Pointer to increment. + * n - Number of bytes to increment the pointer with. + */ +#define INC_PTR_T(T, p, n) \ + reinterpret_cast \ + (reinterpret_cast(p) + (n)) + +/* Increments a constant pointer of a given type by n bytes. + * Param: + * T - Pointer type + * p - Pointer to increment. + * n - Number of bytes to increment the pointer with. + */ +#define INC_CPTR_T(T, p, n) \ + reinterpret_cast \ + (reinterpret_cast(p) + (n)) + +/* Calculates number of entries in a static array. + * Param: + * a - Array. + * Return: + * Number of entries in the array. + */ +#define ELFF_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + +/* Calculates offset of a field inside a structure (or a class) of the + * given type. + * Param: + * T - Structure (or class) type. + * f - Name of a field (member variable) for this structure (or class). + */ +#define ELFF_FIELD_OFFSET(T, f) ((size_t)(size_t*)&(((T *)0)->f)) + +//============================================================================= +// Inline routines. +//============================================================================= + +/* Calculates byte interval between two pointers. + * Param: + * s - Starting pointer of the interval. Must be less, or equal to 'e'. + * e - Ending pointer of the interval. Must be greater, or equal to 's'. + * Return: + * Byte interval between two pointers. + */ +static inline size_t +diff_ptr(const void* s, const void* e) { + assert(s <= e); + return ((size_t)(reinterpret_cast(e) - + reinterpret_cast(s))); +} + +/* Gets one byte from an index inside a memory block. + * Param: + * ptr - Address of the beginning of the memory block. + * bt - Index of a byte inside the block to get. + * Return: + * A byte at the given index inside the given memory block. + */ +static inline uint8_t +get_byte(const void* ptr, uint32_t bt) { + return *(reinterpret_cast(ptr) + bt); +} + +/* Checks if given address range is fully contained within a section. + * Param: + * rp - Beginning of the range to check. + * rsize - Size of the range to check. + * ss - Beginning of the section that should contain the checking range. + * ssize - Size of the section that should contain the checking range. + * Return: + * true, if given address range is fully contained within a section, or + * false, if any part of the address range is not contained in the secton. + */ +static inline bool +is_in_section(const void* rp, size_t rsize, const void* ss, size_t ssize) { + const void* rend = INC_CPTR(rp, rsize); + /* We also make sure here that increment didn't overflow the pointer. */ + return rp >= ss && ss != NULL && (diff_ptr(ss, rend) <= ssize) && rend >= rp; +} + +/* Checks if this code runs on CPU with a little-endian data format. + * Return: + * true, if this code runs on CPU with a little-endian data format, + * or false, if this code runs on CPU with a big-endian data format. + */ +static inline bool +is_little_endian_cpu(void) { + uint16_t tmp = 0x00FF; + /* Lets see if byte has flipped for little-endian. */ + return get_byte(&tmp, 0) == 0xFF; +} + +#endif // ELFF_ELF_DEFS_H_ diff --git a/elff/elf_file.cc b/elff/elf_file.cc new file mode 100644 index 0000000..70ed81c --- /dev/null +++ b/elff/elf_file.cc @@ -0,0 +1,539 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of ElfFile classes that encapsulate an ELF file. + */ + +#include "string.h" +#include "elf_file.h" +#include "elf_alloc.h" +#include "dwarf_cu.h" +#include "dwarf_utils.h" + +/* Tags to parse when collecting info about routines. */ +static const Dwarf_Tag parse_rt_tags[] = { + DW_TAG_compile_unit, + DW_TAG_partial_unit, + DW_TAG_inlined_subroutine, + DW_TAG_subprogram, + 0 +}; +static const DwarfParseContext parse_rt_context = { parse_rt_tags }; + +//============================================================================= +// Base ElfFile implementation +//============================================================================= + +ElfFile::ElfFile() + : sec_table_(NULL), + elf_file_path_(NULL), + sec_count_(0), + cu_count_(0), + last_cu_(NULL), + allocator_(NULL), + fixed_base_address_(0), + is_exec_(0), + elf_handle_(INVALID_ELF_FILE_HANDLE), + sec_entry_size_(0) { +} + +ElfFile::~ElfFile() { + DwarfCU* cu_to_del = last_cu_; + while (cu_to_del != NULL) { + DwarfCU* next_cu_to_del = cu_to_del->prev_cu_; + delete cu_to_del; + cu_to_del = next_cu_to_del; + } + + if (elfhandle_is_valid(elf_handle_)) { + close_elf_file_handle(elf_handle_); + } + + if (elf_file_path_ != NULL) { + delete[] elf_file_path_; + } + + if (sec_table_ != NULL) { + delete[] reinterpret_cast(sec_table_); + } + + /* Must be deleted last! */ + if (allocator_ != NULL) { + delete allocator_; + } +} + +ElfFile* ElfFile::Create(const char* path) { + ElfFile* ret = NULL; + /* Allocate enough space on the stack to fit the largest ELF file header. */ + Elf64_FHdr header; + const Elf_CommonHdr* elf_hdr = &header.common; + + assert(path != NULL && *path != '\0'); + if (path == NULL || *path == '\0') { + _set_errno(EINVAL); + return NULL; + } + + /* + * Open ELF file, and read its header (the largest one possible). + */ + +#ifdef WIN32 + HANDLE file_handle = CreateFile(path, GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, NULL); + assert(file_handle != INVALID_HANDLE_VALUE); + if (file_handle == INVALID_HANDLE_VALUE) { + _set_errno(GetLastError()); + return NULL; + } + + DWORD read_bytes; + BOOL res = ReadFile(file_handle, &header, sizeof(header), &read_bytes, NULL); + CloseHandle(file_handle); + assert(res && read_bytes == sizeof(header)); + if (!res || read_bytes != sizeof(header)) { + _set_errno(GetLastError()); + return NULL; + } +#else // WIN32 + int file_handle = open(path, O_RDONLY | O_BINARY, 0); + assert(file_handle >= 0); + if (file_handle < 0) { + return NULL; + } + const ssize_t read_bytes = read(file_handle, &header, sizeof(header)); + close(file_handle); + assert(read_bytes != -1 && read_bytes == sizeof(header)); + if (read_bytes == -1 || read_bytes != sizeof(header)) { + if (read_bytes != -1) { + _set_errno(EINVAL); + } + return NULL; + } +#endif // WIN32 + + /* Lets see if this is an ELF file at all. */ + if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG) != 0) { + /* File is not an ELF file. */ + _set_errno(ENOEXEC); + return NULL; + } + + /* Lets check ELF's "bitness". */ + assert(elf_hdr->ei_info.ei_class == ELFCLASS32 || + elf_hdr->ei_info.ei_class == ELFCLASS64); + if (elf_hdr->ei_info.ei_class != ELFCLASS32 && + elf_hdr->ei_info.ei_class != ELFCLASS64) { + /* Neither 32, or 64-bit ELF file. Something wrong here. */ + _set_errno(EBADF); + return NULL; + } + + /* Lets instantiate appropriate ElfFileImpl object for this ELF. */ + if (elf_hdr->ei_info.ei_class == ELFCLASS32) { + ret = new ElfFileImpl; + } else { + ret = new ElfFileImpl; + } + assert(ret != NULL); + if (ret != NULL) { + if (!ret->initialize(elf_hdr, path)) { + delete ret; + ret = NULL; + } + } else { + _set_errno(ENOMEM); + } + + return ret; +} + +bool ElfFile::initialize(const Elf_CommonHdr* elf_hdr, const char* path) { + /* Must be created first! */ + allocator_ = new ElfAllocator(); + assert(allocator_ != NULL); + if (allocator_ == NULL) { + _set_errno(ENOMEM); + return false; + } + + /* Copy file path. */ + size_t path_len = strlen(path) + 1; + elf_file_path_ = new char[path_len]; + assert(elf_file_path_ != NULL); + if (elf_file_path_ == NULL) { + _set_errno(ENOMEM); + return false; + } + memcpy(elf_file_path_, path, path_len); + + /* Cache some basic ELF properties. */ + is_ELF_64_ = elf_hdr->ei_info.ei_class == ELFCLASS64; + is_elf_big_endian_ = elf_hdr->ei_info.ei_data == ELFDATA2MSB; + same_endianness_ = is_elf_little_endian() == is_little_endian_cpu(); + is_exec_ = elf_hdr->e_type == 2; + + /* Reopen file for further reads and mappings. */ +#ifdef WIN32 + elf_handle_ = CreateFile(elf_file_path_, GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, NULL); + assert(elf_handle_ != INVALID_HANDLE_VALUE); + if (elf_handle_ == INVALID_HANDLE_VALUE) { + _set_errno(GetLastError()); + return false; + } +#else // WIN32 + elf_handle_ = open(elf_file_path_, O_RDONLY | O_BINARY, 0); + assert(elf_handle_ >= 0); + if (elf_handle_ < 0) { + elf_handle_ = INVALID_ELF_FILE_HANDLE; + return false; + } +#endif // WIN32 + + return true; +} + +bool ElfFile::get_pc_address_info(Elf_Xword address, + Elf_AddressInfo* address_info) { + assert(address_info != NULL); + if (address_info == NULL) { + _set_errno(EINVAL); + return false; + } + + /* Collect routine information for all CUs in this file. */ + if (parse_compilation_units(&parse_rt_context) == -1) { + return false; + } + + /* Iterate through the collected CUs looking for the one that + * contains the given address. */ + address_info->inline_stack = NULL; + DwarfCU* cu = last_cu(); + while (cu != NULL) { + /* Find a leaf DIE object in the current CU that contains the address. */ + Dwarf_AddressInfo info; + info.die_obj = cu->get_leaf_die_for_address(address); + if (info.die_obj != NULL) { + /* Convert the address to a location inside source file. */ + if (cu->get_pc_address_file_info(address, &info)) { + /* Copy location information to the returning structure. */ + address_info->file_name = info.file_name; + address_info->dir_name = info.dir_name; + address_info->line_number = info.line_number; + } else { + address_info->file_name = NULL; + address_info->dir_name = NULL; + address_info->line_number = 0; + } + + /* Lets see if the DIE represents a routine (rather than + * a lexical block, for instance). */ + Dwarf_Tag tag = info.die_obj->get_tag(); + while (!dwarf_tag_is_routine(tag)) { + /* This is not a routine DIE. Lets loop trhough the parents of that + * DIE looking for the first routine DIE. */ + info.die_obj = info.die_obj->parent_die(); + if (info.die_obj == NULL) { + /* Reached compilation unit DIE. Can't go any further. */ + address_info->routine_name = ""; + return true; + } + tag = info.die_obj->get_tag(); + } + + /* Save name of the routine that contains the address. */ + address_info->routine_name = info.die_obj->get_name(); + if (address_info->routine_name == NULL) { + /* In some cases (minimum debugging info in the file) routine + * name may be not avaible. We, however, are obliged by API + * considerations to return something in this field. */ + address_info->routine_name = ""; + } + + /* Lets see if address belongs to an inlined routine. */ + if (tag != DW_TAG_inlined_subroutine) { + address_info->inline_stack = NULL; + return true; + } + + /* + * Address belongs to an inlined routine. Create inline stack. + */ + + /* Allocate inline stack array big enough to fit all parent entries. */ + address_info->inline_stack = + new Elf_InlineInfo[info.die_obj->get_level() + 1]; + assert(address_info->inline_stack != NULL); + if (address_info->inline_stack == NULL) { + _set_errno(ENOMEM); + return false; + } + memset(address_info->inline_stack, 0, + sizeof(Elf_InlineInfo) * (info.die_obj->get_level() + 1)); + + /* Reverse DIEs filling in inline stack entries for inline + * routine tags. */ + int inl_index = 0; + do { + /* Save source file information. */ + DIEAttrib file_desc; + if (info.die_obj->get_attrib(DW_AT_call_file, &file_desc)) { + const Dwarf_STMTL_FileDesc* desc = + cu->get_stmt_file_info(file_desc.value()->u32); + if (desc != NULL) { + address_info->inline_stack[inl_index].inlined_in_file = + desc->file_name; + address_info->inline_stack[inl_index].inlined_in_file_dir = + cu->get_stmt_dir_name(desc->get_dir_index()); + } + } + if (address_info->inline_stack[inl_index].inlined_in_file == NULL) { + address_info->inline_stack[inl_index].inlined_in_file = ""; + address_info->inline_stack[inl_index].inlined_in_file_dir = NULL; + } + + /* Save source line information. */ + if (info.die_obj->get_attrib(DW_AT_call_line, &file_desc)) { + address_info->inline_stack[inl_index].inlined_at_line = file_desc.value()->u32; + } + + /* Advance DIE to the parent routine, and save its name. */ + info.die_obj = info.die_obj->parent_die(); + assert(info.die_obj != NULL); + if (info.die_obj != NULL) { + tag = info.die_obj->get_tag(); + while (!dwarf_tag_is_routine(tag)) { + info.die_obj = info.die_obj->parent_die(); + if (info.die_obj == NULL) { + break; + } + tag = info.die_obj->get_tag(); + } + if (info.die_obj != NULL) { + address_info->inline_stack[inl_index].routine_name = + info.die_obj->get_name(); + } + } + if (address_info->inline_stack[inl_index].routine_name == NULL) { + address_info->inline_stack[inl_index].routine_name = ""; + } + + /* Continue with the parent DIE. */ + inl_index++; + } while (info.die_obj != NULL && tag == DW_TAG_inlined_subroutine); + + return true; + } + cu = cu->prev_cu(); + } + + return false; +} + +void ElfFile::free_pc_address_info(Elf_AddressInfo* address_info) const { + assert(address_info != NULL); + if (address_info != NULL && address_info->inline_stack != NULL) { + delete address_info->inline_stack; + address_info->inline_stack = NULL; + } +} + +//============================================================================= +// ElfFileImpl +//============================================================================= + +template +bool ElfFileImpl::initialize(const Elf_CommonHdr* elf_hdr, + const char* path) { + /* Must be called first! */ + if (!ElfFile::initialize(elf_hdr, path)) { + return false; + } + + /* Cache some header data, so later we can discard the header. */ + const Elf_FHdr* header = + reinterpret_cast*>(elf_hdr); + sec_count_ = pull_val(header->e_shnum); + sec_entry_size_ = pull_val(header->e_shentsize); + fixed_base_address_ = pull_val(header->e_entry) & ~0xFFF; + + /* Cache section table (must have one!) */ + const Elf_Off sec_table_off = pull_val(header->e_shoff); + assert(sec_table_off != 0 && sec_count_ != 0); + if (sec_table_off == 0 || sec_count_ == 0) { + _set_errno(EBADF); + return false; + } + const size_t sec_table_size = sec_count_ * sec_entry_size_; + sec_table_ = new Elf_Byte[sec_table_size]; + assert(sec_table_ != NULL); + if (sec_table_ == NULL) { + _set_errno(ENOMEM); + return false; + } +#ifdef WIN32 + LARGE_INTEGER convert; + convert.QuadPart = sec_table_off; + if ((SetFilePointer(elf_handle_, convert.LowPart, + &convert.HighPart, + FILE_BEGIN) == INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR)) { + _set_errno(GetLastError()); + return false; + } + DWORD read_bytes; + BOOL res = + ReadFile(elf_handle_, sec_table_, sec_table_size, &read_bytes, NULL); + assert(res && read_bytes == sec_table_size); + if (!res || read_bytes != sec_table_size) { + _set_errno(GetLastError()); + return false; + } +#else // WIN32 + ssize_t res = lseek(elf_handle_, sec_table_off, SEEK_SET); + assert(res != -1); + if (res == -1) { + return false; + } + res = read(elf_handle_, sec_table_, sec_table_size); + assert(res != -1 && res == sec_table_size); + if (res == -1 || res != sec_table_size) { + if (res != -1) { + _set_errno(EINVAL); + } + return false; + } +#endif // WIN32 + + /* Map ELF's string section (must have one!). */ + const Elf_Half str_sec_index = pull_val(header->e_shstrndx); + assert(str_sec_index != SHN_UNDEF); + if (str_sec_index == SHN_UNDEF) { + _set_errno(EBADF); + return false; + } + const Elf_SHdr* str_sec = + reinterpret_cast*> + (get_section_by_index(str_sec_index)); + assert(str_sec != NULL); + if (str_sec == NULL) { + _set_errno(EBADF); + return false; + } + if (!string_section_.map(elf_handle_, pull_val(str_sec->sh_offset), + pull_val(str_sec->sh_size))) { + return false; + } + + /* Lets determine DWARF format. According to the docs, DWARF is 64 bit, if + * first 4 bytes in the compilation unit header are set to 0xFFFFFFFF. + * .debug_info section of the ELF file begins with the first CU header. */ + if (!map_section_by_name(".debug_info", &debug_info_)) { + _set_errno(EBADF); + return false; + } + + /* Note that we don't care about endianness here, since 0xFFFFFFFF is an + * endianness-independent value, so we don't have to pull_val here. */ + is_DWARF_64_ = + *reinterpret_cast(debug_info_.data()) == 0xFFFFFFFF; + + return true; +} + +template +int ElfFileImpl::parse_compilation_units( + const DwarfParseContext* parse_context) { + /* Lets see if we already parsed the file. */ + if (last_cu() != NULL) { + return cu_count_; + } + + /* Cache sections required for this parsing. */ + if (!map_section_by_name(".debug_abbrev", &debug_abbrev_) || + !map_section_by_name(".debug_ranges", &debug_ranges_) || + !map_section_by_name(".debug_line", &debug_line_) || + !map_section_by_name(".debug_str", &debug_str_)) { + _set_errno(EBADF); + return false; + } + + /* .debug_info section opens with the first CU header. */ + const void* next_cu = debug_info_.data(); + + /* Iterate through CUs until we reached the end of .debug_info section, or + * advanced to a CU with zero size, indicating the end of CU list for this + * file. */ + while (is_valid_cu(next_cu)) { + /* Instatiate CU, depending on DWARF "bitness". */ + DwarfCU* cu = DwarfCU::create_instance(this, next_cu); + if (cu == NULL) { + _set_errno(ENOMEM); + return -1; + } + + if (cu->parse(parse_context, &next_cu)) { + cu->set_prev_cu(last_cu_); + last_cu_ = cu; + cu_count_++; + } else { + delete cu; + return -1; + } + }; + + return cu_count_; +} + +template +bool ElfFileImpl::get_section_info_by_name(const char* name, + Elf_Off* offset, + Elf_Word* size) { + const Elf_SHdr* cur_section = + reinterpret_cast*>(sec_table_); + + for (Elf_Half sec = 0; sec < sec_count_; sec++) { + const char* sec_name = get_str_sec_str(pull_val(cur_section->sh_name)); + if (sec_name != NULL && strcmp(name, sec_name) == 0) { + *offset = pull_val(cur_section->sh_offset); + *size = pull_val(cur_section->sh_size); + return true; + } + cur_section = reinterpret_cast*> + (INC_CPTR(cur_section, sec_entry_size_)); + } + _set_errno(EINVAL); + return false; +} + +template +bool ElfFileImpl::map_section_by_name( + const char* name, + ElfMappedSection* section) { + if (section->is_mapped()) { + return true; + } + + Elf_Off offset; + Elf_Word size; + if (!get_section_info_by_name(name, &offset, &size)) { + return false; + } + + return section->map(elf_handle_, offset, size); +} diff --git a/elff/elf_file.h b/elff/elf_file.h new file mode 100644 index 0000000..6c57bde --- /dev/null +++ b/elff/elf_file.h @@ -0,0 +1,621 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declaration of ElfFile classes that encapsulate an ELF file. + */ + +#ifndef ELFF_ELF_FILE_H_ +#define ELFF_ELF_FILE_H_ + +#include "dwarf_die.h" +#include "elf_mapped_section.h" +#include "elff_api.h" + +/* Encapsulates architecture-independent functionality of an ELF file. + * + * This class is a base class for templated ElfFileImpl. This class implements + * functionality around an ELF file that is independent from particulars of the + * ELF's CPU architectire, while ElfFileImpl handles all particulars of CPU + * architecture (namely, 32 or 64-bit), for which ELF file has been built. + * + * NOTE: This class operates on ELF sections that have been mapped to memory. + * + */ +class ElfFile { + public: + /* Constructs ElfFile instance. */ + ElfFile(); + + /* Destructs ElfFile instance. */ + virtual ~ElfFile(); + + /* Creates ElfFileImpl instance, depending on ELF file CPU architecture. + * This method will collect initial information about requested ELF file, + * and will instantiate appropriate ElfFileImpl class object for it. + * Param: + * path - Full path to the ELF file. + * Return: + * Initialized ElfFileImpl instance, typecasted back to ElfFile object on + * success, or NULL on failure, with errno providing extended error + * information. + */ + static ElfFile* Create(const char* path); + + /* Checks if ELF file is a 64, or 32-bit ELF file. */ + bool is_ELF_64() const { + return is_ELF_64_; + } + bool is_ELF_32() const { + return !is_ELF_64_; + } + + /* Checks if ELF file data format is big, or little-endian. */ + bool is_elf_big_endian() const { + return is_elf_big_endian_; + } + bool is_elf_little_endian() const { + return !is_elf_big_endian_; + } + + /* Checks whether or not endianness of CPU this library is built for matches + * endianness of the ELF file that is represented with this instance. */ + bool same_endianness() const { + return same_endianness_; + } + + /* Checks if format of DWARF data in this file is 64, or 32-bit. */ + bool is_DWARF_64() const { + return is_DWARF_64_; + } + bool is_DWARF_32() const { + return !is_DWARF_64_; + } + + /* Gets DWARF objects allocator for this instance. */ + class ElfAllocator* allocator() const { + return allocator_; + } + + /* Gets head of compilation unit list, collected during parsing of this file. + * NOTE: list of collected compilation units returned from this method is + * in reverse order relatively to the order CUs have been added to the list + * during ELF file parsing. + */ + class DwarfCU* last_cu() const { + return last_cu_; + } + + /* Gets number of compilation units, collected during parsing of + * this ELF file with parse_compilation_units() method. + */ + int cu_count() const { + return cu_count_; + } + + /* Gets executable file flag */ + bool is_exec() const { + return is_exec_; + } + + protected: + /* Initializes ElfFile instance. This method is called from Create method of + * this class after appropriate ElfFileImpl instance has been created. Note, + * that Create() method will validate that requested file is an ELF file, + * prior to instantiating of an ElfFileImpl object, and calling this method. + * Param: + * elf_hdr - Address of the common ELF file header. + * path - See Create(). + * Return: + * true on success, or false on failure, with errno containing extended + * error information. + */ + virtual bool initialize(const Elf_CommonHdr* elf_hdr, const char* path); + +/*============================================================================= + * Endianness helper methods. + * Since endianness of ELF file may differ from the endianness of the CPU this + * library runs on, every time a value is required from a section of the ELF + * file, it must be first pulled out of that section to a local variable, and + * then used from that local variable. While value is pulled from ELF file + * section, it must be converted accordingly to the endianness of the CPU and + * ELF file. Routines bellow provide such functionality. +=============================================================================*/ + + public: + /* Pulls one byte value from ELF file. Note that for one byte we don't need + * to do any endianness conversion, and these two methods are provided purely + * for completness of the API. + * Param: + * val - References value inside ELF file buffer to pull data from. + * Return + * Pulled value with endianness appropriate for the CPU this library is + * running on. + */ + uint8_t pull_val(const uint8_t* val) const { + return *val; + } + uint8_t pull_val(const uint8_t& val) const { + return val; + } + int8_t pull_val(const int8_t* val) const { + return *val; + } + int8_t pull_val(const int8_t& val) const { + return val; + } + + /* Pulls two byte value from ELF file. + * Param: + * val - References value inside ELF file buffer to pull data from. + * Return + * Pulled value with endianness appropriate for the CPU this library is + * running on. + */ + uint16_t pull_val(const uint16_t* val) const { + if (same_endianness()) { + return *val; + } + if (is_elf_big_endian()) { + return (uint16_t)get_byte(val, 0) << 8 | get_byte(val, 1); + } else { + return (uint16_t)get_byte(val, 1) << 8 | get_byte(val, 0); + } + } + uint16_t pull_val(const uint16_t& val) const { + return same_endianness() ? val : pull_val(&val); + } + int16_t pull_val(const int16_t* val) const { + return static_cast + (pull_val(reinterpret_cast(val))); + } + int16_t pull_val(const int16_t& val) const { + return static_cast + (pull_val(reinterpret_cast(val))); + } + + /* Pulls four byte value from ELF file. + * Param: + * val - References value inside ELF file buffer to pull data from. + * Return + * Pulled value with endianness appropriate for the CPU this library is + * running on. + */ + uint32_t pull_val(const uint32_t* val) const { + if (same_endianness()) { + return *val; + } + if (is_elf_big_endian()) { + return (uint32_t)get_byte(val, 0) << 24 | + (uint32_t)get_byte(val, 1) << 16 | + (uint32_t)get_byte(val, 2) << 8 | + (uint32_t)get_byte(val, 3); + } else { + return (uint32_t)get_byte(val, 3) << 24 | + (uint32_t)get_byte(val, 2) << 16 | + (uint32_t)get_byte(val, 1) << 8 | + (uint32_t)get_byte(val, 0); + } + } + uint32_t pull_val(const uint32_t& val) const { + return same_endianness() ? val : pull_val(&val); + } + int32_t pull_val(const int32_t* val) const { + return static_cast + (pull_val(reinterpret_cast(val))); + } + int32_t pull_val(const int32_t& val) const { + return static_cast + (pull_val(reinterpret_cast(val))); + } + + /* Pulls eight byte value from ELF file. + * Param: + * val - References value inside ELF file buffer to pull data from. + * Return + * Pulled value with endianness appropriate for the CPU this library is + * running on. + */ + uint64_t pull_val(const uint64_t* val) const { + if (same_endianness()) { + return *val; + } + if (is_elf_big_endian()) { + return (uint64_t)get_byte(val, 0) << 56 | + (uint64_t)get_byte(val, 1) << 48 | + (uint64_t)get_byte(val, 2) << 40 | + (uint64_t)get_byte(val, 3) << 32 | + (uint64_t)get_byte(val, 4) << 24 | + (uint64_t)get_byte(val, 5) << 16 | + (uint64_t)get_byte(val, 6) << 8 | + (uint64_t)get_byte(val, 7); + } else { + return (uint64_t)get_byte(val, 7) << 56 | + (uint64_t)get_byte(val, 6) << 48 | + (uint64_t)get_byte(val, 5) << 40 | + (uint64_t)get_byte(val, 4) << 32 | + (uint64_t)get_byte(val, 3) << 24 | + (uint64_t)get_byte(val, 2) << 16 | + (uint64_t)get_byte(val, 1) << 8 | + (uint64_t)get_byte(val, 0); + } + } + uint64_t pull_val(const uint64_t& val) const { + return same_endianness() ? val : pull_val(&val); + } + int64_t pull_val(const int64_t* val) const { + return static_cast + (pull_val(reinterpret_cast(val))); + } + int64_t pull_val(const int64_t& val) const { + return static_cast + (pull_val(reinterpret_cast(val))); + } + +//============================================================================= +// ELF file section management. +//============================================================================= + + public: + /* Gets a string contained in ELF's string section by index. + * Param: + * index - String index (byte offset) in the ELF's string section. + * Return: + * Pointer to the requested string, or NULL if string index exceeds ELF's + * string section size. + * NOTE: pointer returned from this method points to a mapped section of + * ELF file. + */ + const char* get_str_sec_str(Elf_Xword index) const { + assert(string_section_.is_mapped() && index < string_section_.size()); + if (string_section_.is_mapped() && index < string_section_.size()) { + return INC_CPTR_T(char, string_section_.data(), index); + } else { + _set_errno(EINVAL); + return NULL; + } + } + + /* Gets a string contained in ELF's debug string section (.debug_str) + * by index. + * Param: + * index - String index (byte offset) in the ELF's debug string section. + * Return: + * Pointer to the requested string, or NULL if string index exceeds ELF's + * debug string section size. + * NOTE: pointer returned from this method points to a mapped section of + * ELF file. + */ + const char* get_debug_str(Elf_Xword index) const { + assert(debug_str_.is_mapped() && index < debug_str_.size()); + if (debug_str_.is_mapped() && index < debug_str_.size()) { + return INC_CPTR_T(char, debug_str_.data(), index); + } else { + _set_errno(EINVAL); + return NULL; + } + } + + protected: + /* Gets pointer to a section header, given section index within ELF's + * section table. + * Param: + * index - Section index within ELF's section table. + * Return: + * Pointer to a section header (ElfXX_SHdr flavor, depending on ELF's CPU + * architecture) on success, or NULL if section index exceeds number of + * sections for this ELF file. + */ + const void* get_section_by_index(Elf_Half index) const { + assert(index < sec_count_); + if (index < sec_count_) { + return INC_CPTR(sec_table_, static_cast(index) * sec_entry_size_); + } else { + _set_errno(EINVAL); + return NULL; + } + } + +//============================================================================= +// DWARF management. +//============================================================================= + + protected: + /* Parses DWARF, and buids a list of compilation units for this ELF file. + * Compilation unit, collected with this methods are linked together in a + * list, head of which is available via last_cu() method of this class. + * NOTE: CUs in the list returned via last_cu() method are in reverse order + * relatively to the order in which CUs are stored in .debug_info section. + * This is ELF and DWARF data format - dependent method. + * Param: + * parse_context - Parsing context that defines which tags, and which + * properties for which tag should be collected during parsing. NULL + * passed in this parameter indicates that all properties for all tags + * should be collected. + * Return: + * Number of compilation units, collected in this method on success, + * or -1 on failure. + */ + virtual int parse_compilation_units(const DwarfParseContext* parse_context) = 0; + + public: + /* Gets PC address information. + * Param: + * address - PC address to get information for. The address must be relative + * to the beginning of ELF file represented by this class. + * address_info - Upon success contains information about routine(s) that + * contain the given address. + * Return: + * true if routine(s) containing has been found and its information has been + * saved into address_info, or false if no appropriate routine for that + * address has been found, or there was a memory error when collecting + * routine(s) information. In case of failure, errno contains extended error + * information. + */ + bool get_pc_address_info(Elf_Xword address, Elf_AddressInfo* address_info); + + /* Frees resources aqcuired for address information in successful call to + * get_pc_address_info(). + * Param: + * address_info - Address information structure, initialized in successful + * call to get_pc_address_info() routine. + */ + void free_pc_address_info(Elf_AddressInfo* address_info) const; + + /* Gets beginning of the .debug_info section data. + * Return: + * Beginning of the .debug_info section data. + * NOTE: pointer returned from this method points to a mapped section of + * ELF file. + */ + const void* get_debug_info_data() const { + return debug_info_.data(); + } + + /* Gets beginning of the .debug_abbrev section data. + * Return: + * Beginning of the .debug_abbrev section data. + * NOTE: pointer returned from this method points to a mapped section of + * ELF file. + */ + const void* get_debug_abbrev_data() const { + return debug_abbrev_.data(); + } + + /* Gets beginning of the .debug_ranges section data. + * Return: + * Beginning of the .debug_ranges section data. + * NOTE: pointer returned from this method points to a mapped section of + * ELF file. + */ + const void* get_debug_ranges_data() const { + return debug_ranges_.data(); + } + + /* Gets beginning of the .debug_line section data. + * Return: + * Beginning of the .debug_line section data. + * NOTE: pointer returned from this method points to a mapped section of + * ELF file. + */ + const void* get_debug_line_data() const { + return debug_line_.data(); + } + + /* Checks, if given address range is contained in the mapped .debug_info + * section of this file. + * Param: + * ptr - Starting address of the range. + * size - Range size in bytes. + * Return: + * true if given address range is contained in the mapped .debug_info + * section of this file, or false if any part of the range doesn't belong + * to that section. + */ + bool is_valid_die_ptr(const void* ptr, size_t size) const { + return debug_info_.is_contained(ptr, size); + } + + /* Checks, if given address range is contained in the mapped .debug_abbrev + * section of this file. + * Param: + * ptr - Starting address of the range. + * size - Range size in bytes. + * Return: + * true if given address range is contained in the mapped .debug_abbrev + * section of this file, or false if any part of the range doesn't belong + * to that section. + */ + bool is_valid_abbr_ptr(const void* ptr, size_t size) const { + return debug_abbrev_.is_contained(ptr, size); + } + + /* Checks if given pointer addresses a valid compilation unit header in the + * mapped .debug_info section of the ELF file. + * Param: + * cu_header - Pointer to a compilation unit header to check. + * Return + * true, if given pointer addresses a valid compilation unit header, or + * false, if it's not. A valid CU header must be fully conained inside + * .debug_info section of the ELF file, and its size must not be zero. + */ + bool is_valid_cu(const void* cu_header) const { + if (is_DWARF_64()) { + return is_valid_die_ptr(cu_header, sizeof(Dwarf64_CUHdr)) && + reinterpret_cast(cu_header)->size_hdr.size != 0; + } else { + return is_valid_die_ptr(cu_header, sizeof(Dwarf32_CUHdr)) && + reinterpret_cast(cu_header)->size_hdr.size != 0; + } + } + + /* Gets range's low and high pc for the given range reference in the mapped + * .debug_ranges section of an ELF file. + * Template param: + * AddrType - Defines pointer type for the CU the range belongs to. CU's + * pointer type can be defined independently from ELF and DWARF types, + * and is encoded in address_size field of the CU header in .debug_info + * section of ELF file. + * Param: + * offset - Byte offset within .debug_ranges section of the range record. + * low - Upon successful return contains value for range's low pc. + * high - Upon successful return contains value for range's high pc. + * Return: + * true on success, or false, if requested record is not fully contained + * in the .debug_ranges section. + */ + template + bool get_range(Elf_Word offset, AddrType* low, AddrType* high) { + const AddrType* ptr = INC_CPTR_T(AddrType, debug_ranges_.data(), offset); + assert(debug_ranges_.is_contained(ptr, sizeof(AddrType) * 2)); + if (!debug_ranges_.is_contained(ptr, sizeof(AddrType) * 2)) { + _set_errno(EINVAL); + return false; + } + *low = pull_val(ptr); + *high = pull_val(ptr + 1); + return true; + } + + protected: + /* Mapped ELF string section. */ + ElfMappedSection string_section_; + + /* Mapped .debug_info section. */ + ElfMappedSection debug_info_; + + /* Mapped .debug_abbrev section. */ + ElfMappedSection debug_abbrev_; + + /* Mapped .debug_str section. */ + ElfMappedSection debug_str_; + + /* Mapped .debug_line section. */ + ElfMappedSection debug_line_; + + /* Mapped .debug_ranges section. */ + ElfMappedSection debug_ranges_; + + /* Base address of the loaded module (if fixed), or 0 if module doesn't get + * loaded at fixed address. */ + Elf_Xword fixed_base_address_; + + /* Handle to the ELF file represented with this instance. */ + ELF_FILE_HANDLE elf_handle_; + + /* Path to the ELF file represented with this instance. */ + char* elf_file_path_; + + /* DWARF objects allocator for this instance. */ + class ElfAllocator* allocator_; + + /* Beginning of the cached ELF's section table. */ + void* sec_table_; + + /* Number of sections in the ELF file wrapped by this instance. */ + Elf_Half sec_count_; + + /* Byte size of an entry in the section table. */ + Elf_Half sec_entry_size_; + + /* Head of compilation unit list, collected during the parsing. */ + class DwarfCU* last_cu_; + + /* Number of compilation units in last_cu_ list. */ + int cu_count_; + + /* Flags ELF's CPU architecture: 64 (true), or 32 bits (false). */ + bool is_ELF_64_; + + /* Flags endianness of the processed ELF file. true indicates that ELF file + * data is stored in big-endian form, false indicates that ELF file data is + * stored in big-endian form. + */ + bool is_elf_big_endian_; + + /* Flags whether or not endianness of CPU this library is built for matches + * endianness of the ELF file that is represented with this instance. + */ + bool same_endianness_; + + /* Flags DWARF format: 64, or 32 bits. DWARF format is determined by looking + * at the first 4 bytes of .debug_info section (which is the beginning of the + * first compilation unit header). If first 4 bytes contain 0xFFFFFFFF, the + * DWARF is 64 bit. Otherwise, DWARF is 32 bit. */ + bool is_DWARF_64_; + + /* Flags executable file. If this member is 1, ELF file represented with this + * instance is an executable. If this member is 0, file is a shared library. + */ + bool is_exec_; +}; + +/* Encapsulates architecture-dependent functionality of an ELF file. + * Template param: + * Elf_Addr - type for an address field in ELF file. Must be: + * - Elf32_Addr for 32-bit CPU, or + * - Elf64_Addr for 64-bit CPU. + * Elf_Off - type for an offset field in ELF file. Must be: + * - Elf64_Off for 32-bit CPU, or + * - Elf64_Off for 64-bit CPU. + */ +template +class ElfFileImpl : protected ElfFile { +/* Instance of this class must be instantiated from + * ElfFile::Create() method only. */ +friend class ElfFile; + protected: + /* Constructs ElfFileImpl instance. */ + ElfFileImpl() { + }; + + /* Destructs ElfFileImpl instance. */ + ~ElfFileImpl() { + } + + protected: + /* Initializes instance. This is an override of the base class method. + * See ElfFile::initialize(). + */ + bool initialize(const Elf_CommonHdr* elf_hdr, const char* path); + + /* Parses DWARF, and buids list of compilation units for this ELF file. + * This is an implementation of the base class' abstract method. + * See ElfFile::parse_compilation_units(). + */ + virtual int parse_compilation_units(const DwarfParseContext* parse_context); + + /* Gets section information by section name. + * Param: + * name - Name of the section to get information for. + * offset - Upon success contains offset of the section data in ELF file. + * size - Upon success contains size of the section data in ELF file. + * Return: + * true on sucess, or false if section with such name doesn't exist in + * this ELF file. + */ + bool get_section_info_by_name(const char* name, + Elf_Off* offset, + Elf_Word* size); + + /* Maps section by its name. + * Param: + * name - Name of the section to map. + * section - Upon success contains section's mapping information. + * Return: + * true on sucess, or false if section with such name doesn't exist in + * this ELF file, or mapping has failed. + */ + bool map_section_by_name(const char* name, ElfMappedSection* section); +}; + +#endif // ELFF_ELF_FILE_H_ diff --git a/elff/elf_mapped_section.cc b/elff/elf_mapped_section.cc new file mode 100644 index 0000000..46fc6b6 --- /dev/null +++ b/elff/elf_mapped_section.cc @@ -0,0 +1,95 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of a class ElfMappedSection, that encapsulates + * a section of an ELF file, mapped to memory. + */ + +#include "elf_defs.h" +#include "elf_mapped_section.h" + +ElfMappedSection::ElfMappedSection() + : mapped_at_(NULL), + data_(NULL), + size_(0) { +} + +ElfMappedSection::~ElfMappedSection() { + if (mapped_at_ != NULL) { +#ifdef WIN32 + UnmapViewOfFile(mapped_at_); +#else // WIN32 + munmap(mapped_at_, diff_ptr(mapped_at_, data_) + size_); +#endif // WIN32 + } +} + +bool ElfMappedSection::map(ELF_FILE_HANDLE handle, + Elf_Xword offset, + Elf_Word size) { + /* Get the mask for mapping offset alignment. */ +#ifdef WIN32 + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + const Elf_Xword align_mask = sys_info.dwAllocationGranularity - 1; +#else // WIN32 + const Elf_Xword align_mask = getpagesize() - 1; +#endif // WIN32 + + /* Adjust mapping offset and mapping size accordingly to + * the mapping alignment requirements. */ + const Elf_Xword map_offset = offset & ~align_mask; + const Elf_Word map_size = static_cast(offset - map_offset + size); + + /* Make sure mapping size doesn't exceed 4G: may happen on 64-bit ELFs, if + * section size is close to 4G, while section offset is badly misaligned. */ + assert(map_size >= size); + if (map_size < size) { + _set_errno(EFBIG); + return false; + } + + /* Map the section. */ +#ifdef WIN32 + LARGE_INTEGER converter; + converter.QuadPart = map_offset + map_size; + HANDLE map_handle = CreateFileMapping(handle, NULL, PAGE_READONLY, + converter.HighPart, converter.LowPart, + NULL); + assert(map_handle != NULL); + if (map_handle != NULL) { + converter.QuadPart = map_offset; + mapped_at_ = MapViewOfFile(map_handle, FILE_MAP_READ, converter.HighPart, + converter.LowPart, map_size); + assert(mapped_at_ != NULL); + /* Memory mapping (if successful) will hold extra references to the + * mapping, so we can close it right after we mapped file view. */ + CloseHandle(map_handle); + } + if (mapped_at_ == NULL) { + _set_errno(GetLastError()); + return false; + } +#else // WIN32 + mapped_at_ = mmap(0, map_size, PROT_READ, MAP_SHARED, handle, map_offset); + assert(mapped_at_ != MAP_FAILED); + if (mapped_at_ == MAP_FAILED) { + return false; + } +#endif // WIN32 + + data_ = INC_CPTR(mapped_at_, offset - map_offset); + size_ = size; + + return true; +} diff --git a/elff/elf_mapped_section.h b/elff/elf_mapped_section.h new file mode 100644 index 0000000..2f3ca56 --- /dev/null +++ b/elff/elf_mapped_section.h @@ -0,0 +1,88 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declaration of a class ElfMappedSection, that encapsulates + * a section of an ELF file, mapped to memory. + */ + +#ifndef ELFF_ELF_MAPPED_SECTION_H_ +#define ELFF_ELF_MAPPED_SECTION_H_ + +#include "elf_defs.h" + +/* Encapsulates a section of an ELF file, mapped to memory. */ +class ElfMappedSection { + public: + /* Constructs ElfMappedSection instance. */ + ElfMappedSection(); + + /* Destructs ElfMappedSection instance. */ + ~ElfMappedSection(); + + /* Maps ELF file section to memory. + * Param: + * handle - Handle to an opened ELF file. + * offset - Offset of the beginning of the section data in ELF file. + * NOTE: we explicitly use 64-bit type for this parameter, since we may + * still allow 32-bit library to process 64 bits ELF/DWARF formats. We + * really only care about section size being small enough to fit in 32 + * bits value in this case (which seems to be always true for ELF files, + * as section size is encoded with 32-bit value even in 64-bit ELF file). + * size - Section byte size in ELF file. + * Return: + * true on success, or false on failure, with errno providing extended + * error information. + * NOTE: if section has already been mapped, this method immediately + * returns with success. + */ + bool map(ELF_FILE_HANDLE handle, Elf_Xword offset, Elf_Word size); + + /* Checks if section has been mapped. */ + bool is_mapped() const { + return mapped_at_ != NULL; + } + + /* Gets address of the beginning of the mapped section. */ + const void* data() const { + assert(is_mapped()); + return data_; + } + + /* Gets section size. */ + Elf_Word size() const { + assert(is_mapped()); + return size_; + } + + /* Checks if an address range is fully contained in this section. */ + bool is_contained(const void* ptr, size_t rsize) const { + assert(is_mapped()); + return is_mapped() && is_in_section(ptr, rsize, data(), size()); + } + + protected: + /* Beginning of the memory mapping, containing the section. + * NOTE: due to page alignment requirements of the mapping API, mapping + * address may differ from the address where the actual section data + * starts inside that mapping. + */ + void* mapped_at_; + + /* Address of the beginning of the mapped section. */ + const void* data_; + + /* Section size. */ + Elf_Word size_; +}; + +#endif // ELFF_ELF_MAPPED_SECTION_H_ diff --git a/elff/elff-common.h b/elff/elff-common.h new file mode 100644 index 0000000..922de10 --- /dev/null +++ b/elff/elff-common.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Includes common headers for the ELFF library. + */ + +#ifndef ELFF_ELFF_COMMON_H_ +#define ELFF_ELFF_COMMON_H_ + +#include "stddef.h" +#include "sys/types.h" +#include "assert.h" +#include "memory.h" +#include "errno.h" +#ifdef WIN32 +#include "Windows.h" +#else // WIN32 +#include +#include +#include +#endif // WIN32 + +static inline void _set_errno(uint32_t err) { + errno = err; +} + +/* Main operator new. We overwrite it to redirect memory + * allocations to qemu_malloc, instead of malloc. */ +inline void* operator new(size_t size) { + return qemu_malloc(size); +} + +/* Main operator delete. We overwrite it to redirect memory + * deallocation to qemu_free, instead of free. */ +inline void operator delete(void* p) { + if (p != NULL) { + qemu_free(p); + } +} + +/* Main operator delete for arrays. We overwrite it to redirect + * memory deallocation to qemu_free, instead of free. */ +inline void operator delete[](void* p) { + if (p != NULL) { + qemu_free(p); + } +} + +#endif // ELFF_ELFF_COMMON_H_ diff --git a/elff/elff_api.cc b/elff/elff_api.cc new file mode 100644 index 0000000..46b2ad1 --- /dev/null +++ b/elff/elff_api.cc @@ -0,0 +1,84 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains implementation of routines that encapsulte an API for parsing + * an ELF file containing debugging information in DWARF format. + */ + +#include "elff_api.h" +#include "elf_file.h" +#include "dwarf_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ELFF_HANDLE +elff_init(const char* elf_file_path) +{ + ElfFile* elf_file = ElfFile::Create(elf_file_path); + return reinterpret_cast(elf_file); +} + +void +elff_close(ELFF_HANDLE handle) +{ + if (handle != NULL) { + delete reinterpret_cast(handle); + } +} + +int +elff_is_exec(ELFF_HANDLE handle) +{ + assert(handle != NULL); + if (handle == NULL) { + _set_errno(EINVAL); + return -1; + } + return reinterpret_cast(handle)->is_exec(); +} + +int +elff_get_pc_address_info(ELFF_HANDLE handle, + uint64_t address, + Elf_AddressInfo* address_info) +{ + assert(handle != NULL && address_info != NULL); + if (handle == NULL || address_info == NULL) { + _set_errno(EINVAL); + return -1; + } + + if (reinterpret_cast(handle)->get_pc_address_info(address, + address_info)) { + return 0; + } else { + return -1; + } +} + +void +elff_free_pc_address_info(ELFF_HANDLE handle, Elf_AddressInfo* address_info) +{ + assert(handle != NULL && address_info != NULL); + if (handle == NULL || address_info == NULL) { + return; + } + reinterpret_cast(handle)->free_pc_address_info(address_info); +} + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + diff --git a/elff/elff_api.h b/elff/elff_api.h new file mode 100644 index 0000000..7b02746 --- /dev/null +++ b/elff/elff_api.h @@ -0,0 +1,173 @@ +/* Copyright (C) 2007-2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains declaration of types, strctures, routines, etc. that encapsulte + * an API for parsing an ELF file containing debugging information in DWARF + * format. + */ + +#ifndef ELFF_API_H_ +#define ELFF_API_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "qemu-common.h" + +/* Defines type for a handle used in ELFF API. */ +typedef void* ELFF_HANDLE; + +/* Defines an entry for 'inline_stack' array in Elf_AddressInfo structure. + * Each entry in the array represents a routine, where routine represented + * with the previous array entry has been inlined. First element in the array + * (at index 0) represents information for the inlined routine, referenced by + * Elf_AddressInfo structure itself. If name for a routine was not available + * (DW_AT_name attribute was missing), routine name is set to "". + * Last entry in the array has all its fields set to zero. It's sufficient + * just to check for routine_name field of this structure to be NULL to detect + * last entry in the array. + */ +typedef struct Elf_InlineInfo { + /* Name of the routine where previous routine is inlined. + * This field can never be NULL, except for the last array entry. + */ + const char* routine_name; + + /* Source file name where routine is inlined. + * This field can be NULL, if it was not possible to obtain information + * about source file location for the routine. If this field is NULL, content + * of inlined_in_file_dir and inlined_at_line fields is undefined and should + * be ignored. */ + const char* inlined_in_file; + + /* Source file directory where routine is inlined. + * If inlined_in_file field contains NULL, content of this field is undefined + * and should be ignored. */ + const char* inlined_in_file_dir; + + /* Source file line number where routine is inlined. + * If inlined_in_file field contains NULL, content of this field is undefined + * and should be ignored. */ + uint32_t inlined_at_line; +} Elf_InlineInfo; + +/* Checks if an entry is the last entry in the array. + * Return: + * Boolean: 1 if this is last entry, or zero otherwise. + */ +static inline int +elfinlineinfo_is_last_entry(const Elf_InlineInfo* info) { + return info->routine_name == 0; +} + +/* PC address information descriptor. + * This descriptor contains as much information about a PC address as it was + * possible to collect from an ELF file. */ +typedef struct Elf_AddressInfo { + /* Name of the routine containing the address. If name of the routine + * was not available (DW_AT_name attribute was missing) this field + * is set to "". */ + const char* routine_name; + + /* Name of the source file containing the routine. If source location for the + * routine was not available, this field is set to NULL, and content of + * dir_name, and line_number fields of this structure is not defined. */ + const char* file_name; + + /* Path to the source file directory. If file_name field of this structure is + * NULL, content of this field is not defined. */ + const char* dir_name; + + /* Line number in the source file for the address. If file_name field of this + * structure is NULL, content of this field is not defined. */ + uint32_t line_number; + + /* If routine that contains the given address has been inlined (or it is part + * of even deeper inline branch) this array lists information about that + * inline branch rooting to the first routine that has not been inlined. The + * first element in the array references a routine, where routine containing + * the given address has been inlined. The second entry contains information + * about a routine referenced by the first entry (and so on). If routine, + * containing the given address has not been inlined, this field is set to + * NULL. The array ends with an entry containing all zeroes. */ + Elf_InlineInfo* inline_stack; +} Elf_AddressInfo; + +//============================================================================= +// API routines +//============================================================================= + +/* Initializes ELFF API for the given ELF file. + * Param: + * elf_file_path - Path to the ELF file to initialize API for. + * Return: + * On success, this routine returns a handle that can be used in subsequent + * calls to this API dealing with the given ELF file. On failure this routine + * returns NULL, with errno providing extended error information. + * NOTE: handle returned from this routine must be closed using elff_close(). + */ +ELFF_HANDLE elff_init(const char* elf_file_path); + +/* Closes a handle obtained after successful call to elff_init routine. + * Param: + * handle - A handle to close. This handle must be a handle returned from + * a successful call to elff_init routine. + */ +void elff_close(ELFF_HANDLE handle); + +/* Checks if ELF file represents an executable file, or a shared library. + * handle - A handle obtained from successful call to elff_init(). + * Return: + * 1 if ELF file represents an executable file, or + * 0 if ELF file represents a shared library, or + * -1 if handle is invalid. + */ +int elff_is_exec(ELFF_HANDLE handle); + +/* Gets PC address information. + * Param: + * handle - A handle obtained from successful call to elff_init(). + * address - PC address to get information for. Address must be relative to + * the beginning of ELF file represented by the handle parameter. + * address_info - Upon success contains information about routine(s) that + * contain the given address. + * Return: + * 0 if routine(s) containing the given address has been found and information + * has been saved into address_info, or -1 if no appropriate routine for that + * address has been found, or there was a memory error when collecting + * routine(s) information. In case of failure, errno provides extended + * error information. + * NOTE: Successful call to this routine must be complimented with a call + * to free_pc_address_info, so ELFF API can release resources aquired for + * address_info. + */ +int elff_get_pc_address_info(ELFF_HANDLE handle, + uint64_t address, + Elf_AddressInfo* address_info); + +/* Frees resources acquired for address information in successful call to + * get_pc_address_info(). + * Param: + * handle - A handle obtained from successful call to elff_init(). + * address_info - Address information structure, initialized in successful + * call to get_pc_address_info() routine. + */ +void elff_free_pc_address_info(ELFF_HANDLE handle, + Elf_AddressInfo* address_info); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif // ELFF_API_H_ -- cgit v1.1