From: Petr Machata Date: Fri, 8 Oct 2010 23:28:52 +0000 (+0200) Subject: dwarflint: Retrofit proper marking of exprloc and loclistptr to earlier DWARFs X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e0d6dcacff4fd828804851c6fcddedea176f2839;p=thirdparty%2Felfutils.git dwarflint: Retrofit proper marking of exprloc and loclistptr to earlier DWARFs - as a consequence, is_location_attrib is gone - in check_debug_abbrev, we now check for appropriateness all form/attribute pairs, not just those that are location attribs - too-wide references are now checked in one place for all reference types - pointer checking now actually looks sane--the maze of DW_FORM_/DW_AT_ switches was replaced by a straighforward switch on ver->form_class - this introduces a testcase failure - and similar work needs to be done for other cl_*ref classes --- diff --git a/dwarflint/check_debug_abbrev.cc b/dwarflint/check_debug_abbrev.cc index b010f23b7..bca382ad6 100644 --- a/dwarflint/check_debug_abbrev.cc +++ b/dwarflint/check_debug_abbrev.cc @@ -358,13 +358,16 @@ namespace "attribute form")) throw check_base::failed (); + /* Now if both are zero, this was the last attribute. */ null_attrib = attrib_name == 0 && attrib_form == 0; - /* Now if both are zero, this was the last attribute. */ + attribute const *attribute = NULL; + form const *form = NULL; if (!null_attrib) { /* Otherwise validate name and form. */ - if (attrib_name > DW_AT_hi_user) + attribute = ver->get_attribute (attrib_name); + if (attribute == NULL) { wr_error (where) << "invalid name " << pri::hex (attrib_name) @@ -373,7 +376,8 @@ namespace continue; } - if (!ver->form_allowed (attrib_form)) + form = ver->get_form (attrib_form); + if (form == NULL) { wr_error (where) << "invalid form " << pri::hex (attrib_form) @@ -382,6 +386,10 @@ namespace continue; } + if (!ver->form_allowed (attribute->name (), form->name ())) + complain_invalid_form (where, attrib_name, attrib_form, + "attribute"); + std::pair::iterator, bool> inserted = seen.insert (std::make_pair (attrib_name, attr_off)); if (!inserted.second) @@ -433,14 +441,6 @@ namespace }; } - /* Similar for DW_AT_location and friends. */ - else if (is_location_attrib (attrib_name)) - { - if (!ver->form_allowed (attrib_name, attrib_form)) - complain_invalid_form (where, attrib_name, attrib_form, - "location attribute"); - } - /* Similar for DW_AT_ranges. */ else if (attrib_name == DW_AT_ranges || attrib_name == DW_AT_stmt_list) @@ -528,18 +528,3 @@ check_debug_abbrev::~check_debug_abbrev () free (it->second.abbr); } } - -bool -is_location_attrib (uint64_t name) -{ - switch (name) - { - case DW_AT_location: - case DW_AT_frame_base: - case DW_AT_data_location: - case DW_AT_data_member_location: - return true; - default: - return false; - } -} diff --git a/dwarflint/check_debug_abbrev.hh b/dwarflint/check_debug_abbrev.hh index f905bd24f..9d1d77824 100644 --- a/dwarflint/check_debug_abbrev.hh +++ b/dwarflint/check_debug_abbrev.hh @@ -86,8 +86,4 @@ public: ~check_debug_abbrev (); }; -// xxx When dwarf version objects are properly implemented, that's -// where this should end up in. -bool is_location_attrib (uint64_t name); - #endif//DWARFLINT_CHECK_DEBUG_ABBREV_HH diff --git a/dwarflint/check_debug_info.cc b/dwarflint/check_debug_info.cc index 406d0c887..6822d242a 100644 --- a/dwarflint/check_debug_info.cc +++ b/dwarflint/check_debug_info.cc @@ -634,7 +634,9 @@ namespace form_name = value; // xxx Some of what's below is probably duplicated in - // check_debug_abbrev. Consolidate. + // check_debug_abbrev. Plus we really want to run the + // same checks for direct and indirect attributes. + // Consolidate. if (!ver->form_allowed (form_name)) { wr_error (where) @@ -705,76 +707,66 @@ namespace relocation was made against. */ GElf_Sym **symbolp = NULL; - /* Setup locptr checking. */ - if (is_location_attrib (it->name)) + assert (form); + assert (attribute); + + dw_class cls = ver->form_class (form, attribute); + static dw_class_set ref_classes + (cl_reference, cl_loclistptr, cl_lineptr, cl_macptr, + cl_rangelistptr); + + if (ref_classes.test (cls)) + if (form->width (cu) == fw_8 + && cu->head->offset_size == 4) + wr_error (where) + << "reference attribute with form \"" + << pri::form (form_name) << "\" in 32-bit CU." + << std::endl; + + /* Setup pointer checking. */ + switch (cls) { - if (form->width () == fw_8 - && cu->head->offset_size == 4) - wr_error (where) - << "location attribute with form \"" - << pri::form (form_name) << "\" in 32-bit CU." - << std::endl; + case cl_loclistptr: + check_someptr = true; + value_check_cb = check_locptr; + extra_mc = mc_loc; + break; - if (ver->form_class (form, attribute) == cl_loclistptr) - { - value_check_cb = check_locptr; - extra_mc = mc_loc; - check_someptr = true; - } - } - /* Setup rangeptr or lineptr checking. */ - else - switch (it->name) - { - case DW_AT_ranges: - case DW_AT_stmt_list: - { - switch (form_name) - { - case DW_FORM_data8: - if (cu->head->offset_size == 4) - // xxx could now also be checked during abbrev loading - wr_error (where) - << pri::attr (it->name) - << " with form DW_FORM_data8 in 32-bit CU." - << std::endl; - /* fall-through */ - - case DW_FORM_data4: - case DW_FORM_sec_offset: - check_someptr = true; - if (it->name == DW_AT_ranges) - { - value_check_cb = check_rangeptr; - extra_mc = mc_ranges; - } - else - { - assert (it->name == DW_AT_stmt_list); - value_check_cb = check_lineptr; - extra_mc = mc_line; - } - break; - } - break; + case cl_rangelistptr: + check_someptr = true; + value_check_cb = check_rangeptr; + extra_mc = mc_ranges; + break; - case DW_AT_low_pc: - relocatedp = &low_pc_relocated; - symbolp = &low_pc_symbol; - valuep = &low_pc; - break; + case cl_lineptr: + check_someptr = true; + value_check_cb = check_lineptr; + extra_mc = mc_line; + break; - case DW_AT_high_pc: - relocatedp = &high_pc_relocated; - symbolp = &high_pc_symbol; - valuep = &high_pc; - break; + default: + ; + }; - case DW_AT_decl_file: - value_check_cb = check_decl_file; - break; - } - } + /* Setup low_pc / high_pc checking. */ + switch (it->name) + { + case DW_AT_low_pc: + relocatedp = &low_pc_relocated; + symbolp = &low_pc_symbol; + valuep = &low_pc; + break; + + case DW_AT_high_pc: + relocatedp = &high_pc_relocated; + symbolp = &high_pc_symbol; + valuep = &high_pc; + break; + + case DW_AT_decl_file: + value_check_cb = check_decl_file; + break; + } /* Setup per-form checking & relocation. */ switch (form_name) @@ -860,7 +852,7 @@ namespace break; // Read & validate the block body. - if (is_location_attrib (it->name)) + if (cls == cl_exprloc) { uint64_t expr_start = cu->head->offset + read_ctx_get_offset (ctx); @@ -869,8 +861,6 @@ namespace return -1; } else - /* xxx really skip_mismatched? We just don't - know how to process these... */ relocation_skip (reloc, read_ctx_get_offset (ctx) + value, &where, skip_mismatched); diff --git a/dwarflint/dwarf_2.cc b/dwarflint/dwarf_2.cc index 2a240e599..c227ebfec 100644 --- a/dwarflint/dwarf_2.cc +++ b/dwarflint/dwarf_2.cc @@ -34,8 +34,18 @@ namespace { dwarf_2_attributes () { + // Note about location descriptions in DWARF 2 (and 3). In + // DWARF 2, location expressions can have classes of cl_constant + // or cl_block. But we need to tell those block expressions + // from any old block attribute to validate the expression, and + // those constants from any old number to validate the + // reference. So we retrofit all the DW_FORM_block* forms and + // appropriate attributes with cl_exprloc form DWARF 4 and + // cl_loclistptr (even though in DWARF 4 it's actually only + // DW_FORM_exprloc that has this class). + add (ref_attribute (DW_AT_sibling)); - add (const_or_block_attribute (DW_AT_location)); + add (location_attribute (DW_AT_location)); add (string_attribute (DW_AT_name)); add (const_attribute (DW_AT_ordering)); add (const_attribute (DW_AT_byte_size)); @@ -49,7 +59,7 @@ namespace add (const_attribute (DW_AT_discr_value)); add (const_attribute (DW_AT_visibility)); add (ref_attribute (DW_AT_import)); - add (const_or_block_attribute (DW_AT_string_length)); + add (location_attribute (DW_AT_string_length)); add (ref_attribute (DW_AT_common_reference)); add (string_attribute (DW_AT_comp_dir)); add (attribute (DW_AT_const_value, @@ -61,7 +71,7 @@ namespace add (const_or_ref_attribute (DW_AT_lower_bound)); add (string_attribute (DW_AT_producer)); add (flag_attribute (DW_AT_prototyped)); - add (const_or_block_attribute (DW_AT_return_addr)); + add (location_attribute (DW_AT_return_addr)); add (const_attribute (DW_AT_start_scope)); add (const_attribute (DW_AT_bit_stride)); add (const_or_ref_attribute (DW_AT_upper_bound)); @@ -72,7 +82,7 @@ namespace add (ref_attribute (DW_AT_base_types)); add (const_attribute (DW_AT_calling_convention)); add (const_or_ref_attribute (DW_AT_count)); - add (ref_or_block_attribute (DW_AT_data_member_location)); + add (static_location_attribute (DW_AT_data_member_location)); add (const_attribute (DW_AT_decl_column)); add (const_attribute (DW_AT_decl_file)); add (const_attribute (DW_AT_decl_line)); @@ -80,39 +90,55 @@ namespace add (block_attribute (DW_AT_discr_list)); add (const_attribute (DW_AT_encoding)); add (flag_attribute (DW_AT_external)); - add (const_or_block_attribute (DW_AT_frame_base)); + add (location_attribute (DW_AT_frame_base)); add (ref_attribute (DW_AT_friend)); add (const_attribute (DW_AT_identifier_case)); add (const_attribute (DW_AT_macro_info)); add (block_attribute (DW_AT_namelist_item)); add (ref_attribute (DW_AT_priority)); - add (const_or_block_attribute (DW_AT_segment)); + add (location_attribute (DW_AT_segment)); add (ref_attribute (DW_AT_specification)); - add (const_or_block_attribute (DW_AT_static_link)); + add (location_attribute (DW_AT_static_link)); add (ref_attribute (DW_AT_type)); - add (const_or_block_attribute (DW_AT_use_location)); + add (location_attribute (DW_AT_use_location)); add (flag_attribute (DW_AT_variable_parameter)); add (const_attribute (DW_AT_virtuality)); - add (ref_or_block_attribute (DW_AT_vtable_elem_location)); + add (static_location_attribute (DW_AT_vtable_elem_location)); } }; + struct exprloc_form + : public preset_form + { + exprloc_form (int a_name, form_width_t a_width) + : preset_form (a_name, a_width) + {} + }; + + // xxx We still need to retrofit all the cl_*ptr to above list of + // attributes. Except cl_loclistptr which is already done. + typedef preset_form dw2_data_form; + struct dwarf_2_forms : public form_table { dwarf_2_forms () { - add (block_form (DW_FORM_block, fw_uleb)); - add (block_form (DW_FORM_block1, fw_1)); - add (block_form (DW_FORM_block2, fw_2)); - add (block_form (DW_FORM_block4, fw_4)); - - add (const_form (DW_FORM_data1, fw_1)); - add (const_form (DW_FORM_data2, fw_2)); - add (const_form (DW_FORM_data4, fw_4)); - add (const_form (DW_FORM_data8, fw_8)); - add (const_form (DW_FORM_sdata, fw_sleb)); - add (const_form (DW_FORM_udata, fw_uleb)); + add (exprloc_form (DW_FORM_block, fw_uleb)); + add (exprloc_form (DW_FORM_block1, fw_1)); + add (exprloc_form (DW_FORM_block2, fw_2)); + add (exprloc_form (DW_FORM_block4, fw_4)); + + // These constant forms can in theory, in legal DWARF 2, + // represent various pointers. + add (dw2_data_form (DW_FORM_data1, fw_1)); + add (dw2_data_form (DW_FORM_data2, fw_2)); + add (dw2_data_form (DW_FORM_data4, fw_4)); + add (dw2_data_form (DW_FORM_data8, fw_8)); + add (dw2_data_form (DW_FORM_sdata, fw_sleb)); + add (dw2_data_form (DW_FORM_udata, fw_uleb)); add (flag_form (DW_FORM_flag, fw_1)); diff --git a/dwarflint/dwarf_3.cc b/dwarflint/dwarf_3.cc index 64713c5b8..0aaa0764b 100644 --- a/dwarflint/dwarf_3.cc +++ b/dwarflint/dwarf_3.cc @@ -31,39 +31,38 @@ namespace { - typedef preset_attribute block_or_loc_attribute; - typedef preset_attribute - block_const_ref_attribute; - struct dwarf_3_attributes : public attribute_table { dwarf_3_attributes () { - add (block_or_loc_attribute (DW_AT_location)); - add (block_const_ref_attribute (DW_AT_byte_size)); - add (block_const_ref_attribute (DW_AT_bit_offset)); - add (block_const_ref_attribute (DW_AT_bit_size)); + add (location_attribute (DW_AT_location)); + add (dynval_attribute (DW_AT_byte_size)); + add (dynval_attribute (DW_AT_bit_offset)); + add (dynval_attribute (DW_AT_bit_size)); add (attribute (DW_AT_stmt_list, cl_lineptr)); - add (block_or_loc_attribute (DW_AT_string_length)); - add (attribute (DW_AT_const_value, - dw_class_set (cl_block, cl_constant, cl_string))); - add (block_const_ref_attribute (DW_AT_lower_bound)); - add (block_or_loc_attribute (DW_AT_return_addr)); - add (const_attribute (DW_AT_bit_stride)); - add (block_const_ref_attribute (DW_AT_upper_bound)); - add (block_const_ref_attribute (DW_AT_count)); + add (location_attribute (DW_AT_string_length)); + add (dynval_attribute (DW_AT_lower_bound)); + add (location_attribute (DW_AT_return_addr)); + + // Note, DWARF 3 claims only a const class for DW_AT_bit_stride, + // but from 2.19 it's clear that this is an omission. + add (dynval_attribute (DW_AT_bit_stride)); + + add (dynval_attribute (DW_AT_upper_bound)); + add (dynval_attribute (DW_AT_count)); add (attribute (DW_AT_data_member_location, - dw_class_set (cl_block, cl_constant, cl_loclistptr))); - add (block_or_loc_attribute (DW_AT_frame_base)); + dw_class_set (cl_exprloc, cl_constant, cl_loclistptr))); + add (location_attribute (DW_AT_frame_base)); add (attribute (DW_AT_macro_info, cl_macptr)); - add (block_or_loc_attribute (DW_AT_segment)); - add (block_or_loc_attribute (DW_AT_static_link)); - add (block_or_loc_attribute (DW_AT_use_location)); - add (block_or_loc_attribute (DW_AT_vtable_elem_location)); - add (block_const_ref_attribute (DW_AT_associated)); - add (block_attribute (DW_AT_data_location)); - add (block_const_ref_attribute (DW_AT_byte_stride)); + add (location_attribute (DW_AT_segment)); + add (location_attribute (DW_AT_static_link)); + add (location_attribute (DW_AT_use_location)); + add (location_attribute (DW_AT_vtable_elem_location)); + add (dynval_attribute (DW_AT_allocated)); + add (dynval_attribute (DW_AT_associated)); + add (attribute (DW_AT_data_location, cl_exprloc)); + add (dynval_attribute (DW_AT_byte_stride)); add (addr_attribute (DW_AT_entry_pc)); add (flag_attribute (DW_AT_use_UTF8)); add (ref_attribute (DW_AT_extension)); @@ -95,15 +94,24 @@ namespace typedef preset_form dw3_data_form; + typedef preset_form locexpr_form; struct dwarf_3_forms : public form_table { dwarf_3_forms () { + add (offset_form (DW_FORM_ref_addr, cl_reference)); + + // In DWARF 2 we made all the const forms into various cl_*ptr, + // since that's how the standard was worded: it allowed + // DW_AT_location to have any constant form. Revert that. + add (const_form (DW_FORM_data1, fw_1)); + add (const_form (DW_FORM_data2, fw_2)); add (dw3_data_form (DW_FORM_data4, fw_4)); add (dw3_data_form (DW_FORM_data8, fw_8)); - add (offset_form (DW_FORM_ref_addr, cl_reference)); + add (const_form (DW_FORM_sdata, fw_sleb)); + add (const_form (DW_FORM_udata, fw_uleb)); } }; diff --git a/dwarflint/dwarf_4.cc b/dwarflint/dwarf_4.cc index 9b2f53d9e..3894c4999 100644 --- a/dwarflint/dwarf_4.cc +++ b/dwarflint/dwarf_4.cc @@ -30,44 +30,19 @@ namespace { - typedef preset_attribute exprloc_loclist_attribute; - typedef preset_attribute - const_exprloc_ref_attribute; - struct dwarf_4_attributes : public attribute_table { dwarf_4_attributes () { - add (exprloc_loclist_attribute (DW_AT_location)); - add (const_exprloc_ref_attribute (DW_AT_bit_offset)); - add (const_exprloc_ref_attribute (DW_AT_bit_size)); - add (attribute (DW_AT_high_pc, - dw_class_set (cl_address, cl_constant))); - add (exprloc_loclist_attribute (DW_AT_string_length)); - add (attribute (DW_AT_const_value, - dw_class_set (cl_block, cl_constant, cl_string))); - add (const_exprloc_ref_attribute (DW_AT_lower_bound)); - add (exprloc_loclist_attribute (DW_AT_return_addr)); - add (const_exprloc_ref_attribute (DW_AT_bit_stride)); - add (const_exprloc_ref_attribute (DW_AT_upper_bound)); - add (const_exprloc_ref_attribute (DW_AT_count)); - add (attribute (DW_AT_data_member_location, - dw_class_set (cl_constant, cl_exprloc, cl_loclistptr))); - add (exprloc_loclist_attribute (DW_AT_frame_base)); + add (attribute (DW_AT_high_pc, dw_class_set (cl_address, cl_constant))); add (ref_attribute (DW_AT_namelist_item)); - add (exprloc_loclist_attribute (DW_AT_segment)); - add (exprloc_loclist_attribute (DW_AT_static_link)); - add (exprloc_loclist_attribute (DW_AT_use_location)); - add (exprloc_loclist_attribute (DW_AT_vtable_elem_location)); - add (const_exprloc_ref_attribute (DW_AT_allocated)); - add (const_exprloc_ref_attribute (DW_AT_associated)); - add (attribute (DW_AT_data_location, cl_exprloc)); - add (const_exprloc_ref_attribute (DW_AT_byte_stride)); add (ref_attribute (DW_AT_signature)); add (flag_attribute (DW_AT_main_subprogram)); add (const_attribute (DW_AT_data_bit_offset)); add (flag_attribute (DW_AT_const_expr)); + add (flag_attribute (DW_AT_enum_class)); + add (string_attribute (DW_AT_linkage_name)); } }; @@ -92,6 +67,14 @@ namespace add (exprloc_form (DW_FORM_exprloc)); add (flag_form (DW_FORM_flag_present, fw_0)); add (ref_form (DW_FORM_ref_sig8, fw_8)); + + // In DWARF 2 we claim that blocks are exprloc forms (see + // comment there). Revert back to pure blocks now that we have + // proper support for cl_exprloc. + add (block_form (DW_FORM_block, fw_uleb)); + add (block_form (DW_FORM_block1, fw_1)); + add (block_form (DW_FORM_block2, fw_2)); + add (block_form (DW_FORM_block4, fw_4)); } }; diff --git a/dwarflint/dwarf_version-imp.hh b/dwarflint/dwarf_version-imp.hh index 70ad40279..19a63ca1f 100644 --- a/dwarflint/dwarf_version-imp.hh +++ b/dwarflint/dwarf_version-imp.hh @@ -86,6 +86,7 @@ typedef preset_form block_form; typedef preset_form const_form; typedef preset_form ref_form; typedef preset_form flag_form; +typedef preset_form block_form; typedef preset_attribute const_attribute; typedef preset_attribute ref_attribute; @@ -93,10 +94,18 @@ typedef preset_attribute addr_attribute; typedef preset_attribute string_attribute; typedef preset_attribute flag_attribute; typedef preset_attribute block_attribute; -typedef preset_attribute const_or_block_attribute; -typedef preset_attribute ref_or_block_attribute; typedef preset_attribute const_or_ref_attribute; +// [DWARF 3, DWARF 4, section 2.19]: attributes that [...] specify a +// property [...] that is an integer value, where the value may be +// known during compilation or may be computed dynamically during +// execution. +typedef preset_attribute dynval_attribute; + +typedef preset_attribute location_attribute; +typedef preset_attribute static_location_attribute; + class std_dwarf : public dwarf_version {