summaryrefslogtreecommitdiffstats
path: root/libdw
diff options
context:
space:
mode:
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog724
-rw-r--r--libdw/Makefile.am21
-rw-r--r--libdw/cfi.c4
-rw-r--r--libdw/dwarf.h114
-rw-r--r--libdw/dwarf_aggregate_size.c76
-rw-r--r--libdw/dwarf_attr_integrate.c19
-rw-r--r--libdw/dwarf_begin_elf.c142
-rw-r--r--libdw/dwarf_child.c33
-rw-r--r--libdw/dwarf_cu_die.c12
-rw-r--r--libdw/dwarf_cu_info.c103
-rw-r--r--libdw/dwarf_cuoffset.c2
-rw-r--r--libdw/dwarf_die_addr_die.c70
-rw-r--r--libdw/dwarf_dieoffset.c4
-rw-r--r--libdw/dwarf_end.c36
-rw-r--r--libdw/dwarf_error.c14
-rw-r--r--libdw/dwarf_formaddr.c107
-rw-r--r--libdw/dwarf_formblock.c12
-rw-r--r--libdw/dwarf_formref.c2
-rw-r--r--libdw/dwarf_formref_die.c64
-rw-r--r--libdw/dwarf_formsdata.c15
-rw-r--r--libdw/dwarf_formstring.c131
-rw-r--r--libdw/dwarf_formudata.c160
-rw-r--r--libdw/dwarf_frame_register.c2
-rw-r--r--libdw/dwarf_get_units.c131
-rw-r--r--libdw/dwarf_getabbrev.c34
-rw-r--r--libdw/dwarf_getabbrevattr.c32
-rw-r--r--libdw/dwarf_getalt.c146
-rw-r--r--libdw/dwarf_getaranges.c21
-rw-r--r--libdw/dwarf_getattrcnt.c19
-rw-r--r--libdw/dwarf_getattrs.c31
-rw-r--r--libdw/dwarf_getlocation.c323
-rw-r--r--libdw/dwarf_getlocation_attr.c49
-rw-r--r--libdw/dwarf_getlocation_die.c23
-rw-r--r--libdw/dwarf_getlocation_implicit_pointer.c7
-rw-r--r--libdw/dwarf_getmacros.c43
-rw-r--r--libdw/dwarf_getscopes.c4
-rw-r--r--libdw/dwarf_getsrcfiles.c50
-rw-r--r--libdw/dwarf_getsrclines.c495
-rw-r--r--libdw/dwarf_hasattr.c28
-rw-r--r--libdw/dwarf_hasattr_integrate.c20
-rw-r--r--libdw/dwarf_highpc.c28
-rw-r--r--libdw/dwarf_lowpc.c15
-rw-r--r--libdw/dwarf_next_cfi.c8
-rw-r--r--libdw/dwarf_next_lines.c197
-rw-r--r--libdw/dwarf_nextcu.c196
-rw-r--r--libdw/dwarf_offdie.c4
-rw-r--r--libdw/dwarf_peel_type.c23
-rw-r--r--libdw/dwarf_ranges.c516
-rw-r--r--libdw/dwarf_setalt.c11
-rw-r--r--libdw/dwarf_siblingof.c5
-rw-r--r--libdw/libdw.h97
-rw-r--r--libdw/libdw.map14
-rw-r--r--libdw/libdwP.h648
-rw-r--r--libdw/libdw_alloc.c2
-rw-r--r--libdw/libdw_find_split_unit.c147
-rw-r--r--libdw/libdw_findcu.c189
-rw-r--r--libdw/libdw_form.c8
-rw-r--r--libdw/memory-access.h94
58 files changed, 4829 insertions, 696 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 6533eb50..da7ed9d0 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,727 @@
+2018-06-28 Mark Wielaard <[email protected]>
+
+ * dwarf_next_cfi.c (dwarf_next_cfi): Check whether length is zero.
+
+2018-06-27 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (check_section): Allow a single .debug_frame
+ section.
+
+2018-06-26 Mark Wielaard <[email protected]>
+
+ * libdw.h (dwarf_getscn_info): Remove.
+ * libdw.map (ELFUTILS_0.122): Remove dwarf_getscn_info.
+
+2018-06-25 Mark Wielaard <[email protected]>
+
+ * Makefile.am (libdw_a_SOURCES): Add dwarf_next_lines.c.
+ * libdw.h (dwarf_next_lines): New function declaration.
+ * libdw.map (ELFUTILS_0.173): New section.
+ * dwarf_next_lines.c: New files.
+ * dwarf_begin_elf.c (check_section): Don't error out when elf
+ decompression fails.
+ (valid_p): Allow just a single .debug_line section.
+ * dwarf_getsrclines.c (read_srclines): Keep files relative if comp_dir
+ is missing.
+
+2018-06-22 Mark Wielaard <[email protected]>
+
+ * dwarf_nextcu.c (__libdw_next_unit): Set next_off to -1 when it would
+ wrap around.
+
+2018-06-18 Mark Wielaard <[email protected]>
+
+ * dwarf_aggregate_size.c (array_size): New depth argument. Use
+ aggregate_size instead of dwarf_aggregate_size and pass depth.
+ (aggregate_size): New depth argument. Check depth isn't bigger
+ than MAX_DEPTH (256). Pass depth to recursive calls.
+ (dwarf_aggregate_size): ass zero as depth to aggregate_size.
+
+2018-06-18 Mark Wielaard <[email protected]>
+
+ * dwarf_peel_type.c (dwarf_peel_type): Limit modifier chain to 64.
+
+2018-06-18 Mark Wielaard <[email protected]>
+
+ * dwarf_aggregate_size.c (aggregate_size): Check die is not NULL.
+
+2018-06-17 Luiz Angelo Daros de Luca <[email protected]>
+
+ * dwarf_getsrclines.c (read_srclines): Intialize filelist early.
+
+2018-06-15 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation.c (check_constant_offset): Clarify DW_FORM_data16
+ isn't really a constant.
+ (dwarf_getlocation): Don't handle DW_FORM_data16 as block.
+ (dwarf_getlocation_addr): Likewise.
+ (dwarf_getlocations): Likewise.
+
+2018-06-12 Mark Wielaard <[email protected]>
+
+ * memory-access.h (read_3ubyte_unaligned_inc): New define.
+
+2018-06-12 Mark Wielaard <[email protected]>
+
+ * libdw.h (__libdw_dieabbrev): Set die->abbrev to DWARF_END_ABBREV
+ on failure.
+
+2018-06-10 Mark Wielaard <[email protected]>
+
+ * dwarf_attr_integrate.c (dwarf_attr_integrate): Stop after 16 DIE
+ ref chains.
+ * dwarf_hasattr_integrate.c (dwarf_hasattr_integrate): Likewise.
+
+2018-06-08 Mark Wielaard <[email protected]>
+
+ * dwarf_getabbrev.c (dwarf_getabbrev): Check die and offset.
+
+2018-06-08 Mark Wielaard <[email protected]>
+
+ * dwarf_get_units.c (dwarf_get_units): Handle existing error, no
+ dwarf.
+
+2018-06-08 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation.c (store_implicit_value): Return error when
+ seeing bad DWARF or when tsearch runs out of memory.
+ (__libdw_intern_expression): Report error when store_implicit_value
+ reported an error.
+
+2018-06-08 Mark Wielaard <[email protected]>
+
+ * dwarf_getsrclines.c (read_srclines): Sanity check ndirs and nfiles.
+
+2018-06-08 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation_attr.c (addr_valp): Set error and return NULL
+ when there is no .debug_addr section.
+ (dwarf_getlocation_attr): If addr_valp returns NULL, then return -1.
+
+2018-06-07 Mark Wielaard <[email protected]>
+
+ * libdw_findcu.c (__libdw_intern_next_unit): Report DWARF_E_VERSION,
+ not DWARF_E_INVALID_DWARF on unknown version. Set address_size and
+ offset_size to 8 when unknown.
+
+2018-06-06 Mark Wielaard <[email protected]>
+
+ * libdwP.h (__libdw_dieabbrev): Check DIE addr falls in cu.
+
+2018-06-06 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation_die.c (dwarf_getlocation_die): Check offset
+ falls inside cu data.
+
+2018-06-05 Mark Wielaard <[email protected]>
+
+ * dwarf_getsrclines.c (read_srclines): Explicitly set diridx to -1
+ in case dwarf_formudata fails.
+
+2018-06-05 Mark Wielaard <[email protected]>
+
+ * dwarf_getaranges (dwarf_getaranges): Free new_arange if
+ __libdw_findcu fails.
+
+2018-06-05 Mark Wielaard <[email protected]>
+
+ * dwarf_getsrclines.c (read_srclines): Define dirarray early and
+ check whether or not it is equal to dirstack on exit/out before
+ cleanup.
+
+2018-06-05 Mark Wielaard <[email protected]>
+
+ * dwarf_getalt.c (find_debug_altlink): id_path array should be 2
+ larger to contain MAX_BUILD_ID_BYTES.
+
+2018-05-31 Mark Wielaard <[email protected]>
+
+ * libdw_find_split_unit.c (try_split_file): New function extracted
+ from...
+ (__libdw_find_split_unit): ... here. Try both the relative and
+ absolute paths to find a .dwo file.
+
+2018-05-30 Mark Wielaard <[email protected]>
+
+ * libdw/dwarf_getsrclines.c (read_srclines): Change ndir and
+ ndirlist to size_t. Add check to see ndirlist doesn't overflow.
+
+2018-05-31 Mark Wielaard <[email protected]>
+
+ * dwarf_dieoffset.c: Check die->cu != NULL. Return -1, not ~0ul
+ on failure.
+
+2018-05-29 Mark Wielaard <[email protected]>
+
+ * dwarf_cuoffset.c (dwarf_cuoffset): Check die->cu is not NULL.
+ * dwarf_die_addr_die.c (dwarf_die_addr_die): Also search split
+ Dwarfs.
+ * libdwP.h (struct Dwarf): Add split_tree field.
+ (__libdw_find_split_dbg_addr): New internal function definition.
+ (__libdw_finddbg_cb): Likewise.
+ * libdw_find_split_unit.c (__libdw_find_split_unit): Insert split
+ Dwarf into skeleton dbg split_tree.
+ * libdw_findcu.c (__libdw_finddbg_cb): New function.
+ (__libdw_find_split_dbg_addr): Likewise.
+ * dwarf_end (dwarf_end): Destroy split_tree.
+
+2018-05-29 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add GNU DebugFission list entry encodings
+ DW_LLE_GNU_end_of_list_entry,
+ DW_LLE_GNU_base_address_selection_entry,
+ DW_LLE_GNU_start_end_entry and DW_LLE_GNU_start_length_entry.
+ * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Handle
+ GNU DebugFission list entries.
+
+2018-05-28 Mark Wielaard <[email protected]>
+
+ * libdw_find_split_unit.c (__libdw_find_split_unit): End split_dwarf
+ only after we tried every unit id in it.
+
+2018-04-07 Mark Wielaard <[email protected]>
+
+ * libdwP.h (struct Dwarf_CU): Add locs_base.
+ (__libdw_cu_locs_base): New static inline function.
+ * libdw_findcu.c (__libdw_intern_next_unit): Initialize locs_base.
+ * dwarf_begin_elf.c (valid_p): Create fake_loclists_cu if necessary.
+ * dwarf_end.c (dwarf_end): Clean up fake_loclists_cu.
+ * dwarf_getlocation.c (initial_offset): Handle .debug_loclists.
+ (getlocations_addr): Likewise.
+ (dwarf_getlocation_addr): Likewise.
+ * dwarf_getlocation_attr.c (attr_form_cu): Use fake_loclists_cu for
+ DWARF5.
+ (initial_offset): Handle DW_FORM_loclistx.
+ * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Handle
+ .debug_loclists.
+ * libdwP.h (struct Dwarf): Add fake_loclists_cu.
+
+2018-04-12 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DWARF5 location list entry DW_LLE encodings.
+ * begin_elf.c (dwarf_scnnames): Add IDX_debug_loclists.
+ * dwarf_error.c (errmsgs): Remove DWARF_E_NO_LOCLIST. And replace
+ with DWARF_E_NO_DEBUG_LOC, DWARF_E_NO_DEBUG_LOCLISTS and
+ DWARF_E_NO_LOC_VALUE.
+ * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_loclists_base
+ and DW_FORM_loclistx.
+ * dwarf_getlocation.c (attr_ok): Use DWARF_E_NO_LOC_VALUE.
+ (initial_offset): Use DWARF_E_NO_DEBUG_LOC.
+ * libdwP.h: Add IDX_debug_rnglists. Remove DWARF_E_NO_LOCLIST.
+ Add DWARF_E_NO_DEBUG_LOC, DWARF_E_NO_DEBUG_LOCLISTS and
+ DWARF_E_NO_LOC_VALUE.
+
+2018-05-25 Mark Wielaard <[email protected]>
+
+ * libdw_find_split_unit.c (__libdw_find_split_unit): Extract linking
+ skeleton and split compile units code into...
+ * libdwP (__libdw_link_skel_split): ...this new function.
+
+2018-04-06 Mark Wielaard <[email protected]>
+
+ * dwarf_formaddr.c (__libdw_addrx): New function, extracted from...
+ (dwarf_formaddr): here. Use __libdw_addrx.
+ * dwarf_getlocation.c (getlocations_addr): Pass cu to
+ __libdw_read_begin_end_pair_inc.
+ * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Take cu as
+ argument. Handle .debug_rnglists.
+ (initial_offset): Handle .debug_rnglists and DW_FORM_rnglistx.
+ (dwarf_ranges): Likewise. Check cu isn't NULL before use. Pass cu to
+ __libdw_read_begin_end_pair_inc.
+ * libdwP.h (__libdw_read_begin_end_pair_inc): Take cu as argument.
+ (__libdw_cu_ranges_base): Handle DW_AT_rnglists_base.
+ (__libdw_addrx): New function definition.
+
+2018-04-11 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DWARF5 range list entry DW_RLE encodings.
+ * begin_elf.c (dwarf_scnnames): Add IDX_debug_rnglists.
+ * dwarf_error.c (errmsgs): Add DWARF_E_NO_DEBUG_RNGLISTS.
+ * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_rnglists_base
+ and DW_FORM_rnglistx.
+ * dwarf_getscopes.c (pc_match): Also check for
+ DWARF_E_NO_DEBUG_RNGLISTS.
+ * libdwP.h: Add IDX_debug_rnglists.
+
+2018-05-25 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation_attr.c (__libdw_cu_addr_base): Cast offset to
+ uintptr_t before returning as pointer.
+
+2018-05-22 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation.c (__libdw_cu_base_address): Treat errors of
+ getting lowpc or entrypc the same as missing base address (zero).
+ * dwarf_highpc (dwarf_highpc): Handle any address form. Always set
+ error when attribute could not be found.
+
+2018-05-21 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (valid_p): Add a fake_addr_cu to the result.
+ * dwarf_end.c (cu_free): Disconnect the fake_addr_cu from the split
+ dwarf if shared with skeleton.
+ (dwarf_end): release fake_addr_cu.
+ * dwarf_formaddr.c (__libdw_cu_addr_base): Move to...
+ * libdwP.h (__libdw_cu_addr_base): ... here.
+ (struct Dwarf): Add fake_addr_cu field.
+ * dwarf_formudata.c (dwarf_formudata): Handle
+ DW_FORM_GNU_addr_index and DW_FORM_addrx[1234].
+ * dwarf_getlocation_attr.c (addr_valp): New static function.
+ (dwarf_getlocation_attr): Create attribute for values of
+ DW_OP_GNU_const_index, DW_OP_constx and DW_OP_GNU_addr_index and
+ DW_OP_addrx.
+ * libdw_find_split_unit.c (__libdw_find_split_unit): Connect
+ IDX_debug_addr sectiondata and fake_addr_cu between split and
+ skeleton.
+
+2018-05-20 Mark Wielaard <[email protected]>
+
+ * dwarf_cu_info.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add dwarf_cu_info.c.
+ * libdw.h (dwarf_cu_info): New function declaration.
+ * libdw.map (ELFUTILS_0.171): Add dwarf_cu_info.
+
+2018-05-24 Mark Wielaard <[email protected]>
+
+ * dwarf_ranges.c (dwarf_ranges): Check for NULL cu.
+ * libdw_findcu.c (__libdw_intern_next_unit): Initialize ranges_base.
+
+2018-05-18 Mark Wielaard <[email protected]>
+
+ * dwarf_formudata.c (__libdw_formptr): Handle the special case
+ of IDX_debug_ranges for DW_UT_split_compile with version < 5.
+ * dwarf_highpc.c (dwarf_highpc): Use dwarf_lowpc, check for
+ split compile cudie.
+ * dwarf_lowpc.c (dwarf_lowpc): Check for split compile cudie.
+ * dwarf_ranges.c (dwarf_ranges): Switch cu and sectiondata for
+ split compile units.
+ * libdwP.h (struct Dwarf_CU): Add ranges_base field.
+ (__libdw_cu_ranges_base): New static inline function.
+
+2018-05-18 Mark Wielaard <[email protected]>
+
+ * libdw_findcu.c (__libdw_intern_next_unit): Init files to NULL.
+ * dwarf_getsrclines.c (dwarf_getsrclines): Handle split units by
+ taking the line table from the skeleton.
+ * dwarf_getsrcfiles.c (dwarf_getsrcfiles): Handle split units by
+ only taking the files from .debug_line offset zero (if it exists),
+ otherwise fall back to the skeleton.
+
+2018-05-17 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (__libdw_debugdir): New function.
+ (valid_p): Call __libdw_debugdir.
+ * dwarf_end.c (dwarf_end.c): Free debugdir.
+ * dwarf_getalt.c (__libdw_filepath): Extract __libdw_debugdir logic.
+ take debugdir as argument instead of fd.
+ (find_debug_altlink): Call __libdw_filepath with debugdir.
+ * libdwP.h (struct Dwarf): Add debugdir field.
+ (__libdw_debugdir): New function prototype.
+ (__libdw_filepath): Adjust prototype to take a const char * instead of
+ an int.
+ * libdw_find_split_unit.c (__libdw_find_split_unit): Call
+ __libdw_filepath with debugdir.
+
+2018-05-17 Mark Wielaard <[email protected]>
+
+ * dwarf_attr_integrate.c (dwarf_attr_integrate): Handle split_compile
+ unit DIE, search skeleton_compile unit DIE.
+ * dwarf_hasattr_integrate.c (dwarf_hasattr_integrate): Likewise.
+ * libdwP.h (is_cudie): Check cu is not NULL.
+
+2018-05-19 Mark Wielaard <[email protected]>
+
+ * libdwP.h (__libdw_find_split_unit): Mark as internal_function.
+
+2018-05-15 Mark Wielaard <[email protected]>
+
+ * Makefile.am (libdw_a_SOURCES): Add libdw_find_split_unit.c.
+ * dwarf_end.c (cu_free): Free split Dwarf.
+ * dwarf_get_units.c (dwarf_get_units): Handle DW_UT_skeleton by
+ calling __libdw_find_split_unit.
+ * libdwP.h (struct Dwarf_CU): Add split Dwarf_CU field.
+ (__libdw_find_split_unit): New function prototype.
+ (str_offsets_base_off): Use cu Dwarf if dbg is NULL.
+ (filepath): Rename to ...
+ (__libdw_filepath): This. Which is the actual function name in
+ dwarf_getalt.c.
+ (libdw_find_split_unit.c): New file.
+ * libdw_findcu.c (__libdw_intern_next_unit): Initialize split to -1.
+
+2018-05-15 Mark Wielaard <[email protected]>
+
+ * libdwP.h (__libdw_first_die_from_cu_start): Adjust commented out
+ asserts.
+ * libdw_findcu.c (__libdw_intern_next_unit): For version 4 DWARF if
+ the cudie has a DW_AT_GNU_dwi_id set the unit_id8 and unit_type to
+ DW_UT_skeleton or DW_UT_split_compile based on whether the cudie has
+ child DIEs and a DW_AT_GNU_dwo_name attribute.
+
+2018-05-14 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add GNU Debug Fission extensions. DW_AT_GNU_dwo_name,
+ DW_AT_GNU_dwo_id, DW_AT_GNU_ranges_base, DW_AT_GNU_addr_base,
+ DW_AT_GNU_pubnames, DW_AT_GNU_pubtypes. DW_FORM_GNU_addr_index,
+ DW_FORM_GNU_str_index. DW_OP_GNU_addr_index, DW_OP_GNU_const_index.
+ * dwarf_formaddr.c (dwarf_formaddr): Handle DW_FORM_GNU_addr_index
+ as DW_FORM_addrx.
+ (__libdw_cu_addr_base): Check for both DW_AT_GNU_addr_base and
+ DW_AT_addr_base.
+ * dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_GNU_str_index
+ as DW_FORM_strx.
+ * dwarf_formudata.c (dwarf_formudata): Recognize DW_AT_GNU_addr_base
+ as addrptr. Recognize DW_AT_GNU_ranges_base as rangelistptr.
+ * dwarf_getlocation.c (__libdw_intern_expression): Handle
+ DW_OP_GNU_addr_index as DW_OP_addrx and DW_OP_GNU_const_index as
+ DW_OP_constx.
+ * libdw_form.c (__libdw_form_val_compute_len): Handle
+ DW_FORM_GNU_addr_index and DW_FORM_GNU_str_index taking an uleb128.
+
+2018-05-12 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (check_section): Also recognize .dwo section
+ name variants.
+
+2018-05-11 Mark Wielaard <[email protected]>
+
+ * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_macros as macptr.
+ * dwarf_getmacros.c (get_table_for_offset): Add DW_MACRO_define_sup,
+ DW_MACRO_undef_sup, DW_MACRO_import_sup, DW_MACRO_define_strx and
+ DW_MACRO_undef_strx. Add str_offsets_base_off to fake CU. Deal with
+ DW_AT_macros. Use libdw_valid_user_form.
+
+2018-05-09 Mark Wielaard <[email protected]>
+
+ * dwarf_formstring.c (__libdw_cu_str_off_base): Moved to...
+ * libdwP.h (__libdw_cu_str_off_base): ...here. Make static inline.
+ (str_offsets_base_off): New internal function that also parses
+ .debug_str_offsets header if necessary.
+
+2018-05-11 Mark Wielaard <[email protected]>
+
+ * dwarf_siblingof.c (dwarf_siblingof): Don't reference cu till it is
+ known the Dwarf_Die is came from is valid.
+ * libdwP.h (__libdw_dieabbrev): Check cu is not NULL.
+
+2018-05-08 Mark Wielaard <[email protected]>
+
+ * dwarf_formref.c (__libdw_formref): Explicitly don't handle
+ DW_FORM_ref_sup4 and DW_FORM_ref_sup8.
+ * dwarf_formref_die.c (dwarf_formref_die): Handle DW_FORM_ref_sup4
+ and DW_FORM_ref_sup8.
+ * dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_strp_sup
+ as DW_FORM_GNU_strp_alt.
+
+2018-05-05 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DWARF line content descriptions.
+ * libdwP.h (libdw_valid_user_form): New static function.
+ * dwarf_getsrclines.c (read_srclines): Check and parse version 5
+ DWARF header, dir and file tables separately from older versions
+ where different.
+
+2018-04-24 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (dwarf_scnnames): Add ".debug_line_str".
+ * dwarf_error.c (errmsgs): Add DWARF_E_NO_DEBUG_STR and
+ DWARF_E_NO_DEBUG_LINE_STR.
+ * dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_line_strp.
+ Get data from either .debug_str or .debug_line_str.
+ * libdwP.h: Add IDX_debug_line_str, DWARF_E_NO_DEBUG_STR and
+ DWARF_E_NO_DEBUG_LINE_STR.
+
+2018-04-03 Mark Wielaard <[email protected]>
+
+ * dwarf_formudata.c (__libdw_formptr): Take and return const
+ unsigned char pointers.
+ * dwarf_getlocation.c (attr_base_address): Rename to...
+ (__libdw_cu_base_address): this. Take Dwarf_CU, check and set
+ base_address.
+ (initial_offset_base): Renamed to...
+ (initial_offset): this. Only provide offset.
+ (getlocations_addr): Move data size check and
+ address base addition into __libdw_read_begin_end_pair_inc. Use
+ __libdw_cu_base_address and initial_offset. Drop Elf_Data NULL
+ check (already done by initial_offset, through __libdw_formptr).
+ (dwarf_getlocations): Use __libdw_cu_base_address and initial_offset.
+ Drop Elf_Data NULL check.
+ * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Change argument
+ type of readp to Add readend argument. Check data size. Include base
+ in begin and end result.
+ (initial_offset): New static function.
+ (dwarf_ranges): Don't check Elf_Data being NULL (already done by
+ initial_offset, through __libdw_formptr). Use __libdw_cu_base_address
+ and initial_offset. Remove base check and addition (already done by
+ __libdw_read_begin_end_pair_inc.
+ * libdwP.h (Dwarf_CU): Add base_address field.
+ (__libdw_read_begin_end_pair_inc): Change argument type of readp to
+ const. Add readend argument.
+ (__libdw_formptr): Take and return const unsigned char pointers.
+ * libdw_findcu.c (__libdw_intern_next_unit): Initialize Dwarf_CU
+ base_address.
+
+2018-04-04 Mark Wielaard <[email protected]>
+
+ * libdw_findcu.c (__libdw_intern_next_unit): Initialize Dwarf_CU
+ addr_base and str_off_base.
+
+2018-03-23 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_str_offsets,
+ increase size.
+ * dwarf_error.c (errmsgs): Add DWARF_E_NO_STR_OFFSETS.
+ * dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_strx[1234].
+ (__libdw_cu_str_off_base): New function.
+ * dwarf_formudata.c (dwarf_formudata): Handle IDX_debug_str_offsets
+ as stroffsetsptr.
+ * libdwP.h: Add IDX_debug_str_offsets and DWARF_E_NO_STR_OFFSETS.
+ (struct Dwarf_CU): Add str_off_base field.
+ (__libdw_cu_str_off_base): New function declaration.
+
+2018-03-22 Mark Wielaard <[email protected]>
+
+ * dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_addr.
+ * dwarf_error.c (errmsgs): Add DWARF_E_NO_DEBUG_ADDR.
+ * dwarf_formaddr.c (dwarf_formaddr): Handle DW_FORM_addrx[1234].
+ (__libdw_cu_addr_base): New function.
+ * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_addr_base as
+ addrptr.
+ * libdwP.h: Add IDX_debug_addr and DWARF_E_NO_DEBUG_ADDR.
+ (struct Dwarf_CU): Add addr_base field.
+ (__libdw_cu_addr_base): New function definition.
+ * memory-access.h (file_byte_order): New static function.
+ (read_3ubyte_unaligned): New inline function.
+
+2018-03-29 Mark Wielaard <[email protected]>
+
+ * libdw.h (dwarf_decl_file): Extend documentation.
+ (dwarf_linesrc): Likewise.
+ (dwarf_filesrc): Likewise.
+
+2018-03-06 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DW_OP_implicit_pointer, DW_OP_addrx, DW_OP_constx,
+ DW_OP_entry_value, DW_OP_const_type, DW_OP_regval_type,
+ DW_OP_deref_type, DW_OP_xderef_type, DW_OP_convert and
+ DW_OP_reinterpret.
+ * dwarf_getlocation.c (__libdw_intern_expression): Handle
+ DW_OP_convert, DW_OP_reinterpret, DW_OP_addrx, DW_OP_constx,
+ DW_OP_regval_type, DW_OP_entry_value, DW_OP_implicit_pointer,
+ DW_OP_deref_type, DW_OP_xderef_type and DW_OP_const_type.
+ * dwarf_getlocation_attr.c (dwarf_getlocation_attr): Handle
+ DW_OP_entry_value, DW_OP_const_type and DW_OP_implicit_pointer.
+ * dwarf_getlocation_die.c (dwarf_getlocation_die): Handle
+ DW_OP_implicit_pointer, DW_OP_convert, DW_OP_reinterpret,
+ DW_OP_const_type, DW_OP_regval_type, DW_OP_deref_type and
+ DW_OP_xderef_type.
+ * dwarf_getlocation_implicit_pointer.c
+ (dwarf_getlocation_implicit_pointer): Handle DW_OP_implicit_pointer.
+
+2018-03-01 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DW_AT_GNU_locviews and DW_AT_GNU_entry_view.
+ * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_GNU_locviews
+ as a loclistptr.
+
+2018-02-09 Mark Wielaard <[email protected]>
+
+ * dwarf_formblock.c (dwarf_formblock): Handle DW_FORM_data16 as a
+ 16 byte block.
+
+2018-02-09 Mark Wielaard <[email protected]>
+
+ * dwarf_child.c (__libdw_find_attr): Handle DW_FORM_implicit_const.
+ * dwarf_formsdata.c (dwarf_formsdata): Likewise.
+ * dwarf_formudata.c (dwarf_formudata): Likewise.
+ * dwarf_getabbrev.c (__libdw_getabbrev): Likewise.
+ * dwarf_getattrs.c (dwarf_getattrs): Likewise.
+ * dwarf_hasattr.c (dwarf_hasattr): Likewise.
+ * dwarf_getabbrevattr.c (dwarf_getabbrevattr_data): New function
+ that will also return any data associated with the abbrev. Which
+ currently is only for DW_FORM_implicit_const. Based on...
+ (dwarf_getabbrevattr): ... this function. Which now just calls
+ dwarf_getabbrevattr_data.
+ * libdw.h (dwarf_getabbrevattr_data): Declare new function.
+ * libdw.map (ELFUTILS_0.170): Add dwarf_getabbrevattr_data.
+ * libdwP.h (dwarf_getabbrevattr_data): INTDECL.
+ * memory-access.h (__libdw_get_sleb128_unchecked): New inlined
+ function based on __libdw_get_uleb128_unchecked.
+
+2018-02-08 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DWARF5 DW_FORMs.
+ * libdwP.h (__libdw_form_val_compute_len): Handle fix length
+ DW_FORM_implicit_const, DW_FORM_addrx[1234], DW_FORM_strx[1234],
+ DW_FORM_ref_sup[48] and DW_FORM_data16.
+ * libdw_form.c (__libdw_form_val_compute_len): DW_FORM_strp_sup
+ and DW_FORM_line_strp are offset_size. DW_FORM_addrx, DW_FORM_strx,
+ DW_FORM_loclistx and DW_FORM_rnglistx are uleb128.
+
+2018-01-30 Mark Wielaard <[email protected]>
+
+ * Makefile.am (libdw_a_SOURCES): Add dwarf_get_units.c.
+ * dwarf_get_units.c: New file.
+ * libdw.h (dwarf_get_units): New function declaration.
+ * libdw.map (ELFUTILS_0.170): Add dwarf_get_units.
+
+2018-01-29 Mark Wielaard <[email protected]>
+
+ * dwarf.h (DW_UT_*): Add DWARF Unit Header Types.
+ * dwarf_cu_die.c (dwarf_cu_die): Rename arguments. type_signaturep
+ is now called unit_idp. type_offsetp is now called subdie_offsetp.
+ * dwarf_formref_die.c (dwarf_formref_die): Scan both .debug_info
+ and .debug_types sections for type units when type signature ref
+ not found.
+ * dwarf_getaranges.c (dwarf_getaranges): Use __libdw_findcu and
+ __libdw_first_die_off_from_cu instead of trying by hand.
+ * dwarf_getlocation_die.c (dwarf_getlocation_die): Use ISV4TU
+ instead of checking type_offset by hand.
+ * dwarf_getlocation_implicit_pointer.c
+ (dwarf_getlocation_implicit_pointer): Likewise.
+ * dwarf_nextcu.c (dwarf_next_unit): Call __libdw_next_unit.
+ (__libdw_next_unit): New function based on dwarf_next_unit with
+ DWARF5 header support.
+ * libdwP.h (struct Dwarf_CU): Renamed type_offset to subdie_offset
+ and type_sig8 to unit_id8.
+ (ISV4TU): New macro to determine whether a CU is a version 4 type
+ unit (which comes from the .debug_types section).
+ (DIE_OFFSET_FROM_CU_OFFSET): Replaced macro by real function...
+ (__libdw_first_die_from_cu_start): ... that also handles DWARF5
+ unit headers.
+ (__libdw_first_die_off_from_cu): New function that calls the above
+ using the CU fields.
+ (CUDIE): Use __libdw_first_die_off_from_cu.
+ (SUBDIE): New macro that provides the DIE for a CU using the
+ subdie_offset.
+ (__libdw_next_unit): New internal function declaration.
+ * libdw_findcu.c (__libdw_intern_next_unit): Use __libdw_next_unit.
+ Accept DWARF version 5 headers. Setup unit_type.
+ (__libdw_findcu): Rename debug_types argument to v4_debug_types
+ argument (to indicate that we are looking in the .debug_types
+ section). Support finding the exact offset (unit header start).
+
+2018-01-25 Mark Wielaard <[email protected]>
+
+ * Makefile.am (libdw_a_SOURCES): Add dwarf_die_addr_die.c.
+ * dwarf_die_addr_die.c: New file.
+ * libdw.h (dwarf_die_addr_die): New function declaration.
+ * libdw.map (ELFUTILS_0.171): New section with dwarf_die_addr_die.
+ * libdwP.h (__libdw_findcu_addr): New internal function declaration.
+ * libdw_findcu.c (__libdw_findcu_addr): New internal function.
+
+2018-02-09 Joshua Watt <[email protected]>
+
+ * cfi.c (execute_cfi): Use FALLTHROUGH macro instead of comment.
+ * dwarf_frame_register.c (dwarf_frame_register): Likewise.
+
+2018-01-22 Mark Wielaard <[email protected]>
+
+ * Makefile.am (AM_CPPFLAGS): Add -I libdwelf.
+ * dwarf_begin_elf.c (dwarf_begin_elf): Initialize Dwarf alt_fd to -1.
+ * dwarf_end.c (dwarf_end): Call dwarf_end and close on the alt_dwarf
+ and alt_fd if we allocated them.
+ * dwarf_fromref_die.c (dwarf_formref_die): Call dwarf_getalt.
+ * dwarf_formstring.c (dwarf_formstring): Likewise.
+ * dwarf_getalt.c (__libdw_filepath): New internal function.
+ (find_debug_altlink): New static function.
+ (dwarf_getalt): Check Dwarf alt_dwarf and call find_debug_altlink.
+ Cache result.
+ * dwarf_setalt.c (dwarf_setalt): Clean up Dwarf alt_dwarf and alt_fd
+ if we allocated.
+ * libdw.h (dwarf_getalt): Extend documentation.
+ (dwarf_setalt): Likewise.
+ * libdwP.h (struct Dwarf): Add alt_fd field.
+ (filepath): Declare new internal function.
+
+2018-01-14 Petr Machata <[email protected]>
+
+ * dwarf_formsdata.c (dwarf_formsdata):
+ <DW_FORM_data1>: Cast to signed char.
+ <DW_FORM_data2,4,8>: Use read_*sbyte_unaligned instead of
+ read_*ubyte_unaligned.
+
+2017-12-26 Mark Wielaard <[email protected]>
+
+ * libdwP.h (struct Dwarf_Abbrev): Pack struct. Remove attrcnt,
+ use bitfields for has_children and code.
+ * dwarf_getabbrev.c (__libdw_getabbrev): Don't count attrs.
+ * dwarf_getattrcnt.c (dwarf_getattrcnt): Count attrs.
+
+2017-12-26 Mark Wielaard <[email protected]>
+
+ * memory-access.h (__libdw_get_uleb128_unchecked): New function.
+ (get_uleb128_unchecked): New define.
+ * dwarf_child.c (__libdw_find_attr): Use get_uleb128_unchecked to
+ read attr name and form.
+ * dwarf_getabbrevattr.c (dwarf_getabbrevattr): Likewise.
+ * dwarf_getattrs.c (dwarf_getattrs): Likewise.
+ * dwarf_hasattr.c (dwarf_hasattr): Likewise.
+
+2017-12-28 Mark Wielaard <[email protected]>
+
+ * dwarf_offdie.c (__libdw_offdie): Check sectiondata exists.
+
+2017-05-09 Ulf Hermann <[email protected]>
+ Mark Wielaard <[email protected]>
+
+ * libdwP.h (__libdw_in_section): Fix check for the upper border of
+ the range.
+ (__libdw_offset_in_section): Likewise.
+
+2017-12-20 Mark Wielaard <[email protected]>
+
+ * libdwP.h (struct Dwarf_CU): Add sec_idx field.
+ (cu_sec_idx): Return cu->sec_idx.
+ * libdw_findcu.c (__libdw_intern_next_unit): Set cu sec_idx to
+ IDX_debug_info or IDX_debug_types.
+ * dwarf_begin_elf.c (valid_p): Set fake_loc_cu->sec_idx to
+ IDX_debug_loc.
+ * dwarf_getmacros.c (read_macros): Set fake_cu->sec_idx to
+ IDX_debug_macro or IDX_debug_macinfo.
+
+2017-12-12 Mark Wielaard <[email protected]>
+
+ * dwarf_aggregate_size.c (dwarf_aggregate_size): Don't peel the
+ given DIE. Reserve memory for a new DIE first.
+
+2017-12-11 Dima Kogan <[email protected]>
+
+ * dwarf_aggregate_size.c (array_size): Handle multi-dimensional
+ arrays properly.
+
+2017-11-03 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation.c (__libdw_intern_expression): Handle
+ DW_OP_GNU_variable_value.
+ * dwarf_getlocation_attr.c (dwarf_getlocation_attr): Likewise.
+ * dwarf_getlocation_die.c (dwarf_getlocation_die): Likewise.
+
+2017-11-03 Mark Wielaard <[email protected]>
+
+ * dwarf_getlocation.c (attr_ok): Always accept DW_FORM_exprloc.
+ Update list of acceptable attribute codes based on DWARF5.
+
+2017-11-03 Mark Wielaard <[email protected]>
+
+ * dwarf.h: Add DW_OP_GNU_variable_value.
+
+2017-10-03 Mark Wielaard <[email protected]>
+
+ * libdw.h: Define LIBDW_CIE_ID and use it in dwarf_cfi_cie_p.
+
+2017-08-18 Ulf Hermann <[email protected]>
+
+ * memory-access.h: Use attribute_packed.
+
+2017-02-27 Ulf Hermann <[email protected]>
+
+ * libdwP.h: Use attribute_hidden.
+ * libdw_alloc.c: Likewise.
+
+2017-02-27 Ulf Hermann <[email protected]>
+
+ * Makefile.am: Use fpic_CFLAGS and dso_LDFLAGS.
+
2017-07-26 Mark Wielaard <[email protected]>
* dwarf.h: Add DW_MACRO_* and compat defines for DW_MACRO_GNU_*.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index b3e781d8..166e37cf 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to create Makefile.in
##
-## Copyright (C) 2002-2010, 2012, 2014, 2016 Red Hat, Inc.
+## Copyright (C) 2002-2010, 2012, 2014, 2016, 2018 Red Hat, Inc.
## This file is part of elfutils.
##
## This file is free software; you can redistribute it and/or modify
@@ -29,9 +29,9 @@
##
include $(top_srcdir)/config/eu.am
if BUILD_STATIC
-AM_CFLAGS += -fPIC
+AM_CFLAGS += $(fpic_CFLAGS)
endif
-AM_CPPFLAGS += -I$(srcdir)/../libelf
+AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf
VERSION = 1
lib_LIBRARIES = libdw.a
@@ -90,7 +90,10 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c \
dwarf_getlocation_die.c dwarf_getlocation_attr.c \
dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
- dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c
+ dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c \
+ dwarf_die_addr_die.c dwarf_get_units.c \
+ libdw_find_split_unit.c dwarf_cu_info.c \
+ dwarf_next_lines.c
# Minimal library with symbols needed by those libebl backends that we
# ship statically. This is so that e.g. strip doesn't end up bringing
@@ -105,7 +108,11 @@ libdw_static_pic_a_SOURCES = libdw_form.c dwarf_child.c dwarf_attr.c \
dwarf_aggregate_size.c dwarf_siblingof.c dwarf_formsdata.c \
dwarf_srclang.c dwarf_formflag.c dwarf_diecu.c \
dwarf_bytesize.c dwarf_bitsize.c dwarf_peel_type.c \
- dwarf_default_lower_bound.c
+ dwarf_default_lower_bound.c libdw_find_split_unit.c \
+ dwarf_getalt.c dwarf_haschildren.c \
+ dwarf_begin.c dwarf_begin_elf.c dwarf_end.c frame-cache.c \
+ dwarf_get_units.c dwarf_formstring.c \
+ ../libdwelf/dwelf_dwarf_gnu_debugaltlink.c
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
@@ -129,8 +136,8 @@ libdw_so_SOURCES =
libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS)
# The rpath is necessary for libebl because its $ORIGIN use will
# not fly in a setuid executable that links in libdw.
- $(AM_V_CCLD)$(LINK) -shared -o $@ \
- -Wl,--soname,$@.$(VERSION),-z,defs,-z,relro \
+ $(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
+ -Wl,--soname,$@.$(VERSION) \
-Wl,--enable-new-dtags,-rpath,$(pkglibdir) \
-Wl,--version-script,$<,--no-undefined \
-Wl,--whole-archive $(libdw_so_LIBS) -Wl,--no-whole-archive \
diff --git a/libdw/cfi.c b/libdw/cfi.c
index daa845f3..341e055b 100644
--- a/libdw/cfi.c
+++ b/libdw/cfi.c
@@ -138,7 +138,7 @@ execute_cfi (Dwarf_CFI *cache,
case DW_CFA_advance_loc1:
operand = *program++;
- /* Fallthrough */
+ FALLTHROUGH;
case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX:
advance_loc:
loc += operand * cie->code_alignment_factor;
@@ -301,7 +301,7 @@ execute_cfi (Dwarf_CFI *cache,
case DW_CFA_restore_extended:
get_uleb128 (operand, program, end);
- /* Fallthrough */
+ FALLTHROUGH;
case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX:
if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore))
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 902d2617..dc597335 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -1,5 +1,5 @@
/* This file defines standard DWARF types, structures, and macros.
- Copyright (C) 2000-2011, 2014, 2016, 2017 Red Hat, Inc.
+ Copyright (C) 2000-2011, 2014, 2016, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -29,6 +29,20 @@
#ifndef _DWARF_H
#define _DWARF_H 1
+/* DWARF Unit Header Types. */
+enum
+ {
+ DW_UT_compile = 0x01,
+ DW_UT_type = 0x02,
+ DW_UT_partial = 0x03,
+ DW_UT_skeleton = 0x04,
+ DW_UT_split_compile = 0x05,
+ DW_UT_split_type = 0x06,
+
+ DW_UT_lo_user = 0x80,
+ DW_UT_hi_user = 0xff
+ };
+
/* DWARF tags. */
enum
{
@@ -325,8 +339,17 @@ enum
DW_AT_GNU_all_tail_call_sites = 0x2116,
DW_AT_GNU_all_call_sites = 0x2117,
DW_AT_GNU_all_source_call_sites = 0x2118,
+ DW_AT_GNU_locviews = 0x2137,
+ DW_AT_GNU_entry_view = 0x2138,
DW_AT_GNU_macros = 0x2119,
DW_AT_GNU_deleted = 0x211a,
+ /* GNU Debug Fission extensions. */
+ DW_AT_GNU_dwo_name = 0x2130,
+ DW_AT_GNU_dwo_id = 0x2131,
+ DW_AT_GNU_ranges_base = 0x2132,
+ DW_AT_GNU_addr_base = 0x2133,
+ DW_AT_GNU_pubnames = 0x2134,
+ DW_AT_GNU_pubtypes = 0x2135,
DW_AT_hi_user = 0x3fff
};
@@ -368,7 +391,29 @@ enum
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
+ DW_FORM_strx = 0x1a,
+ DW_FORM_addrx = 0x1b,
+ DW_FORM_ref_sup4 = 0x1c,
+ DW_FORM_strp_sup = 0x1d,
+ DW_FORM_data16 = 0x1e,
+ DW_FORM_line_strp = 0x1f,
DW_FORM_ref_sig8 = 0x20,
+ DW_FORM_implicit_const = 0x21,
+ DW_FORM_loclistx = 0x22,
+ DW_FORM_rnglistx = 0x23,
+ DW_FORM_ref_sup8 = 0x24,
+ DW_FORM_strx1 = 0x25,
+ DW_FORM_strx2 = 0x26,
+ DW_FORM_strx3 = 0x27,
+ DW_FORM_strx4 = 0x28,
+ DW_FORM_addrx1 = 0x29,
+ DW_FORM_addrx2 = 0x2a,
+ DW_FORM_addrx3 = 0x2b,
+ DW_FORM_addrx4 = 0x2c,
+
+ /* GNU Debug Fission extensions. */
+ DW_FORM_GNU_addr_index = 0x1f01,
+ DW_FORM_GNU_str_index = 0x1f02,
DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */
DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */
@@ -533,6 +578,17 @@ enum
DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode. */
DW_OP_stack_value = 0x9f, /* No operands, special like DW_OP_piece. */
+ DW_OP_implicit_pointer = 0xa0,
+ DW_OP_addrx = 0xa1,
+ DW_OP_constx = 0xa2,
+ DW_OP_entry_value = 0xa3,
+ DW_OP_const_type = 0xa4,
+ DW_OP_regval_type = 0xa5,
+ DW_OP_deref_type = 0xa6,
+ DW_OP_xderef_type = 0xa7,
+ DW_OP_convert = 0xa8,
+ DW_OP_reinterpret = 0xa9,
+
/* GNU extensions. */
DW_OP_GNU_push_tls_address = 0xe0,
DW_OP_GNU_uninit = 0xf0,
@@ -546,6 +602,12 @@ enum
DW_OP_GNU_reinterpret = 0xf9,
DW_OP_GNU_parameter_ref = 0xfa,
+ /* GNU Debug Fission extensions. */
+ DW_OP_GNU_addr_index = 0xfb,
+ DW_OP_GNU_const_index = 0xfc,
+
+ DW_OP_GNU_variable_value = 0xfd,
+
DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */
DW_OP_hi_user = 0xff /* Implementation-defined range end. */
};
@@ -737,6 +799,17 @@ enum
DW_DEFAULTED_out_of_class = 2
};
+/* DWARF line content descriptions. */
+enum
+ {
+ DW_LNCT_path = 0x1,
+ DW_LNCT_directory_index = 0x2,
+ DW_LNCT_timestamp = 0x3,
+ DW_LNCT_size = 0x4,
+ DW_LNCT_MD5 = 0x5,
+ DW_LNCT_lo_user = 0x2000,
+ DW_LNCT_hi_user = 0x3fff
+ };
/* DWARF standard opcode encodings. */
enum
@@ -813,6 +886,45 @@ enum
#define DW_MACRO_GNU_hi_user DW_MACRO_hi_user
+/* Range list entry encoding. */
+enum
+ {
+ DW_RLE_end_of_list = 0x0,
+ DW_RLE_base_addressx = 0x1,
+ DW_RLE_startx_endx = 0x2,
+ DW_RLE_startx_length = 0x3,
+ DW_RLE_offset_pair = 0x4,
+ DW_RLE_base_address = 0x5,
+ DW_RLE_start_end = 0x6,
+ DW_RLE_start_length = 0x7
+ };
+
+
+/* Location list entry encoding. */
+enum
+ {
+ DW_LLE_end_of_list = 0x0,
+ DW_LLE_base_addressx = 0x1,
+ DW_LLE_startx_endx = 0x2,
+ DW_LLE_startx_length = 0x3,
+ DW_LLE_offset_pair = 0x4,
+ DW_LLE_default_location = 0x5,
+ DW_LLE_base_address = 0x6,
+ DW_LLE_start_end = 0x7,
+ DW_LLE_start_length = 0x8
+ };
+
+
+/* GNU DebugFission list entry encodings (.debug_loc.dwo). */
+enum
+ {
+ DW_LLE_GNU_end_of_list_entry = 0x0,
+ DW_LLE_GNU_base_address_selection_entry = 0x1,
+ DW_LLE_GNU_start_end_entry = 0x2,
+ DW_LLE_GNU_start_length_entry = 0x3
+ };
+
+
/* DWARF call frame instruction encodings. */
enum
{
diff --git a/libdw/dwarf_aggregate_size.c b/libdw/dwarf_aggregate_size.c
index 838468dd..75105e4d 100644
--- a/libdw/dwarf_aggregate_size.c
+++ b/libdw/dwarf_aggregate_size.c
@@ -46,13 +46,17 @@ get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
return type;
}
+static int aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
+ Dwarf_Die *type_mem, int depth);
+
static int
array_size (Dwarf_Die *die, Dwarf_Word *size,
- Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
+ Dwarf_Attribute *attr_mem, int depth)
{
Dwarf_Word eltsize;
- if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem),
- &eltsize) != 0)
+ Dwarf_Die type_mem, aggregate_type_mem;
+ if (aggregate_size (get_type (die, attr_mem, &type_mem), &eltsize,
+ &aggregate_type_mem, depth) != 0)
return -1;
/* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type
@@ -63,7 +67,7 @@ array_size (Dwarf_Die *die, Dwarf_Word *size,
return -1;
bool any = false;
- Dwarf_Word total = 0;
+ Dwarf_Word count_total = 1;
do
{
Dwarf_Word count;
@@ -134,53 +138,63 @@ array_size (Dwarf_Die *die, Dwarf_Word *size,
continue;
}
- /* This is a subrange_type or enumeration_type and we've set COUNT.
- Now determine the stride for this array dimension. */
- Dwarf_Word stride = eltsize;
- if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_byte_stride,
- attr_mem) != NULL)
- {
- if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
- return -1;
- }
- else if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_bit_stride,
- attr_mem) != NULL)
- {
- if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
- return -1;
- if (stride % 8) /* XXX maybe compute in bits? */
- return -1;
- stride /= 8;
- }
+ count_total *= count;
any = true;
- total += stride * count;
}
while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
if (!any)
return -1;
- *size = total;
+ /* This is a subrange_type or enumeration_type and we've set COUNT.
+ Now determine the stride for this array. */
+ Dwarf_Word stride = eltsize;
+ if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_stride,
+ attr_mem) != NULL)
+ {
+ if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
+ return -1;
+ }
+ else if (INTUSE(dwarf_attr_integrate) (die, DW_AT_bit_stride,
+ attr_mem) != NULL)
+ {
+ if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
+ return -1;
+ if (stride % 8) /* XXX maybe compute in bits? */
+ return -1;
+ stride /= 8;
+ }
+
+ *size = count_total * stride;
return 0;
}
static int
-aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem)
+aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
+ Dwarf_Die *type_mem, int depth)
{
Dwarf_Attribute attr_mem;
+/* Arrays of arrays of subrange types of arrays... Don't recurse too deep. */
+#define MAX_DEPTH 256
+ if (die == NULL || depth++ >= MAX_DEPTH)
+ return -1;
+
if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL)
return INTUSE(dwarf_formudata) (&attr_mem, size);
switch (INTUSE(dwarf_tag) (die))
{
case DW_TAG_subrange_type:
- return aggregate_size (get_type (die, &attr_mem, type_mem),
- size, type_mem); /* Tail call. */
+ {
+ Dwarf_Die aggregate_type_mem;
+ return aggregate_size (get_type (die, &attr_mem, type_mem),
+ size, &aggregate_type_mem, depth);
+ }
case DW_TAG_array_type:
- return array_size (die, size, &attr_mem, type_mem);
+ return array_size (die, size, &attr_mem, depth);
/* Assume references and pointers have pointer size if not given an
explicit DW_AT_byte_size. */
@@ -198,12 +212,12 @@ aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem)
int
dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size)
{
- Dwarf_Die type_mem;
+ Dwarf_Die die_mem, type_mem;
- if (INTUSE (dwarf_peel_type) (die, die) != 0)
+ if (INTUSE (dwarf_peel_type) (die, &die_mem) != 0)
return -1;
- return aggregate_size (die, size, &type_mem);
+ return aggregate_size (&die_mem, size, &type_mem, 0);
}
INTDEF (dwarf_aggregate_size)
OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
diff --git a/libdw/dwarf_attr_integrate.c b/libdw/dwarf_attr_integrate.c
index 812d74b9..fc068638 100644
--- a/libdw/dwarf_attr_integrate.c
+++ b/libdw/dwarf_attr_integrate.c
@@ -1,5 +1,5 @@
/* Return specific DWARF attribute of a DIE, integrating indirections.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name,
Dwarf_Attribute *result)
{
Dwarf_Die die_mem;
-
+ int chain = 16; /* Largest DIE ref chain we will follow. */
do
{
Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, search_name, result);
@@ -53,8 +53,21 @@ dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name,
die = INTUSE(dwarf_formref_die) (attr, &die_mem);
}
- while (die != NULL);
+ while (die != NULL && chain-- != 0);
+ /* Not NULL if it didn't have abstract_origin and specification
+ attributes. If it is a split CU then see if the skeleton
+ has it. */
+ if (die != NULL && is_cudie (die)
+ && die->cu->unit_type == DW_UT_split_compile)
+ {
+ Dwarf_CU *skel_cu = __libdw_find_split_unit (die->cu);
+ if (skel_cu != NULL)
+ {
+ Dwarf_Die skel_die = CUDIE (skel_cu);
+ return INTUSE(dwarf_attr) (&skel_die, search_name, result);
+ }
+ }
return NULL;
}
INTDEF (dwarf_attr_integrate)
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index afa15cef..184a6dc9 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -1,7 +1,6 @@
/* Create descriptor from ELF descriptor for processing file.
- Copyright (C) 2002-2011, 2014, 2015 Red Hat, Inc.
+ Copyright (C) 2002-2011, 2014, 2015, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2002.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -43,24 +42,30 @@
#include <fcntl.h>
#include <endian.h>
+#include "libelfP.h"
#include "libdwP.h"
-/* Section names. */
-static const char dwarf_scnnames[IDX_last][18] =
+/* Section names. (Note .debug_str_offsets is the largest 19 chars.) */
+static const char dwarf_scnnames[IDX_last][19] =
{
[IDX_debug_info] = ".debug_info",
[IDX_debug_types] = ".debug_types",
[IDX_debug_abbrev] = ".debug_abbrev",
+ [IDX_debug_addr] = ".debug_addr",
[IDX_debug_aranges] = ".debug_aranges",
[IDX_debug_line] = ".debug_line",
+ [IDX_debug_line_str] = ".debug_line_str",
[IDX_debug_frame] = ".debug_frame",
[IDX_debug_loc] = ".debug_loc",
+ [IDX_debug_loclists] = ".debug_loclists",
[IDX_debug_pubnames] = ".debug_pubnames",
[IDX_debug_str] = ".debug_str",
+ [IDX_debug_str_offsets] = ".debug_str_offsets",
[IDX_debug_macinfo] = ".debug_macinfo",
[IDX_debug_macro] = ".debug_macro",
[IDX_debug_ranges] = ".debug_ranges",
+ [IDX_debug_rnglists] = ".debug_rnglists",
[IDX_gnu_debugaltlink] = ".gnu_debugaltlink"
};
#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0]))
@@ -113,14 +118,26 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
size_t cnt;
bool gnu_compressed = false;
for (cnt = 0; cnt < ndwarf_scnnames; ++cnt)
- if (strcmp (scnname, dwarf_scnnames[cnt]) == 0)
- break;
- else if (scnname[0] == '.' && scnname[1] == 'z'
- && strcmp (&scnname[2], &dwarf_scnnames[cnt][1]) == 0)
- {
- gnu_compressed = true;
- break;
- }
+ {
+ size_t dbglen = strlen (dwarf_scnnames[cnt]);
+ size_t scnlen = strlen (scnname);
+ if (strncmp (scnname, dwarf_scnnames[cnt], dbglen) == 0
+ && (dbglen == scnlen
+ || (scnlen == dbglen + 4
+ && strstr (scnname, ".dwo") == scnname + dbglen)))
+ break;
+ else if (scnname[0] == '.' && scnname[1] == 'z'
+ && (strncmp (&scnname[2], &dwarf_scnnames[cnt][1],
+ dbglen - 1) == 0
+ && (scnlen == dbglen + 1
+ || (scnlen == dbglen + 5
+ && strstr (scnname,
+ ".dwo") == scnname + dbglen + 1))))
+ {
+ gnu_compressed = true;
+ break;
+ }
+ }
if (cnt >= ndwarf_scnnames)
/* Not a debug section; ignore it. */
@@ -139,17 +156,9 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
{
if (elf_compress (scn, 0, 0) < 0)
{
- /* If we failed to decompress the section and it's the
- debug_info section, then fail with specific error rather
- than the generic NO_DWARF. Without debug_info we can't do
- anything (see also valid_p()). */
- if (cnt == IDX_debug_info)
- {
- Dwarf_Sig8_Hash_free (&result->sig8_hash);
- __libdw_seterrno (DWARF_E_COMPRESSED_ERROR);
- free (result);
- return NULL;
- }
+ /* It would be nice if we could fail with a specific error.
+ But we don't know if this was an essential section or not.
+ So just continue for now. See also valid_p(). */
return result;
}
}
@@ -170,6 +179,26 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
}
+/* Helper function to set debugdir field. We want to cache the dir
+ where we found this Dwarf ELF file to locate alt and dwo files. */
+char *
+__libdw_debugdir (int fd)
+{
+ /* strlen ("/proc/self/fd/") = 14 + strlen (<MAXINT>) = 10 + 1 = 25. */
+ char devfdpath[25];
+ sprintf (devfdpath, "/proc/self/fd/%u", fd);
+ char *fdpath = realpath (devfdpath, NULL);
+ char *fddir;
+ if (fdpath != NULL && fdpath[0] == '/'
+ && (fddir = strrchr (fdpath, '/')) != NULL)
+ {
+ *++fddir = '\0';
+ return fdpath;
+ }
+ return NULL;
+}
+
+
/* Check whether all the necessary DWARF information is available. */
static Dwarf *
valid_p (Dwarf *result)
@@ -177,11 +206,11 @@ valid_p (Dwarf *result)
/* We looked at all the sections. Now determine whether all the
sections with debugging information we need are there.
- XXX Which sections are absolutely necessary? Add tests if
- necessary. For now we require only .debug_info. Hopefully this
- is correct. */
+ Require at least one section that can be read "standalone". */
if (likely (result != NULL)
- && unlikely (result->sectiondata[IDX_debug_info] == NULL))
+ && unlikely (result->sectiondata[IDX_debug_info] == NULL
+ && result->sectiondata[IDX_debug_line] == NULL
+ && result->sectiondata[IDX_debug_frame] == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
__libdw_seterrno (DWARF_E_NO_DWARF);
@@ -189,6 +218,9 @@ valid_p (Dwarf *result)
result = NULL;
}
+ /* For dwarf_location_attr () we need a "fake" CU to indicate
+ where the "fake" attribute data comes from. This is a block
+ inside the .debug_loc or .debug_loclists section. */
if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
{
result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
@@ -201,6 +233,7 @@ valid_p (Dwarf *result)
}
else
{
+ result->fake_loc_cu->sec_idx = IDX_debug_loc;
result->fake_loc_cu->dbg = result;
result->fake_loc_cu->startp
= result->sectiondata[IDX_debug_loc]->d_buf;
@@ -210,6 +243,60 @@ valid_p (Dwarf *result)
}
}
+ if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL)
+ {
+ result->fake_loclists_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ if (unlikely (result->fake_loclists_cu == NULL))
+ {
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_NOMEM);
+ free (result->fake_loc_cu);
+ free (result);
+ result = NULL;
+ }
+ else
+ {
+ result->fake_loclists_cu->sec_idx = IDX_debug_loclists;
+ result->fake_loclists_cu->dbg = result;
+ result->fake_loclists_cu->startp
+ = result->sectiondata[IDX_debug_loclists]->d_buf;
+ result->fake_loclists_cu->endp
+ = (result->sectiondata[IDX_debug_loclists]->d_buf
+ + result->sectiondata[IDX_debug_loclists]->d_size);
+ }
+ }
+
+ /* For DW_OP_constx/GNU_const_index and DW_OP_addrx/GNU_addr_index
+ the dwarf_location_attr () will need a "fake" address CU to
+ indicate where the attribute data comes from. This is a just
+ inside the .debug_addr section, if it exists. */
+ if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL)
+ {
+ result->fake_addr_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ if (unlikely (result->fake_addr_cu == NULL))
+ {
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_NOMEM);
+ free (result->fake_loc_cu);
+ free (result->fake_loclists_cu);
+ free (result);
+ result = NULL;
+ }
+ else
+ {
+ result->fake_addr_cu->sec_idx = IDX_debug_addr;
+ result->fake_addr_cu->dbg = result;
+ result->fake_addr_cu->startp
+ = result->sectiondata[IDX_debug_addr]->d_buf;
+ result->fake_addr_cu->endp
+ = (result->sectiondata[IDX_debug_addr]->d_buf
+ + result->sectiondata[IDX_debug_addr]->d_size);
+ }
+ }
+
+ if (result != NULL)
+ result->debugdir = __libdw_debugdir (result->elf->fildes);
+
return result;
}
@@ -325,6 +412,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
result->other_byte_order = true;
result->elf = elf;
+ result->alt_fd = -1;
/* Initialize the memory handling. */
result->mem_default_size = mem_default_size;
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index cc95fb3f..9446b880 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -1,5 +1,5 @@
/* Return child of current DIE.
- Copyright (C) 2003-2011, 2014 Red Hat, Inc.
+ Copyright (C) 2003-2011, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -43,36 +43,27 @@ internal_function
__libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
unsigned int *codep, unsigned int *formp)
{
- Dwarf *dbg = die->cu->dbg;
const unsigned char *readp;
/* Find the abbreviation entry. */
Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp);
if (unlikely (abbrevp == DWARF_END_ABBREV))
{
- invalid_dwarf:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
}
- /* Search the name attribute. */
- unsigned char *const endp
- = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf
- + dbg->sectiondata[IDX_debug_abbrev]->d_size);
-
+ /* Search the name attribute. Attribute has been checked when
+ Dwarf_Abbrev was created, we can read unchecked. */
const unsigned char *attrp = abbrevp->attrp;
while (1)
{
/* Get attribute name and form. */
- if (unlikely (attrp >= endp))
- goto invalid_dwarf;
unsigned int attr_name;
- get_uleb128 (attr_name, attrp, endp);
+ get_uleb128_unchecked (attr_name, attrp);
- if (unlikely (attrp >= endp))
- goto invalid_dwarf;
unsigned int attr_form;
- get_uleb128 (attr_form, attrp, endp);
+ get_uleb128_unchecked (attr_form, attrp);
/* We can stop if we found the attribute with value zero. */
if (attr_name == 0 && attr_form == 0)
@@ -86,7 +77,12 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
if (formp != NULL)
*formp = attr_form;
- return (unsigned char *) readp;
+ /* Normally the attribute data comes from the DIE/info,
+ except for implicit_form, where it comes from the abbrev. */
+ if (attr_form == DW_FORM_implicit_const)
+ return (unsigned char *) attrp;
+ else
+ return (unsigned char *) readp;
}
/* Skip over the rest of this attribute (if there is any). */
@@ -101,6 +97,13 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
// __libdw_form_val_len will have done a bounds check.
readp += len;
+
+ // If the value is in the abbrev data, skip it.
+ if (attr_form == DW_FORM_implicit_const)
+ {
+ int64_t attr_value __attribute__((__unused__));
+ get_sleb128_unchecked (attr_value, attrp);
+ }
}
}
diff --git a/libdw/dwarf_cu_die.c b/libdw/dwarf_cu_die.c
index 194da58b..7594e7dc 100644
--- a/libdw/dwarf_cu_die.c
+++ b/libdw/dwarf_cu_die.c
@@ -37,8 +37,8 @@
Dwarf_Die *
dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half *versionp,
Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
- uint8_t *offset_sizep, uint64_t *type_signaturep,
- Dwarf_Off *type_offsetp)
+ uint8_t *offset_sizep, uint64_t *unit_idp,
+ Dwarf_Off *subdie_offsetp)
{
if (cu == NULL)
return NULL;
@@ -53,10 +53,10 @@ dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half *versionp,
*address_sizep = cu->address_size;
if (offset_sizep != NULL)
*offset_sizep = cu->offset_size;
- if (type_signaturep != NULL)
- *type_signaturep = cu->type_sig8;
- if (type_offsetp != NULL)
- *type_offsetp = cu->type_offset;
+ if (unit_idp != NULL)
+ *unit_idp = cu->unit_id8;
+ if (subdie_offsetp != NULL)
+ *subdie_offsetp = cu->subdie_offset;
return result;
}
diff --git a/libdw/dwarf_cu_info.c b/libdw/dwarf_cu_info.c
new file mode 100644
index 00000000..30aee6c7
--- /dev/null
+++ b/libdw/dwarf_cu_info.c
@@ -0,0 +1,103 @@
+/* Provides information and DIEs associated with the Dwarf_CU unit.
+ Copyright (C) 2018 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "libdwP.h"
+
+
+int
+dwarf_cu_info (Dwarf_CU *cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie,
+ uint64_t *unit_id,
+ uint8_t *address_size, uint8_t *offset_size)
+{
+ if (cu == NULL)
+ return -1;
+
+ if (version != NULL)
+ *version = cu->version;
+
+ if (unit_type != NULL)
+ *unit_type = cu->unit_type;
+
+ if (cudie != NULL)
+ {
+ if (cu->version >= 2 && cu->version <= 5
+ && cu->unit_type >= DW_UT_compile
+ && cu->unit_type <= DW_UT_split_type)
+ *cudie = CUDIE (cu);
+ else
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ }
+
+ if (subdie != NULL)
+ {
+ if (cu->version >= 2 && cu->version <= 5)
+ {
+ /* For types, return the actual type DIE. For skeletons,
+ find the associated split compile unit and return its
+ DIE. */
+ if (cu->unit_type == DW_UT_type
+ || cu->unit_type == DW_UT_split_type)
+ *subdie = SUBDIE(cu);
+ else if (cu->unit_type == DW_UT_skeleton)
+ {
+ Dwarf_CU *split_cu = __libdw_find_split_unit (cu);
+ if (split_cu != NULL)
+ *subdie = CUDIE(split_cu);
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+ else
+ goto invalid;
+ }
+
+ if (unit_id != NULL)
+ *unit_id = cu->unit_id8;
+
+ if (address_size != NULL)
+ *address_size = cu->address_size;
+
+ if (offset_size != NULL)
+ *offset_size = cu->offset_size;
+
+ return 0;
+}
diff --git a/libdw/dwarf_cuoffset.c b/libdw/dwarf_cuoffset.c
index ba376486..f13b02fd 100644
--- a/libdw/dwarf_cuoffset.c
+++ b/libdw/dwarf_cuoffset.c
@@ -38,7 +38,7 @@
Dwarf_Off
dwarf_cuoffset (Dwarf_Die *die)
{
- return (die == NULL
+ return ((die == NULL || die->cu == NULL)
? (Dwarf_Off) -1l
: (Dwarf_Off) (die->addr - die->cu->startp));
}
diff --git a/libdw/dwarf_die_addr_die.c b/libdw/dwarf_die_addr_die.c
new file mode 100644
index 00000000..65729166
--- /dev/null
+++ b/libdw/dwarf_die_addr_die.c
@@ -0,0 +1,70 @@
+/* Return offset of DIE.
+ Copyright (C) 2018 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+Dwarf_Die *
+dwarf_die_addr_die (Dwarf *dbg, void *addr, Dwarf_Die *result)
+{
+ if (dbg == NULL)
+ return NULL;
+
+ Dwarf_CU *cu = __libdw_findcu_addr (dbg, addr);
+
+ if (cu == NULL)
+ {
+ Dwarf *alt = INTUSE (dwarf_getalt) (dbg);
+ if (alt != NULL)
+ cu = __libdw_findcu_addr (alt, addr);
+ }
+
+ if (cu == NULL)
+ {
+ Dwarf *split = __libdw_find_split_dbg_addr (dbg, addr);
+ if (split != NULL)
+ cu = __libdw_findcu_addr (split, addr);
+ }
+
+ if (cu == NULL)
+ {
+ memset (result, '\0', sizeof (Dwarf_Die));
+ return NULL;
+ }
+
+ *result = (Dwarf_Die) { .addr = addr, .cu = cu };
+
+ return result;
+}
diff --git a/libdw/dwarf_dieoffset.c b/libdw/dwarf_dieoffset.c
index 8028f6dd..3a8e2cb6 100644
--- a/libdw/dwarf_dieoffset.c
+++ b/libdw/dwarf_dieoffset.c
@@ -38,8 +38,8 @@
Dwarf_Off
dwarf_dieoffset (Dwarf_Die *die)
{
- return (die == NULL
- ? ~0ul
+ return ((die == NULL || die->cu == NULL)
+ ? (Dwarf_Off) -1
: (Dwarf_Off) (die->addr - die->cu->startp + die->cu->start));
}
INTDEF(dwarf_dieoffset)
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 6c6d985a..29795c10 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -1,5 +1,5 @@
/* Release debugging handling context.
- Copyright (C) 2002-2011, 2014 Red Hat, Inc.
+ Copyright (C) 2002-2011, 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2002.
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
+#include <unistd.h>
#include "libdwP.h"
#include "cfi.h"
@@ -54,6 +55,16 @@ cu_free (void *arg)
Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
tdestroy (p->locs, noop_free);
+
+ /* Free split dwarf one way (from skeleton to split). */
+ if (p->unit_type == DW_UT_skeleton
+ && p->split != NULL && p->split != (void *)-1)
+ {
+ /* The fake_addr_cu might be shared, only release one. */
+ if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
+ p->split->dbg->fake_addr_cu = NULL;
+ INTUSE(dwarf_end) (p->split->dbg);
+ }
}
@@ -80,6 +91,9 @@ dwarf_end (Dwarf *dwarf)
/* Search tree for decoded .debug_lines units. */
tdestroy (dwarf->files_lines, noop_free);
+ /* And the split Dwarf. */
+ tdestroy (dwarf->split_tree, noop_free);
+
struct libdw_memblock *memp = dwarf->mem_tail;
/* The first block is allocated together with the Dwarf object. */
while (memp->prev != NULL)
@@ -102,6 +116,26 @@ dwarf_end (Dwarf *dwarf)
cu_free (dwarf->fake_loc_cu);
free (dwarf->fake_loc_cu);
}
+ if (dwarf->fake_loclists_cu != NULL)
+ {
+ cu_free (dwarf->fake_loclists_cu);
+ free (dwarf->fake_loclists_cu);
+ }
+ if (dwarf->fake_addr_cu != NULL)
+ {
+ cu_free (dwarf->fake_addr_cu);
+ free (dwarf->fake_addr_cu);
+ }
+
+ /* Did we find and allocate the alt Dwarf ourselves? */
+ if (dwarf->alt_fd != -1)
+ {
+ INTUSE(dwarf_end) (dwarf->alt_dwarf);
+ close (dwarf->alt_fd);
+ }
+
+ /* The cached dir we found the Dwarf ELF file in. */
+ free (dwarf->debugdir);
/* Free the context descriptor. */
free (dwarf);
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
index 939ec047..46ea16b3 100644
--- a/libdw/dwarf_error.c
+++ b/libdw/dwarf_error.c
@@ -1,7 +1,6 @@
/* Retrieve ELF descriptor used for DWARF access.
- Copyright (C) 2002, 2003, 2004, 2005, 2009, 2014, 2015 Red Hat, Inc.
+ Copyright (C) 2002-2005, 2009, 2014, 2015, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2002.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -73,6 +72,9 @@ static const char *errmsgs[] =
[DWARF_E_NO_ENTRY] = N_("no entries found"),
[DWARF_E_INVALID_DWARF] = N_("invalid DWARF"),
[DWARF_E_NO_STRING] = N_("no string data"),
+ [DWARF_E_NO_DEBUG_STR] = N_(".debug_str section missing"),
+ [DWARF_E_NO_DEBUG_LINE_STR] = N_(".debug_line_str section missing"),
+ [DWARF_E_NO_STR_OFFSETS] = N_(".debug_str_offsets section missing"),
[DWARF_E_NO_ADDR] = N_("no address value"),
[DWARF_E_NO_CONSTANT] = N_("no constant value"),
[DWARF_E_NO_REFERENCE] = N_("no reference value"),
@@ -83,7 +85,9 @@ static const char *errmsgs[] =
[DWARF_E_VERSION] = N_("invalid DWARF version"),
[DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"),
[DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"),
- [DWARF_E_NO_LOCLIST] = N_("no location list value"),
+ [DWARF_E_NO_DEBUG_LOC] = N_(".debug_loc section missing"),
+ [DWARF_E_NO_DEBUG_LOCLISTS] = N_(".debug_loclists section missing"),
+ [DWARF_E_NO_LOC_VALUE] = N_("not a location list value"),
[DWARF_E_NO_BLOCK] = N_("no block data"),
[DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"),
[DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"),
@@ -91,11 +95,13 @@ static const char *errmsgs[] =
[DWARF_E_NO_FLAG] = N_("no flag value"),
[DWARF_E_INVALID_OFFSET] = N_("invalid offset"),
[DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"),
+ [DWARF_E_NO_DEBUG_RNGLISTS] = N_(".debug_rnglists section missing"),
[DWARF_E_INVALID_CFI] = N_("invalid CFI section"),
[DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"),
[DWARF_E_INVALID_OPCODE] = N_("invalid opcode"),
[DWARF_E_NOT_CUDIE] = N_("not a CU (unit) DIE"),
- [DWARF_E_UNKNOWN_LANGUAGE] = N_("unknown language code")
+ [DWARF_E_UNKNOWN_LANGUAGE] = N_("unknown language code"),
+ [DWARF_E_NO_DEBUG_ADDR] = N_(".debug_addr section missing"),
};
#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c
index ddc48382..9cd3d200 100644
--- a/libdw/dwarf_formaddr.c
+++ b/libdw/dwarf_formaddr.c
@@ -1,7 +1,6 @@
/* Return address represented by attribute.
- Copyright (C) 2003-2010 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -36,20 +35,112 @@
int
+__libdw_addrx (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr)
+{
+ Dwarf_Off addr_off = __libdw_cu_addr_base (cu);
+ if (addr_off == (Dwarf_Off) -1)
+ return -1;
+
+ Dwarf *dbg = cu->dbg;
+ if (dbg->sectiondata[IDX_debug_addr] == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DEBUG_ADDR);
+ return -1;
+ }
+
+ /* The section should at least contain room for one address. */
+ int address_size = cu->address_size;
+ if (cu->address_size > dbg->sectiondata[IDX_debug_addr]->d_size)
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ if (addr_off > (dbg->sectiondata[IDX_debug_addr]->d_size
+ - address_size))
+ goto invalid_offset;
+
+ idx *= address_size;
+ if (idx > (dbg->sectiondata[IDX_debug_addr]->d_size
+ - address_size - addr_off))
+ goto invalid_offset;
+
+ const unsigned char *datap;
+ datap = dbg->sectiondata[IDX_debug_addr]->d_buf + addr_off + idx;
+ if (address_size == 4)
+ *addr = read_4ubyte_unaligned (dbg, datap);
+ else
+ *addr = read_8ubyte_unaligned (dbg, datap);
+
+ return 0;
+}
+
+int
dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
{
if (attr == NULL)
return -1;
- if (unlikely (attr->form != DW_FORM_addr))
+ Dwarf_Word idx;
+ Dwarf_CU *cu = attr->cu;
+ Dwarf *dbg = cu->dbg;
+ const unsigned char *datap = attr->valp;
+ const unsigned char *endp = attr->cu->endp;
+ switch (attr->form)
{
- __libdw_seterrno (DWARF_E_NO_ADDR);
- return -1;
+ /* There is one form that just encodes the whole address. */
+ case DW_FORM_addr:
+ if (__libdw_read_address (dbg, cu_sec_idx (cu), datap,
+ cu->address_size, return_addr))
+ return -1;
+ return 0;
+
+ /* All others encode an index into the .debug_addr section where
+ the address can be found. */
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_addrx:
+ if (datap >= endp)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ get_uleb128 (idx, datap, endp);
+ break;
+
+ case DW_FORM_addrx1:
+ if (datap >= endp - 1)
+ goto invalid;
+ idx = *datap;
+ break;
+
+ case DW_FORM_addrx2:
+ if (datap >= endp - 2)
+ goto invalid;
+ idx = read_2ubyte_unaligned (dbg, datap);
+ break;
+
+ case DW_FORM_addrx3:
+ if (datap >= endp - 3)
+ goto invalid;
+ idx = read_3ubyte_unaligned (dbg, datap);
+ break;
+
+ case DW_FORM_addrx4:
+ if (datap >= endp - 4)
+ goto invalid;
+ idx = read_4ubyte_unaligned (dbg, datap);
+ break;
+
+ default:
+ __libdw_seterrno (DWARF_E_NO_ADDR);
+ return -1;
}
- if (__libdw_read_address (attr->cu->dbg,
- cu_sec_idx (attr->cu), attr->valp,
- attr->cu->address_size, return_addr))
+ /* So we got an index. Lets see if it is valid and we can get the actual
+ address. */
+ if (__libdw_addrx (cu, idx, return_addr) != 0)
return -1;
return 0;
diff --git a/libdw/dwarf_formblock.c b/libdw/dwarf_formblock.c
index 13f9e72a..924baf45 100644
--- a/libdw/dwarf_formblock.c
+++ b/libdw/dwarf_formblock.c
@@ -1,5 +1,5 @@
/* Return block represented by attribute.
- Copyright (C) 2004-2010, 2014 Red Hat, Inc.
+ Copyright (C) 2004-2010, 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2004.
@@ -75,6 +75,16 @@ dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block)
return_block->data = (unsigned char *) datap;
break;
+ case DW_FORM_data16:
+ /* The DWARFv5 spec calls this constant class, but we interpret
+ it as a block that the user will need to interpret when
+ converting to a value. */
+ if (unlikely (endp - datap < 16))
+ goto invalid;
+ return_block->length = 16;
+ return_block->data = (unsigned char *) datap;
+ break;
+
default:
__libdw_seterrno (DWARF_E_NO_BLOCK);
return -1;
diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c
index 2240a258..2bae2a44 100644
--- a/libdw/dwarf_formref.c
+++ b/libdw/dwarf_formref.c
@@ -86,6 +86,8 @@ __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
case DW_FORM_ref_addr:
case DW_FORM_ref_sig8:
case DW_FORM_GNU_ref_alt:
+ case DW_FORM_ref_sup4:
+ case DW_FORM_ref_sup8:
/* These aren't handled by dwarf_formref, only by dwarf_formref_die. */
__libdw_seterrno (DWARF_E_INVALID_REFERENCE);
return -1;
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 7e2b11a2..f196331a 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -1,5 +1,5 @@
/* Look up the DIE in a reference-form attribute.
- Copyright (C) 2005-2010 Red Hat, Inc.
+ Copyright (C) 2005-2010, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -44,16 +44,23 @@ dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result)
struct Dwarf_CU *cu = attr->cu;
Dwarf_Off offset;
- if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt)
+ if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt
+ || attr->form == DW_FORM_ref_sup4 || attr->form == DW_FORM_ref_sup8)
{
/* This has an absolute offset. */
- uint8_t ref_size = (cu->version == 2 && attr->form == DW_FORM_ref_addr
- ? cu->address_size
- : cu->offset_size);
+ uint8_t ref_size;
+ if (cu->version == 2 && attr->form == DW_FORM_ref_addr)
+ ref_size = cu->address_size;
+ else if (attr->form == DW_FORM_ref_sup4)
+ ref_size = 4;
+ else if (attr->form == DW_FORM_ref_sup8)
+ ref_size = 8;
+ else
+ ref_size = cu->offset_size;
Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt
- ? cu->dbg->alt_dwarf : cu->dbg);
+ ? INTUSE(dwarf_getalt) (cu->dbg) : cu->dbg);
if (dbg_ret == NULL)
{
@@ -73,27 +80,38 @@ dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result)
if (attr->form == DW_FORM_ref_sig8)
{
/* This doesn't have an offset, but instead a value we
- have to match in the .debug_types type unit headers. */
+ have to match in the type unit headers. */
uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp);
cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig, NULL);
if (cu == NULL)
- /* Not seen before. We have to scan through the type units. */
- do
- {
- cu = __libdw_intern_next_unit (attr->cu->dbg, true);
- if (cu == NULL)
- {
- __libdw_seterrno (INTUSE(dwarf_errno) ()
- ?: DWARF_E_INVALID_REFERENCE);
- return NULL;
- }
- }
- while (cu->type_sig8 != sig);
-
- datap = cu->dbg->sectiondata[IDX_debug_types]->d_buf;
- size = cu->dbg->sectiondata[IDX_debug_types]->d_size;
- offset = cu->start + cu->type_offset;
+ {
+ /* Not seen before. We have to scan through the type units.
+ Since DWARFv5 these can (also) be found in .debug_info,
+ so scan that first. */
+ bool scan_debug_types = false;
+ do
+ {
+ cu = __libdw_intern_next_unit (attr->cu->dbg, scan_debug_types);
+ if (cu == NULL)
+ {
+ if (scan_debug_types == false)
+ scan_debug_types = true;
+ else
+ {
+ __libdw_seterrno (INTUSE(dwarf_errno) ()
+ ?: DWARF_E_INVALID_REFERENCE);
+ return NULL;
+ }
+ }
+ }
+ while (cu == NULL || cu->unit_id8 != sig);
+ }
+
+ int secid = cu_sec_idx (cu);
+ datap = cu->dbg->sectiondata[secid]->d_buf;
+ size = cu->dbg->sectiondata[secid]->d_size;
+ offset = cu->start + cu->subdie_offset;
}
else
{
diff --git a/libdw/dwarf_formsdata.c b/libdw/dwarf_formsdata.c
index e7deaee1..def32c9d 100644
--- a/libdw/dwarf_formsdata.c
+++ b/libdw/dwarf_formsdata.c
@@ -1,5 +1,5 @@
/* Return signed constant represented by attribute.
- Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -53,25 +53,25 @@ dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_sval)
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
- *return_sval = *attr->valp;
+ *return_sval = (signed char) *attr->valp;
break;
case DW_FORM_data2:
if (datap + 2 > endp)
goto invalid;
- *return_sval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
+ *return_sval = read_2sbyte_unaligned (attr->cu->dbg, attr->valp);
break;
case DW_FORM_data4:
if (datap + 4 > endp)
goto invalid;
- *return_sval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ *return_sval = read_4sbyte_unaligned (attr->cu->dbg, attr->valp);
break;
case DW_FORM_data8:
if (datap + 8 > endp)
goto invalid;
- *return_sval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+ *return_sval = read_8sbyte_unaligned (attr->cu->dbg, attr->valp);
break;
case DW_FORM_sdata:
@@ -86,6 +86,11 @@ dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_sval)
get_uleb128 (*return_sval, datap, endp);
break;
+ case DW_FORM_implicit_const:
+ // The data comes from the abbrev, which has been bounds checked.
+ get_sleb128_unchecked (*return_sval, datap);
+ break;
+
default:
__libdw_seterrno (DWARF_E_NO_CONSTANT);
return -1;
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index 83abd53d..c3e892a8 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -1,7 +1,6 @@
/* Return string associated with given attribute.
- Copyright (C) 2003-2010, 2013 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2013, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -47,8 +46,11 @@ dwarf_formstring (Dwarf_Attribute *attrp)
/* A simple inlined string. */
return (const char *) attrp->valp;
- Dwarf *dbg = attrp->cu->dbg;
- Dwarf *dbg_ret = attrp->form == DW_FORM_GNU_strp_alt ? dbg->alt_dwarf : dbg;
+ Dwarf_CU *cu = attrp->cu;
+ Dwarf *dbg = cu->dbg;
+ Dwarf *dbg_ret = ((attrp->form == DW_FORM_GNU_strp_alt
+ || attrp->form == DW_FORM_strp_sup)
+ ? INTUSE(dwarf_getalt) (dbg) : dbg);
if (unlikely (dbg_ret == NULL))
{
@@ -56,20 +58,123 @@ dwarf_formstring (Dwarf_Attribute *attrp)
return NULL;
}
-
- if (unlikely (attrp->form != DW_FORM_strp
- && attrp->form != DW_FORM_GNU_strp_alt)
- || dbg_ret->sectiondata[IDX_debug_str] == NULL)
+ Elf_Data *data = ((attrp->form == DW_FORM_line_strp)
+ ? dbg_ret->sectiondata[IDX_debug_line_str]
+ : dbg_ret->sectiondata[IDX_debug_str]);
+ if (data == NULL)
{
- __libdw_seterrno (DWARF_E_NO_STRING);
+ __libdw_seterrno ((attrp->form == DW_FORM_line_strp)
+ ? DWARF_E_NO_DEBUG_LINE_STR
+ : DWARF_E_NO_DEBUG_STR);
return NULL;
}
uint64_t off;
- if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp,
- attrp->cu->offset_size, &off, IDX_debug_str, 1))
- return NULL;
+ if (attrp->form == DW_FORM_strp
+ || attrp->form == DW_FORM_GNU_strp_alt
+ || attrp->form == DW_FORM_strp_sup)
+ {
+ if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (cu),
+ attrp->valp, cu->offset_size, &off,
+ IDX_debug_str, 1))
+ return NULL;
+ }
+ else if (attrp->form == DW_FORM_line_strp)
+ {
+ if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (cu),
+ attrp->valp, cu->offset_size, &off,
+ IDX_debug_line_str, 1))
+ return NULL;
+ }
+ else
+ {
+ Dwarf_Word idx;
+ const unsigned char *datap = attrp->valp;
+ const unsigned char *endp = cu->endp;
+ switch (attrp->form)
+ {
+ case DW_FORM_strx:
+ case DW_FORM_GNU_str_index:
+ if (datap >= endp)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+ get_uleb128 (idx, datap, endp);
+ break;
+
+ case DW_FORM_strx1:
+ if (datap >= endp - 1)
+ goto invalid;
+ idx = *datap;
+ break;
+
+ case DW_FORM_strx2:
+ if (datap >= endp - 2)
+ goto invalid;
+ idx = read_2ubyte_unaligned (dbg, datap);
+ break;
+
+ case DW_FORM_strx3:
+ if (datap >= endp - 3)
+ goto invalid;
+ idx = read_3ubyte_unaligned (dbg, datap);
+ break;
+
+ case DW_FORM_strx4:
+ if (datap >= endp - 4)
+ goto invalid;
+ idx = read_4ubyte_unaligned (dbg, datap);
+ break;
+
+ default:
+ __libdw_seterrno (DWARF_E_NO_STRING);
+ return NULL;
+ }
+
+ /* So we got an index in the .debug_str_offsets. Lets see if it
+ is valid and we can get the actual .debug_str offset. */
+ Dwarf_Off str_off = __libdw_cu_str_off_base (cu);
+ if (str_off == (Dwarf_Off) -1)
+ return NULL;
+
+ if (dbg->sectiondata[IDX_debug_str_offsets] == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_STR_OFFSETS);
+ return NULL;
+ }
+
+ /* The section should at least contain room for one offset. */
+ int offset_size = cu->offset_size;
+ if (cu->offset_size > dbg->sectiondata[IDX_debug_str_offsets]->d_size)
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return NULL;
+ }
+
+ /* And the base offset should be at least inside the section. */
+ if (str_off > (dbg->sectiondata[IDX_debug_str_offsets]->d_size
+ - offset_size))
+ goto invalid_offset;
+
+ size_t max_idx = (dbg->sectiondata[IDX_debug_str_offsets]->d_size
+ - offset_size - str_off) / offset_size;
+ if (idx > max_idx)
+ goto invalid_offset;
+
+ datap = (dbg->sectiondata[IDX_debug_str_offsets]->d_buf
+ + str_off + (idx * offset_size));
+ if (offset_size == 4)
+ off = read_4ubyte_unaligned (dbg, datap);
+ else
+ off = read_8ubyte_unaligned (dbg, datap);
+
+ if (off > dbg->sectiondata[IDX_debug_str]->d_size)
+ goto invalid_offset;
+ }
- return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off;
+ return (const char *) data->d_buf + off;
}
INTDEF(dwarf_formstring)
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index e41981a4..26f86f12 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -1,5 +1,5 @@
/* Return unsigned constant represented by attribute.
- Copyright (C) 2003-2012, 2014 Red Hat, Inc.
+ Copyright (C) 2003-2012, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -34,15 +34,26 @@
#include <dwarf.h>
#include "libdwP.h"
-internal_function unsigned char *
+internal_function const unsigned char *
__libdw_formptr (Dwarf_Attribute *attr, int sec_index,
- int err_nodata, unsigned char **endpp,
+ int err_nodata, const unsigned char **endpp,
Dwarf_Off *offsetp)
{
if (attr == NULL)
return NULL;
const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index];
+ Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission. */
+ if (unlikely (d == NULL
+ && sec_index == IDX_debug_ranges
+ && attr->cu->version < 5
+ && attr->cu->unit_type == DW_UT_split_compile))
+ {
+ skel = __libdw_find_split_unit (attr->cu);
+ if (skel != NULL)
+ d = skel->dbg->sectiondata[IDX_debug_ranges];
+ }
+
if (unlikely (d == NULL))
{
__libdw_seterrno (err_nodata);
@@ -52,10 +63,41 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
Dwarf_Word offset;
if (attr->form == DW_FORM_sec_offset)
{
- if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
- cu_sec_idx (attr->cu), attr->valp,
- attr->cu->offset_size, &offset, sec_index, 0))
- return NULL;
+ /* GNU DebugFission is slightly odd. It uses DW_FORM_sec_offset
+ in split units, but they are really (unrelocated) offsets
+ from the skeleton DW_AT_GNU_ranges_base (which is only used
+ for the split unit, not the skeleton ranges itself, see also
+ DW_AT_rnglists_base, which is used in DWARF5 for both, but
+ points to the offsets index). So it isn't really a formptr,
+ but an offset + base calculation. */
+ if (unlikely (skel != NULL))
+ {
+ Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)];
+ const unsigned char *datap = attr->valp;
+ size_t size = attr->cu->offset_size;
+ if (unlikely (data == NULL
+ || datap < (const unsigned char *) data->d_buf
+ || data->d_size < size
+ || ((size_t) (datap
+ - (const unsigned char *) data->d_buf)
+ > data->d_size - size)))
+ goto invalid;
+
+ if (size == 4)
+ offset = read_4ubyte_unaligned (attr->cu->dbg, datap);
+ else
+ offset = read_8ubyte_unaligned (attr->cu->dbg, datap);
+
+ offset += __libdw_cu_ranges_base (skel);
+ }
+ else
+ {
+ if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
+ cu_sec_idx (attr->cu), attr->valp,
+ attr->cu->offset_size, &offset,
+ sec_index, 0))
+ return NULL;
+ }
}
else if (attr->cu->version > 3)
goto invalid;
@@ -141,11 +183,24 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
case DW_AT_string_length:
case DW_AT_use_location:
case DW_AT_vtable_elem_location:
- /* loclistptr */
- if (__libdw_formptr (attr, IDX_debug_loc,
- DWARF_E_NO_LOCLIST, NULL,
- return_uval) == NULL)
- return -1;
+ case DW_AT_GNU_locviews:
+ case DW_AT_loclists_base:
+ if (attr->cu->version < 5)
+ {
+ /* loclistptr */
+ if (__libdw_formptr (attr, IDX_debug_loc,
+ DWARF_E_NO_DEBUG_LOC, NULL,
+ return_uval) == NULL)
+ return -1;
+ }
+ else
+ {
+ /* loclist, loclistsptr */
+ if (__libdw_formptr (attr, IDX_debug_loclists,
+ DWARF_E_NO_DEBUG_LOCLISTS, NULL,
+ return_uval) == NULL)
+ return -1;
+ }
break;
case DW_AT_macro_info:
@@ -157,6 +212,7 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
break;
case DW_AT_GNU_macros:
+ case DW_AT_macros:
/* macptr into .debug_macro */
if (__libdw_formptr (attr, IDX_debug_macro,
DWARF_E_NO_ENTRY, NULL,
@@ -166,11 +222,24 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
case DW_AT_ranges:
case DW_AT_start_scope:
- /* rangelistptr */
- if (__libdw_formptr (attr, IDX_debug_ranges,
- DWARF_E_NO_DEBUG_RANGES, NULL,
- return_uval) == NULL)
- return -1;
+ case DW_AT_GNU_ranges_base:
+ case DW_AT_rnglists_base:
+ if (attr->cu->version < 5)
+ {
+ /* rangelistptr */
+ if (__libdw_formptr (attr, IDX_debug_ranges,
+ DWARF_E_NO_DEBUG_RANGES, NULL,
+ return_uval) == NULL)
+ return -1;
+ }
+ else
+ {
+ /* rnglistsptr */
+ if (__libdw_formptr (attr, IDX_debug_rnglists,
+ DWARF_E_NO_DEBUG_RNGLISTS, NULL,
+ return_uval) == NULL)
+ return -1;
+ }
break;
case DW_AT_stmt_list:
@@ -181,6 +250,23 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
return -1;
break;
+ case DW_AT_addr_base:
+ case DW_AT_GNU_addr_base:
+ /* addrptr */
+ if (__libdw_formptr (attr, IDX_debug_addr,
+ DWARF_E_NO_DEBUG_ADDR, NULL,
+ return_uval) == NULL)
+ return -1;
+ break;
+
+ case DW_AT_str_offsets_base:
+ /* stroffsetsptr */
+ if (__libdw_formptr (attr, IDX_debug_str_offsets,
+ DWARF_E_NO_STR_OFFSETS, NULL,
+ return_uval) == NULL)
+ return -1;
+ break;
+
default:
/* sec_offset can only be used by one of the above attrs. */
if (attr->form == DW_FORM_sec_offset)
@@ -216,11 +302,51 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
break;
case DW_FORM_udata:
+ case DW_FORM_rnglistx:
+ case DW_FORM_loclistx:
if (datap + 1 > endp)
goto invalid;
get_uleb128 (*return_uval, datap, endp);
break;
+ case DW_FORM_implicit_const:
+ // The data comes from the abbrev, which has been bounds checked.
+ get_sleb128_unchecked (*return_uval, datap);
+ break;
+
+ /* These are indexes into the .debug_addr section, normally resolved
+ with dwarf_formaddr. Here treat as constants. */
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_addrx:
+ if (datap >= endp)
+ goto invalid;
+ get_uleb128 (*return_uval, datap, endp);
+ break;
+
+ case DW_FORM_addrx1:
+ if (datap >= endp - 1)
+ goto invalid;
+ *return_uval = *datap;
+ break;
+
+ case DW_FORM_addrx2:
+ if (datap >= endp - 2)
+ goto invalid;
+ *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap);
+ break;
+
+ case DW_FORM_addrx3:
+ if (datap >= endp - 3)
+ goto invalid;
+ *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap);
+ break;
+
+ case DW_FORM_addrx4:
+ if (datap >= endp - 4)
+ goto invalid;
+ *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap);
+ break;
+
default:
__libdw_seterrno (DWARF_E_NO_CONSTANT);
return -1;
diff --git a/libdw/dwarf_frame_register.c b/libdw/dwarf_frame_register.c
index 37e8e917..d0159fb8 100644
--- a/libdw/dwarf_frame_register.c
+++ b/libdw/dwarf_frame_register.c
@@ -62,7 +62,7 @@ dwarf_frame_register (Dwarf_Frame *fs, int regno, Dwarf_Op *ops_mem,
/* Use the default rule for registers not yet mentioned in CFI. */
if (fs->cache->default_same_value)
goto same_value;
- /*FALLTHROUGH*/
+ FALLTHROUGH;
case reg_undefined:
/* The value is known to be unavailable. */
break;
diff --git a/libdw/dwarf_get_units.c b/libdw/dwarf_get_units.c
new file mode 100644
index 00000000..6215bf4b
--- /dev/null
+++ b/libdw/dwarf_get_units.c
@@ -0,0 +1,131 @@
+/* Iterate through the CU units for a given Dwarf.
+ Copyright (C) 2016, 2017 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include "libdwP.h"
+
+int
+dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie)
+{
+ /* Handle existing error. */
+ if (dwarf == NULL)
+ return -1;
+
+ Dwarf_Off off;
+ bool v4type;
+ if (cu == NULL)
+ {
+ off = 0;
+ v4type = false;
+ }
+ else
+ {
+ off = cu->end;
+ v4type = cu->sec_idx != IDX_debug_info;
+
+ /* Make sure we got a real (not fake) CU. */
+ if (cu->sec_idx != IDX_debug_info && cu->sec_idx != IDX_debug_types)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ /* Do we have to switch to the other section, or are we at the end? */
+ if (! v4type)
+ {
+ if (off >= cu->dbg->sectiondata[IDX_debug_info]->d_size)
+ {
+ if (cu->dbg->sectiondata[IDX_debug_types] == NULL)
+ return 1;
+
+ off = 0;
+ v4type = true;
+ }
+ }
+ else
+ if (off >= cu->dbg->sectiondata[IDX_debug_types]->d_size)
+ return 1;
+ }
+
+ *next_cu = __libdw_findcu (dwarf, off, v4type);
+ if (*next_cu == NULL)
+ return -1;
+
+ Dwarf_CU *next = (*next_cu);
+
+ if (version != NULL)
+ *version = next->version;
+
+ if (unit_type != NULL)
+ *unit_type = next->unit_type;
+
+ if (cudie != NULL)
+ {
+ if (next->version >= 2 && next->version <= 5
+ && next->unit_type >= DW_UT_compile
+ && next->unit_type <= DW_UT_split_type)
+ *cudie = CUDIE (next);
+ else
+ memset (cudie, '\0', sizeof (Dwarf_Die));
+ }
+
+ if (subdie != NULL)
+ {
+ if (next->version >= 2 && next->version <= 5)
+ {
+ /* For types, return the actual type DIE. For skeletons,
+ find the associated split compile unit and return its
+ DIE. */
+ if (next->unit_type == DW_UT_type
+ || next->unit_type == DW_UT_split_type)
+ *subdie = SUBDIE(next);
+ else if (next->unit_type == DW_UT_skeleton)
+ {
+ Dwarf_CU *split_cu = __libdw_find_split_unit (next);
+ if (split_cu != NULL)
+ *subdie = CUDIE(split_cu);
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+
+ return 0;
+}
diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
index ef51b847..988d12c2 100644
--- a/libdw/dwarf_getabbrev.c
+++ b/libdw/dwarf_getabbrev.c
@@ -1,5 +1,5 @@
/* Get abbreviation at given offset.
- Copyright (C) 2003, 2004, 2005, 2006, 2014 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -121,8 +121,7 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
abb->attrp = (unsigned char *) abbrevp;
abb->offset = offset;
- /* Skip over all the attributes and count them while doing so. */
- abb->attrcnt = 0;
+ /* Skip over all the attributes and check rest of the abbrev is valid. */
unsigned int attrname;
unsigned int attrform;
do
@@ -133,8 +132,15 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
if (abbrevp >= end)
goto invalid;
get_uleb128 (attrform, abbrevp, end);
+ if (attrform == DW_FORM_implicit_const)
+ {
+ int64_t formval __attribute__((__unused__));
+ if (abbrevp >= end)
+ goto invalid;
+ get_sleb128 (formval, abbrevp, end);
+ }
}
- while (attrname != 0 && attrform != 0 && ++abb->attrcnt);
+ while (attrname != 0 && attrform != 0);
/* Return the length to the caller if she asked for it. */
if (lengthp != NULL)
@@ -152,7 +158,21 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
Dwarf_Abbrev *
dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
{
- return __libdw_getabbrev (die->cu->dbg, die->cu,
- die->cu->orig_abbrev_offset + offset, lengthp,
- NULL);
+ if (die == NULL || die->cu == NULL)
+ return NULL;
+
+ Dwarf_CU *cu = die->cu;
+ Dwarf *dbg = cu->dbg;
+ Dwarf_Off abbrev_offset = cu->orig_abbrev_offset;
+ Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev];
+ if (data == NULL)
+ return NULL;
+
+ if (offset >= data->d_size - abbrev_offset)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return NULL;
+ }
+
+ return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp, NULL);
}
diff --git a/libdw/dwarf_getabbrevattr.c b/libdw/dwarf_getabbrevattr.c
index 3b4da99c..54ff604f 100644
--- a/libdw/dwarf_getabbrevattr.c
+++ b/libdw/dwarf_getabbrevattr.c
@@ -1,5 +1,5 @@
/* Get specific attribute of abbreviation.
- Copyright (C) 2003, 2004, 2005, 2014 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2005, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -37,8 +37,9 @@
int
-dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
- unsigned int *formp, Dwarf_Off *offsetp)
+dwarf_getabbrevattr_data (Dwarf_Abbrev *abbrev, size_t idx,
+ unsigned int *namep, unsigned int *formp,
+ Dwarf_Sword *datap, Dwarf_Off *offsetp)
{
if (abbrev == NULL)
return -1;
@@ -48,15 +49,21 @@ dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
const unsigned char *start_attrp;
unsigned int name;
unsigned int form;
+ Dwarf_Word data;
do
{
start_attrp = attrp;
- /* Attribute code and form are encoded as ULEB128 values.i
- XXX We have no way to bounds check. */
- get_uleb128 (name, attrp, attrp + len_leb128 (name));
- get_uleb128 (form, attrp, attrp + len_leb128 (form));
+ /* Attribute code and form are encoded as ULEB128 values.
+ Already checked when Dwarf_Abbrev was created, read unchecked. */
+ get_uleb128_unchecked (name, attrp);
+ get_uleb128_unchecked (form, attrp);
+
+ if (form == DW_FORM_implicit_const)
+ get_sleb128_unchecked (data, attrp);
+ else
+ data = 0;
/* If both values are zero the index is out of range. */
if (name == 0 && form == 0)
@@ -69,8 +76,19 @@ dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
*namep = name;
if (formp != NULL)
*formp = form;
+ if (datap != NULL)
+ *datap = data;
if (offsetp != NULL)
*offsetp = (start_attrp - abbrev->attrp) + abbrev->offset;
return 0;
}
+INTDEF(dwarf_getabbrevattr_data)
+
+int
+dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, unsigned int *namep,
+ unsigned int *formp, Dwarf_Off *offsetp)
+{
+ return INTUSE(dwarf_getabbrevattr_data) (abbrev, idx, namep, formp,
+ NULL, offsetp);
+}
diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
index cc434f03..0a12dfae 100644
--- a/libdw/dwarf_getalt.c
+++ b/libdw/dwarf_getalt.c
@@ -1,5 +1,5 @@
/* Retrieves the DWARF descriptor for debugaltlink data.
- Copyright (C) 2014 Red Hat, Inc.
+ Copyright (C) 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -31,12 +31,154 @@
#endif
#include "libdwP.h"
+#include "libelfP.h"
+#include "libdwelfP.h"
+#include "system.h"
+
+#include <inttypes.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+char *
+internal_function
+__libdw_filepath (const char *debugdir, const char *dir, const char *file)
+{
+ if (file == NULL)
+ return NULL;
+
+ if (file[0] == '/')
+ return strdup (file);
+
+ if (dir != NULL && dir[0] == '/')
+ {
+ size_t dirlen = strlen (dir);
+ size_t filelen = strlen (file);
+ size_t len = dirlen + 1 + filelen + 1;
+ char *path = malloc (len);
+ if (path != NULL)
+ {
+ char *c = mempcpy (path, dir, dirlen);
+ if (dir[dirlen - 1] != '/')
+ *c++ = '/';
+ mempcpy (c, file, filelen + 1);
+ }
+ return path;
+ }
+
+ if (debugdir != NULL)
+ {
+ size_t debugdirlen = strlen (debugdir);
+ size_t dirlen = dir != NULL ? strlen (dir) : 0;
+ size_t filelen = strlen (file);
+ size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
+ char *path = malloc (len);
+ if (path != NULL)
+ {
+ char *c = mempcpy (path, debugdir, debugdirlen);
+ if (dirlen > 0)
+ {
+ c = mempcpy (c, dir, dirlen);
+ if (dir[dirlen - 1] != '/')
+ *c++ = '/';
+ }
+ mempcpy (c, file, filelen + 1);
+ return path;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+find_debug_altlink (Dwarf *dbg)
+{
+ const char *altname;
+ const void *build_id;
+ ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
+ &altname,
+ &build_id);
+
+ /* Couldn't even get the debugaltlink. It probably doesn't exist. */
+ if (build_id_len <= 0)
+ return;
+
+ const uint8_t *id = (const uint8_t *) build_id;
+ size_t id_len = build_id_len;
+ int fd = -1;
+
+ /* We only look in the standard path. And relative to the dbg file. */
+#define DEBUGINFO_PATH "/usr/lib/debug"
+
+ /* We don't handle very short or really large build-ids. We need at
+ at least 3 and allow for up to 64 (normally ids are 20 long). */
+#define MIN_BUILD_ID_BYTES 3
+#define MAX_BUILD_ID_BYTES 64
+ if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
+ {
+ /* Note sizeof a string literal includes the trailing zero. */
+ char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ + 2 + 1 + (MAX_BUILD_ID_BYTES - 1) * 2 + sizeof ".debug"];
+ sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
+ sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
+ "%02" PRIx8 "/", (uint8_t) id[0]);
+ for (size_t i = 1; i < id_len; ++i)
+ sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
+ strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ + 3 + (id_len - 1) * 2], ".debug");
+
+ fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
+ }
+
+ /* Fall back on (possible relative) alt file path. */
+ if (fd < 0)
+ {
+ char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname);
+ if (altpath != NULL)
+ {
+ fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
+ free (altpath);
+ }
+ }
+
+ if (fd >= 0)
+ {
+ Dwarf *alt = dwarf_begin (fd, O_RDONLY);
+ if (alt != NULL)
+ {
+ dbg->alt_dwarf = alt;
+ dbg->alt_fd = fd;
+ }
+ else
+ close (fd);
+ }
+}
Dwarf *
dwarf_getalt (Dwarf *main)
{
- if (main == NULL)
+ /* Only try once. */
+ if (main == NULL || main->alt_dwarf == (void *) -1)
return NULL;
+
+ if (main->alt_dwarf != NULL)
+ return main->alt_dwarf;
+
+ find_debug_altlink (main);
+
+ /* If we found nothing, make sure we don't try again. */
+ if (main->alt_dwarf == NULL)
+ {
+ main->alt_dwarf = (void *) -1;
+ return NULL;
+ }
+
return main->alt_dwarf;
}
INTDEF (dwarf_getalt)
diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c
index 4252746e..bff9c860 100644
--- a/libdw/dwarf_getaranges.c
+++ b/libdw/dwarf_getaranges.c
@@ -1,5 +1,5 @@
/* Return list address ranges.
- Copyright (C) 2000-2010 Red Hat, Inc.
+ Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2000.
@@ -195,16 +195,15 @@ dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
new_arange->arange.length = range_length;
/* We store the actual CU DIE offset, not the CU header offset. */
- const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
- + offset);
- unsigned int offset_size;
- if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
- offset_size = 8;
- else
- offset_size = 4;
- new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
- offset_size,
- false);
+ Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
+ if (unlikely (cu == NULL))
+ {
+ /* We haven't gotten a chance to link in the new_arange
+ into the arangelist, don't leak it. */
+ free (new_arange);
+ goto fail;
+ }
+ new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
new_arange->next = arangelist;
arangelist = new_arange;
diff --git a/libdw/dwarf_getattrcnt.c b/libdw/dwarf_getattrcnt.c
index 2bfb4ac5..a05976d4 100644
--- a/libdw/dwarf_getattrcnt.c
+++ b/libdw/dwarf_getattrcnt.c
@@ -1,5 +1,5 @@
/* Get number of attributes of abbreviation.
- Copyright (C) 2003, 2004 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -40,7 +40,22 @@ dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp)
if (abbrev == NULL)
return -1;
- *attrcntp = abbrev->attrcnt;
+ const unsigned char *abbrevp = abbrev->attrp;
+
+ /* Skip over all the attributes and count them while doing so. */
+ int attrcnt = 0;
+ unsigned int attrname;
+ unsigned int attrform;
+ do
+ {
+ /* We can use unchecked since they were checked when the Dwrf_Abbrev
+ was created. */
+ get_uleb128_unchecked (attrname, abbrevp);
+ get_uleb128_unchecked (attrform, abbrevp);
+ }
+ while (attrname != 0 && attrform != 0 && ++attrcnt);
+
+ *attrcntp = attrcnt;
return 0;
}
diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c
index 0da8b5ba..50faf988 100644
--- a/libdw/dwarf_getattrs.c
+++ b/libdw/dwarf_getattrs.c
@@ -1,5 +1,5 @@
/* Get attributes of the DIE.
- Copyright (C) 2004, 2005, 2008, 2009, 2014 Red Hat, Inc.
+ Copyright (C) 2004, 2005, 2008, 2009, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2004.
@@ -51,7 +51,6 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
if (unlikely (abbrevp == DWARF_END_ABBREV))
{
- invalid_dwarf:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1l;
}
@@ -61,24 +60,15 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
const unsigned char *const offset_attrp = abbrevp->attrp + offset;
/* Go over the list of attributes. */
- Dwarf *dbg = die->cu->dbg;
- const unsigned char *endp;
- endp = ((const unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf
- + dbg->sectiondata[IDX_debug_abbrev]->d_size);
while (1)
{
- /* Are we still in bounds? */
- if (unlikely (attrp >= endp))
- goto invalid_dwarf;
-
- /* Get attribute name and form. */
+ /* Get attribute name and form. Dwarf_Abbrev was checked when
+ created, so we can read unchecked. */
Dwarf_Attribute attr;
const unsigned char *remembered_attrp = attrp;
- get_uleb128 (attr.code, attrp, endp);
- if (unlikely (attrp >= endp))
- goto invalid_dwarf;
- get_uleb128 (attr.form, attrp, endp);
+ get_uleb128_unchecked (attr.code, attrp);
+ get_uleb128_unchecked (attr.form, attrp);
/* We can stop if we found the attribute with value zero. */
if (attr.code == 0 && attr.form == 0)
@@ -93,7 +83,10 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
if (remembered_attrp >= offset_attrp)
{
/* Fill in the rest. */
- attr.valp = (unsigned char *) die_addr;
+ if (attr.form == DW_FORM_implicit_const)
+ attr.valp = (unsigned char *) attrp;
+ else
+ attr.valp = (unsigned char *) die_addr;
attr.cu = die->cu;
/* Now call the callback function. */
@@ -114,6 +107,12 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
// __libdw_form_val_len will have done a bounds check.
die_addr += len;
+
+ if (attr.form == DW_FORM_implicit_const)
+ {
+ int64_t attr_value __attribute__((__unused__));
+ get_sleb128_unchecked (attr_value, attrp);
+ }
}
}
/* NOTREACHED */
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index a4a2761e..fc59a2ab 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -1,7 +1,6 @@
/* Return location expression list.
- Copyright (C) 2000-2010, 2013-2015 Red Hat, Inc.
+ Copyright (C) 2000-2010, 2013-2015, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2000.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -45,10 +44,34 @@ attr_ok (Dwarf_Attribute *attr)
if (attr == NULL)
return false;
- /* Must be one of the attributes listed below. */
+ /* If it is an exprloc, it is obviously OK. */
+ if (dwarf_whatform (attr) == DW_FORM_exprloc)
+ return true;
+
+ /* Otherwise must be one of the attributes listed below. Older
+ DWARF versions might have encoded the exprloc as block, and we
+ cannot easily distinquish attributes in the loclist class because
+ the same forms are used for different classes. */
switch (attr->code)
{
case DW_AT_location:
+ case DW_AT_byte_size:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_lower_bound:
+ case DW_AT_bit_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_byte_stride:
+ case DW_AT_rank:
+ case DW_AT_call_value:
+ case DW_AT_call_target:
+ case DW_AT_call_target_clobbered:
+ case DW_AT_call_data_location:
+ case DW_AT_call_data_value:
case DW_AT_data_member_location:
case DW_AT_vtable_elem_location:
case DW_AT_string_length:
@@ -64,7 +87,7 @@ attr_ok (Dwarf_Attribute *attr)
break;
default:
- __libdw_seterrno (DWARF_E_NO_LOCLIST);
+ __libdw_seterrno (DWARF_E_NO_LOC_VALUE);
return false;
}
@@ -97,19 +120,23 @@ loc_compare (const void *p1, const void *p2)
}
/* For each DW_OP_implicit_value, we store a special entry in the cache.
- This points us directly to the block data for later fetching. */
-static void
+ This points us directly to the block data for later fetching.
+ Returns zero on success, -1 on bad DWARF or 1 if tsearch failed. */
+static int
store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
{
struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
sizeof (struct loc_block_s), 1);
const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2;
- // Ignored, equal to op->number. And data length already checked.
- (void) __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word));
+ uint64_t len = __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word));
+ if (unlikely (len != op->number))
+ return -1;
block->addr = op;
block->data = (unsigned char *) data;
block->length = op->number;
- (void) tsearch (block, cache, loc_compare);
+ if (unlikely (tsearch (block, cache, loc_compare) == NULL))
+ return 1;
+ return 0;
}
int
@@ -147,6 +174,8 @@ check_constant_offset (Dwarf_Attribute *attr,
default:
return 1;
+ /* Note, we don't regard DW_FORM_data16 as a constant form,
+ even though technically it is according to the standard. */
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -299,6 +328,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
break;
case DW_OP_call_ref:
+ case DW_OP_GNU_variable_value:
/* DW_FORM_ref_addr, depends on offset size of CU. */
if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
ref_size,
@@ -427,8 +457,14 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
case DW_OP_plus_uconst:
case DW_OP_regx:
case DW_OP_piece:
+ case DW_OP_convert:
case DW_OP_GNU_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_reinterpret:
+ case DW_OP_addrx:
+ case DW_OP_GNU_addr_index:
+ case DW_OP_constx:
+ case DW_OP_GNU_const_index:
get_uleb128 (newloc->number, data, end_data);
break;
@@ -446,6 +482,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
break;
case DW_OP_bit_piece:
+ case DW_OP_regval_type:
case DW_OP_GNU_regval_type:
get_uleb128 (newloc->number, data, end_data);
if (unlikely (data >= end_data))
@@ -454,6 +491,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
break;
case DW_OP_implicit_value:
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
/* This cannot be used in a CFI expression. */
if (unlikely (dbg == NULL))
@@ -467,6 +505,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
data += newloc->number; /* Skip the block. */
break;
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
/* DW_FORM_ref_addr, depends on offset size of CU. */
if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
@@ -479,13 +518,16 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */
break;
+ case DW_OP_deref_type:
case DW_OP_GNU_deref_type:
+ case DW_OP_xderef_type:
if (unlikely (data + 1 >= end_data))
goto invalid;
newloc->number = *data++;
get_uleb128 (newloc->number2, data, end_data);
break;
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
{
size_t size;
@@ -553,7 +595,16 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
result[n].offset = loclist->offset;
if (result[n].atom == DW_OP_implicit_value)
- store_implicit_value (dbg, cache, &result[n]);
+ {
+ int store = store_implicit_value (dbg, cache, &result[n]);
+ if (unlikely (store != 0))
+ {
+ if (store < 0)
+ goto invalid;
+ else
+ goto nomem;
+ }
+ }
struct loclist *loc = loclist;
loclist = loclist->next;
@@ -616,7 +667,13 @@ dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
if (result != 1)
return result;
- /* If it has a block form, it's a single location expression. */
+ /* If it has a block form, it's a single location expression.
+ Except for DW_FORM_data16, which is a 128bit constant. */
+ if (attr->form == DW_FORM_data16)
+ {
+ __libdw_seterrno (DWARF_E_NO_BLOCK);
+ return -1;
+ }
Dwarf_Block block;
if (INTUSE(dwarf_formblock) (attr, &block) != 0)
return -1;
@@ -624,47 +681,113 @@ dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
}
-static int
-attr_base_address (Dwarf_Attribute *attr, Dwarf_Addr *basep)
+Dwarf_Addr
+__libdw_cu_base_address (Dwarf_CU *cu)
{
- /* Fetch the CU's base address. */
- Dwarf_Die cudie = CUDIE (attr->cu);
-
- /* Find the base address of the compilation unit. It will
- normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
- the base address could be overridden by DW_AT_entry_pc. It's
- been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
- for compilation units with discontinuous ranges. */
- Dwarf_Attribute attr_mem;
- if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
- && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
- DW_AT_entry_pc,
- &attr_mem),
- basep) != 0)
+ if (cu->base_address == (Dwarf_Addr) -1)
{
- if (INTUSE(dwarf_errno) () != 0)
- return -1;
-
- /* The compiler provided no base address when it should
- have. Buggy GCC does this when it used absolute
- addresses in the location list and no DW_AT_ranges. */
- *basep = 0;
+ Dwarf_Addr base;
+
+ /* Fetch the CU's base address. */
+ Dwarf_Die cudie = CUDIE (cu);
+
+ /* Find the base address of the compilation unit. It will
+ normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
+ the base address could be overridden by DW_AT_entry_pc. It's
+ been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+ for compilation units with discontinuous ranges. */
+ Dwarf_Attribute attr_mem;
+ if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0
+ && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
+ DW_AT_entry_pc,
+ &attr_mem),
+ &base) != 0)
+ {
+ /* The compiler provided no base address when it should
+ have. Buggy GCC does this when it used absolute
+ addresses in the location list and no DW_AT_ranges. */
+ base = 0;
+ }
+ cu->base_address = base;
}
- return 0;
+
+ return cu->base_address;
}
static int
-initial_offset_base (Dwarf_Attribute *attr, ptrdiff_t *offset,
- Dwarf_Addr *basep)
+initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
{
- if (attr_base_address (attr, basep) != 0)
- return -1;
+ size_t secidx = (attr->cu->version < 5
+ ? IDX_debug_loc : IDX_debug_loclists);
Dwarf_Word start_offset;
- if (__libdw_formptr (attr, IDX_debug_loc,
- DWARF_E_NO_LOCLIST,
- NULL, &start_offset) == NULL)
- return -1;
+ if (attr->form == DW_FORM_loclistx)
+ {
+ Dwarf_Word idx;
+ Dwarf_CU *cu = attr->cu;
+ const unsigned char *datap = attr->valp;
+ const unsigned char *endp = cu->endp;
+ if (datap >= endp)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ get_uleb128 (idx, datap, endp);
+
+ Elf_Data *data = cu->dbg->sectiondata[secidx];
+ if (data == NULL && cu->unit_type == DW_UT_split_compile)
+ {
+ cu = __libdw_find_split_unit (cu);
+ if (cu != NULL)
+ data = cu->dbg->sectiondata[secidx];
+ }
+
+ if (data == NULL)
+ {
+ __libdw_seterrno (secidx == IDX_debug_loc
+ ? DWARF_E_NO_DEBUG_LOC
+ : DWARF_E_NO_DEBUG_LOCLISTS);
+ return -1;
+ }
+
+ Dwarf_Off loc_base_off = __libdw_cu_locs_base (cu);
+
+ /* The section should at least contain room for one offset. */
+ size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
+ size_t offset_size = cu->offset_size;
+ if (offset_size > sec_size)
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ /* And the base offset should be at least inside the section. */
+ if (loc_base_off > (sec_size - offset_size))
+ goto invalid_offset;
+
+ size_t max_idx = (sec_size - offset_size - loc_base_off) / offset_size;
+ if (idx > max_idx)
+ goto invalid_offset;
+
+ datap = (cu->dbg->sectiondata[secidx]->d_buf
+ + loc_base_off + (idx * offset_size));
+ if (offset_size == 4)
+ start_offset = read_4ubyte_unaligned (cu->dbg, datap);
+ else
+ start_offset = read_8ubyte_unaligned (cu->dbg, datap);
+
+ start_offset += loc_base_off;
+ }
+ else
+ {
+ if (__libdw_formptr (attr, secidx,
+ (secidx == IDX_debug_loc
+ ? DWARF_E_NO_DEBUG_LOC
+ : DWARF_E_NO_DEBUG_LOCLISTS),
+ NULL, &start_offset) == NULL)
+ return -1;
+ }
*offset = start_offset;
return 0;
@@ -676,22 +799,19 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr,
size_t *exprlen)
{
- unsigned char *readp = locs->d_buf + offset;
- unsigned char *readendp = locs->d_buf + locs->d_size;
-
- next:
- if (readendp - readp < attr->cu->address_size * 2)
- {
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
- }
+ Dwarf_CU *cu = attr->cu;
+ Dwarf *dbg = cu->dbg;
+ size_t secidx = cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
+ const unsigned char *readp = locs->d_buf + offset;
+ const unsigned char *readendp = locs->d_buf + locs->d_size;
Dwarf_Addr begin;
Dwarf_Addr end;
- switch (__libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
- &readp, attr->cu->address_size,
+ next:
+ switch (__libdw_read_begin_end_pair_inc (cu, secidx,
+ &readp, readendp,
+ cu->address_size,
&begin, &end, basep))
{
case 0: /* got location range. */
@@ -704,25 +824,38 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
return -1;
}
- if (readendp - readp < 2)
- goto invalid;
-
/* We have a location expression. */
Dwarf_Block block;
- block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
- block.data = readp;
+ if (secidx == IDX_debug_loc)
+ {
+ if (readendp - readp < 2)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ block.length = read_2ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ if (readendp - readp < 1)
+ goto invalid;
+ get_uleb128 (block.length, readp, readendp);
+ }
+ block.data = (unsigned char *) readp;
if (readendp - readp < (ptrdiff_t) block.length)
goto invalid;
readp += block.length;
- *startp = *basep + begin;
- *endp = *basep + end;
+ /* Note these addresses include any base (if necessary) already. */
+ *startp = begin;
+ *endp = end;
/* If address is minus one we want them all, otherwise only matching. */
if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp))
goto next;
- if (getlocation (attr->cu, &block, expr, exprlen, IDX_debug_loc) != 0)
+ if (getlocation (cu, &block, expr, exprlen, secidx) != 0)
return -1;
return readp - (unsigned char *) locs->d_buf;
@@ -738,9 +871,11 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
if (llbufs == NULL)
maxlocs = SIZE_MAX;
- /* If it has a block form, it's a single location expression. */
+ /* If it has a block form, it's a single location expression.
+ Except for DW_FORM_data16, which is a 128bit constant. */
Dwarf_Block block;
- if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+ if (attr->form != DW_FORM_data16
+ && INTUSE(dwarf_formblock) (attr, &block) == 0)
{
if (maxlocs == 0)
return 0;
@@ -751,11 +886,14 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
return listlens[0] == 0 ? 0 : 1;
}
- int error = INTUSE(dwarf_errno) ();
- if (unlikely (error != DWARF_E_NO_BLOCK))
+ if (attr->form != DW_FORM_data16)
{
- __libdw_seterrno (error);
- return -1;
+ int error = INTUSE(dwarf_errno) ();
+ if (unlikely (error != DWARF_E_NO_BLOCK))
+ {
+ __libdw_seterrno (error);
+ return -1;
+ }
}
int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
@@ -769,19 +907,19 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
size_t got = 0;
/* This is a true loclistptr, fetch the initial base address and offset. */
- if (initial_offset_base (attr, &off, &base) != 0)
+ base = __libdw_cu_base_address (attr->cu);
+ if (base == (Dwarf_Addr) -1)
return -1;
- const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
- if (d == NULL)
- {
- __libdw_seterrno (DWARF_E_NO_LOCLIST);
- return -1;
- }
+ if (initial_offset (attr, &off) != 0)
+ return -1;
+
+ size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
+ const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
while (got < maxlocs
&& (off = getlocations_addr (attr, off, &base, &start, &end,
- address, d, &expr, &expr_len)) > 0)
+ address, d, &expr, &expr_len)) > 0)
{
/* This one matches the address. */
if (llbufs != NULL)
@@ -813,9 +951,11 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
if (offset == 0)
{
- /* If it has a block form, it's a single location expression. */
+ /* If it has a block form, it's a single location expression.
+ Except for DW_FORM_data16, which is a 128bit constant. */
Dwarf_Block block;
- if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+ if (attr->form != DW_FORM_data16
+ && INTUSE(dwarf_formblock) (attr, &block) == 0)
{
if (getlocation (attr->cu, &block, expr, exprlen,
cu_sec_idx (attr->cu)) != 0)
@@ -827,11 +967,14 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
return 1;
}
- int error = INTUSE(dwarf_errno) ();
- if (unlikely (error != DWARF_E_NO_BLOCK))
+ if (attr->form != DW_FORM_data16)
{
- __libdw_seterrno (error);
- return -1;
+ int error = INTUSE(dwarf_errno) ();
+ if (unlikely (error != DWARF_E_NO_BLOCK))
+ {
+ __libdw_seterrno (error);
+ return -1;
+ }
}
int result = check_constant_offset (attr, expr, exprlen);
@@ -849,17 +992,17 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
/* We must be looking at a true loclistptr, fetch the initial
base address and offset. */
- if (initial_offset_base (attr, &offset, basep) != 0)
+ *basep = __libdw_cu_base_address (attr->cu);
+ if (*basep == (Dwarf_Addr) -1)
return -1;
- }
- const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
- if (d == NULL)
- {
- __libdw_seterrno (DWARF_E_NO_LOCLIST);
- return -1;
+ if (initial_offset (attr, &offset) != 0)
+ return -1;
}
+ size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
+ const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
+
return getlocations_addr (attr, offset, basep, startp, endp,
(Dwarf_Word) -1, d, expr, exprlen);
}
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
index 8b6a4afd..99bcc828 100644
--- a/libdw/dwarf_getlocation_attr.c
+++ b/libdw/dwarf_getlocation_attr.c
@@ -1,5 +1,5 @@
/* Return DWARF attribute associated with a location expression op.
- Copyright (C) 2013, 2014 Red Hat, Inc.
+ Copyright (C) 2013, 2014, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ attr_form_cu (Dwarf_Attribute *attr)
{
/* If the attribute has block/expr form the data comes from the
.debug_info from the same cu as the attr. Otherwise it comes from
- the .debug_loc data section. */
+ the .debug_loc or .debug_loclists data section. */
switch (attr->form)
{
case DW_FORM_block1:
@@ -48,10 +48,26 @@ attr_form_cu (Dwarf_Attribute *attr)
case DW_FORM_exprloc:
return attr->cu;
default:
- return attr->cu->dbg->fake_loc_cu;
+ return (attr->cu->version < 5
+ ? attr->cu->dbg->fake_loc_cu
+ : attr->cu->dbg->fake_loclists_cu);
}
}
+static unsigned char *
+addr_valp (Dwarf_CU *cu, Dwarf_Word index)
+{
+ Elf_Data *debug_addr = cu->dbg->sectiondata[IDX_debug_addr];
+ if (debug_addr == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DEBUG_ADDR);
+ return NULL;
+ }
+
+ Dwarf_Word offset = __libdw_cu_addr_base (cu) + (index * cu->address_size);
+ return (unsigned char *) debug_addr->d_buf + offset;
+}
+
int
dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribute *result)
{
@@ -67,6 +83,7 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
result->cu = attr_form_cu (attr);
break;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
result->code = DW_AT_location;
result->form = DW_FORM_exprloc;
@@ -74,6 +91,7 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
result->cu = attr_form_cu (attr);
break;
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
result->code = DW_AT_const_value;
result->form = DW_FORM_block1;
@@ -81,6 +99,29 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
result->cu = attr_form_cu (attr);
break;
+ case DW_OP_GNU_const_index:
+ case DW_OP_constx:
+ result->code = DW_AT_const_value;
+ if (attr->cu->address_size == 4)
+ result->form = DW_FORM_data4;
+ else
+ result->form = DW_FORM_data8;
+ result->valp = addr_valp (attr->cu, op->number);
+ if (result->valp == NULL)
+ return -1;
+ result->cu = attr->cu->dbg->fake_addr_cu;
+ break;
+
+ case DW_OP_GNU_addr_index:
+ case DW_OP_addrx:
+ result->code = DW_AT_low_pc;
+ result->form = DW_FORM_addr;
+ result->valp = addr_valp (attr->cu, op->number);
+ if (result->valp == NULL)
+ return -1;
+ result->cu = attr->cu->dbg->fake_addr_cu;
+ break;
+
case DW_OP_call2:
case DW_OP_call4:
case DW_OP_call_ref:
@@ -96,7 +137,9 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
}
break;
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
+ case DW_OP_GNU_variable_value:
{
Dwarf_Die die;
if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0)
diff --git a/libdw/dwarf_getlocation_die.c b/libdw/dwarf_getlocation_die.c
index b4908d2b..673c61cf 100644
--- a/libdw/dwarf_getlocation_die.c
+++ b/libdw/dwarf_getlocation_die.c
@@ -1,5 +1,5 @@
/* Return DIE associated with a location expression op.
- Copyright (C) 2013 Red Hat, Inc.
+ Copyright (C) 2013, 2017 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -43,32 +43,51 @@ dwarf_getlocation_die (Dwarf_Attribute *attr, const Dwarf_Op *op,
Dwarf_Off dieoff;
switch (op->atom)
{
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
case DW_OP_call_ref:
+ case DW_OP_GNU_variable_value:
dieoff = op->number;
break;
case DW_OP_GNU_parameter_ref:
+ case DW_OP_convert:
case DW_OP_GNU_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_reinterpret:
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
case DW_OP_call2:
case DW_OP_call4:
+ if (op->number > (attr->cu->end - attr->cu->start))
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
dieoff = attr->cu->start + op->number;
break;
+ case DW_OP_regval_type:
case DW_OP_GNU_regval_type:
+ case DW_OP_deref_type:
case DW_OP_GNU_deref_type:
+ if (op->number2 > (attr->cu->end - attr->cu->start))
+ goto invalid_offset;
dieoff = attr->cu->start + op->number2;
break;
+ case DW_OP_xderef_type:
+ dieoff = op->number2;
+ break;
+
default:
__libdw_seterrno (DWARF_E_INVALID_ACCESS);
return -1;
}
if (__libdw_offdie (attr->cu->dbg, dieoff, result,
- attr->cu->type_offset != 0) == NULL)
+ ISV4TU(attr->cu)) == NULL)
return -1;
return 0;
diff --git a/libdw/dwarf_getlocation_implicit_pointer.c b/libdw/dwarf_getlocation_implicit_pointer.c
index 95053820..0c1cd00a 100644
--- a/libdw/dwarf_getlocation_implicit_pointer.c
+++ b/libdw/dwarf_getlocation_implicit_pointer.c
@@ -1,5 +1,5 @@
/* Return associated attribute for DW_OP_GNU_implicit_pointer.
- Copyright (C) 2010 Red Hat, Inc.
+ Copyright (C) 2010, 2017 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -55,7 +55,8 @@ dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr, const Dwarf_Op *op,
if (attr == NULL)
return -1;
- if (unlikely (op->atom != DW_OP_GNU_implicit_pointer))
+ if (unlikely (op->atom != DW_OP_implicit_pointer
+ && op->atom != DW_OP_GNU_implicit_pointer))
{
__libdw_seterrno (DWARF_E_INVALID_ACCESS);
return -1;
@@ -63,7 +64,7 @@ dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr, const Dwarf_Op *op,
Dwarf_Die die;
if (__libdw_offdie (attr->cu->dbg, op->number, &die,
- attr->cu->type_offset != 0) == NULL)
+ ISV4TU(attr->cu)) == NULL)
return -1;
if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index db6582b6..fd929669 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -1,7 +1,6 @@
/* Get macro information.
- Copyright (C) 2002-2009, 2014 Red Hat, Inc.
+ Copyright (C) 2002-2009, 2014, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2002.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -192,6 +191,8 @@ get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
+ MACRO_PROTO (p_udata_strsup, DW_FORM_udata, DW_FORM_strp_sup);
+ MACRO_PROTO (p_udata_strx, DW_FORM_udata, DW_FORM_strx);
MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
MACRO_PROTO (p_none);
@@ -205,10 +206,11 @@ get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
[DW_MACRO_start_file - 1] = p_udata_udata,
[DW_MACRO_end_file - 1] = p_none,
[DW_MACRO_import - 1] = p_secoffset,
- /* When adding support for DWARF5 supplementary object files and
- indirect string tables also add support for DW_MACRO_define_sup,
- DW_MACRO_undef_sup, DW_MACRO_import_sup, DW_MACRO_define_strx
- and DW_MACRO_undef_strx. */
+ [DW_MACRO_define_sup - 1] = p_udata_strsup,
+ [DW_MACRO_undef_sup - 1] = p_udata_strsup,
+ [DW_MACRO_import_sup - 1] = p_secoffset, /* XXX - but in sup!. */
+ [DW_MACRO_define_strx - 1] = p_udata_strx,
+ [DW_MACRO_undef_strx - 1] = p_udata_strx,
};
if ((flags & 0x4) != 0)
@@ -357,11 +359,18 @@ read_macros (Dwarf *dbg, int sec_index,
/* A fake CU with bare minimum data to fool dwarf_formX into
doing the right thing with the attributes that we put out.
We pretend it is the same version as the actual table.
- Version 4 for the old GNU extension, version 5 for DWARF5. */
+ Version 4 for the old GNU extension, version 5 for DWARF5.
+ To handle DW_FORM_strx[1234] we set the .str_offsets_base
+ from the given CU.
+ XXX We will need to deal with DW_MACRO_import_sup and change
+ out the dbg somehow for the DW_FORM_sec_offset to make sense. */
Dwarf_CU fake_cu = {
.dbg = dbg,
+ .sec_idx = sec_index,
.version = table->version,
.offset_size = table->is_64bit ? 8 : 4,
+ .str_off_base = str_offsets_base_off (dbg, (cudie != NULL
+ ? cudie->cu: NULL)),
.startp = (void *) startp + offset,
.endp = (void *) endp,
};
@@ -384,14 +393,25 @@ read_macros (Dwarf *dbg, int sec_index,
for (Dwarf_Word i = 0; i < proto->nforms; ++i)
{
- /* We pretend this is a DW_AT_GNU_macros attribute so that
+ /* We pretend this is a DW_AT[_GNU]_macros attribute so that
DW_FORM_sec_offset forms get correctly interpreted as
- offset into .debug_macro. */
- attributes[i].code = DW_AT_GNU_macros;
+ offset into .debug_macro. XXX Deal with DW_MACRO_import_sup
+ (swap .dbg) for DW_FORM_sec_offset? */
+ attributes[i].code = (fake_cu.version == 4 ? DW_AT_GNU_macros
+ : DW_AT_macros);
attributes[i].form = proto->forms[i];
attributes[i].valp = (void *) readp;
attributes[i].cu = &fake_cu;
+ /* We don't want forms that aren't allowed because they could
+ read from the "abbrev" like DW_FORM_implicit_const. */
+ if (! libdw_valid_user_form (attributes[i].form))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ free (attributesp);
+ return -1;
+ }
+
size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
if (unlikely (len == (size_t) -1))
{
@@ -561,7 +581,8 @@ dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
{
/* DW_AT_GNU_macros, DW_AT_macros */
Dwarf_Word macoff;
- if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
+ if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0
+ && get_offset_from (cudie, DW_AT_macros, &macoff) != 0)
return -1;
offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
callback, arg, offset, accept_0xff,
diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c
index df480d33..5662eecf 100644
--- a/libdw/dwarf_getscopes.c
+++ b/libdw/dwarf_getscopes.c
@@ -62,7 +62,9 @@ pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
if (result < 0)
{
int error = INTUSE(dwarf_errno) ();
- if (error != DWARF_E_NOERROR && error != DWARF_E_NO_DEBUG_RANGES)
+ if (error != DWARF_E_NOERROR
+ && error != DWARF_E_NO_DEBUG_RANGES
+ && error != DWARF_E_NO_DEBUG_RNGLISTS)
{
__libdw_seterrno (error);
return -1;
diff --git a/libdw/dwarf_getsrcfiles.c b/libdw/dwarf_getsrcfiles.c
index 5af6f68b..12fdabf2 100644
--- a/libdw/dwarf_getsrcfiles.c
+++ b/libdw/dwarf_getsrcfiles.c
@@ -1,7 +1,6 @@
/* Return source file information of CU.
- Copyright (C) 2004, 2005, 2013, 2015 Red Hat, Inc.
+ Copyright (C) 2004, 2005, 2013, 2015, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2004.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -51,14 +50,47 @@ dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles)
/* Get the information if it is not already known. */
struct Dwarf_CU *const cu = cudie->cu;
- if (cu->lines == NULL)
+ if (cu->files == NULL)
{
- Dwarf_Lines *lines;
- size_t nlines;
-
- /* Let the more generic function do the work. It'll create more
- data but that will be needed in an real program anyway. */
- res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines);
+ /* For split units there might be a simple file table (without lines).
+ If not, use the one from the skeleton. */
+ if (cu->unit_type == DW_UT_split_compile
+ || cu->unit_type == DW_UT_split_type)
+ {
+ /* We tried, assume we fail... */
+ cu->files = (void *) -1;
+
+ /* See if there is a .debug_line section, for split CUs
+ the table is at offset zero. */
+ if (cu->dbg->sectiondata[IDX_debug_line] != NULL)
+ {
+ /* We are only interested in the files, the lines will
+ always come from the skeleton. */
+ res = __libdw_getsrclines (cu->dbg, 0,
+ __libdw_getcompdir (cudie),
+ cu->address_size, NULL,
+ &cu->files);
+ }
+ else
+ {
+ Dwarf_CU *skel = __libdw_find_split_unit (cu);
+ if (skel != NULL)
+ {
+ Dwarf_Die skeldie = CUDIE (skel);
+ res = INTUSE(dwarf_getsrcfiles) (&skeldie, files, nfiles);
+ cu->files = skel->files;
+ }
+ }
+ }
+ else
+ {
+ Dwarf_Lines *lines;
+ size_t nlines;
+
+ /* Let the more generic function do the work. It'll create more
+ data but that will be needed in an real program anyway. */
+ res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines);
+ }
}
else if (cu->files != (void *) -1l)
/* We already have the information. */
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index d02c38db..1432b1db 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -1,7 +1,6 @@
/* Return line number information of CU.
- Copyright (C) 2004-2010, 2013, 2014, 2015, 2016 Red Hat, Inc.
+ Copyright (C) 2004-2010, 2013, 2014, 2015, 2016, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2004.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -154,20 +153,9 @@ read_srclines (Dwarf *dbg,
{
int res = -1;
+ struct filelist *filelist = NULL;
size_t nfilelist = 0;
- unsigned int ndirlist = 0;
-
- struct filelist null_file =
- {
- .info =
- {
- .name = "???",
- .mtime = 0,
- .length = 0
- },
- .next = NULL
- };
- struct filelist *filelist = &null_file;
+ size_t ndirlist = 0;
/* If there are a large number of lines, files or dirs don't blow up
the stack. Stack allocate some entries, only dynamically malloc
@@ -177,16 +165,7 @@ read_srclines (Dwarf *dbg,
#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
#define MAX_STACK_DIRS (MAX_STACK_ALLOC / 16)
- struct dirlist
- {
- const char *dir;
- size_t len;
- };
- struct dirlist dirstack[MAX_STACK_DIRS];
- struct dirlist *dirarray = dirstack;
-
- /* We are about to process the statement program. Initialize the
- state machine registers (see 6.2.2 in the v2.1 specification). */
+ /* Initial statement program state (except for stmt_list, see below). */
struct line_state state =
{
.linelist = NULL,
@@ -204,6 +183,17 @@ read_srclines (Dwarf *dbg,
.discriminator = 0
};
+ /* The dirs normally go on the stack, but if there are too many
+ we alloc them all. Set up stack storage early, so we can check on
+ error if we need to free them or not. */
+ struct dirlist
+ {
+ const char *dir;
+ size_t len;
+ };
+ struct dirlist dirstack[MAX_STACK_DIRS];
+ struct dirlist *dirarray = dirstack;
+
if (unlikely (linep + 4 > lineendp))
{
invalid_data:
@@ -222,25 +212,45 @@ read_srclines (Dwarf *dbg,
}
/* Check whether we have enough room in the section. */
- if (unlikely (unit_length > (size_t) (lineendp - linep)
- || unit_length < 2 + length + 5 * 1))
+ if (unlikely (unit_length > (size_t) (lineendp - linep)))
goto invalid_data;
lineendp = linep + unit_length;
/* The next element of the header is the version identifier. */
+ if ((size_t) (lineendp - linep) < 2)
+ goto invalid_data;
uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
- if (unlikely (version < 2) || unlikely (version > 4))
+ if (unlikely (version < 2) || unlikely (version > 5))
{
__libdw_seterrno (DWARF_E_VERSION);
goto out;
}
+ /* DWARF5 explicitly lists address and segment_selector sizes. */
+ if (version >= 5)
+ {
+ if ((size_t) (lineendp - linep) < 2)
+ goto invalid_data;
+ size_t line_address_size = *linep++;
+ size_t segment_selector_size = *linep++;
+ if (line_address_size != address_size || segment_selector_size != 0)
+ goto invalid_data;
+ }
+
/* Next comes the header length. */
Dwarf_Word header_length;
if (length == 4)
- header_length = read_4ubyte_unaligned_inc (dbg, linep);
+ {
+ if ((size_t) (lineendp - linep) < 4)
+ goto invalid_data;
+ header_length = read_4ubyte_unaligned_inc (dbg, linep);
+ }
else
- header_length = read_8ubyte_unaligned_inc (dbg, linep);
+ {
+ if ((size_t) (lineendp - linep) < 8)
+ goto invalid_data;
+ header_length = read_8ubyte_unaligned_inc (dbg, linep);
+ }
const unsigned char *header_start = linep;
/* Next the minimum instruction length. */
@@ -250,13 +260,17 @@ read_srclines (Dwarf *dbg,
uint_fast8_t max_ops_per_instr = 1;
if (version >= 4)
{
- if (unlikely (lineendp - linep < 5))
+ if (unlikely ((size_t) (lineendp - linep) < 1))
goto invalid_data;
max_ops_per_instr = *linep++;
if (unlikely (max_ops_per_instr == 0))
goto invalid_data;
}
+ /* 4 more bytes, is_stmt, line_base, line_range and opcode_base. */
+ if ((size_t) (lineendp - linep) < 4)
+ goto invalid_data;
+
/* Then the flag determining the default value of the is_stmt
register. */
uint_fast8_t default_is_stmt = *linep++;
@@ -277,31 +291,85 @@ read_srclines (Dwarf *dbg,
goto invalid_data;
linep += opcode_base - 1;
- /* First comes the list of directories. Add the compilation
- directory first since the index zero is used for it. */
- struct dirlist comp_dir_elem =
- {
- .dir = comp_dir,
- .len = comp_dir ? strlen (comp_dir) : 0,
- };
- ndirlist = 1;
+ /* To read DWARF5 dir and file lists we need to know the forms. For
+ now we skip everything, except the DW_LNCT_path and
+ DW_LNCT_directory_index. */
+ uint16_t forms[256];
+ unsigned char nforms = 0;
+ unsigned char form_path = -1; /* Which forms is DW_LNCT_path. */
+ unsigned char form_idx = -1; /* And which is DW_LNCT_directory_index. */
+
+ /* To read/skip form data. */
+ Dwarf_CU fake_cu = {
+ .dbg = dbg,
+ .sec_idx = IDX_debug_line,
+ .version = 5,
+ .offset_size = length,
+ .address_size = address_size,
+ .startp = (void *) linep,
+ .endp = (void *) lineendp,
+ };
/* First count the entries. */
- const unsigned char *dirp = linep;
- unsigned int ndirs = 0;
- while (*dirp != 0)
+ size_t ndirs = 0;
+ if (version < 5)
+ {
+ const unsigned char *dirp = linep;
+ while (*dirp != 0)
+ {
+ uint8_t *endp = memchr (dirp, '\0', lineendp - dirp);
+ if (endp == NULL)
+ goto invalid_data;
+ ++ndirs;
+ dirp = endp + 1;
+ }
+ ndirs = ndirs + 1; /* There is always the "unknown" dir. */
+ }
+ else
{
- uint8_t *endp = memchr (dirp, '\0', lineendp - dirp);
- if (endp == NULL)
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ nforms = *linep++;
+ for (int i = 0; i < nforms; i++)
+ {
+ uint16_t desc, form;
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ get_uleb128 (desc, linep, lineendp);
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ get_uleb128 (form, linep, lineendp);
+
+ if (! libdw_valid_user_form (form))
+ goto invalid_data;
+
+ forms[i] = form;
+ if (desc == DW_LNCT_path)
+ form_path = i;
+ }
+
+ if (nforms > 0 && form_path == (unsigned char) -1)
+ goto invalid_data;
+
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ get_uleb128 (ndirs, linep, lineendp);
+
+ if (nforms == 0 && ndirs != 0)
+ goto invalid_data;
+
+ /* Assume there is at least 1 byte needed per form to describe
+ the directory. Filters out insanely large ndirs. */
+ if (nforms != 0 && ndirs > (size_t) (lineendp - linep) / nforms)
goto invalid_data;
- ++ndirs;
- dirp = endp + 1;
}
- ndirlist += ndirs;
/* Arrange the list in array form. */
+ ndirlist = ndirs;
if (ndirlist >= MAX_STACK_DIRS)
{
+ if (ndirlist > SIZE_MAX / sizeof (*dirarray))
+ goto no_mem;
dirarray = (struct dirlist *) malloc (ndirlist * sizeof (*dirarray));
if (unlikely (dirarray == NULL))
{
@@ -310,20 +378,82 @@ read_srclines (Dwarf *dbg,
goto out;
}
}
- dirarray[0] = comp_dir_elem;
- for (unsigned int n = 1; n < ndirlist; n++)
+
+ /* Entry zero is implicit for older versions, but explicit for 5+. */
+ struct dirlist comp_dir_elem;
+ if (version < 5)
{
- dirarray[n].dir = (char *) linep;
- uint8_t *endp = memchr (linep, '\0', lineendp - linep);
- assert (endp != NULL);
- dirarray[n].len = endp - linep;
- linep = endp + 1;
+ /* First comes the list of directories. Add the compilation
+ directory first since the index zero is used for it. */
+ comp_dir_elem.dir = comp_dir;
+ comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0,
+ dirarray[0] = comp_dir_elem;
+ for (unsigned int n = 1; n < ndirlist; n++)
+ {
+ dirarray[n].dir = (char *) linep;
+ uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+ assert (endp != NULL);
+ dirarray[n].len = endp - linep;
+ linep = endp + 1;
+ }
+ /* Skip the final NUL byte. */
+ ++linep;
+ }
+ else
+ {
+ Dwarf_Attribute attr;
+ attr.code = DW_AT_name;
+ attr.cu = &fake_cu;
+ for (unsigned int n = 0; n < ndirlist; n++)
+ {
+ const char *dir = NULL;
+ for (unsigned char m = 0; m < nforms; m++)
+ {
+ if (m == form_path)
+ {
+ attr.form = forms[m];
+ attr.valp = (void *) linep;
+ dir = dwarf_formstring (&attr);
+ }
+
+ size_t len = __libdw_form_val_len (&fake_cu, forms[m], linep);
+ if ((size_t) (lineendp - linep) < len)
+ goto invalid_data;
+
+ linep += len;
+ }
+
+ if (dir == NULL)
+ goto invalid_data;
+
+ dirarray[n].dir = dir;
+ dirarray[n].len = strlen (dir);
+ }
}
- /* Skip the final NUL byte. */
- ++linep;
+
+ /* File index zero doesn't exist for DWARF < 5. Files are indexed
+ starting from 1. But for DWARF5 they are indexed starting from
+ zero, but the default index is still 1. In both cases the
+ "first" file is special and refers to the main compile unit file,
+ equal to the DW_AT_name of the DW_TAG_compile_unit. */
+ struct filelist null_file =
+ {
+ .info =
+ {
+ .name = "???",
+ .mtime = 0,
+ .length = 0
+ },
+ .next = NULL
+ };
+ filelist = &null_file;
+ nfilelist = 1;
/* Allocate memory for a new file. For the first MAX_STACK_FILES
- entries just return a slot in the preallocated stack array. */
+ entries just return a slot in the preallocated stack array.
+ This is slightly complicated because in DWARF < 5 new files could
+ be defined with DW_LNE_define_file after the normal file list was
+ read. */
struct filelist flstack[MAX_STACK_FILES];
#define NEW_FILE() ({ \
struct filelist *fl = (nfilelist < MAX_STACK_FILES \
@@ -337,69 +467,181 @@ read_srclines (Dwarf *dbg,
fl; })
/* Now read the files. */
- nfilelist = 1;
-
- if (unlikely (linep >= lineendp))
- goto invalid_data;
- while (*linep != 0)
+ if (version < 5)
{
- struct filelist *new_file = NEW_FILE ();
-
- /* First comes the file name. */
- char *fname = (char *) linep;
- uint8_t *endp = memchr (fname, '\0', lineendp - linep);
- if (endp == NULL)
- goto invalid_data;
- size_t fnamelen = endp - (uint8_t *) fname;
- linep = endp + 1;
-
- /* Then the index. */
- Dwarf_Word diridx;
if (unlikely (linep >= lineendp))
goto invalid_data;
- get_uleb128 (diridx, linep, lineendp);
- if (unlikely (diridx >= ndirlist))
+ while (*linep != 0)
{
- __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
- goto out;
- }
+ struct filelist *new_file = NEW_FILE ();
- if (*fname == '/')
- /* It's an absolute path. */
- new_file->info.name = fname;
- else
- {
- new_file->info.name = libdw_alloc (dbg, char, 1,
- dirarray[diridx].len + 1
- + fnamelen + 1);
- char *cp = new_file->info.name;
+ /* First comes the file name. */
+ char *fname = (char *) linep;
+ uint8_t *endp = memchr (fname, '\0', lineendp - linep);
+ if (endp == NULL)
+ goto invalid_data;
+ size_t fnamelen = endp - (uint8_t *) fname;
+ linep = endp + 1;
- if (dirarray[diridx].dir != NULL)
+ /* Then the index. */
+ Dwarf_Word diridx;
+ if (unlikely (linep >= lineendp))
+ goto invalid_data;
+ get_uleb128 (diridx, linep, lineendp);
+ if (unlikely (diridx >= ndirlist))
{
- /* This value could be NULL in case the DW_AT_comp_dir
- was not present. We cannot do much in this case.
- The easiest thing is to convert the path in an
- absolute path. */
- cp = stpcpy (cp, dirarray[diridx].dir);
+ __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+ goto out;
+ }
+
+ if (*fname == '/')
+ /* It's an absolute path. */
+ new_file->info.name = fname;
+ else
+ {
+ new_file->info.name = libdw_alloc (dbg, char, 1,
+ dirarray[diridx].len + 1
+ + fnamelen + 1);
+ char *cp = new_file->info.name;
+
+ if (dirarray[diridx].dir != NULL)
+ {
+ /* This value could be NULL in case the DW_AT_comp_dir
+ was not present. We cannot do much in this case.
+ Just keep the file relative. */
+ cp = stpcpy (cp, dirarray[diridx].dir);
+ *cp++ = '/';
+ }
+ strcpy (cp, fname);
+ assert (strlen (new_file->info.name)
+ < dirarray[diridx].len + 1 + fnamelen + 1);
}
- *cp++ = '/';
- strcpy (cp, fname);
- assert (strlen (new_file->info.name)
- < dirarray[diridx].len + 1 + fnamelen + 1);
+
+ /* Next comes the modification time. */
+ if (unlikely (linep >= lineendp))
+ goto invalid_data;
+ get_uleb128 (new_file->info.mtime, linep, lineendp);
+
+ /* Finally the length of the file. */
+ if (unlikely (linep >= lineendp))
+ goto invalid_data;
+ get_uleb128 (new_file->info.length, linep, lineendp);
}
+ /* Skip the final NUL byte. */
+ ++linep;
+ }
+ else
+ {
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ nforms = *linep++;
+ form_path = form_idx = -1;
+ for (int i = 0; i < nforms; i++)
+ {
+ uint16_t desc, form;
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ get_uleb128 (desc, linep, lineendp);
+ if ((size_t) (lineendp - linep) < 1)
+ goto invalid_data;
+ get_uleb128 (form, linep, lineendp);
- /* Next comes the modification time. */
- if (unlikely (linep >= lineendp))
+ if (! libdw_valid_user_form (form))
+ goto invalid_data;
+
+ forms[i] = form;
+ if (desc == DW_LNCT_path)
+ form_path = i;
+ else if (desc == DW_LNCT_directory_index)
+ form_idx = i;
+ }
+
+ if (nforms > 0 && (form_path == (unsigned char) -1
+ || form_idx == (unsigned char) -1))
goto invalid_data;
- get_uleb128 (new_file->info.mtime, linep, lineendp);
- /* Finally the length of the file. */
- if (unlikely (linep >= lineendp))
+ size_t nfiles;
+ get_uleb128 (nfiles, linep, lineendp);
+
+ if (nforms == 0 && nfiles != 0)
+ goto invalid_data;
+
+ /* Assume there is at least 1 byte needed per form to describe
+ the file. Filters out insanely large nfiles. */
+ if (nforms != 0 && nfiles > (size_t) (lineendp - linep) / nforms)
goto invalid_data;
- get_uleb128 (new_file->info.length, linep, lineendp);
+
+ Dwarf_Attribute attr;
+ attr.cu = &fake_cu;
+ for (unsigned int n = 0; n < nfiles; n++)
+ {
+ const char *fname = NULL;
+ Dwarf_Word diridx = (Dwarf_Word) -1;
+ for (unsigned char m = 0; m < nforms; m++)
+ {
+ if (m == form_path)
+ {
+ attr.code = DW_AT_name;
+ attr.form = forms[m];
+ attr.valp = (void *) linep;
+ fname = dwarf_formstring (&attr);
+ }
+ else if (m == form_idx)
+ {
+ attr.code = DW_AT_decl_file; /* Close enough. */
+ attr.form = forms[m];
+ attr.valp = (void *) linep;
+ if (dwarf_formudata (&attr, &diridx) != 0)
+ diridx = (Dwarf_Word) -1;
+ }
+
+ size_t len = __libdw_form_val_len (&fake_cu, forms[m], linep);
+ if ((size_t) (lineendp - linep) < len)
+ goto invalid_data;
+
+ linep += len;
+ }
+
+ if (fname == NULL || diridx == (Dwarf_Word) -1)
+ goto invalid_data;
+
+ size_t fnamelen = strlen (fname);
+
+ if (unlikely (diridx >= ndirlist))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+ goto out;
+ }
+
+ /* Yes, weird. Looks like an off-by-one in the spec. */
+ struct filelist *new_file = n == 0 ? &null_file : NEW_FILE ();
+
+ /* We follow the same rules as above for DWARF < 5, even
+ though the standard doesn't explicitly mention absolute
+ paths and ignoring the dir index. */
+ if (*fname == '/')
+ /* It's an absolute path. */
+ new_file->info.name = (char *) fname;
+ else
+ {
+ new_file->info.name = libdw_alloc (dbg, char, 1,
+ dirarray[diridx].len + 1
+ + fnamelen + 1);
+ char *cp = new_file->info.name;
+
+ /* In the DWARF >= 5 case, dir can never be NULL. */
+ cp = stpcpy (cp, dirarray[diridx].dir);
+ *cp++ = '/';
+ strcpy (cp, fname);
+ assert (strlen (new_file->info.name)
+ < dirarray[diridx].len + 1 + fnamelen + 1);
+ }
+
+ /* For now we just ignore the modification time and file length. */
+ new_file->info.mtime = 0;
+ new_file->info.length = 0;
+ }
}
- /* Skip the final NUL byte. */
- ++linep;
/* Consistency check. */
if (unlikely (linep != header_start + header_length))
@@ -408,6 +650,9 @@ read_srclines (Dwarf *dbg,
goto out;
}
+ /* We are about to process the statement program. Most state machine
+ registers have already been initialize above. Just add the is_stmt
+ default. See 6.2.2 in the v2.1 specification. */
state.is_stmt = default_is_stmt;
/* Apply the "operation advance" from a special opcode or
@@ -557,11 +802,12 @@ read_srclines (Dwarf *dbg,
if (dirarray[diridx].dir != NULL)
/* This value could be NULL in case the
DW_AT_comp_dir was not present. We
- cannot do much in this case. The easiest
- thing is to convert the path in an
- absolute path. */
- cp = stpcpy (cp, dirarray[diridx].dir);
- *cp++ = '/';
+ cannot do much in this case. Just
+ keep the file relative. */
+ {
+ cp = stpcpy (cp, dirarray[diridx].dir);
+ *cp++ = '/';
+ }
strcpy (cp, fname);
}
@@ -820,7 +1066,7 @@ read_srclines (Dwarf *dbg,
free (state.linelist);
state.linelist = ll;
}
- if (ndirlist >= MAX_STACK_DIRS)
+ if (dirarray != dirstack)
free (dirarray);
for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
{
@@ -918,6 +1164,31 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
struct Dwarf_CU *const cu = cudie->cu;
if (cu->lines == NULL)
{
+ /* For split units always pick the lines from the skeleton. */
+ if (cu->unit_type == DW_UT_split_compile
+ || cu->unit_type == DW_UT_split_type)
+ {
+ /* We tries, assume we fail... */
+ cu->lines = (void *) -1l;
+
+ Dwarf_CU *skel = __libdw_find_split_unit (cu);
+ if (skel != NULL)
+ {
+ Dwarf_Die skeldie = CUDIE (skel);
+ int res = INTUSE(dwarf_getsrclines) (&skeldie, lines, nlines);
+ if (res == 0)
+ {
+ cu->lines = skel->lines;
+ *lines = cu->lines;
+ *nlines = cu->lines->nlines;
+ }
+ return res;
+ }
+
+ __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
+ return -1;
+ }
+
/* Failsafe mode: no data found. */
cu->lines = (void *) -1l;
cu->files = (void *) -1l;
diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c
index 2bb8dc82..90053b13 100644
--- a/libdw/dwarf_hasattr.c
+++ b/libdw/dwarf_hasattr.c
@@ -1,5 +1,5 @@
/* Check whether given DIE has specific attribute.
- Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2014, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -45,32 +45,20 @@ dwarf_hasattr (Dwarf_Die *die, unsigned int search_name)
Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
if (unlikely (abbrevp == DWARF_END_ABBREV))
{
- invalid_dwarf:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return 0;
}
- Dwarf *dbg = die->cu->dbg;
-
- /* Search the name attribute. */
- unsigned char *const endp
- = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf
- + dbg->sectiondata[IDX_debug_abbrev]->d_size);
-
+ /* Search the name attribute. Dwarf_Abbrev was checked when created,
+ so we can read unchecked here. */
const unsigned char *attrp = abbrevp->attrp;
while (1)
{
- /* Are we still in bounds? This test needs to be refined. */
- if (unlikely (attrp >= endp))
- goto invalid_dwarf;
-
/* Get attribute name and form. */
unsigned int attr_name;
- get_uleb128 (attr_name, attrp, endp);
+ get_uleb128_unchecked (attr_name, attrp);
unsigned int attr_form;
- if (unlikely (attrp >= endp))
- goto invalid_dwarf;
- get_uleb128 (attr_form, attrp, endp);
+ get_uleb128_unchecked (attr_form, attrp);
/* We can stop if we found the attribute with value zero. */
if (attr_name == 0 || attr_form == 0)
@@ -78,6 +66,12 @@ dwarf_hasattr (Dwarf_Die *die, unsigned int search_name)
if (attr_name == search_name)
return 1;
+
+ if (attr_form == DW_FORM_implicit_const)
+ {
+ int64_t attr_value __attribute__ ((unused));
+ get_sleb128_unchecked (attr_value, attrp);
+ }
}
}
INTDEF (dwarf_hasattr)
diff --git a/libdw/dwarf_hasattr_integrate.c b/libdw/dwarf_hasattr_integrate.c
index 2d5348cf..1d946280 100644
--- a/libdw/dwarf_hasattr_integrate.c
+++ b/libdw/dwarf_hasattr_integrate.c
@@ -1,5 +1,5 @@
/* Check whether DIE has specific attribute, integrating DW_AT_abstract_origin.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@ int
dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name)
{
Dwarf_Die die_mem;
-
+ int chain = 16; /* Largest DIE ref chain we will follow. */
do
{
if (INTUSE(dwarf_hasattr) (die, search_name))
@@ -53,7 +53,21 @@ dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name)
die = INTUSE(dwarf_formref_die) (attr, &die_mem);
}
- while (die != NULL);
+ while (die != NULL && chain-- != 0);
+
+ /* Not NULL if it didn't have abstract_origin and specification
+ attributes. If it is a split CU then see if the skeleton
+ has it. */
+ if (die != NULL && is_cudie (die)
+ && die->cu->unit_type == DW_UT_split_compile)
+ {
+ Dwarf_CU *skel_cu = __libdw_find_split_unit (die->cu);
+ if (skel_cu != NULL)
+ {
+ Dwarf_Die skel_die = CUDIE (skel_cu);
+ return INTUSE(dwarf_hasattr) (&skel_die, search_name);
+ }
+ }
return 0;
}
diff --git a/libdw/dwarf_highpc.c b/libdw/dwarf_highpc.c
index 20702545..5b2f0fd6 100644
--- a/libdw/dwarf_highpc.c
+++ b/libdw/dwarf_highpc.c
@@ -1,7 +1,6 @@
/* Return high PC attribute of DIE.
- Copyright (C) 2003, 2005, 2012 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2012, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -39,19 +38,22 @@ int
dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
{
Dwarf_Attribute attr_high_mem;
- Dwarf_Attribute *attr_high = INTUSE(dwarf_attr) (die, DW_AT_high_pc,
- &attr_high_mem);
+ Dwarf_Attribute *attr_high;
+ /* Split compile DIEs inherit high_pc from their skeleton DIE. */
+ if (is_cudie (die) && die->cu->unit_type == DW_UT_split_compile)
+ attr_high = INTUSE(dwarf_attr_integrate) (die, DW_AT_high_pc,
+ &attr_high_mem);
+ else
+ attr_high = INTUSE(dwarf_attr) (die, DW_AT_high_pc, &attr_high_mem);
+
if (attr_high == NULL)
- return -1;
+ goto no_addr;
- if (attr_high->form == DW_FORM_addr)
- return INTUSE(dwarf_formaddr) (attr_high, return_addr);
+ if (INTUSE(dwarf_formaddr) (attr_high, return_addr) == 0)
+ return 0;
/* DWARF 4 allows high_pc to be a constant offset from low_pc. */
- Dwarf_Attribute attr_low_mem;
- if (INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
- &attr_low_mem),
- return_addr) == 0)
+ if (INTUSE(dwarf_lowpc) (die, return_addr) == 0)
{
Dwarf_Word uval;
if (INTUSE(dwarf_formudata) (attr_high, &uval) == 0)
@@ -59,8 +61,10 @@ dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
*return_addr += uval;
return 0;
}
- __libdw_seterrno (DWARF_E_NO_ADDR);
}
+
+no_addr:
+ __libdw_seterrno (DWARF_E_NO_ADDR);
return -1;
}
INTDEF(dwarf_highpc)
diff --git a/libdw/dwarf_lowpc.c b/libdw/dwarf_lowpc.c
index b3be2b0e..4d743a72 100644
--- a/libdw/dwarf_lowpc.c
+++ b/libdw/dwarf_lowpc.c
@@ -1,7 +1,6 @@
/* Return low PC attribute of DIE.
- Copyright (C) 2003, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -38,10 +37,12 @@
int
dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
{
- Dwarf_Attribute attr_mem;
-
- return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
- &attr_mem),
- return_addr);
+ Dwarf_Attribute attr_mem, *attr;
+ /* Split compile DIEs inherit low_pc from their skeleton DIE. */
+ if (is_cudie (die) && die->cu->unit_type == DW_UT_split_compile)
+ attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_low_pc, &attr_mem);
+ else
+ attr = INTUSE(dwarf_attr) (die, DW_AT_low_pc, &attr_mem);
+ return INTUSE(dwarf_formaddr) (attr, return_addr);
}
INTDEF(dwarf_lowpc)
diff --git a/libdw/dwarf_next_cfi.c b/libdw/dwarf_next_cfi.c
index 53fc3697..fa28d99b 100644
--- a/libdw/dwarf_next_cfi.c
+++ b/libdw/dwarf_next_cfi.c
@@ -54,6 +54,7 @@ dwarf_next_cfi (const unsigned char e_ident[],
we don't know yet whether this is a 64-bit object or not. */
|| unlikely (off + 4 >= data->d_size))
{
+ done:
*next_off = (Dwarf_Off) -1l;
return 1;
}
@@ -79,6 +80,13 @@ dwarf_next_cfi (const unsigned char e_ident[],
}
length = read_8ubyte_unaligned_inc (&dw, bytes);
}
+
+ /* Not explicitly in the DWARF spec, but mentioned in the LSB exception
+ frames (.eh_frame) spec. If Length contains the value 0, then this
+ CIE shall be considered a terminator and processing shall end. */
+ if (length == 0)
+ goto done;
+
if (unlikely ((uint64_t) (limit - bytes) < length)
|| unlikely (length < offset_size + 1))
goto invalid;
diff --git a/libdw/dwarf_next_lines.c b/libdw/dwarf_next_lines.c
new file mode 100644
index 00000000..9b76b47e
--- /dev/null
+++ b/libdw/dwarf_next_lines.c
@@ -0,0 +1,197 @@
+/* Iterate through the debug line table.
+ Copyright (C) 2018 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libdwP.h>
+
+
+int
+dwarf_next_lines (Dwarf *dbg, Dwarf_Off off,
+ Dwarf_Off *next_off, Dwarf_CU **cu,
+ Dwarf_Files **srcfiles, size_t *nfiles,
+ Dwarf_Lines **srclines, size_t *nlines)
+{
+ /* Ignore existing errors. */
+ if (dbg == NULL)
+ return -1;
+
+ Elf_Data *lines = dbg->sectiondata[IDX_debug_line];
+ if (lines == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
+ return -1;
+ }
+
+ if (off == (Dwarf_Off) -1
+ || lines->d_size < 4
+ || off >= lines->d_size)
+ {
+ *next_off = (Dwarf_Off) -1;
+ return 1;
+ }
+
+ /* Read enough of the header to know where the next table is and
+ whether we need to lookup the CU (version < 5). */
+ const unsigned char *linep = lines->d_buf + off;
+ const unsigned char *lineendp = lines->d_buf + lines->d_size;
+
+ if ((size_t) (lineendp - linep) < 4)
+ {
+ invalid_data:
+ __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+ return -1;
+ }
+
+ *next_off = off + 4;
+ Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
+ if (unit_length == DWARF3_LENGTH_64_BIT)
+ {
+ if ((size_t) (lineendp - linep) < 8)
+ goto invalid_data;
+ unit_length = read_8ubyte_unaligned_inc (dbg, linep);
+ *next_off += 8;
+ }
+
+ if (unit_length > (size_t) (lineendp - linep))
+ goto invalid_data;
+
+ *next_off += unit_length;
+ lineendp = linep + unit_length;
+
+ if ((size_t) (lineendp - linep) < 2)
+ goto invalid_data;
+ uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
+
+ Dwarf_Die cudie;
+ if (version < 5)
+ {
+ /* We need to find the matching CU to get the comp_dir. Use the
+ given CU as hint where to start searching. Normally it will
+ be the next CU that has a statement list. */
+ Dwarf_CU *given_cu = *cu;
+ Dwarf_CU *next_cu = given_cu;
+ bool found = false;
+ while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
+ &cudie, NULL) == 0)
+ {
+ if (dwarf_hasattr (&cudie, DW_AT_stmt_list))
+ {
+ Dwarf_Attribute attr;
+ Dwarf_Word stmt_off;
+ if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
+ &stmt_off) == 0
+ && stmt_off == off)
+ {
+ found = true;
+ break;
+ }
+ }
+ else if (off == 0
+ && (next_cu->unit_type == DW_UT_split_compile
+ || next_cu->unit_type == DW_UT_split_type))
+ {
+ /* For split units (in .dwo files) there is only one table
+ at offset zero (containing just the files, no lines). */
+ found = true;
+ break;
+ }
+ }
+
+ if (!found && given_cu != NULL)
+ {
+ /* The CUs might be in a different order from the line
+ tables. Need to do a linear search (but stop at the given
+ CU, since we already searched those. */
+ next_cu = NULL;
+ while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
+ &cudie, NULL) == 0
+ && next_cu != given_cu)
+ {
+ Dwarf_Attribute attr;
+ Dwarf_Word stmt_off;
+ if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
+ &stmt_off) == 0
+ && stmt_off == off)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found)
+ *cu = next_cu;
+ else
+ *cu = NULL;
+ }
+ else
+ *cu = NULL;
+
+ const char *comp_dir;
+ unsigned address_size;
+ if (*cu != NULL)
+ {
+ comp_dir = __libdw_getcompdir (&cudie);
+ address_size = (*cu)->address_size;
+ }
+ else
+ {
+ comp_dir = NULL;
+
+ size_t esize;
+ char *ident = elf_getident (dbg->elf, &esize);
+ if (ident == NULL || esize < EI_NIDENT)
+ goto invalid_data;
+ address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
+ }
+
+ if (__libdw_getsrclines (dbg, off, comp_dir, address_size,
+ srclines, srcfiles) != 0)
+ return -1;
+
+ if (nlines != NULL)
+ {
+ if (srclines != NULL && *srclines != NULL)
+ *nlines = (*srclines)->nlines;
+ else
+ *nlines = 0;
+ }
+
+ if (nfiles != NULL)
+ {
+ if (srcfiles != NULL && *srcfiles != NULL)
+ *nfiles = (*srcfiles)->nfiles;
+ else
+ *nfiles = 0;
+ }
+
+ return 0;
+}
diff --git a/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c
index fa9b0af3..be113270 100644
--- a/libdw/dwarf_nextcu.c
+++ b/libdw/dwarf_nextcu.c
@@ -1,5 +1,5 @@
/* Advance to next CU header.
- Copyright (C) 2002-2010 Red Hat, Inc.
+ Copyright (C) 2002-2010, 2016, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2002.
@@ -39,11 +39,31 @@ int
dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
size_t *header_sizep, Dwarf_Half *versionp,
Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
- uint8_t *offset_sizep, uint64_t *type_signaturep,
- Dwarf_Off *type_offsetp)
+ uint8_t *offset_sizep, uint64_t *v4_type_signaturep,
+ Dwarf_Off *v4_type_offsetp)
{
- const bool debug_types = type_signaturep != NULL;
- const size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
+ const bool v4_debug_types = v4_type_signaturep != NULL;
+ return __libdw_next_unit (dwarf, v4_debug_types, off, next_off,
+ header_sizep, versionp, NULL,
+ abbrev_offsetp, address_sizep, offset_sizep,
+ v4_type_signaturep, v4_type_offsetp);
+}
+INTDEF(dwarf_next_unit)
+
+int
+internal_function
+__libdw_next_unit (Dwarf *dwarf, bool v4_debug_types, Dwarf_Off off,
+ Dwarf_Off *next_off, size_t *header_sizep,
+ Dwarf_Half *versionp, uint8_t *unit_typep,
+ Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
+ uint8_t *offset_sizep, uint64_t *unit_id8p,
+ Dwarf_Off *subdie_offsetp)
+{
+ /* Note that debug_type units come from .debug_types in DWARF < 5 and
+ from .debug_info in DWARF >= 5. If the user requested the
+ v4_type_signature we return from .debug_types always. If no signature
+ is requested we return units (any type) from .debug_info. */
+ const size_t sec_idx = v4_debug_types ? IDX_debug_types : IDX_debug_info;
/* Maybe there has been an error before. */
if (dwarf == NULL)
@@ -61,12 +81,14 @@ dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
return 1;
}
- /* This points into the .debug_info section to the beginning of the
- CU entry. */
+ /* This points into the .debug_info or .debug_types section to the
+ beginning of the CU entry. */
const unsigned char *data = dwarf->sectiondata[sec_idx]->d_buf;
const unsigned char *bytes = data + off;
- /* The format of the CU header is described in dwarf2p1 7.5.1:
+ /* The format of the CU header is described in dwarf2p1 7.5.1 and
+ changed in DWARFv5 (to include unit type, switch location of some
+ fields and add some optional fields).
1. A 4-byte or 12-byte unsigned integer representing the length
of the .debug_info contribution for that compilation unit, not
@@ -74,23 +96,58 @@ dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
this is a 4-byte unsigned integer (which must be less than
0xfffffff0); in the 64-bit DWARF format, this consists of the
4-byte value 0xffffffff followed by an 8-byte unsigned integer
- that gives the actual length (see Section 7.2.2).
+ that gives the actual length (see Section 7.2.2). This field
+ indicates whether this unit is 32-bit of 64-bit DWARF, which
+ affects all other offset fields in this header.
2. A 2-byte unsigned integer representing the version of the
DWARF information for that compilation unit. For DWARF Version
- 2.1, the value in this field is 2.
+ 2.1, the value in this field is 2 (3 for v3, 4 for v4, 5 for v5).
+ This fields determines the order of the next fields and whether
+ there are any optional fields in this header.
- 3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev
+ 3. For DWARF 2, 3 and 4 (including v4 type units):
+ A 4-byte or 8-byte unsigned offset into the .debug_abbrev
section. This offset associates the compilation unit with a
particular set of debugging information entry abbreviations. In
the 32-bit DWARF format, this is a 4-byte unsigned length; in
the 64-bit DWARF format, this is an 8-byte unsigned length (see
Section 7.4).
- 4. A 1-byte unsigned integer representing the size in bytes of
+ For DWARF 5:
+ A 1-byte unsigned integer representing the unit (header) type.
+ This field determines what the optional fields in the header
+ represent. If this is an unknown unit type then we cannot
+ assume anything about the rest of the unit (header).
+
+ 4. For all DWARF versions (including v4 type units):
+ A 1-byte unsigned integer representing the size in bytes of
an address on the target architecture. If the system uses
segmented addressing, this value represents the size of the
- offset portion of an address. */
+ offset portion of an address. This is the last field in the header
+ for DWARF versions 2, 3 and 4 (except for v4 type units).
+
+ 5. For DWARF 5 only (this is field 3 for DWARF 2, 3, 4 and v4 types):
+ A 4-byte or 8-byte unsigned offset into the .debug_abbrev
+ section. This offset associates the compilation unit with a
+ particular set of debugging information entry abbreviations. In
+ the 32-bit DWARF format, this is a 4-byte unsigned length; in
+ the 64-bit DWARF format, this is an 8-byte unsigned length.
+
+ 6. For v4 type units (this is really field 5 for v4 types) and
+ DWARF 5 optional (skeleton, split_compile, type and
+ split_type): An 8 byte (opaque) integer constant value. For
+ v4 and v5 type units this is the type signature. For skeleton
+ and split compile units this is the compilation ID.
+
+ 7. For v4 type units (this is really field 6 for v4 types) and
+ DWARF 5 optional (type and split_type) and v4 type units:
+ A 4-byte or 8-byte unsigned offset. In the 32-bit DWARF format,
+ this is a 4-byte unsigned length; in the 64-bit DWARF format,
+ this is an 8-byte unsigned length. This is the type DIE offset
+ (which is not necessarily the first DIE in the unit).
+ */
+
uint64_t length = read_4ubyte_unaligned_inc (dwarf, bytes);
size_t offset_size = 4;
/* Lengths of 0xfffffff0 - 0xffffffff are escape codes. Oxffffffff is
@@ -106,14 +163,6 @@ dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
return -1;
}
- /* Now we know how large the header is. */
- if (unlikely (DIE_OFFSET_FROM_CU_OFFSET (off, offset_size, debug_types)
- >= dwarf->sectiondata[sec_idx]->d_size))
- {
- *next_off = -1;
- return 1;
- }
-
if (length == DWARF3_LENGTH_64_BIT)
/* This is a 64-bit DWARF format. */
length = read_8ubyte_unaligned_inc (dwarf, bytes);
@@ -121,41 +170,99 @@ dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
/* Read the version stamp. Always a 16-bit value. */
uint_fast16_t version = read_2ubyte_unaligned_inc (dwarf, bytes);
+ /* We keep unit_type at zero for older DWARF since we cannot
+ easily guess whether it is a compile or partial unit. */
+ uint8_t unit_type = 0;
+ if (version >= 5)
+ unit_type = *bytes++;
+
+ /* All these are optional. */
+ Dwarf_Off subdie_off = 0;
+ uint64_t sig_id = 0;
+ Dwarf_Off abbrev_offset = 0;
+ uint8_t address_size = 0;
+
+ if (version < 2 || version > 5
+ || (version == 5 && ! (unit_type == DW_UT_compile
+ || unit_type == DW_UT_partial
+ || unit_type == DW_UT_skeleton
+ || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_type
+ || unit_type == DW_UT_split_type)))
+ {
+ /* We cannot really know more about the header. Just report
+ the length of the unit, version and unit type. */
+ goto done;
+ }
+
+ /* We have to guess the unit_type. But we don't have a real CUDIE. */
+ if (version < 5)
+ unit_type = v4_debug_types ? DW_UT_type : DW_UT_compile;
+
+ /* Now we know how large the header is (should be). */
+ if (unlikely (__libdw_first_die_from_cu_start (off, offset_size, version,
+ unit_type)
+ >= dwarf->sectiondata[sec_idx]->d_size))
+ {
+ *next_off = -1;
+ return 1;
+ }
+
+ /* The address size. Always an 8-bit value.
+ Comes after abbrev_offset for version < 5, otherwise unit type
+ and address size (if a known unit type) comes before abbrev_offset. */
+ if (version >= 5)
+ address_size = *bytes++;
+
/* Get offset in .debug_abbrev. Note that the size of the entry
depends on whether this is a 32-bit or 64-bit DWARF definition. */
- uint64_t abbrev_offset;
if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
&abbrev_offset, IDX_debug_abbrev, 0))
return -1;
- /* The address size. Always an 8-bit value. */
- uint8_t address_size = *bytes++;
+ if (version < 5)
+ address_size = *bytes++;
- if (debug_types)
+ /* Extra fields, signature/id and type offset/padding. */
+ if (v4_debug_types
+ || (version >= 5
+ && (unit_type == DW_UT_skeleton || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_type || unit_type == DW_UT_split_type)))
{
- uint64_t type_sig8 = read_8ubyte_unaligned_inc (dwarf, bytes);
-
- Dwarf_Off type_offset;
- if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
- &type_offset, sec_idx, 0))
- return -1;
+ sig_id = read_8ubyte_unaligned_inc (dwarf, bytes);
+
+ if ((v4_debug_types
+ || unit_type == DW_UT_type || unit_type == DW_UT_split_type))
+ {
+ if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
+ &subdie_off, sec_idx, 0))
+ return -1;
+
+ /* Validate that the TYPE_OFFSET points past the header. */
+ if (unlikely (subdie_off < (size_t) (bytes - (data + off))))
+ goto invalid;
+ }
+ }
- /* Validate that the TYPE_OFFSET points past the header. */
- if (unlikely (type_offset < (size_t) (bytes - (data + off))))
- goto invalid;
+ done:
+ if (unit_id8p != NULL)
+ *unit_id8p = sig_id;
- *type_signaturep = type_sig8;
- if (type_offsetp != NULL)
- *type_offsetp = type_offset;
- }
+ if (subdie_offsetp != NULL)
+ *subdie_offsetp = subdie_off;
- /* Store the header length. */
+ /* Store the header length. This is really how much we have read
+ from the header. If we didn't recognize the unit type the
+ header might actually be bigger. */
if (header_sizep != NULL)
*header_sizep = bytes - (data + off);
if (versionp != NULL)
*versionp = version;
+ if (unit_typep != NULL)
+ *unit_typep = unit_type;
+
if (abbrev_offsetp != NULL)
*abbrev_offsetp = abbrev_offset;
@@ -166,13 +273,18 @@ dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
if (offset_sizep != NULL)
*offset_sizep = offset_size;
- /* See definition of DIE_OFFSET_FROM_CU_OFFSET macro
- for an explanation of the trick in this expression. */
+ /* The length of the unit doesn't include the length field itself.
+ The length field is either, with offset == 4: 2 * 4 - 4 == 4,
+ or with offset == 8: 2 * 8 - 4 == 12. */
*next_off = off + 2 * offset_size - 4 + length;
+ /* This means that the length field is bogus, but return the CU anyway.
+ We just won't return anything after this. */
+ if (*next_off <= off)
+ *next_off = (Dwarf_Off) -1;
+
return 0;
}
-INTDEF(dwarf_next_unit)
int
dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
diff --git a/libdw/dwarf_offdie.c b/libdw/dwarf_offdie.c
index 15f55c22..883720de 100644
--- a/libdw/dwarf_offdie.c
+++ b/libdw/dwarf_offdie.c
@@ -1,5 +1,5 @@
/* Return DIE at given offset.
- Copyright (C) 2002-2010 Red Hat, Inc.
+ Copyright (C) 2002-2010, 2017 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2002.
@@ -45,7 +45,7 @@ __libdw_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result,
Elf_Data *const data = dbg->sectiondata[debug_types ? IDX_debug_types
: IDX_debug_info];
- if (offset >= data->d_size)
+ if (data == NULL || offset >= data->d_size)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
diff --git a/libdw/dwarf_peel_type.c b/libdw/dwarf_peel_type.c
index 6bbfd424..59fc6f15 100644
--- a/libdw/dwarf_peel_type.c
+++ b/libdw/dwarf_peel_type.c
@@ -46,14 +46,19 @@ dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result)
*result = *die;
tag = INTUSE (dwarf_tag) (result);
- while (tag == DW_TAG_typedef
- || tag == DW_TAG_const_type
- || tag == DW_TAG_volatile_type
- || tag == DW_TAG_restrict_type
- || tag == DW_TAG_atomic_type
- || tag == DW_TAG_immutable_type
- || tag == DW_TAG_packed_type
- || tag == DW_TAG_shared_type)
+
+/* Stack 8 of all these modifiers, after that it gets silly. */
+#define MAX_DEPTH (8 * 8)
+ int max_depth = MAX_DEPTH;
+ while ((tag == DW_TAG_typedef
+ || tag == DW_TAG_const_type
+ || tag == DW_TAG_volatile_type
+ || tag == DW_TAG_restrict_type
+ || tag == DW_TAG_atomic_type
+ || tag == DW_TAG_immutable_type
+ || tag == DW_TAG_packed_type
+ || tag == DW_TAG_shared_type)
+ && max_depth-- > 0)
{
Dwarf_Attribute attr_mem;
Dwarf_Attribute *attr = INTUSE (dwarf_attr_integrate) (result, DW_AT_type,
@@ -67,7 +72,7 @@ dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result)
tag = INTUSE (dwarf_tag) (result);
}
- if (tag == DW_TAG_invalid)
+ if (tag == DW_TAG_invalid || max_depth <= 0)
return -1;
return 0;
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
index 4b6853d3..f67d8a5a 100644
--- a/libdw/dwarf_ranges.c
+++ b/libdw/dwarf_ranges.c
@@ -1,5 +1,5 @@
/* Enumerate the PC ranges covered by a DIE.
- Copyright (C) 2005, 2007, 2009 Red Hat, Inc.
+ Copyright (C) 2005, 2007, 2009, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -36,48 +36,427 @@
/* Read up begin/end pair and increment read pointer.
- If it's normal range record, set up `*beginp' and `*endp' and return 0.
+ - If it's a default location, set `*beginp' (0), `*endp' (-1) and return 0.
- If it's base address selection record, set up `*basep' and return 1.
- If it's end of rangelist, don't set anything and return 2
- If an error occurs, don't set anything and return -1. */
internal_function int
-__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
- unsigned char **addrp, int width,
+__libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
+ const unsigned char **addrp,
+ const unsigned char *addrend,
+ int width,
Dwarf_Addr *beginp, Dwarf_Addr *endp,
Dwarf_Addr *basep)
{
- Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
- : (Elf64_Addr) (Elf32_Addr) -1);
- Dwarf_Addr begin;
- Dwarf_Addr end;
+ Dwarf *dbg = cu->dbg;
+ if (sec_index == IDX_debug_loc
+ && cu->version < 5
+ && cu->unit_type == DW_UT_split_compile)
+ {
+ /* GNU DebugFission. */
+ const unsigned char *addr = *addrp;
+ if (addrend - addr < 1)
+ goto invalid;
+
+ const char code = *addr++;
+ uint64_t begin = 0, end = 0, base = *basep, addr_idx;
+ switch (code)
+ {
+ case DW_LLE_GNU_end_of_list_entry:
+ *addrp = addr;
+ return 2;
+
+ case DW_LLE_GNU_base_address_selection_entry:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &base) != 0)
+ return -1;
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_LLE_GNU_start_end_entry:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &end) != 0)
+ return -1;
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_GNU_start_length_entry:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 4)
+ goto invalid;
+ end = read_4ubyte_unaligned_inc (dbg, addr);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ default:
+ goto invalid;
+ }
+ }
+ else if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
+ {
+ Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
+ : (Elf64_Addr) (Elf32_Addr) -1);
+ Dwarf_Addr begin;
+ Dwarf_Addr end;
+
+ const unsigned char *addr = *addrp;
+ if (addrend - addr < width * 2)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+
+ bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
+ begin);
+ bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
+ end);
+ *addrp = addr;
+
+ /* Unrelocated escape for begin means base address selection. */
+ if (begin == escape && !begin_relocated)
+ {
+ if (unlikely (end == escape))
+ goto invalid;
+
+ *basep = end;
+ return 1;
+ }
+
+ /* Unrelocated pair of zeroes means end of range list. */
+ if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
+ return 2;
+
+ /* Don't check for begin_relocated == end_relocated. Serve the data
+ to the client even though it may be buggy. */
+ *beginp = begin + *basep;
+ *endp = end + *basep;
- unsigned char *addr = *addrp;
- bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin);
- bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end);
- *addrp = addr;
+ return 0;
+ }
+ else if (sec_index == IDX_debug_rnglists)
+ {
+ const unsigned char *addr = *addrp;
+ if (addrend - addr < 1)
+ goto invalid;
+
+ const char code = *addr++;
+ uint64_t begin = 0, end = 0, base = *basep, addr_idx;
+ switch (code)
+ {
+ case DW_RLE_end_of_list:
+ *addrp = addr;
+ return 2;
+
+ case DW_RLE_base_addressx:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &base) != 0)
+ return -1;
+
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_RLE_startx_endx:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &end) != 0)
+ return -1;
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_RLE_startx_length:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ case DW_RLE_offset_pair:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (begin, addr, addrend);
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin + base;
+ *endp = end + base;
+ *addrp = addr;
+ return 0;
+
+ case DW_RLE_base_address:
+ if (addrend - addr < width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
+
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_RLE_start_end:
+ if (addrend - addr < 2 * width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_RLE_start_length:
+ if (addrend - addr < width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ default:
+ goto invalid;
+ }
+ }
+ else if (sec_index == IDX_debug_loclists)
+ {
+ const unsigned char *addr = *addrp;
+ if (addrend - addr < 1)
+ goto invalid;
+
+ const char code = *addr++;
+ uint64_t begin = 0, end = 0, base = *basep, addr_idx;
+ switch (code)
+ {
+ case DW_LLE_end_of_list:
+ *addrp = addr;
+ return 2;
+
+ case DW_LLE_base_addressx:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &base) != 0)
+ return -1;
+
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_LLE_startx_endx:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &end) != 0)
+ return -1;
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_startx_length:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_offset_pair:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (begin, addr, addrend);
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin + base;
+ *endp = end + base;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_default_location:
+ *beginp = 0;
+ *endp = (Dwarf_Addr) -1;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_base_address:
+ if (addrend - addr < width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
+
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_LLE_start_end:
+ if (addrend - addr < 2 * width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_start_length:
+ if (addrend - addr < width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ default:
+ goto invalid;
+ }
+ }
+ else
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+}
+
+static int
+initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
+{
+ size_t secidx = (attr->cu->version < 5
+ ? IDX_debug_ranges : IDX_debug_rnglists);
- /* Unrelocated escape for begin means base address selection. */
- if (begin == escape && !begin_relocated)
+ Dwarf_Word start_offset;
+ if (attr->form == DW_FORM_rnglistx)
{
- if (unlikely (end == escape))
+ Dwarf_Word idx;
+ Dwarf_CU *cu = attr->cu;
+ const unsigned char *datap = attr->valp;
+ const unsigned char *endp = cu->endp;
+ if (datap >= endp)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
+ get_uleb128 (idx, datap, endp);
- if (basep != NULL)
- *basep = end;
- return 1;
- }
+ Elf_Data *data = cu->dbg->sectiondata[secidx];
+ if (data == NULL && cu->unit_type == DW_UT_split_compile)
+ {
+ cu = __libdw_find_split_unit (cu);
+ if (cu != NULL)
+ data = cu->dbg->sectiondata[secidx];
+ }
+
+ if (data == NULL)
+ {
+ __libdw_seterrno (secidx == IDX_debug_ranges
+ ? DWARF_E_NO_DEBUG_RANGES
+ : DWARF_E_NO_DEBUG_RNGLISTS);
+ return -1;
+ }
- /* Unrelocated pair of zeroes means end of range list. */
- if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
- return 2;
+ Dwarf_Off range_base_off = __libdw_cu_ranges_base (cu);
- /* Don't check for begin_relocated == end_relocated. Serve the data
- to the client even though it may be buggy. */
- *beginp = begin;
- *endp = end;
+ /* The section should at least contain room for one offset. */
+ size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
+ size_t offset_size = cu->offset_size;
+ if (offset_size > sec_size)
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ /* And the base offset should be at least inside the section. */
+ if (range_base_off > (sec_size - offset_size))
+ goto invalid_offset;
+
+ size_t max_idx = (sec_size - offset_size - range_base_off) / offset_size;
+ if (idx > max_idx)
+ goto invalid_offset;
+
+ datap = (cu->dbg->sectiondata[secidx]->d_buf
+ + range_base_off + (idx * offset_size));
+ if (offset_size == 4)
+ start_offset = read_4ubyte_unaligned (cu->dbg, datap);
+ else
+ start_offset = read_8ubyte_unaligned (cu->dbg, datap);
+
+ start_offset += range_base_off;
+ }
+ else
+ {
+ if (__libdw_formptr (attr, secidx,
+ (secidx == IDX_debug_ranges
+ ? DWARF_E_NO_DEBUG_RANGES
+ : DWARF_E_NO_DEBUG_RNGLISTS),
+ NULL, &start_offset) == NULL)
+ return -1;
+ }
+ *offset = start_offset;
return 0;
}
@@ -101,68 +480,64 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
return 0;
/* We have to look for a noncontiguous range. */
-
- const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
- if (d == NULL && offset != 0)
+ Dwarf_CU *cu = die->cu;
+ if (cu == NULL)
{
- __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
return -1;
}
- unsigned char *readp;
- unsigned char *readendp;
+ size_t secidx = (cu->version < 5 ? IDX_debug_ranges : IDX_debug_rnglists);
+ const Elf_Data *d = cu->dbg->sectiondata[secidx];
+ if (d == NULL && cu->unit_type == DW_UT_split_compile)
+ {
+ Dwarf_CU *skel = __libdw_find_split_unit (cu);
+ if (skel != NULL)
+ {
+ cu = skel;
+ d = cu->dbg->sectiondata[secidx];
+ }
+ }
+
+ const unsigned char *readp;
+ const unsigned char *readendp;
if (offset == 0)
{
Dwarf_Attribute attr_mem;
Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
&attr_mem);
+ if (attr == NULL
+ && is_cudie (die)
+ && die->cu->unit_type == DW_UT_split_compile)
+ attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_ranges, &attr_mem);
if (attr == NULL)
/* No PC attributes in this DIE at all, so an empty range list. */
return 0;
- Dwarf_Word start_offset;
- if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
- DWARF_E_NO_DEBUG_RANGES,
- &readendp, &start_offset)) == NULL)
+ *basep = __libdw_cu_base_address (attr->cu);
+ if (*basep == (Dwarf_Addr) -1)
return -1;
- offset = start_offset;
- assert ((Dwarf_Word) offset == start_offset);
-
- /* Fetch the CU's base address. */
- Dwarf_Die cudie = CUDIE (attr->cu);
-
- /* Find the base address of the compilation unit. It will
- normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
- the base address could be overridden by DW_AT_entry_pc. It's
- been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
- for compilation units with discontinuous ranges. */
- if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
- && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
- DW_AT_entry_pc,
- &attr_mem),
- basep) != 0)
- *basep = (Dwarf_Addr) -1;
+ if (initial_offset (attr, &offset) != 0)
+ return -1;
}
else
{
- if (__libdw_offset_in_section (die->cu->dbg,
- IDX_debug_ranges, offset, 1))
- return -1l;
-
- readp = d->d_buf + offset;
- readendp = d->d_buf + d->d_size;
+ if (__libdw_offset_in_section (cu->dbg,
+ secidx, offset, 1))
+ return -1;
}
- next:
- if (readendp - readp < die->cu->address_size * 2)
- goto invalid;
+ readp = d->d_buf + offset;
+ readendp = d->d_buf + d->d_size;
Dwarf_Addr begin;
Dwarf_Addr end;
- switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
- &readp, die->cu->address_size,
+ next:
+ switch (__libdw_read_begin_end_pair_inc (cu, secidx,
+ &readp, readendp,
+ cu->address_size,
&begin, &end, basep))
{
case 0:
@@ -172,22 +547,11 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
case 2:
return 0;
default:
- return -1l;
- }
-
- /* We have an address range entry. Check that we have a base. */
- if (*basep == (Dwarf_Addr) -1)
- {
- if (INTUSE(dwarf_errno) () == 0)
- {
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- }
return -1;
}
- *startp = *basep + begin;
- *endp = *basep + end;
+ *startp = begin;
+ *endp = end;
return readp - (unsigned char *) d->d_buf;
}
INTDEF (dwarf_ranges)
diff --git a/libdw/dwarf_setalt.c b/libdw/dwarf_setalt.c
index 9bd566ff..9051b8e0 100644
--- a/libdw/dwarf_setalt.c
+++ b/libdw/dwarf_setalt.c
@@ -1,5 +1,5 @@
/* Provides the data referenced by the .gnu_debugaltlink section.
- Copyright (C) 2014 Red Hat, Inc.
+ Copyright (C) 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -32,9 +32,18 @@
#include "libdwP.h"
+#include <unistd.h>
+
void
dwarf_setalt (Dwarf *main, Dwarf *alt)
{
+ if (main->alt_fd != -1)
+ {
+ INTUSE(dwarf_end) (main->alt_dwarf);
+ close (main->alt_fd);
+ main->alt_fd = -1;
+ }
+
main->alt_dwarf = alt;
}
INTDEF (dwarf_setalt)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
index df39c1cb..613d2090 100644
--- a/libdw/dwarf_siblingof.c
+++ b/libdw/dwarf_siblingof.c
@@ -58,8 +58,6 @@ dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
sibattr.cu = this_die.cu;
/* That's the address we start looking. */
unsigned char *addr = this_die.addr;
- /* End of the buffer. */
- unsigned char *endp = sibattr.cu->endp;
/* Search for the beginning of the next die on this level. We
must not return the dies for children of the given die. */
@@ -96,6 +94,8 @@ dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
/* This abbreviation has children. */
++level;
+ /* End of the buffer. */
+ unsigned char *endp = sibattr.cu->endp;
while (1)
{
@@ -125,6 +125,7 @@ dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
while (level > 0);
/* Maybe we reached the end of the CU. */
+ unsigned char *endp = sibattr.cu->endp;
if (addr >= endp)
return 1;
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 63a38ff9..e20961be 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -1,5 +1,5 @@
/* Interfaces for libdw.
- Copyright (C) 2002-2010, 2013, 2014, 2016 Red Hat, Inc.
+ Copyright (C) 2002-2010, 2013, 2014, 2016, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -211,7 +211,9 @@ typedef union
Dwarf_FDE fde;
} Dwarf_CFI_Entry;
-#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == DW_CIE_ID_64)
+/* Same as DW_CIE_ID_64 from dwarf.h to keep libdw.h independent. */
+#define LIBDW_CIE_ID 0xffffffffffffffffULL
+#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == LIBDW_CIE_ID)
/* Opaque type representing a frame state described by CFI. */
typedef struct Dwarf_Frame_s Dwarf_Frame;
@@ -248,7 +250,9 @@ extern Elf *dwarf_getelf (Dwarf *dwarf);
extern Dwarf *dwarf_cu_getdwarf (Dwarf_CU *cu);
/* Retrieves the DWARF descriptor for debugaltlink data. Returns NULL
- if no alternate debug data has been supplied. */
+ if no alternate debug data has been supplied yet. libdw will try
+ to set the alt file on first use of an alt FORM if not yet explicitly
+ provided by dwarf_setalt. */
extern Dwarf *dwarf_getalt (Dwarf *main);
/* Provides the data referenced by the .gnu_debugaltlink section. The
@@ -256,16 +260,15 @@ extern Dwarf *dwarf_getalt (Dwarf *main);
same build ID). It is the responsibility of the caller to ensure
that the data referenced by ALT stays valid while it is used by
MAIN, until dwarf_setalt is called on MAIN with a different
- descriptor, or dwarf_end. */
+ descriptor, or dwarf_end. Must be called before inspecting DIEs
+ that might have alt FORMs. Otherwise libdw will try to set the
+ alt file itself on first use. */
extern void dwarf_setalt (Dwarf *main, Dwarf *alt);
/* Release debugging handling context. */
extern int dwarf_end (Dwarf *dwarf);
-/* Get the data block for the .debug_info section. */
-extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf);
-
/* Read the header for the DWARF CU. */
extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
@@ -283,6 +286,33 @@ extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
__nonnull_attribute__ (3);
+/* Gets the next Dwarf_CU (unit), version, unit type and if available
+ the CU DIE and sub (type) DIE of the unit. Returns 0 on success,
+ -1 on error or 1 if there are no more units. To start iterating
+ provide NULL for CU. If version < 5 the unit type is set from the
+ CU DIE if available (DW_UT_compile for DW_TAG_compile_unit,
+ DW_UT_type for DW_TAG_type_unit or DW_UT_partial for
+ DW_TAG_partial_unit), otherwise it is set to zero. If unavailable
+ (the version or unit type is unknown) the CU DIE is cleared.
+ Likewise if the sub DIE isn't isn't available (the unit type is not
+ DW_UT_type or DW_UT_split_type) the sub DIE tag is cleared. */
+extern int dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie)
+ __nonnull_attribute__ (3);
+
+/* Provides information and DIEs associated with the given Dwarf_CU
+ unit. Returns -1 on error, zero on success. Arguments not needed
+ may be NULL. If they are NULL and aren't known yet, they won't be
+ looked up. If the subdie doesn't exist for this unit_type it will
+ be cleared. If there is no unit_id for this unit type it will be
+ set to zero. */
+extern int dwarf_cu_info (Dwarf_CU *cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie,
+ uint64_t *unit_id,
+ uint8_t *address_size, uint8_t *offset_size);
+
/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
The E_IDENT from the originating ELF file indicates the address
size and byte order used in the CFI section contained in DATA;
@@ -344,6 +374,18 @@ extern Dwarf_Die *dwarf_diecu (Dwarf_Die *die, Dwarf_Die *result,
uint8_t *address_sizep, uint8_t *offset_sizep)
__nonnull_attribute__ (2);
+/* Given a Dwarf_Die addr returns a (reconstructed) Dwarf_Die, or NULL
+ if the given addr didn't come from a valid Dwarf_Die. In particular
+ it will make sure that the correct Dwarf_CU pointer is set for the
+ Dwarf_Die, the Dwarf_Abbrev pointer will not be set up yet (it will
+ only be once the Dwarf_Die is used to read attributes, children or
+ siblings). This functions can be used to keep a reference to a
+ Dwarf_Die which you want to refer to later. The addr, and the result
+ of this function, is only valid while the associated Dwarf is valid. */
+extern Dwarf_Die *dwarf_die_addr_die (Dwarf *dbg, void *addr,
+ Dwarf_Die *result)
+ __nonnull_attribute__ (3);
+
/* Return the CU DIE and the header info associated with a Dwarf_Die
or Dwarf_Attribute. A Dwarf_Die or a Dwarf_Attribute is associated
with a particular Dwarf_CU handle. This function returns the CU or
@@ -561,6 +603,12 @@ extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx,
unsigned int *namep, unsigned int *formp,
Dwarf_Off *offset);
+/* Get specific attribute of abbreviation and any data encoded with it.
+ Specifically for DW_FORM_implicit_const data will be set to the
+ constant value associated. */
+extern int dwarf_getabbrevattr_data (Dwarf_Abbrev *abbrev, size_t idx,
+ unsigned int *namep, unsigned int *formp,
+ Dwarf_Sword *datap, Dwarf_Off *offset);
/* Get string from-debug_str section. */
extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset,
@@ -640,11 +688,15 @@ extern int dwarf_linediscriminator (Dwarf_Line *line, unsigned int *discp)
__nonnull_attribute__ (2);
-/* Find line information for address. */
+/* Find line information for address. The returned string is NULL when
+ an error occured, or the file path. The file path is either absolute
+ or relative to the compilation directory. See dwarf_decl_file. */
extern const char *dwarf_linesrc (Dwarf_Line *line,
Dwarf_Word *mtime, Dwarf_Word *length);
-/* Return file information. */
+/* Return file information. The returned string is NULL when
+ an error occured, or the file path. The file path is either absolute
+ or relative to the compilation directory. See dwarf_decl_file. */
extern const char *dwarf_filesrc (Dwarf_Files *file, size_t idx,
Dwarf_Word *mtime, Dwarf_Word *length);
@@ -661,6 +713,24 @@ extern int dwarf_getsrcdirs (Dwarf_Files *files,
const char *const **result, size_t *ndirs)
__nonnull_attribute__ (2, 3);
+/* Iterates through the debug line units. Returns 0 on success, -1 on
+ error or 1 if there are no more units. To start iterating use zero
+ for OFF and set *CU to NULL. On success NEXT_OFF will be set to
+ the next offset to use. The *CU will be set if this line table
+ needed a specific CU and needs to be given when calling
+ dwarf_next_lines again (to help dwarf_next_lines quickly find the
+ next CU). *CU might be set to NULL when it couldn't be found (the
+ compilation directory entry will be the empty string in that case)
+ or for DWARF 5 or later tables, which are self contained. SRCFILES
+ and SRCLINES may be NULL if the caller is not interested in the
+ actual line or file table. On success and when not NULL, NFILES
+ and NLINES will be set to the number of files in the file table and
+ number of lines in the line table. */
+extern int dwarf_next_lines (Dwarf *dwarf, Dwarf_Off off,
+ Dwarf_Off *next_off, Dwarf_CU **cu,
+ Dwarf_Files **srcfiles, size_t *nfiles,
+ Dwarf_Lines **srclines, size_t *nlines)
+ __nonnull_attribute__ (3,4);
/* Return location expression, decoded as a list of operations. */
extern int dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **expr,
@@ -816,7 +886,14 @@ extern ptrdiff_t dwarf_getfuncs (Dwarf_Die *cudie,
void *arg, ptrdiff_t offset);
-/* Return file name containing definition of the given declaration. */
+/* Return file name containing definition of the given declaration.
+ Of the DECL has an (indirect, see dwarf_attr_integrate) decl_file
+ attribute. The returned file path is either absolute, or relative
+ to the compilation directory. Given the decl DIE, the compilation
+ directory can be retrieved through:
+ dwarf_formstring (dwarf_attr (dwarf_diecu (decl, &cudie, NULL, NULL),
+ DW_AT_comp_dir, &attr));
+ Returns NULL if no decl_file could be found or an error occured. */
extern const char *dwarf_decl_file (Dwarf_Die *decl);
/* Get line number of beginning of given declaration. */
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 14307056..3fef2ede 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -49,7 +49,6 @@ ELFUTILS_0.122 {
dwarf_getlocation_addr;
dwarf_getmacros;
dwarf_getpubnames;
- dwarf_getscn_info;
dwarf_getscopes;
dwarf_getscopes_die;
dwarf_getscopevar;
@@ -344,3 +343,16 @@ ELFUTILS_0.170 {
dwarf_default_lower_bound;
dwarf_line_file;
} ELFUTILS_0.167;
+
+ELFUTILS_0.171 {
+ global:
+ dwarf_die_addr_die;
+ dwarf_get_units;
+ dwarf_getabbrevattr_data;
+ dwarf_cu_info;
+} ELFUTILS_0.170;
+
+ELFUTILS_0.173 {
+ global:
+ dwarf_next_lines;
+} ELFUTILS_0.171;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 6ad322c1..eebb7d12 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -1,7 +1,6 @@
-/* Internal definitions for libdwarf.
- Copyright (C) 2002-2011, 2013-2016 Red Hat, Inc.
+/* Internal definitions for libdw.
+ Copyright (C) 2002-2011, 2013-2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2002.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -74,14 +73,19 @@ enum
IDX_debug_types,
IDX_debug_abbrev,
IDX_debug_aranges,
+ IDX_debug_addr,
IDX_debug_line,
+ IDX_debug_line_str,
IDX_debug_frame,
IDX_debug_loc,
+ IDX_debug_loclists,
IDX_debug_pubnames,
IDX_debug_str,
+ IDX_debug_str_offsets,
IDX_debug_macinfo,
IDX_debug_macro,
IDX_debug_ranges,
+ IDX_debug_rnglists,
IDX_gnu_debugaltlink,
IDX_last
};
@@ -108,6 +112,9 @@ enum
DWARF_E_NO_ENTRY,
DWARF_E_INVALID_DWARF,
DWARF_E_NO_STRING,
+ DWARF_E_NO_DEBUG_STR,
+ DWARF_E_NO_DEBUG_LINE_STR,
+ DWARF_E_NO_STR_OFFSETS,
DWARF_E_NO_ADDR,
DWARF_E_NO_CONSTANT,
DWARF_E_NO_REFERENCE,
@@ -118,7 +125,9 @@ enum
DWARF_E_VERSION,
DWARF_E_INVALID_DIR_IDX,
DWARF_E_ADDR_OUTOFRANGE,
- DWARF_E_NO_LOCLIST,
+ DWARF_E_NO_DEBUG_LOC,
+ DWARF_E_NO_DEBUG_LOCLISTS,
+ DWARF_E_NO_LOC_VALUE,
DWARF_E_NO_BLOCK,
DWARF_E_INVALID_LINE_IDX,
DWARF_E_INVALID_ARANGE_IDX,
@@ -126,11 +135,13 @@ enum
DWARF_E_NO_FLAG,
DWARF_E_INVALID_OFFSET,
DWARF_E_NO_DEBUG_RANGES,
+ DWARF_E_NO_DEBUG_RNGLISTS,
DWARF_E_INVALID_CFI,
DWARF_E_NO_ALT_DEBUGLINK,
DWARF_E_INVALID_OPCODE,
DWARF_E_NOT_CUDIE,
DWARF_E_UNKNOWN_LANGUAGE,
+ DWARF_E_NO_DEBUG_ADDR,
};
@@ -142,6 +153,10 @@ struct Dwarf
/* The underlying ELF file. */
Elf *elf;
+ /* The (absolute) path to the ELF dir, if known. To help locating
+ alt and dwo files. */
+ char *debugdir;
+
/* dwz alternate DWARF file. */
Dwarf *alt_dwarf;
@@ -154,6 +169,10 @@ struct Dwarf
/* If true, we allocated the ELF descriptor ourselves. */
bool free_elf;
+ /* If >= 0, we allocated the alt_dwarf ourselves and must end it and
+ close this file descriptor. */
+ int alt_fd;
+
/* Information for traversing the .debug_pubnames section. This is
an array and separately allocated with malloc. */
struct pubnames_s
@@ -174,6 +193,9 @@ struct Dwarf
Dwarf_Off next_tu_offset;
Dwarf_Sig8_Hash sig8_hash;
+ /* Search tree for split Dwarf associated with CUs in this debug. */
+ void *split_tree;
+
/* Search tree for .debug_macro operator tables. */
void *macro_ops;
@@ -187,8 +209,14 @@ struct Dwarf
struct Dwarf_CFI_s *cfi;
/* Fake loc CU. Used when synthesizing attributes for Dwarf_Ops that
- came from a location list entry in dwarf_getlocation_attr. */
+ came from a location list entry in dwarf_getlocation_attr.
+ Depending on version this is the .debug_loc or .debug_loclists
+ section (could be both if mixing CUs with different DWARF versions). */
struct Dwarf_CU *fake_loc_cu;
+ struct Dwarf_CU *fake_loclists_cu;
+
+ /* Similar for addrx/constx, which will come from .debug_addr section. */
+ struct Dwarf_CU *fake_addr_cu;
/* Internal memory handling. This is basically a simplified
reimplementation of obstacks. Unfortunately the standard obstack
@@ -212,13 +240,12 @@ struct Dwarf
/* Abbreviation representation. */
struct Dwarf_Abbrev
{
- Dwarf_Off offset;
- unsigned char *attrp;
- unsigned int attrcnt;
- unsigned int code;
- unsigned int tag;
- bool has_children;
-};
+ Dwarf_Off offset; /* Offset to start of abbrev into .debug_abbrev. */
+ unsigned char *attrp; /* Pointer to start of attribute name/form pairs. */
+ bool has_children : 1; /* Whether or not the DIE has children. */
+ unsigned int code : 31; /* The (unique) abbrev code. */
+ unsigned int tag; /* The tag of the DIE. */
+} attribute_packed;
#include "dwarf_abbrev_hash.h"
@@ -293,9 +320,23 @@ struct Dwarf_CU
uint8_t offset_size;
uint16_t version;
- /* Zero if this is a normal CU. Nonzero if it is a type unit. */
- size_t type_offset;
- uint64_t type_sig8;
+ size_t sec_idx; /* Normally .debug_info, could be .debug_type or "fake". */
+
+ /* The unit type if version >= 5. Otherwise 0 for normal CUs (from
+ .debug_info) or 1 for v4 type units (from .debug_types). */
+ uint8_t unit_type;
+
+ /* Zero if the unit type doesn't support a die/type offset and/or id/sig.
+ Nonzero if it is a v4 type unit or for DWARFv5 units depending on
+ unit_type. */
+ size_t subdie_offset;
+ uint64_t unit_id8;
+
+ /* If this is a skeleton unit this points to the split compile unit.
+ Or the other way around if this is a split compile unit. Set to -1
+ if not yet searched. Always use __libdw_find_split_unit to access
+ this field. */
+ struct Dwarf_CU *split;
/* Hash table for the abbreviations. */
Dwarf_Abbrev_Hash abbrev_hash;
@@ -313,13 +354,57 @@ struct Dwarf_CU
/* Known location lists. */
void *locs;
+ /* Base address for use with ranges and locs.
+ Don't access directly, call __libdw_cu_base_address. */
+ Dwarf_Addr base_address;
+
+ /* The offset into the .debug_addr section where index zero begins.
+ Don't access directly, call __libdw_cu_addr_base. */
+ Dwarf_Off addr_base;
+
+ /* The offset into the .debug_str_offsets section where index zero begins.
+ Don't access directly, call __libdw_cu_str_off_base. */
+ Dwarf_Off str_off_base;
+
+ /* The offset into the .debug_ranges section to use for GNU
+ DebugFission split units. Don't access directly, call
+ __libdw_cu_ranges_base. */
+ Dwarf_Off ranges_base;
+
+ /* The start of the offset table in .debug_loclists.
+ Don't access directly, call __libdw_cu_locs_base. */
+ Dwarf_Off locs_base;
+
/* Memory boundaries of this CU. */
void *startp;
void *endp;
};
-/* Compute the offset of a CU's first DIE from its offset. This
- is either:
+#define ISV4TU(cu) ((cu)->version == 4 && (cu)->sec_idx == IDX_debug_types)
+
+/* Compute the offset of a CU's first DIE from the CU offset.
+ CU must be a valid/known version/unit_type. */
+static inline Dwarf_Off
+__libdw_first_die_from_cu_start (Dwarf_Off cu_start,
+ uint8_t offset_size,
+ uint16_t version,
+ uint8_t unit_type)
+{
+/*
+ assert (offset_size == 4 || offset_size == 8);
+ assert (version >= 2 && version <= 5);
+ assert (unit_type == DW_UT_compile
+ || unit_type == DW_UT_partial
+ || unit_type == DW_UT_skeleton
+ || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_type
+ || unit_type == DW_UT_split_type);
+*/
+
+ Dwarf_Off off = cu_start;
+ if (version < 5)
+ {
+ /*
LEN VER OFFSET ADDR
4-bytes + 2-bytes + 4-bytes + 1-byte for 32-bit dwarf
12-bytes + 2-bytes + 8-bytes + 1-byte for 64-bit dwarf
@@ -328,22 +413,61 @@ struct Dwarf_CU
12-bytes + 2-bytes + 8-bytes + 1-byte + 8-bytes + 8-bytes for 64-bit
Note the trick in the computation. If the offset_size is 4
- the '- 4' term changes the '3 *' into a '2 *'. If the
- offset_size is 8 it accounts for the 4-byte escape value
+ the '- 4' term changes the '3 *' (or '4 *') into a '2 *' (or '3 *).
+ If the offset_size is 8 it accounts for the 4-byte escape value
used at the start of the length. */
-#define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size, type_unit) \
- ((type_unit) ? ((cu_offset) + 4 * (offset_size) - 4 + 3 + 8) \
- : ((cu_offset) + 3 * (offset_size) - 4 + 3))
+ if (unit_type != DW_UT_type)
+ off += 3 * offset_size - 4 + 3;
+ else
+ off += 4 * offset_size - 4 + 3 + 8;
+ }
+ else
+ {
+ /*
+ LEN VER TYPE ADDR OFFSET SIGNATURE TYPE-OFFSET
+ 4-bytes + 2-bytes + 1-byte + 1-byte + 4-bytes + 8-bytes + 4-bytes 32-bit
+ 12-bytes + 2-bytes + 1-byte + 1-byte + 8-bytes + 8-bytes + 8-bytes 64-bit
+ Both signature and type offset are optional.
+
+ Note same 4/8 offset size trick as above.
+ We explicitly ignore unknow unit types (see asserts above). */
+ off += 3 * offset_size - 4 + 4;
+ if (unit_type == DW_UT_skeleton || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ {
+ off += 8;
+ if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ off += offset_size;
+ }
+ }
+
+ return off;
+}
+
+static inline Dwarf_Off
+__libdw_first_die_off_from_cu (struct Dwarf_CU *cu)
+{
+ return __libdw_first_die_from_cu_start (cu->start,
+ cu->offset_size,
+ cu->version,
+ cu->unit_type);
+}
#define CUDIE(fromcu) \
((Dwarf_Die) \
{ \
.cu = (fromcu), \
- .addr = ((char *) fromcu->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \
- + DIE_OFFSET_FROM_CU_OFFSET ((fromcu)->start, \
- (fromcu)->offset_size, \
- (fromcu)->type_offset != 0)) \
- }) \
+ .addr = ((char *) (fromcu)->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \
+ + __libdw_first_die_off_from_cu (fromcu)) \
+ })
+
+#define SUBDIE(fromcu) \
+ ((Dwarf_Die) \
+ { \
+ .cu = (fromcu), \
+ .addr = ((char *) (fromcu)->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \
+ + (fromcu)->start + (fromcu)->subdie_offset) \
+ })
/* Prototype of a single .debug_macro operator. */
@@ -399,6 +523,44 @@ libdw_macro_nforms (Dwarf_Macro *macro)
return macro->table->table[macro->table->opcodes[macro->opcode - 1]].nforms;
}
+/* Returns true for any allowed FORM in the opcode_operands_table as
+ mentioned in the DWARF5 spec (6.3.1 Macro Information Header).
+ Or those mentioned in DWARF5 spec (6.2.4.2 Vendor-defined Content
+ Descriptions) for the directory/file table (plus DW_FORM_strp_sup). */
+static inline bool
+libdw_valid_user_form (int form)
+{
+ switch (form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data16:
+ case DW_FORM_flag:
+ case DW_FORM_line_strp:
+ case DW_FORM_sdata:
+ case DW_FORM_sec_offset:
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ case DW_FORM_strp_sup:
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ case DW_FORM_udata:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
/* We have to include the file at this point because the inline
functions access internals of the Dwarf structure. */
#include "memory-access.h"
@@ -434,7 +596,19 @@ extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
__attribute__ ((__malloc__)) __nonnull_attribute__ (1);
/* Default OOM handler. */
-extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden")));
+extern void __libdw_oom (void) __attribute ((noreturn)) attribute_hidden;
+
+/* Read next unit (or v4 debug type) and return next offset. Doesn't
+ create an actual Dwarf_CU just provides necessary header fields. */
+extern int
+internal_function
+__libdw_next_unit (Dwarf *dbg, bool v4_debug_types, Dwarf_Off off,
+ Dwarf_Off *next_off, size_t *header_sizep,
+ Dwarf_Half *versionp, uint8_t *unit_typep,
+ Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
+ uint8_t *offset_sizep, uint64_t *unit_id8p,
+ Dwarf_Off *subdie_offsetp)
+ __nonnull_attribute__ (4) internal_function;
/* Allocate the internal data for a unit not seen before. */
extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
@@ -444,6 +618,18 @@ extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu)
__nonnull_attribute__ (1) internal_function;
+/* Find CU for given DIE address. */
+extern struct Dwarf_CU *__libdw_findcu_addr (Dwarf *dbg, void *addr)
+ __nonnull_attribute__ (1) internal_function;
+
+/* Find split Dwarf for given DIE address. */
+extern struct Dwarf *__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
+ __nonnull_attribute__ (1) internal_function;
+
+/* Find the split (or skeleton) unit. */
+extern struct Dwarf_CU *__libdw_find_split_unit (Dwarf_CU *cu)
+ internal_function;
+
/* Get abbreviation with given code. */
extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
unsigned int code)
@@ -467,6 +653,9 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp)
/* Get the abbreviation code. */
unsigned int code;
const unsigned char *addr = die->addr;
+ if (unlikely (die->cu == NULL
+ || addr >= (const unsigned char *) die->cu->endp))
+ return die->abbrev = DWARF_END_ABBREV;
get_uleb128 (code, addr, die->cu->endp);
if (readp != NULL)
*readp = addr;
@@ -484,7 +673,7 @@ extern size_t __libdw_form_val_compute_len (struct Dwarf_CU *cu,
const unsigned char *valp)
__nonnull_attribute__ (1, 3) internal_function;
-/* Find the length of a form attribute. */
+/* Find the length of a form attribute in DIE/info data. */
static inline size_t
__nonnull_attribute__ (1, 3)
__libdw_form_val_len (struct Dwarf_CU *cu, unsigned int form,
@@ -495,10 +684,24 @@ __libdw_form_val_len (struct Dwarf_CU *cu, unsigned int form,
static const uint8_t form_lengths[] =
{
[DW_FORM_flag_present] = 0x80,
- [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1, [DW_FORM_flag] = 1,
+ [DW_FORM_implicit_const] = 0x80, /* Value is in abbrev, not in info. */
+
+ [DW_FORM_flag] = 1,
+ [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1,
+ [DW_FORM_addrx1] = 1, [DW_FORM_strx1] = 1,
+
[DW_FORM_data2] = 2, [DW_FORM_ref2] = 2,
- [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4,
- [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sig8] = 8,
+ [DW_FORM_addrx2] = 2, [DW_FORM_strx2] = 2,
+
+ [DW_FORM_addrx3] = 3, [DW_FORM_strx3] = 3,
+
+ [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4, [DW_FORM_ref_sup4] = 4,
+ [DW_FORM_addrx4] = 4, [DW_FORM_strx4] = 4,
+
+ [DW_FORM_ref_sig8] = 8,
+ [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sup8] = 8,
+
+ [DW_FORM_data16] = 16,
};
/* Return immediately for forms with fixed lengths. */
@@ -626,7 +829,8 @@ __libdw_offset_in_section (Dwarf *dbg, int sec_index,
if (data == NULL)
return -1;
if (unlikely (offset > data->d_size)
- || unlikely (data->d_size - offset < size))
+ || unlikely (data->d_size < size)
+ || unlikely (offset > data->d_size - size))
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
return -1;
@@ -643,7 +847,8 @@ __libdw_in_section (Dwarf *dbg, int sec_index,
if (data == NULL)
return false;
if (unlikely (addr < data->d_buf)
- || unlikely (data->d_size - (addr - data->d_buf) < size))
+ || unlikely (data->d_size < size)
+ || unlikely ((size_t)(addr - data->d_buf) > data->d_size - size))
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
return false;
@@ -714,13 +919,13 @@ __libdw_read_offset (Dwarf *dbg, Dwarf *dbg_ret,
static inline size_t
cu_sec_idx (struct Dwarf_CU *cu)
{
- return cu->type_offset == 0 ? IDX_debug_info : IDX_debug_types;
+ return cu->sec_idx;
}
static inline bool
is_cudie (Dwarf_Die *cudie)
{
- return CUDIE (cudie->cu).addr == cudie->addr;
+ return cudie->cu != NULL && CUDIE (cudie->cu).addr == cudie->addr;
}
/* Read up begin/end pair and increment read pointer.
@@ -728,15 +933,18 @@ is_cudie (Dwarf_Die *cudie)
- If it's base address selection record, set up *BASEP and return 1.
- If it's end of rangelist, don't set anything and return 2
- If an error occurs, don't set anything and return <0. */
-int __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
- unsigned char **addr, int width,
+int __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
+ const unsigned char **readp,
+ const unsigned char *readend,
+ int width,
Dwarf_Addr *beginp, Dwarf_Addr *endp,
Dwarf_Addr *basep)
internal_function;
-unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
- int err_nodata, unsigned char **endpp,
- Dwarf_Off *offsetp)
+const unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
+ int err_nodata,
+ const unsigned char **endpp,
+ Dwarf_Off *offsetp)
internal_function;
/* Fills in the given attribute to point at an empty location expression. */
@@ -757,6 +965,363 @@ int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
/* Load and return value of DW_AT_comp_dir from CUDIE. */
const char *__libdw_getcompdir (Dwarf_Die *cudie);
+/* Get the base address for the CU, fetches it when not yet set.
+ This is used as initial base address for ranges and loclists. */
+Dwarf_Addr __libdw_cu_base_address (Dwarf_CU *cu);
+
+/* Get the address base for the CU, fetches it when not yet set. */
+static inline Dwarf_Off
+__libdw_cu_addr_base (Dwarf_CU *cu)
+{
+ if (cu->addr_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ Dwarf_Off offset = 0;
+ if (dwarf_attr (&cu_die, DW_AT_GNU_addr_base, &attr) != NULL
+ || dwarf_attr (&cu_die, DW_AT_addr_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+ cu->addr_base = offset;
+ }
+
+ return cu->addr_base;
+}
+
+/* Gets the .debug_str_offsets base offset to use. static inline to
+ be shared between libdw and eu-readelf. */
+static inline Dwarf_Off
+str_offsets_base_off (Dwarf *dbg, Dwarf_CU *cu)
+{
+ /* If we don't have a CU, then find and use the first one in the
+ debug file (when we support .dwp files, we must actually find the
+ one matching our "caller" - aka macro or line). If we (now) have
+ a cu and str_offsets_base attribute, just use that. Otherwise
+ use the first offset. But we might have to parse the header
+ first, but only if this is version 5. Assume if all else fails,
+ this is version 4, without header. */
+
+ if (cu == NULL && dbg != NULL)
+ {
+ Dwarf_CU *first_cu;
+ if (dwarf_get_units (dbg, NULL, &first_cu,
+ NULL, NULL, NULL, NULL) == 0)
+ cu = first_cu;
+ }
+
+ if (cu != NULL)
+ {
+ if (cu->str_off_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (dwarf_attr (&cu_die, DW_AT_str_offsets_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ {
+ cu->str_off_base = off;
+ return cu->str_off_base;
+ }
+ }
+ /* For older DWARF simply assume zero (no header). */
+ if (cu->version < 5)
+ {
+ cu->str_off_base = 0;
+ return cu->str_off_base;
+ }
+
+ if (dbg == NULL)
+ dbg = cu->dbg;
+ }
+ else
+ return cu->str_off_base;
+ }
+
+ /* No str_offsets_base attribute, we have to assume "zero".
+ But there could be a header first. */
+ Dwarf_Off off = 0;
+ if (dbg == NULL)
+ goto no_header;
+
+ Elf_Data *data = dbg->sectiondata[IDX_debug_str_offsets];
+ if (data == NULL)
+ goto no_header;
+
+ const unsigned char *start;
+ const unsigned char *readp;
+ const unsigned char *readendp;
+ start = readp = (const unsigned char *) data->d_buf;
+ readendp = (const unsigned char *) data->d_buf + data->d_size;
+
+ uint64_t unit_length;
+ uint16_t version;
+
+ unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+ if (unlikely (unit_length == 0xffffffff))
+ {
+ if (unlikely (readendp - readp < 8))
+ goto no_header;
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ /* In theory the offset size could be different
+ between CU and str_offsets unit. But we just
+ ignore that here. */
+ }
+
+ /* We need at least 2-bytes (version) + 2-bytes (padding) =
+ 4 bytes to complete the header. And this unit cannot go
+ beyond the section data. */
+ if (readendp - readp < 4
+ || unit_length < 4
+ || (uint64_t) (readendp - readp) < unit_length)
+ goto no_header;
+
+ version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 5)
+ goto no_header;
+ /* padding */
+ read_2ubyte_unaligned_inc (dbg, readp);
+
+ off = (Dwarf_Off) (readp - start);
+
+ no_header:
+ if (cu != NULL)
+ cu->str_off_base = off;
+
+ return off;
+}
+
+
+/* Get the string offsets base for the CU, fetches it when not yet set. */
+static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
+{
+ return str_offsets_base_off (NULL, cu);
+}
+
+
+/* Either a direct offset into .debug_ranges for version < 5, or the
+ start of the offset table in .debug_rnglists for version > 5. */
+static inline Dwarf_Off
+__libdw_cu_ranges_base (Dwarf_CU *cu)
+{
+ if (cu->ranges_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Off offset = 0;
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (cu->version < 5)
+ {
+ if (dwarf_attr (&cu_die, DW_AT_GNU_ranges_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+ }
+ else
+ {
+ if (dwarf_attr (&cu_die, DW_AT_rnglists_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+
+ /* There wasn't an rnglists_base, if the Dwarf does have a
+ .debug_rnglists section, then it might be we need the
+ base after the first header. */
+ Elf_Data *data = cu->dbg->sectiondata[IDX_debug_rnglists];
+ if (offset == 0 && data != NULL)
+ {
+ Dwarf *dbg = cu->dbg;
+ const unsigned char *readp = data->d_buf;
+ const unsigned char *const dataend
+ = (unsigned char *) data->d_buf + data->d_size;
+
+ uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+ unsigned int offset_size = 4;
+ if (unlikely (unit_length == 0xffffffff))
+ {
+ if (unlikely (readp > dataend - 8))
+ goto no_header;
+
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ offset_size = 8;
+ }
+
+ if (readp > dataend - 8
+ || unit_length < 8
+ || unit_length > (uint64_t) (dataend - readp))
+ goto no_header;
+
+ uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 5)
+ goto no_header;
+
+ uint8_t address_size = *readp++;
+ if (address_size != 4 && address_size != 8)
+ goto no_header;
+
+ uint8_t segment_size = *readp++;
+ if (segment_size != 0)
+ goto no_header;
+
+ uint32_t offset_entry_count;
+ offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
+
+ const unsigned char *offset_array_start = readp;
+ if (offset_entry_count <= 0)
+ goto no_header;
+
+ uint64_t needed = offset_entry_count * offset_size;
+ if (unit_length - 8 < needed)
+ goto no_header;
+
+ offset = (Dwarf_Off) (offset_array_start
+ - (unsigned char *) data->d_buf);
+ }
+ }
+ no_header:
+ cu->ranges_base = offset;
+ }
+
+ return cu->ranges_base;
+}
+
+
+/* The start of the offset table in .debug_loclists for DWARF5. */
+static inline Dwarf_Off
+__libdw_cu_locs_base (Dwarf_CU *cu)
+{
+ if (cu->locs_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Off offset = 0;
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (dwarf_attr (&cu_die, DW_AT_loclists_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+
+ /* There wasn't an loclists_base, if the Dwarf does have a
+ .debug_loclists section, then it might be we need the
+ base after the first header. */
+ Elf_Data *data = cu->dbg->sectiondata[IDX_debug_loclists];
+ if (offset == 0 && data != NULL)
+ {
+ Dwarf *dbg = cu->dbg;
+ const unsigned char *readp = data->d_buf;
+ const unsigned char *const dataend
+ = (unsigned char *) data->d_buf + data->d_size;
+
+ uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+ unsigned int offset_size = 4;
+ if (unlikely (unit_length == 0xffffffff))
+ {
+ if (unlikely (readp > dataend - 8))
+ goto no_header;
+
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ offset_size = 8;
+ }
+
+ if (readp > dataend - 8
+ || unit_length < 8
+ || unit_length > (uint64_t) (dataend - readp))
+ goto no_header;
+
+ uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 5)
+ goto no_header;
+
+ uint8_t address_size = *readp++;
+ if (address_size != 4 && address_size != 8)
+ goto no_header;
+
+ uint8_t segment_size = *readp++;
+ if (segment_size != 0)
+ goto no_header;
+
+ uint32_t offset_entry_count;
+ offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
+
+ const unsigned char *offset_array_start = readp;
+ if (offset_entry_count <= 0)
+ goto no_header;
+
+ uint64_t needed = offset_entry_count * offset_size;
+ if (unit_length - 8 < needed)
+ goto no_header;
+
+ offset = (Dwarf_Off) (offset_array_start
+ - (unsigned char *) data->d_buf);
+ }
+
+ no_header:
+ cu->locs_base = offset;
+ }
+
+ return cu->locs_base;
+}
+
+/* Helper function for tsearch/tfind split_tree Dwarf. */
+int __libdw_finddbg_cb (const void *arg1, const void *arg2);
+
+/* Link skeleton and split compile units. */
+static inline void
+__libdw_link_skel_split (Dwarf_CU *skel, Dwarf_CU *split)
+{
+ skel->split = split;
+ split->split = skel;
+
+ /* Get .debug_addr and addr_base greedy.
+ We also need it for the fake addr cu.
+ There is only one per split debug. */
+ Dwarf *dbg = skel->dbg;
+ Dwarf *sdbg = split->dbg;
+ if (sdbg->sectiondata[IDX_debug_addr] == NULL
+ && dbg->sectiondata[IDX_debug_addr] != NULL)
+ {
+ sdbg->sectiondata[IDX_debug_addr]
+ = dbg->sectiondata[IDX_debug_addr];
+ split->addr_base = __libdw_cu_addr_base (skel);
+ sdbg->fake_addr_cu = dbg->fake_addr_cu;
+ }
+}
+
+
+/* Given an address index for a CU return the address.
+ Returns -1 and sets libdw_errno if an error occurs. */
+int __libdw_addrx (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr);
+
+
+/* Helper function to set debugdir field in Dwarf, used from dwarf_begin_elf
+ and libdwfl process_file. */
+char * __libdw_debugdir (int fd);
+
+
+/* Given the directory of a debug file, an absolute or relative dir
+ to look in, and file returns a full path.
+
+ If the file is absolute (starts with a /) a copy of file is returned.
+ the file isn't absolute, but dir is absolute, then a path that is
+ the concatenation of dir and file is returned. If neither file,
+ nor dir is absolute, the path will be constructed using dir (if not
+ NULL) and file relative to the debugdir (if valid).
+
+ The debugdir and the dir may be NULL (in which case they aren't used).
+ If file is NULL, or no full path can be constructed NULL is returned.
+
+ The caller is responsible for freeing the result if not NULL. */
+char * __libdw_filepath (const char *debugdir, const char *dir,
+ const char *file)
+ internal_function;
+
/* Aliases to avoid PLTs. */
INTDECL (dwarf_aggregate_size)
@@ -777,6 +1342,7 @@ INTDECL (dwarf_formref_die)
INTDECL (dwarf_formsdata)
INTDECL (dwarf_formstring)
INTDECL (dwarf_formudata)
+INTDECL (dwarf_getabbrevattr_data)
INTDECL (dwarf_getalt)
INTDECL (dwarf_getarange_addr)
INTDECL (dwarf_getarangeinfo)
diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c
index 28a8cf6e..d6af23a2 100644
--- a/libdw/libdw_alloc.c
+++ b/libdw/libdw_alloc.c
@@ -70,7 +70,7 @@ dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler)
void
-__attribute ((noreturn, visibility ("hidden")))
+__attribute ((noreturn)) attribute_hidden
__libdw_oom (void)
{
while (1)
diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c
new file mode 100644
index 00000000..da039e50
--- /dev/null
+++ b/libdw/libdw_find_split_unit.c
@@ -0,0 +1,147 @@
+/* Find the split (or skeleton) unit for a given unit.
+ Copyright (C) 2018 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils 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.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include "libelfP.h"
+
+#include <limits.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+void
+try_split_file (Dwarf_CU *cu, const char *dwo_path)
+{
+ int split_fd = open (dwo_path, O_RDONLY);
+ if (split_fd != -1)
+ {
+ Dwarf *split_dwarf = dwarf_begin (split_fd, DWARF_C_READ);
+ if (split_dwarf != NULL)
+ {
+ Dwarf_CU *split = NULL;
+ while (dwarf_get_units (split_dwarf, split, &split,
+ NULL, NULL, NULL, NULL) == 0)
+ {
+ if (split->unit_type == DW_UT_split_compile
+ && cu->unit_id8 == split->unit_id8)
+ {
+ if (tsearch (split->dbg, &cu->dbg->split_tree,
+ __libdw_finddbg_cb) == NULL)
+ {
+ /* Something went wrong. Don't link. */
+ __libdw_seterrno (DWARF_E_NOMEM);
+ break;
+ }
+
+ /* Link skeleton and split compile units. */
+ __libdw_link_skel_split (cu, split);
+
+ /* We have everything we need from this ELF
+ file. And we are going to close the fd to
+ not run out of file descriptors. */
+ elf_cntl (split_dwarf->elf, ELF_C_FDDONE);
+ break;
+ }
+ }
+ if (cu->split == (Dwarf_CU *) -1)
+ dwarf_end (split_dwarf);
+ }
+ /* Always close, because we don't want to run out of file
+ descriptors. See also the elf_fcntl ELF_C_FDDONE call
+ above. */
+ close (split_fd);
+ }
+}
+
+Dwarf_CU *
+internal_function
+__libdw_find_split_unit (Dwarf_CU *cu)
+{
+ /* Only try once. */
+ if (cu->split != (Dwarf_CU *) -1)
+ return cu->split;
+
+ /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
+ The split unit will be the first in the dwo file and should have the
+ same id as the skeleton. */
+ if (cu->unit_type == DW_UT_skeleton)
+ {
+ Dwarf_Die cudie = CUDIE (cu);
+ Dwarf_Attribute dwo_name;
+ /* It is fine if dwo_dir doesn't exists, but then dwo_name needs
+ to be an absolute path. */
+ if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
+ || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL)
+ {
+ /* First try the dwo file name in the same directory
+ as we found the skeleton file. */
+ const char *dwo_file = dwarf_formstring (&dwo_name);
+ const char *debugdir = cu->dbg->debugdir;
+ char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
+ if (dwo_path != NULL)
+ {
+ try_split_file (cu, dwo_path);
+ free (dwo_path);
+ }
+
+ if (cu->split == (Dwarf_CU *) -1)
+ {
+ /* Try compdir plus dwo_name. */
+ Dwarf_Attribute compdir;
+ dwarf_attr (&cudie, DW_AT_comp_dir, &compdir);
+ const char *dwo_dir = dwarf_formstring (&compdir);
+ if (dwo_dir != NULL)
+ {
+ dwo_path = __libdw_filepath (debugdir, dwo_dir, dwo_file);
+ if (dwo_path != NULL)
+ {
+ try_split_file (cu, dwo_path);
+ free (dwo_path);
+ }
+ }
+ }
+ /* XXX If still not found we could try stripping dirs from the
+ comp_dir and adding them from the comp_dir, assuming
+ someone moved a whole build tree around. */
+ }
+ }
+
+ /* If we found nothing, make sure we don't try again. */
+ if (cu->split == (Dwarf_CU *) -1)
+ cu->split = NULL;
+
+ return cu->split;
+}
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index 082307b0..ed744231 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -1,5 +1,5 @@
/* Find CU for given offset.
- Copyright (C) 2003-2010, 2014 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2014, 2016, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <[email protected]>, 2003.
@@ -61,6 +61,40 @@ findcu_cb (const void *arg1, const void *arg2)
return 0;
}
+int
+__libdw_finddbg_cb (const void *arg1, const void *arg2)
+{
+ Dwarf *dbg1 = (Dwarf *) arg1;
+ Dwarf *dbg2 = (Dwarf *) arg2;
+
+ Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
+ unsigned char *dbg1_start = dbg1_data->d_buf;
+ size_t dbg1_size = dbg1_data->d_size;
+
+ Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
+ unsigned char *dbg2_start = dbg2_data->d_buf;
+ size_t dbg2_size = dbg2_data->d_size;
+
+ /* Find out which of the two arguments is the search value. It has
+ a size of 0. */
+ if (dbg1_size == 0)
+ {
+ if (dbg1_start < dbg2_start)
+ return -1;
+ if (dbg1_start >= dbg2_start + dbg2_size)
+ return 1;
+ }
+ else
+ {
+ if (dbg2_start < dbg1_start)
+ return 1;
+ if (dbg2_start >= dbg1_start + dbg1_size)
+ return -1;
+ }
+
+ return 0;
+}
+
struct Dwarf_CU *
internal_function
__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
@@ -71,30 +105,41 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
Dwarf_Off oldoff = *offsetp;
uint16_t version;
+ uint8_t unit_type;
uint8_t address_size;
uint8_t offset_size;
Dwarf_Off abbrev_offset;
- uint64_t type_sig8 = 0;
- Dwarf_Off type_offset = 0;
-
- if (INTUSE(dwarf_next_unit) (dbg, oldoff, offsetp, NULL,
- &version, &abbrev_offset,
- &address_size, &offset_size,
- debug_types ? &type_sig8 : NULL,
- debug_types ? &type_offset : NULL) != 0)
+ uint64_t unit_id8;
+ Dwarf_Off subdie_offset;
+
+ if (__libdw_next_unit (dbg, debug_types, oldoff, offsetp, NULL,
+ &version, &unit_type, &abbrev_offset,
+ &address_size, &offset_size,
+ &unit_id8, &subdie_offset) != 0)
/* No more entries. */
return NULL;
- /* We only know how to handle the DWARF version 2 through 4 formats. */
- if (unlikely (version < 2) || unlikely (version > 4))
+ /* We only know how to handle the DWARF version 2 through 5 formats.
+ For v4 debug types we only handle version 4. */
+ if (unlikely (version < 2) || unlikely (version > 5)
+ || (debug_types && unlikely (version != 4)))
{
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ __libdw_seterrno (DWARF_E_VERSION);
return NULL;
}
+ /* We only handle 32 or 64 bit (4 or 8 byte) addresses and offsets.
+ Just assume we are dealing with 64bit in case the size is "unknown".
+ Too much code assumes if it isn't 4 then it is 8 (or the other way
+ around). */
+ if (unlikely (address_size != 4 && address_size != 8))
+ address_size = 8;
+ if (unlikely (offset_size != 4 && offset_size != 8))
+ offset_size = 8;
+
/* Invalid or truncated debug section data? */
- Elf_Data *data = dbg->sectiondata[debug_types
- ? IDX_debug_types : IDX_debug_info];
+ size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
+ Elf_Data *data = dbg->sectiondata[sec_idx];
if (unlikely (*offsetp > data->d_size))
*offsetp = data->d_size;
@@ -102,24 +147,71 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
newp->dbg = dbg;
+ newp->sec_idx = sec_idx;
newp->start = oldoff;
newp->end = *offsetp;
newp->address_size = address_size;
newp->offset_size = offset_size;
newp->version = version;
- newp->type_sig8 = type_sig8;
- newp->type_offset = type_offset;
+ newp->unit_id8 = unit_id8;
+ newp->subdie_offset = subdie_offset;
Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
+ newp->files = NULL;
newp->lines = NULL;
newp->locs = NULL;
-
- if (debug_types)
- Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, type_sig8, newp);
+ newp->split = (Dwarf_CU *) -1;
+ newp->base_address = (Dwarf_Addr) -1;
+ newp->addr_base = (Dwarf_Off) -1;
+ newp->str_off_base = (Dwarf_Off) -1;
+ newp->ranges_base = (Dwarf_Off) -1;
+ newp->locs_base = (Dwarf_Off) -1;
newp->startp = data->d_buf + newp->start;
newp->endp = data->d_buf + newp->end;
+ /* v4 debug type units have version == 4 and unit_type == DW_UT_type. */
+ if (debug_types)
+ newp->unit_type = DW_UT_type;
+ else if (version < 5)
+ {
+ /* This is a reasonable guess (and needed to get the CUDIE). */
+ newp->unit_type = DW_UT_compile;
+
+ /* But set it correctly from the actual CUDIE tag. */
+ Dwarf_Die cudie = CUDIE (newp);
+ int tag = INTUSE(dwarf_tag) (&cudie);
+ if (tag == DW_TAG_compile_unit)
+ {
+ Dwarf_Attribute dwo_id;
+ if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
+ {
+ Dwarf_Word id8;
+ if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
+ {
+ if (INTUSE(dwarf_haschildren) (&cudie) == 0
+ && INTUSE(dwarf_hasattr) (&cudie,
+ DW_AT_GNU_dwo_name) == 1)
+ newp->unit_type = DW_UT_skeleton;
+ else
+ newp->unit_type = DW_UT_split_compile;
+
+ newp->unit_id8 = id8;
+ }
+ }
+ }
+ else if (tag == DW_TAG_partial_unit)
+ newp->unit_type = DW_UT_partial;
+ else if (tag == DW_TAG_type_unit)
+ newp->unit_type = DW_UT_type;
+ }
+ else
+ newp->unit_type = unit_type;
+
+ /* Store a reference to any type unit ids in the hash for quick lookup. */
+ if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
+ Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
+
/* Add the new entry to the search tree. */
if (tsearch (newp, tree, findcu_cb) == NULL)
{
@@ -134,11 +226,11 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
struct Dwarf_CU *
internal_function
-__libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool debug_types)
+__libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
{
- void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
+ void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
Dwarf_Off *next_offset
- = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
+ = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
/* Maybe we already know that CU. */
struct Dwarf_CU fake = { .start = start, .end = 0 };
@@ -155,14 +247,61 @@ __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool debug_types)
/* No. Then read more CUs. */
while (1)
{
- struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, debug_types);
+ struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
if (newp == NULL)
return NULL;
/* Is this the one we are looking for? */
- if (start < *next_offset)
- // XXX Match exact offset.
+ if (start < *next_offset || start == newp->start)
return newp;
}
/* NOTREACHED */
}
+
+struct Dwarf_CU *
+internal_function
+__libdw_findcu_addr (Dwarf *dbg, void *addr)
+{
+ void **tree;
+ Dwarf_Off start;
+ if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
+ && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
+ + dbg->sectiondata[IDX_debug_info]->d_size))
+ {
+ tree = &dbg->cu_tree;
+ start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
+ }
+ else if (dbg->sectiondata[IDX_debug_types] != NULL
+ && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
+ && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
+ + dbg->sectiondata[IDX_debug_types]->d_size))
+ {
+ tree = &dbg->tu_tree;
+ start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
+ }
+ else
+ return NULL;
+
+ struct Dwarf_CU fake = { .start = start, .end = 0 };
+ struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
+
+ if (found != NULL)
+ return *found;
+
+ return NULL;
+}
+
+Dwarf *
+internal_function
+__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
+{
+ /* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */
+ Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
+ Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
+ Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
+
+ if (found != NULL)
+ return *found;
+
+ return NULL;
+}
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index 72e2390c..584c8467 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -60,6 +60,8 @@ __libdw_form_val_compute_len (struct Dwarf_CU *cu, unsigned int form,
break;
case DW_FORM_strp:
+ case DW_FORM_strp_sup:
+ case DW_FORM_line_strp:
case DW_FORM_sec_offset:
case DW_FORM_GNU_ref_alt:
case DW_FORM_GNU_strp_alt:
@@ -103,6 +105,12 @@ __libdw_form_val_compute_len (struct Dwarf_CU *cu, unsigned int form,
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
+ case DW_FORM_addrx:
+ case DW_FORM_loclistx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_strx:
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
get_uleb128 (u128, valp, endp);
result = valp - startp;
break;
diff --git a/libdw/memory-access.h b/libdw/memory-access.h
index a749b5a9..a39ad6d2 100644
--- a/libdw/memory-access.h
+++ b/libdw/memory-access.h
@@ -1,7 +1,6 @@
/* Unaligned memory access functionality.
- Copyright (C) 2000-2014 Red Hat, Inc.
+ Copyright (C) 2000-2014, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <[email protected]>, 2001.
This file is free software; you can redistribute it and/or modify
it under the terms of either
@@ -31,6 +30,7 @@
#define _MEMORY_ACCESS_H 1
#include <byteswap.h>
+#include <endian.h>
#include <limits.h>
#include <stdint.h>
@@ -87,8 +87,26 @@ __libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end)
return UINT64_MAX;
}
+static inline uint64_t
+__libdw_get_uleb128_unchecked (const unsigned char **addrp)
+{
+ uint64_t acc = 0;
+
+ /* Unroll the first step to help the compiler optimize
+ for the common single-byte case. */
+ get_uleb128_step (acc, *addrp, 0);
+
+ const size_t max = len_leb128 (uint64_t);
+ for (size_t i = 1; i < max; ++i)
+ get_uleb128_step (acc, *addrp, i);
+ /* Other implementations set VALUE to UINT_MAX in this
+ case. So we better do this as well. */
+ return UINT64_MAX;
+}
+
/* Note, addr needs to me smaller than end. */
#define get_uleb128(var, addr, end) ((var) = __libdw_get_uleb128 (&(addr), end))
+#define get_uleb128_unchecked(var, addr) ((var) = __libdw_get_uleb128_unchecked (&(addr)))
/* The signed case is similar, but we sign-extend the result. */
@@ -121,7 +139,26 @@ __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
return INT64_MAX;
}
+static inline int64_t
+__libdw_get_sleb128_unchecked (const unsigned char **addrp)
+{
+ int64_t acc = 0;
+
+ /* Unroll the first step to help the compiler optimize
+ for the common single-byte case. */
+ get_sleb128_step (acc, *addrp, 0);
+
+ /* Subtract one step, so we don't shift into sign bit. */
+ const size_t max = len_leb128 (int64_t) - 1;
+ for (size_t i = 1; i < max; ++i)
+ get_sleb128_step (acc, *addrp, i);
+ /* Other implementations set VALUE to INT_MAX in this
+ case. So we better do this as well. */
+ return INT64_MAX;
+}
+
#define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
+#define get_sleb128_unchecked(var, addr) ((var) = __libdw_get_sleb128_unchecked (&(addr)))
/* We use simple memory access functions in case the hardware allows it.
@@ -170,7 +207,7 @@ union unaligned
int16_t s2;
int32_t s4;
int64_t s8;
- } __attribute__ ((packed));
+ } attribute_packed;
# define read_2ubyte_unaligned(Dbg, Addr) \
read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
@@ -278,6 +315,57 @@ read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
t_; })
+/* 3ubyte reads are only used for DW_FORM_addrx3 and DW_FORM_strx3.
+ And are probably very rare. They are not optimized. They are
+ handled as if reading a 4byte value with the first (for big endian)
+ or last (for little endian) byte zero. */
+
+static inline int
+file_byte_order (bool other_byte_order)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return other_byte_order ? __BIG_ENDIAN : __LITTLE_ENDIAN;
+#else
+ return other_byte_order ? __LITTLE_ENDIAN : __BIG_ENDIAN;
+#endif
+}
+
+static inline uint32_t
+read_3ubyte_unaligned (Dwarf *dbg, const unsigned char *p)
+{
+ union
+ {
+ uint32_t u4;
+ unsigned char c[4];
+ } d;
+ bool other_byte_order = dbg->other_byte_order;
+
+ if (file_byte_order (other_byte_order) == __BIG_ENDIAN)
+ {
+ d.c[0] = 0x00;
+ d.c[1] = p[0];
+ d.c[2] = p[1];
+ d.c[3] = p[2];
+ }
+ else
+ {
+ d.c[0] = p[0];
+ d.c[1] = p[1];
+ d.c[2] = p[2];
+ d.c[3] = 0x00;
+ }
+
+ if (other_byte_order)
+ return bswap_32 (d.u4);
+ else
+ return d.u4;
+}
+
+
+#define read_3ubyte_unaligned_inc(Dbg, Addr) \
+ ({ uint32_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 3); \
+ t_; })
#define read_addr_unaligned_inc(Nbytes, Dbg, Addr) \
(assert ((Nbytes) == 4 || (Nbytes) == 8), \