# include <config.h>
#endif
+#include <dwarf.h>
+#include <sstream>
+#include <cassert>
+#include <algorithm>
+
+#include "../libdw/c++/dwarf"
+
#include "check_debug_info.hh"
#include "check_debug_abbrev.hh"
#include "pri.hh"
#include "messages.hh"
#include "misc.hh"
-#include <dwarf.h>
-#include <sstream>
-#include <cassert>
-#include <algorithm>
-
checkdescriptor const *
check_debug_abbrev::descriptor ()
{
void
complain (where const *where,
- attribute const *attribute, form const *form,
+ int attrib_name, int form_name,
bool indirect, char const *qualifier)
{
wr_error (*where)
- << "attribute " << *attribute << " with " << qualifier
- << (indirect ? " indirect" : "") << " form "
- << *form << '.' << std::endl;
+ << "attribute " << elfutils::dwarf::attributes::name (attrib_name)
+ << " with " << qualifier << (indirect ? " indirect" : "")
+ << " form " << elfutils::dwarf::forms::name (form_name)
+ << '.' << std::endl;
}
bool
/* Now if both are zero, this was the last attribute. */
null_attrib = attrib_name == 0 && attrib_form == 0;
- attribute const *attribute = NULL;
REALLOC (cur, attribs);
continue;
}
- attribute = ver->get_attribute (attrib_name);
+ attribute const *attribute = ver->get_attribute (attrib_name);
if (attribute == NULL)
{
wr_error (where)
<< "invalid or unknown name " << pri::hex (attrib_name)
<< '.' << std::endl;
// libdw should handle unknown attribute, as long as
- // the form is kosher.
- continue;
+ // the form is kosher, so don't fail the check.
}
+ form const *form = check_debug_abbrev::check_form
+ (ver, attribute, attrib_form, &where, false);
+ if (form == NULL)
+ // Error message has been emitted in check_form.
+ failed = true;
+
+ if (form == NULL || attribute == NULL)
+ continue;
+
std::pair<std::map<unsigned, uint64_t>::iterator, bool> inserted
= seen.insert (std::make_pair (attrib_name, attr_off));
if (!inserted.second)
failed = true;
}
- form const *form = check_debug_abbrev::check_form
- (ver, attrib_form, attribute, &where, false);
- if (form == NULL)
- {
- // Error message is emitted in check_form.
- failed = true;
- continue;
- }
-
if (attrib_name == DW_AT_sibling)
{
if (!cur->has_children)
}
form const *
-check_debug_abbrev::check_form (dwarf_version const *ver, int form_name,
- attribute const *attribute, where const *where,
- bool indirect)
+check_debug_abbrev::check_form (dwarf_version const *ver,
+ attribute const *attribute,
+ int form_name,
+ where const *where, bool indirect)
{
form const *form = ver->get_form (form_name);
if (form == NULL)
return NULL;
}
- if (!ver->form_allowed (attribute->name (), form_name))
+ if (attribute != NULL)
{
- complain (where, attribute, form, indirect, "invalid");
- return NULL;
+
+ int attrib_name = attribute->name ();
+ if (!ver->form_allowed (attribute, form))
+ {
+ complain (where, attrib_name, form_name, indirect, "invalid");
+ return NULL;
+ }
+ else if (attrib_name == DW_AT_sibling
+ && sibling_form_suitable (ver, form) == sfs_long)
+ complain (where, attrib_name, form_name, indirect, "unsuitable");
}
- else if (attribute->name () == DW_AT_sibling
- && sibling_form_suitable (ver, form_name) == sfs_long)
- complain (where, attribute, form, indirect, "unsuitable");
return form;
}
check_debug_abbrev (checkstack &stack, dwarflint &lint);
static form const *check_form (dwarf_version const *ver,
+ attribute const *attr,
int form_name,
- attribute const *attribute,
where const *where,
bool indirect);
it->name != 0 || it->form != 0; ++it)
{
where.ref = &it->where;
+ int form_name = it->form;
+ // In following, attribute may be NULL, but form never
+ // should. We always need to know the form to be able to
+ // read .debug_info, so we fail in check_debug_abbrev if
+ // it's invalid or unknown.
attribute const *attribute = ver->get_attribute (it->name);
- int form_name = it->form;
form const *form = ver->get_form (form_name);
if (attribute != NULL
&& ver->form_class (form, attribute) == cl_indirect)
return -1;
form_name = value;
form = check_debug_abbrev::check_form
- (ver, form_name, attribute, &where, true);
+ (ver, attribute, form_name, &where, true);
+ // N.B. check_form emits appropriate error messages.
if (form == NULL)
return -1;
}
+ assert (form != NULL);
dw_class cls = attribute != NULL
? ver->form_class (form, attribute)
(cl_reference, cl_loclistptr, cl_lineptr, cl_macptr,
cl_rangelistptr);
- if (cls != max_dw_class && ref_classes.test (cls))
+ if (form != NULL && cls != max_dw_class && ref_classes.test (cls))
{
form_bitness_t bitness = form->bitness ();
if ((bitness == fb_32 && cu->head->offset_size == 8)
{}
virtual bool
- form_allowed (int attribute_name, int form_name) const
+ form_allowed (attribute const *attr, form const *form) const
{
- if (attribute_name == DW_AT_GNU_odr_signature)
- {
- form const *f = get_form (form_name);
- return f->classes ()[cl_constant] && f->width (NULL) == fw_8;
- }
+ if (attr->name () == DW_AT_GNU_odr_signature)
+ return form->classes ()[cl_constant] && form->width (NULL) == fw_8;
else
- return std_dwarf::form_allowed (attribute_name, form_name);
+ return std_dwarf::form_allowed (attr, form);
}
};
}
}
bool
-dwarf_version::form_allowed (int attribute_name, int form_name) const
+dwarf_version::form_allowed (attribute const *attr, form const *form) const
{
- attribute const *attribute = this->get_attribute (attribute_name);
- assert (attribute != NULL);
- dw_class_set const &attr_classes = attribute->classes ();
-
- form const *form = this->get_form (form_name);
- assert (form != NULL);
+ dw_class_set const &attr_classes = attr->classes ();
dw_class_set const &form_classes = form->classes ();
-
return (attr_classes & form_classes).any ();
}
sibling_form_suitable_t
-sibling_form_suitable (dwarf_version const *ver, int form)
+sibling_form_suitable (dwarf_version const *ver, form const *form)
{
- if (!ver->form_allowed (DW_AT_sibling, form))
+ if (!ver->form_allowed (ver->get_attribute (DW_AT_sibling), form))
return sfs_invalid;
- else if (form == DW_FORM_ref_addr)
+ else if (form->name () == DW_FORM_ref_addr)
return sfs_long;
else
return sfs_ok;
/// Figure out whether, in given DWARF version, given attribute is
/// allowed to have given form.
- virtual bool form_allowed (int attribute_name, int form_name) const;
+ virtual bool form_allowed (attribute const *attr, form const *form) const
+ __attribute__ ((nonnull (1, 2)));
/// Answer a class of FORM given ATTRIBUTE as a context. If there's
/// exactly one candidate class, that's the one answered. If
sfs_invalid, ///< This form isn't allowed at DW_AT_sibling
};
sibling_form_suitable_t sibling_form_suitable (dwarf_version const *ver,
- int form);
+ form const *form)
+ __attribute__ ((nonnull (1, 2)));
#endif//DWARFLINT_DWARF_VERSION_HH
srcdir=$srcdir/tests
testfiles hello.bad-1 hello.bad-3 garbage-1 garbage-2 garbage-3 garbage-4 \
- garbage-5 garbage-6
+ garbage-5 garbage-6 garbage-7
testrun_compare ./dwarflint hello.bad-1 <<EOF
error: .debug_info: DIE 0x83: abbrev section at 0x0 doesn't contain code 83.
error: .debug_abbrev: abbr. attribute 0x23: attribute frame_base with invalid form block1.
error: .debug_abbrev: abbr. attribute 0x34: attribute location with invalid form block1.
EOF
+
+testrun_compare ./dwarflint garbage-7 <<EOF
+error: .debug_abbrev: abbr. attribute 0x7e: invalid or unknown name 0x703.
+error: .debug_abbrev: abbr. attribute 0x7e: invalid form 0x0.
+error: .debug_abbrev: abbreviation 122: missing zero to mark end-of-table.
+EOF