"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)
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)
continue;
}
+ if (!ver->form_allowed (attribute->name (), form->name ()))
+ complain_invalid_form (where, attrib_name, attrib_form,
+ "attribute");
+
std::pair<std::map<unsigned, uint64_t>::iterator, bool> inserted
= seen.insert (std::make_pair (attrib_name, attr_off));
if (!inserted.second)
};
}
- /* 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)
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;
- }
-}
~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
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)
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)
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);
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);
{
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));
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,
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));
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));
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<sc_block, cl_exprloc, cl_block>
+ {
+ exprloc_form (int a_name, form_width_t a_width)
+ : preset_form<sc_block, cl_exprloc, cl_block> (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<sc_value,
+ cl_constant, cl_lineptr, cl_loclistptr,
+ cl_macptr, cl_rangelistptr> 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));
namespace
{
- typedef preset_attribute<cl_block, cl_loclistptr> block_or_loc_attribute;
- typedef preset_attribute<cl_block, cl_constant, cl_reference>
- 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));
typedef preset_form<sc_value,
cl_constant, cl_lineptr, cl_loclistptr,
cl_macptr, cl_rangelistptr> dw3_data_form;
+ typedef preset_form<sc_block, cl_block, cl_exprloc> 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));
}
};
namespace
{
- typedef preset_attribute<cl_exprloc, cl_loclistptr> exprloc_loclist_attribute;
- typedef preset_attribute<cl_constant, cl_exprloc, cl_reference>
- 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));
}
};
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));
}
};
typedef preset_form<sc_value, cl_constant> const_form;
typedef preset_form<sc_value, cl_reference> ref_form;
typedef preset_form<sc_value, cl_flag> flag_form;
+typedef preset_form<sc_block, cl_block> block_form;
typedef preset_attribute<cl_constant> const_attribute;
typedef preset_attribute<cl_reference> ref_attribute;
typedef preset_attribute<cl_string> string_attribute;
typedef preset_attribute<cl_flag> flag_attribute;
typedef preset_attribute<cl_block> block_attribute;
-typedef preset_attribute<cl_block, cl_constant> const_or_block_attribute;
-typedef preset_attribute<cl_block, cl_reference> ref_or_block_attribute;
typedef preset_attribute<cl_reference, cl_constant> 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<cl_constant, cl_exprloc,
+ cl_reference> dynval_attribute;
+
+typedef preset_attribute<cl_exprloc, cl_loclistptr> location_attribute;
+typedef preset_attribute<cl_exprloc, cl_reference> static_location_attribute;
+
class std_dwarf
: public dwarf_version
{