checks.hh checks_i.hh \
coverage.cc coverage.hh \
cu_coverage.cc cu_coverage.hh cu_coverage_i.hh \
+ die_locus.cc die_locus.hh \
dwarf_2.cc dwarf_2.hh \
dwarf_3.cc dwarf_3.hh \
dwarf_4.cc dwarf_4.hh \
expected-at.cc expected.hh \
files.cc files.hh \
highlevel_check.cc highlevel_check.hh highlevel_check_i.hh \
+ locus.cc locus.hh \
main.cc \
messages.cc messages.hh \
misc.cc misc.hh \
reloc.cc reloc.hh \
section_id.cc section_id.hh \
sections.cc sections.hh sections_i.hh \
- where.c where.h \
wrap.cc wrap.hh \
\
check_debug_abbrev.cc check_debug_abbrev.hh check_debug_abbrev_i.hh \
locstats_SOURCES = \
locstats.cc \
+ die_locus.cc die_locus.hh \
files.cc files.hh \
+ locus.cc locus.hh \
option.cc option.hh option_i.hh \
- pri.cc pri.hh \
- where.c where.h
+ section_id.cc section_id.hh \
+ pri.cc pri.hh
tests_test_coverage_SOURCES = tests/test-coverage.cc coverage.cc pri.cc \
../src/dwarfstrings.c
/* Pedantic checking of DWARF files
- Copyright (C) 2009,2010 Red Hat, Inc.
+ Copyright (C) 2009,2010,2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
<http://www.openinventionnetwork.com>. */
#include "addr-record.hh"
-#include "misc.hh"
size_t
-addr_record_find_addr (struct addr_record *ar, uint64_t addr)
+addr_record::find (uint64_t addr) const
{
size_t a = 0;
- size_t b = ar->size;
+ size_t b = size ();
while (a < b)
{
size_t i = (a + b) / 2;
- uint64_t v = ar->addrs[i];
+ uint64_t v = (*this)[i];
if (v > addr)
b = i;
}
bool
-addr_record_has_addr (struct addr_record *ar, uint64_t addr)
+addr_record::has_addr (uint64_t addr) const
{
- if (ar->size == 0
- || addr < ar->addrs[0]
- || addr > ar->addrs[ar->size - 1])
+ if (begin () == end ()
+ || addr < front ()
+ || addr > back ())
return false;
- size_t a = addr_record_find_addr (ar, addr);
- return a < ar->size && ar->addrs[a] == addr;
+ const_iterator it = begin () + find (addr);
+ return it != end () && *it == addr;
}
void
-addr_record_add (struct addr_record *ar, uint64_t addr)
+addr_record::add (uint64_t addr)
{
- size_t a = addr_record_find_addr (ar, addr);
- if (a >= ar->size || ar->addrs[a] != addr)
- {
- REALLOC (ar, addrs);
- size_t len = ar->size - a;
- memmove (ar->addrs + a + 1, ar->addrs + a, len * sizeof (*ar->addrs));
-
- ar->addrs[a] = addr;
- ar->size++;
- }
-}
-
-void
-addr_record_free (struct addr_record *ar)
-{
- if (ar != NULL)
- free (ar->addrs);
-}
-
-void
-ref_record_add (struct ref_record *rr, uint64_t addr, struct where *referrer)
-{
- REALLOC (rr, refs);
- struct ref *ref = rr->refs + rr->size++;
- ref->addr = addr;
- ref->who = *referrer;
-}
-
-void
-ref_record_free (struct ref_record *rr)
-{
- if (rr != NULL)
- free (rr->refs);
+ iterator it = begin () + find (addr);
+ if (it == end () || *it != addr)
+ insert (it, addr);
}
/* Pedantic checking of DWARF files
- Copyright (C) 2009,2010 Red Hat, Inc.
+ Copyright (C) 2009,2010,2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
#include <stdlib.h>
#include <stdint.h>
-#include "where.h"
-#ifdef __cplusplus
-extern "C"
-{
-#else
-# include <stdbool.h>
-#endif
-
- /* Functions and data structures for address record handling. We
- use that to check that all DIE references actually point to an
- existing die, not somewhere mid-DIE, where it just happens to be
- interpretable as a DIE. */
+#include <vector>
- struct addr_record
- {
- size_t size;
- size_t alloc;
- uint64_t *addrs;
- };
+#include "locus.hh"
- size_t addr_record_find_addr (struct addr_record *ar, uint64_t addr);
- bool addr_record_has_addr (struct addr_record *ar, uint64_t addr);
- void addr_record_add (struct addr_record *ar, uint64_t addr);
- void addr_record_free (struct addr_record *ar);
+/// Address record is used to check that all DIE references actually
+/// point to an existing die, not somewhere mid-DIE, where it just
+/// happens to be interpretable as a DIE. This is stored as sorted
+/// array for quick lookup and duplicate removal.
+struct addr_record
+ : private std::vector<uint64_t>
+{
+ typedef std::vector<uint64_t> _super_t;
+ size_t find (uint64_t addr) const;
- /* Functions and data structures for reference handling. Just like
- the above, we use this to check validity of DIE references.
- Unlike the above, this is not stored as sorted set, but simply as
- an array of records, because duplicates are unlikely. */
+public:
+ bool has_addr (uint64_t addr) const;
+ void add (uint64_t addr);
+};
- struct ref
- {
- uint64_t addr; // Referree address
- struct where who; // Referrer
- };
+/// One reference for use in ref_record, parametrized by locus type.
+template <class L>
+struct ref_T
+{
+ uint64_t addr; // Referee address
+ L who; // Referrer
- struct ref_record
- {
- size_t size;
- size_t alloc;
- struct ref *refs;
- };
+ ref_T ()
+ : addr (-1)
+ {}
- void ref_record_add (struct ref_record *rr, uint64_t addr,
- struct where *referrer);
- void ref_record_free (struct ref_record *rr);
+ ref_T (uint64_t a_addr, L const &a_who)
+ : addr (a_addr)
+ , who (a_who)
+ {}
+};
-#ifdef __cplusplus
-}
-#endif
+/// Reference record is used to check validity of DIE references.
+/// Unlike the above, this is not stored as sorted set, but simply as
+/// an array of records, because duplicates are unlikely.
+template <class L>
+class ref_record_T
+ : private std::vector<ref_T<L> >
+{
+ typedef std::vector<ref_T<L> > _super_t;
+public:
+ using _super_t::const_iterator;
+ using _super_t::begin;
+ using _super_t::end;
+ using _super_t::push_back;
+};
#endif//DWARFLINT_ADDR_RECORD_H
#include "messages.hh"
#include "misc.hh"
+char const *
+locus_simple_fmt::abbr_offset_n ()
+{
+ return "abbr. offset";
+}
+
+abbrev_attrib_locus::abbrev_attrib_locus (uint64_t abbr_offset,
+ uint64_t attr_offset,
+ int a_name)
+ : _m_abbr_offset (abbr_offset)
+ , _m_attr_offset (attr_offset)
+ , _m_name (a_name)
+{}
+
+abbrev_attrib_locus::abbrev_attrib_locus (abbrev_attrib_locus const ©)
+ : _m_abbr_offset (copy._m_abbr_offset)
+ , _m_attr_offset (copy._m_attr_offset)
+ , _m_name (copy._m_name)
+{}
+
+std::string
+abbrev_attrib_locus::name () const
+{
+ return pri::attr_name (_m_name);
+}
+
+void
+abbrev_attrib_locus::set_name (int a_name)
+{
+ _m_name = a_name;
+}
+
+abbrev_attrib_locus
+abbrev_attrib_locus::non_symbolic ()
+{
+ return abbrev_attrib_locus (_m_abbr_offset, _m_attr_offset);
+}
+
+std::string
+abbrev_attrib_locus::format (bool brief) const
+{
+ std::stringstream ss;
+ if (!brief)
+ ss << section_name[sec_abbrev] << ": ";
+ if (_m_name != -1)
+ ss << "abbr. 0x" << std::hex << _m_abbr_offset << ", attr. " << name ();
+ else
+ ss << "abbr. attribute 0x" << std::hex << _m_attr_offset;
+ return ss.str ();
+}
+
checkdescriptor const *
check_debug_abbrev::descriptor ()
{
};
void
- complain (where const *where,
- int attrib_name, int form_name,
+ complain (locus const &loc, int form_name,
bool indirect, char const *qualifier)
{
- wr_error (*where)
- << "attribute " << elfutils::dwarf::attributes::name (attrib_name)
- << " with " << qualifier << (indirect ? " indirect" : "")
- << " form " << elfutils::dwarf::forms::name (form_name)
+ wr_error (loc)
+ << "attribute with " << qualifier << (indirect ? " indirect" : "")
+ << " form " << elfutils::dwarf::forms::identifier (form_name)
<< '.' << std::endl;
}
// But since we got here, apparently there was a .debug_abbrev
// section with size of more than 0 bytes, which is wasteful.
if (ret)
- {
- where wh = WHERE (sec_abbrev, NULL);
- wr_message (wh, mc_abbrevs | mc_impact_1 | mc_acc_bloat)
- << "no abbreviations." << std::endl;
- }
+ wr_message (section_locus (sec_abbrev),
+ mc_abbrevs | mc_impact_1 | mc_acc_bloat)
+ << "no abbreviations." << std::endl;
return ret;
}
struct abbrev_table *section = NULL;
uint64_t first_attr_off = 0;
- struct where where = WHERE (sec_abbrev, NULL);
// Tolerate failure here.
dwarf_version const *ver = NULL;
static dwarf_version const *latest_ver = dwarf_version::get_latest ();
- where.addr1 = 0;
bool failed = false;
while (true)
if (read_ctx_eof (&ctx))
{
if (!check_no_abbreviations (abbrevs))
- wr_error (&where, ": missing zero to mark end-of-table.\n");
+ wr_error (section_locus (sec_abbrev))
+ << "missing zero to mark end-of-table.\n";
break;
}
do
{
abbr_off = read_ctx_get_offset (&ctx);
- where_reset_2 (&where, abbr_off);
/* Abbreviation code. */
- if (!checked_read_uleb128 (&ctx, &abbr_code, &where, "abbrev code"))
+ if (!checked_read_uleb128 (&ctx, &abbr_code,
+ section_locus (sec_abbrev, abbr_off),
+ "abbrev code"))
throw check_base::failed ();
/* Note: we generally can't tell the difference between
|| ((abbr_off += 1), false));
if (zero_seq_off != (uint64_t)-1)
- {
- struct where wh = WHERE (where.section, NULL);
- wr_message_padding_0 (mc_abbrevs | mc_header,
- &wh, zero_seq_off, abbr_off);
- }
+ wr_message_padding_0 (mc_abbrevs | mc_header,
+ section_locus (sec_abbrev),
+ zero_seq_off, abbr_off);
}
if (read_ctx_eof (&ctx))
break;
}
+ abbrev_locus where (abbr_off);
+
/* OK, we got some genuine abbreviation. See if we need to
allocate a new section. */
if (section == NULL)
{
abbrev_table t;
- WIPE (t);
section = &abbrevs.insert (std::make_pair (abbr_off, t)).first->second;
section->offset = abbr_off;
- where_reset_1 (&where, abbr_off);
- where_reset_2 (&where, abbr_off);
-
// Find CU that uses this abbrev table, so that we know what
// version to validate against.
if (cu_headers != NULL)
ver = dwarf_version::get_latest ();
}
}
- else if (ver == NULL)
+ else if (ver == NULL) // Only emit this once.
{
- struct where wh = WHERE (sec_info, NULL);
- wr_error (wh)
+ wr_error (section_locus (sec_info))
<< "couldn't load CU headers for processing .debug_abbrev; "
"assuming latest DWARF flavor."
<< std::endl;
assert (ver != NULL);
}
- struct abbrev *original = section->find_abbrev (abbr_code);
+ abbrev *original = section->find_abbrev (abbr_code);
+ abbrev *cur;
+ abbrev fake (where);
if (unlikely (original != NULL))
- wr_error (where)
- << "duplicate abbrev code " << abbr_code
- << "; already defined at " << original->where << '.' << std::endl;
-
- struct abbrev fake;
- struct abbrev *cur;
- /* Don't actually save this abbrev if it's duplicate. */
- if (likely (original == NULL))
+ {
+ wr_error (where) << "duplicate abbrev code (first was at "
+ << original->where << ").\n";
+ /* Don't actually save this abbrev if it's duplicate. */
+ cur = &fake;
+ }
+ else
{
REALLOC (section, abbr);
cur = section->abbr + section->size++;
+ new (cur) abbrev (where);
}
- else
- cur = &fake;
- WIPE (*cur);
cur->code = abbr_code;
- cur->where = where;
/* Abbreviation tag. */
uint64_t abbr_tag;
- if (!checked_read_uleb128 (&ctx, &abbr_tag, &where, "abbrev tag"))
+ if (!checked_read_uleb128 (&ctx, &abbr_tag, where, "abbrev tag"))
throw check_base::failed ();
if (abbr_tag > DW_TAG_hi_user)
/* Shift to match elfutils reporting. */
attr_off -= first_attr_off;
- where_reset_3 (&where, attr_off);
+ abbrev_attrib_locus attr_locus (abbr_off, attr_off);
/* Load attribute name and form. */
- if (!checked_read_uleb128 (&ctx, &attrib_name, &where,
+ if (!checked_read_uleb128 (&ctx, &attrib_name, attr_locus,
"attribute name"))
throw check_base::failed ();
- if (!checked_read_uleb128 (&ctx, &attrib_form, &where,
+ if (!checked_read_uleb128 (&ctx, &attrib_form, attr_locus,
"attribute form"))
throw check_base::failed ();
REALLOC (cur, attribs);
+ attr_locus.set_name (attrib_name);
struct abbrev_attrib *acur = cur->attribs + cur->size++;
- WIPE (*acur);
+ new (acur) abbrev_attrib ();
acur->name = attrib_name;
acur->form = attrib_form;
- acur->where = where;
+ acur->where = attr_locus;
if (null_attrib)
break;
/* Otherwise validate name and form. */
if (attrib_name == 0)
{
- wr_error (where) << "invalid attribute code 0." << std::endl;
+ wr_error (attr_locus.non_symbolic ())
+ << "invalid attribute code 0." << std::endl;
// We can handle this, so keep going. But this is not
// kosher for high-level checks.
failed = true;
if (attribute == NULL)
// libdw should handle unknown attribute, as long as
// the form is kosher, so don't fail the check.
- wr_message (where, mc_abbrevs | mc_impact_1)
+ wr_message (attr_locus.non_symbolic (),
+ mc_abbrevs | mc_impact_1)
<< "invalid or unknown name " << pri::hex (attrib_name)
<< '.' << std::endl;
else if (opt_nognu)
- wr_message (where, mc_abbrevs | mc_impact_1)
- << "attribute " << *attribute
- << " from later DWARF version."
+ wr_message (attr_locus, mc_abbrevs | mc_impact_1)
+ << "attribute from later DWARF version."
<< std::endl;
}
form const *form = check_debug_abbrev::check_form
- (ver, attribute, attrib_form, &where, false);
+ (ver, attribute, attrib_form, attr_locus, false);
if (form == NULL)
{
// Error message has been emitted in check_form.
= seen.insert (std::make_pair (attrib_name, attr_off));
if (!inserted.second)
{
- wr_error (where)
- << "duplicate attribute "
- << elfutils::dwarf::attributes::name (attrib_name)
+ wr_error (attr_locus.non_symbolic ())
+ << "duplicate attribute " << attr_locus.name ()
<< " (first was at " << pri::hex (inserted.first->second)
<< ")." << std::endl;
+
// I think we may allow such files for high-level
// consumption, so don't fail the check...
if (attrib_name == DW_AT_sibling)
failed = true;
}
- if (attrib_name == DW_AT_sibling)
- {
- if (!cur->has_children)
- wr_message (where, mc_die_rel | mc_acc_bloat | mc_impact_1)
- << "superfluous DW_AT_sibling attribute at childless abbrev."
- << std::endl;
- }
+ if (attrib_name == DW_AT_sibling && !cur->has_children)
+ wr_message (attr_locus, mc_die_rel | mc_acc_bloat | mc_impact_1)
+ << "superfluous DW_AT_sibling attribute at childless abbrev."
+ << std::endl;
if (attrib_name == DW_AT_ranges)
ranges = true;
else if (attrib_name == DW_AT_low_pc)
}
while (!null_attrib);
- where_reset_2 (&where, where.addr2); // drop addr 3
if (high_pc && !low_pc)
wr_error (where)
<< "the abbrev has DW_AT_high_pc without also having DW_AT_low_pc."
form const *
check_debug_abbrev::check_form (dwarf_version const *ver,
attribute const *attribute,
- int form_name,
- where const *where, bool indirect)
+ int form_name, locus const &loc, bool indirect)
{
form const *form = ver->get_form (form_name);
if (form == NULL)
{
- wr_error (*where)
+ wr_error (loc)
<< "invalid form " << pri::hex (form_name)
<< '.' << std::endl;
return NULL;
int attrib_name = attribute->name ();
if (!ver->form_allowed (attribute, form))
{
- complain (where, attrib_name, form_name, indirect, "invalid");
+ complain (loc, 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");
+ complain (loc, form_name, indirect, "unsuitable");
}
return form;
/* Low-level checking of .debug_abbrev.
- Copyright (C) 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
#include "check_debug_info_i.hh"
#include "dwarf_version_i.hh"
+namespace locus_simple_fmt
+{
+ char const *abbr_offset_n ();
+}
+
+typedef fixed_locus<sec_abbrev,
+ locus_simple_fmt::abbr_offset_n,
+ locus_simple_fmt::hex> abbrev_locus;
+
+class abbrev_attrib_locus
+ : public locus
+{
+ uint64_t _m_abbr_offset;
+ uint64_t _m_attr_offset;
+ int _m_name;
+
+public:
+ explicit abbrev_attrib_locus (uint64_t abbr_offset = -1,
+ uint64_t attr_offset = -1,
+ int name = -1);
+
+ abbrev_attrib_locus (abbrev_attrib_locus const ©);
+
+ abbrev_attrib_locus non_symbolic ();
+
+ void set_name (int name);
+ std::string format (bool brief = false) const;
+ std::string name () const;
+};
+
struct abbrev_attrib
{
- struct where where;
+ abbrev_attrib_locus where;
uint16_t name;
uint8_t form;
+
+ abbrev_attrib ()
+ : where ()
+ , name (0)
+ , form (0)
+ {}
};
struct abbrev
{
+ abbrev_locus where;
uint64_t code;
- struct where where;
/* Attributes. */
- struct abbrev_attrib *attribs;
+ abbrev_attrib *attribs;
size_t size;
size_t alloc;
/* Whether some DIE uses this abbrev. */
bool used;
+
+ explicit abbrev (abbrev_locus const &loc)
+ : where (loc)
+ , code (0)
+ , attribs (0)
+ , size (0)
+ , alloc (0)
+ , tag (0)
+ , has_children (false)
+ , used (false)
+ {}
};
struct abbrev_table
bool used; /* There are CUs using this table. */
abbrev *find_abbrev (uint64_t abbrev_code) const;
+
+ abbrev_table ()
+ : next (NULL)
+ , abbr (NULL)
+ , offset (0)
+ , size (0)
+ , alloc (0)
+ , used (false)
+ {}
};
class check_debug_abbrev
static form const *check_form (dwarf_version const *ver,
attribute const *attr,
int form_name,
- where const *where,
+ locus const &loc,
bool indirect);
~check_debug_abbrev ();
#include "misc.hh"
#include "pri.hh"
+char const *
+locus_simple_fmt::cudie_n ()
+{
+ return "CU DIE";
+}
+
+std::string
+arange_locus::format (bool brief) const
+{
+ std::stringstream ss;
+ if (!brief)
+ ss << section_name[sec_aranges] << ": ";
+
+ if (_m_arange_offset != (Dwarf_Off)-1)
+ ss << "arange 0x" << std::hex << _m_arange_offset;
+ else if (_m_table_offset != (Dwarf_Off)-1)
+ ss << "table " << std::dec << _m_table_offset;
+ else
+ ss << "arange";
+
+ if (_m_cudie_locus != NULL)
+ ss << " (" << _m_cudie_locus->format (true) << ')';
+
+ return ss.str ();
+}
+
checkdescriptor const *
check_debug_aranges::descriptor ()
{
|| !necessary_alignment (start, length, sec->shdr.sh_addralign))
{
char buf[128];
- where where = WHERE (info.id, NULL);
char const *what = info.what;
char const *cu = "CU DIEs";
if (info.reverse)
what = cu;
cu = tmp;
}
- wr_message (where, mc_aranges | mc_impact_3)
+ wr_message (section_locus (info.id), mc_aranges | mc_impact_3)
<< "addresses " << range_fmt (buf, sizeof (buf), start, start + length)
<< " are covered with " << cu << ", but not with " << what << "."
<< std::endl;
inline static void
aranges_coverage_add (struct coverage *aranges_coverage,
uint64_t begin, uint64_t length,
- struct where *where)
+ locus const &loc)
{
if (aranges_coverage->is_overlap (begin, length))
{
char buf[128];
/* Not a show stopper, this shouldn't derail high-level. */
- wr_message (*where, mc_aranges | mc_impact_2 | mc_error)
+ wr_message (loc, mc_aranges | mc_impact_2 | mc_error)
<< "the range " << range_fmt (buf, sizeof buf, begin, begin + length)
<< " overlaps with another one." << std::endl;
}
while (!read_ctx_eof (&ctx))
{
- struct where where = WHERE (sec_aranges, NULL);
- where_reset_1 (&where, read_ctx_get_offset (&ctx));
+ arange_locus where (read_ctx_get_offset (&ctx));
const unsigned char *atab_begin = ctx.ptr;
/* Size. */
wr_error (&where, ": can't read table length.\n");
return false;
}
- if (!read_size_extra (&ctx, size32, &size, &offset_size, &where))
+ if (!read_size_extra (&ctx, size32, &size, &offset_size, where))
return false;
struct read_ctx sub_ctx;
retval = false;
goto next;
}
- if (!supported_version (version, 1, &where, 2))
+ if (!supported_version (version, 1, where, 2))
{
retval = false;
goto next;
struct relocation *rel;
if ((rel = relocation_next (&sec->rel, ctx_offset,
- &where, skip_mismatched)))
+ where, skip_mismatched)))
relocate_one (file, &sec->rel, rel, offset_size,
- &cu_offset, &where, sec_info, NULL);
+ &cu_offset, where, sec_info, NULL);
else if (file->ehdr.e_type == ET_REL)
wr_message (mc_impact_2 | mc_aranges | mc_reloc | mc_header, &where,
PRI_LACK_RELOCATION, "debug info offset");
if (cu_chain != NULL && (cu = cu_find_cu (cu_chain, cu_offset)) == NULL)
wr_error (&where, ": unresolved reference to " PRI_CU ".\n", cu_offset);
- struct where where_cudie;
+ cudie_locus cudie_loc (cu != NULL ? cu->cudie_offset : -1);
if (cu != NULL)
{
- where_cudie = WHERE (sec_info, NULL);
- where_reset_1 (&where_cudie, cu->cudie_offset);
- where.ref = &where_cudie;
- where_cudie.formatting = wf_cudie;
+ where.set_cudie (&cudie_loc);
if (cu->has_arange)
wr_error (where)
<< "there has already been arange section for this CU."
/* Address size. */
int address_size;
error_code err = read_address_size (&sub_ctx, file->addr_64,
- &address_size, &where);
+ &address_size, where);
if (err != err_ok)
retval = false;
if (err == err_fatal)
way, the better to catch structural errors accurately.
So report arange offset instead. If this becomes a
problem, we will achieve this by two-pass analysis. */
- where_reset_2 (&where, read_ctx_get_offset (&sub_ctx));
+ where.set_arange (read_ctx_get_offset (&sub_ctx));
/* Record address. */
uint64_t address;
}
if ((rel = relocation_next (&sec->rel, ctx_offset,
- &where, skip_mismatched)))
+ where, skip_mismatched)))
{
address_relocated = true;
relocate_one (file, &sec->rel, rel, address_size,
- &address, &where, rel_address, NULL);
+ &address, where, rel_target::rel_address, NULL);
}
else if (file->ehdr.e_type == ET_REL && address != 0)
wr_message (mc_impact_2 | mc_aranges | mc_reloc, &where,
wr_error (&where, ": zero-length address range.\n");
/* Skip coverage analysis if we have errors. */
else if (retval && aranges_coverage != NULL)
- aranges_coverage_add (aranges_coverage, address, length, &where);
+ aranges_coverage_add (aranges_coverage, address, length, where);
}
if (sub_ctx.ptr != sub_ctx.end)
{
uint64_t start, end;
- struct where wh = WHERE (where.section, NULL);
+ section_locus wh (sec_aranges);
if (read_check_zero_padding (&sub_ctx, &start, &end))
- wr_message_padding_0 (mc_aranges, &wh, start, end);
+ wr_message_padding_0 (mc_aranges, wh, start, end);
else
{
- wr_message_padding_n0 (mc_aranges | mc_error, &wh,
+ wr_message_padding_n0 (mc_aranges | mc_error, wh,
start, start + size);
retval = false;
}
/* Low-level checking of .debug_aranges.
- Copyright (C) 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
#include "check_debug_info_i.hh"
#include "cu_coverage_i.hh"
+namespace locus_simple_fmt
+{
+ char const *cudie_n ();
+};
+
+class cudie_locus
+ : public fixed_locus<sec_info,
+ locus_simple_fmt::cudie_n,
+ locus_simple_fmt::dec>
+{
+ typedef fixed_locus<sec_info,
+ locus_simple_fmt::cudie_n,
+ locus_simple_fmt::dec> _super_t;
+public:
+ template <class T>
+ cudie_locus (T const &die)
+ : _super_t (die.offset ())
+ {}
+
+ cudie_locus (Dwarf_Off offset)
+ : _super_t (offset)
+ {}
+};
+
+class arange_locus
+ : public locus
+{
+ Dwarf_Off _m_table_offset;
+ Dwarf_Off _m_arange_offset;
+ locus const *_m_cudie_locus;
+
+public:
+ explicit arange_locus (Dwarf_Off table_offset = -1,
+ Dwarf_Off arange_offset = -1)
+ : _m_table_offset (table_offset)
+ , _m_arange_offset (arange_offset)
+ , _m_cudie_locus (NULL)
+ {}
+
+ explicit arange_locus (locus const &cudie_locus)
+ : _m_table_offset (-1)
+ , _m_arange_offset (-1)
+ , _m_cudie_locus (&cudie_locus)
+ {}
+
+ void
+ set_cudie (locus const *cudie_locus)
+ {
+ _m_cudie_locus = cudie_locus;
+ }
+
+ void
+ set_arange (Dwarf_Off arange_offset)
+ {
+ _m_arange_offset = arange_offset;
+ }
+
+ std::string format (bool brief = false) const;
+};
+
class check_debug_aranges
: public check<check_debug_aranges>
{
#include "check_debug_info.hh"
#include "check_debug_line.hh"
#include "check_debug_aranges.hh"
-#include "misc.hh"
checkdescriptor const *
read_cu_headers::descriptor ()
}
bool
- check_die_references (struct cu *cu,
- struct ref_record *die_refs)
+ check_die_references (cu *cu, ref_record *die_refs)
{
bool retval = true;
- for (size_t i = 0; i < die_refs->size; ++i)
- {
- struct ref *ref = die_refs->refs + i;
- if (!addr_record_has_addr (&cu->die_addrs, ref->addr))
- {
- wr_error (ref->who)
- << "unresolved reference to " << pri::DIE (ref->addr)
- << '.' << std::endl;
- retval = false;
- }
- }
+ for (ref_record::const_iterator it = die_refs->begin ();
+ it != die_refs->end (); ++it)
+ if (!cu->die_addrs.has_addr (it->addr))
+ {
+ wr_error (it->who)
+ << "unresolved reference to " << pri::DIE (it->addr)
+ << '.' << std::endl;
+ retval = false;
+ }
return retval;
}
{
bool retval = true;
for (struct cu *it = cu_chain; it != NULL; it = it->next)
- for (size_t i = 0; i < it->die_refs.size; ++i)
+ for (ref_record::const_iterator rt = it->die_refs.begin ();
+ rt != it->die_refs.end (); ++rt)
{
- struct ref *ref = it->die_refs.refs + i;
struct cu *ref_cu = NULL;
for (struct cu *jt = cu_chain; jt != NULL; jt = jt->next)
- if (addr_record_has_addr (&jt->die_addrs, ref->addr))
+ if (jt->die_addrs.has_addr (rt->addr))
{
ref_cu = jt;
break;
if (ref_cu == NULL)
{
- wr_error (ref->who)
+ wr_error (rt->who)
<< "unresolved (non-CU-local) reference to "
- << pri::hex (ref->addr) << '.' << std::endl;
+ << pri::hex (rt->addr) << '.' << std::endl;
retval = false;
}
else if (ref_cu == it)
reference is valid, which it is. But warn about this
anyway, perhaps local reference could be formed on
smaller number of bytes. */
- wr_message (ref->who, mc_impact_2 | mc_acc_suboptimal | mc_die_rel)
- << "local reference to " << pri::DIE (ref->addr)
+ wr_message (rt->who, mc_impact_2 | mc_acc_suboptimal | mc_die_rel)
+ << "local reference to " << pri::DIE (rt->addr)
<< " formed as global." << std::endl;
}
while (!read_ctx_eof (&ctx))
{
const unsigned char *cu_begin = ctx.ptr;
- struct where where = WHERE (sec_info, NULL);
- where_reset_1 (&where, read_ctx_get_offset (&ctx));
-
- cu_head head;
- head.offset = where.addr1;
- head.where = where;
+ uint64_t offset = read_ctx_get_offset (&ctx);
+ cu_head head (offset);
/* Reading CU head is a bit tricky, because we don't know if
we have run into (superfluous but allowed) zero padding
if (!read_ctx_need_data (&ctx, 4)
&& read_check_zero_padding (&ctx, &off_start, &off_end))
{
- wr_message_padding_0 (mc_info | mc_header, &where,
+ wr_message_padding_0 (mc_info | mc_header, head.where,
off_start, off_end);
break;
}
uint32_t size32;
if (!read_ctx_read_4ubyte (&ctx, &size32))
{
- wr_error (where) << "can't read CU length." << std::endl;
+ wr_error (head.where) << "can't read CU length." << std::endl;
throw check_base::failed ();
}
if (size32 == 0
&& read_check_zero_padding (&ctx, &off_start, &off_end))
{
- wr_message_padding_0 (mc_info | mc_header, &where,
+ wr_message_padding_0 (mc_info | mc_header, head.where,
off_start, off_end);
break;
}
Dwarf_Off cu_size;
if (!read_size_extra (&ctx, size32, &cu_size,
- &head.offset_size, &where))
+ &head.offset_size, head.where))
throw check_base::failed ();
if (!read_ctx_need_data (&ctx, cu_size))
{
- wr_error (where)
+ wr_error (head.where)
<< "section doesn't have enough data to read CU of size "
<< cu_size << '.' << std::endl;
throw check_base::failed ();
if (dwarf_version::get (version) == NULL)
{
wr_error (head.where) << "unsupported CU version "
- << version << '.' << std::endl;
+ << version << '.' << std::endl;
throw check_base::failed ();
}
if (version == 2 && head.offset_size == 8) // xxx?
}
struct relocation *rel
- = relocation_next (reloc, ctx_offset, &head.where, skip_ok);
+ = relocation_next (reloc, ctx_offset, head.where, skip_ok);
if (rel != NULL)
{
relocate_one (file, reloc, rel, head.offset_size,
- &head.abbrev_offset, &head.where, sec_abbrev, NULL);
+ &head.abbrev_offset, head.where, sec_abbrev, NULL);
rel->invalid = true; // mark as invalid so it's skipped
// next time we pass by this
}
/* Address size. */
error_code err = read_address_size (&ctx, file->addr_64,
- &head.address_size, &head.where);
+ &head.address_size, head.where);
if (err == err_fatal)
throw check_base::failed ();
else if (err == err_nohl)
if (!read_ctx_skip (&ctx, head.size))
{
- wr_error (where) << pri::not_enough ("next CU") << std::endl;
+ wr_error (head.where) << pri::not_enough ("next CU") << std::endl;
throw check_base::failed ();
}
return ret;
}
- section_id
+ rel_target
reloc_target (form const *form, attribute const *attribute)
{
switch (form->name ())
case DW_AT_low_pc:
case DW_AT_high_pc:
case DW_AT_entry_pc:
- return rel_exec;
+ return rel_target::rel_exec;
case DW_AT_const_value:
/* Appears in some kernel modules. It's not allowed by the
standard, but leave that for high-level checks. */
- return rel_address;
+ return rel_target::rel_address;
};
break;
std::cout << "XXX don't know how to handle form=" << *form
<< ", at=" << *attribute << std::endl;
- return rel_value;
+ return rel_target::rel_value;
}
struct value_check_cb_ctx
{
struct read_ctx *const ctx;
- struct where *const where;
+ die_locus const *where;
struct cu *const cu;
- struct ref_record *local_die_refs;
+ ref_record *local_die_refs;
Elf_Data *strings;
struct coverage *strings_coverage;
struct coverage *pc_coverage;
if (ctx->local_die_refs != NULL)
/* Address holds a CU-local reference, so add CU offset
to turn it into section offset. */
- ref_record_add (ctx->local_die_refs,
- addr + ctx->cu->head->offset, ctx->where);
+ ctx->local_die_refs->push_back (ref (addr + ctx->cu->head->offset,
+ *ctx->where));
}
/* Callback for global DIE references. */
void
check_die_ref_global (uint64_t addr, struct value_check_cb_ctx const *ctx)
{
- ref_record_add (&ctx->cu->die_refs, addr, ctx->where);
+ ctx->cu->die_refs.push_back (ref (addr, *ctx->where));
}
/* Callback for strp values. */
<< "rangeptr value " << pri::hex (value)
<< " not aligned to CU address size." << std::endl;
*ctx->need_rangesp = true;
- ref_record_add (&ctx->cu->range_refs, value, ctx->where);
+ ctx->cu->range_refs.push_back (ref (value, *ctx->where));
}
/* Callback for lineptr values. */
if (ctx->cu->stmt_list.addr != (uint64_t)-1)
wr_error (*ctx->where)
<< "DW_AT_stmt_list mentioned twice in a CU." << std::endl;
- ctx->cu->stmt_list.addr = value;
- ctx->cu->stmt_list.who = *ctx->where;
+ ctx->cu->stmt_list = ref (value, *ctx->where);
}
/* Callback for locptr values. */
void
check_locptr (uint64_t value, struct value_check_cb_ctx const *ctx)
{
- ref_record_add (&ctx->cu->loc_refs, value, ctx->where);
+ ctx->cu->loc_refs.push_back (ref (value, *ctx->where));
}
void
check_decl_file (uint64_t value, struct value_check_cb_ctx const *ctx)
{
- ref_record_add (&ctx->cu->decl_file_refs, value, ctx->where);
+ ctx->cu->decl_file_refs.push_back (ref (value, *ctx->where));
}
/* The real sibling checking takes place down in read_die_chain.
if (addr == 0)
{
wr_error (*ctx->where)
- << "DW_AT_sibling with a value of 0." << std::endl;
+ << "has a value of 0." << std::endl;
// Don't let this up.
*ctx->retval_p = -2;
}
int
read_die_chain (dwarf_version const *ver,
elf_file const &file,
- struct read_ctx *ctx,
- struct cu *cu,
- struct abbrev_table const *abbrevs,
+ read_ctx *ctx,
+ cu *cu,
+ abbrev_table const *abbrevs,
Elf_Data *strings,
- struct ref_record *local_die_refs,
- struct coverage *strings_coverage,
- struct relocation_data *reloc,
- struct coverage *pc_coverage,
+ ref_record *local_die_refs,
+ coverage *strings_coverage,
+ relocation_data *reloc,
+ coverage *pc_coverage,
bool *need_rangesp,
unsigned level)
{
uint64_t sibling_addr = 0;
uint64_t die_off, prev_die_off = 0;
struct abbrev *abbrev = NULL;
- struct where where = WHERE (sec_info, NULL);
unsigned long die_count = 0;
int retval = 0;
struct value_check_cb_ctx cb_ctx = {
- ctx, &where, cu,
+ ctx, NULL, cu,
local_die_refs,
strings, strings_coverage,
pc_coverage,
while (!read_ctx_eof (ctx))
{
- where = cu->head->where;
die_off = read_ctx_get_offset (ctx);
/* Shift reported DIE offset by CU offset, to match the way
readelf reports DIEs. */
- where_reset_2 (&where, die_off + cu->head->offset);
+ die_locus where (cu->head->offset + die_off);
+ cb_ctx.where = &where;
uint64_t abbr_code;
- if (!checked_read_uleb128 (ctx, &abbr_code, &where, "abbrev code"))
+ if (!checked_read_uleb128 (ctx, &abbr_code, where, "abbrev code"))
return -1;
-#define DEF_PREV_WHERE \
- struct where prev_where = where; \
- where_reset_2 (&prev_where, prev_die_off + cu->head->offset)
+#define DEF_PREV_WHERE die_locus prev_where (cu->head->offset + prev_die_off)
/* Check sibling value advertised last time through the loop. */
if (sibling_addr != 0)
}
}
- addr_record_add (&cu->die_addrs, cu->head->offset + die_off);
+ cu->die_addrs.add (cu->head->offset + die_off);
uint64_t low_pc = (uint64_t)-1, high_pc = (uint64_t)-1;
bool low_pc_relocated = false, high_pc_relocated = false;
for (struct abbrev_attrib *it = abbrev->attribs;
it->name != 0 || it->form != 0; ++it)
{
- where.ref = &it->where;
+ where.set_attrib_name (it->name);
int form_name = it->form;
// In following, attribute may be NULL, but form never
{
uint64_t value;
if (!read_sc_value (&value, form->width (cu->head),
- ctx, &where))
+ ctx, where))
return -1;
form_name = value;
form = check_debug_abbrev::check_form
- (ver, attribute, form_name, &where, true);
+ (ver, attribute, form_name, where, true);
// N.B. check_form emits appropriate error messages.
if (form == NULL)
return -1;
storage_class_t storclass = form->storage_class ();
if (!read_generic_value (ctx, form->width (cu->head), storclass,
- &where, &value, &block))
+ where, &value, &block))
{
// Note that for fw_uleb and fw_sleb we report the
// error the second time now.
// field? See check_debug_loc_range::op_read_form
if (!check_location_expression
(ver, file, &block, cu,
- expr_start, reloc, value, &where))
+ expr_start, reloc, value, where))
return -1;
}
else
relocation_skip (reloc, read_ctx_get_offset (ctx),
- &where, skip_mismatched);
+ where, skip_mismatched);
}
/* Relocate the value if appropriate. */
struct relocation *rel;
if ((rel = relocation_next (reloc, ctx_offset,
- &where, skip_mismatched)))
+ where, skip_mismatched)))
{
if (relocate == rel_no)
wr_message (where, (mc_impact_4 | mc_die_other
if (attribute != NULL)
{
form_width_t width = form->width (cu->head);
- relocate_one (&file, reloc, rel, width, &value, &where,
+ relocate_one (&file, reloc, rel, width, &value, where,
reloc_target (form, attribute), symbolp);
}
else
{
if (symbolp != NULL)
- WIPE (*symbolp);
+ memset (*symbolp, 0, sizeof (**symbolp));
if (type_is_rel
&& (relocate == rel_require
|| (relocate == rel_nonzero
if (valuep != NULL)
*valuep = value;
}
- where.ref = NULL;
+ where.set_attrib_name (-1);
if (high_pc != (uint64_t)-1 && low_pc != (uint64_t)-1
&& high_pc_relative)
else
{
if (!high_pc_relative)
- check_range_relocations (mc_die_other, &where,
+ check_range_relocations (where, mc_die_other,
&file,
low_pc_symbol, high_pc_symbol,
"DW_AT_low_pc and DW_AT_high_pc");
}
}
- where.ref = &abbrev->where;
-
if (abbrev->has_children)
{
int st = read_die_chain (ver, file, ctx, cu, abbrevs, strings,
}
if (sibling_addr != 0)
- wr_error (where)
+ wr_error (die_locus (cu->head->offset + prev_die_off))
<< "this DIE should have had its sibling at " << pri::hex (sibling_addr)
<< ", but the DIE chain ended." << std::endl;
check_debug_abbrev::abbrev_map const &abbrev_tables = _m_abbrevs->abbrevs;
if (dump_die_offsets)
- fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL));
+ fprintf (stderr, "%s: CU starts\n", cu->head->where.format ().c_str ());
bool retval = true;
dwarf_version const *ver = dwarf_version::get (cu->head->version);
struct abbrev_table const &abbrevs = abbrev_it->second;
/* Read DIEs. */
- struct ref_record local_die_refs;
- WIPE (local_die_refs);
+ ref_record local_die_refs;
cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset;
int st = read_die_chain (ver, _m_file, ctx, cu, &abbrevs, strings,
else if (!check_die_references (cu, &local_die_refs))
retval = false;
- ref_record_free (&local_die_refs);
return retval;
}
sec &sec = _m_sec_info->sect;
Elf_Data *const strings = _m_sec_str->sect.data;
- struct ref_record die_refs;
- WIPE (die_refs);
+ ref_record die_refs;
bool success = true;
it != cu_headers.end (); ++it)
{
cu_head const &head = *it;
- where const &where = head.where;
+ cu_locus where = head.where;
{
cu cur;
memset (&cur, 0, sizeof (cur));
{
uint64_t off_start, off_end;
if (read_check_zero_padding (&cu_ctx, &off_start, &off_end))
- wr_message_padding_0 (mc_info, &where, off_start, off_end);
+ wr_message_padding_0 (mc_info, where, off_start, off_end);
else
{
// Garbage coordinates:
uint64_t start = read_ctx_get_offset (&ctx) + off_start;
uint64_t end = read_ctx_get_offset (&ctx) + head.total_size;
- wr_message_padding_n0 (mc_info, &where, start, end);
+ wr_message_padding_n0 (mc_info, where, start, end);
}
}
if (success)
{
+ section_locus wh (sec_info);
if (ctx.ptr != ctx.end)
/* Did we read up everything? */
- {
- where wh = WHERE (sec_info, NULL);
- wr_message (mc_die_other | mc_impact_4, &wh,
- ": CU lengths don't exactly match Elf_Data contents.");
- }
+ wr_message (mc_die_other | mc_impact_4, &wh,
+ ": CU lengths don't exactly match Elf_Data contents.");
else
/* Did we consume all the relocations? */
- relocation_skip_rest (&sec.rel, sec.id);
+ relocation_skip_rest (&sec.rel, wh);
/* If we managed to read up everything, now do abbrev usage
analysis. */
that's not necessary anymore. */
check_global_die_references (!cus.empty () ? &cus.front () : NULL);
- ref_record_free (&die_refs);
if (strings_coverage != NULL)
{
check_debug_info::~check_debug_info ()
{
- for (std::vector<cu>::iterator it = cus.begin ();
- it != cus.end (); ++it)
- {
- addr_record_free (&it->die_addrs);
- ref_record_free (&it->die_refs);
- ref_record_free (&it->range_refs);
- ref_record_free (&it->loc_refs);
- ref_record_free (&it->decl_file_refs);
- }
}
cu *
it != _m_info->cus.end (); ++it)
{
if (it->stmt_list.addr == (uint64_t)-1)
- for (size_t i = 0; i < it->decl_file_refs.size; ++i)
- wr_error (it->decl_file_refs.refs[i].who)
+ for (ref_record::const_iterator jt = it->decl_file_refs.begin ();
+ jt != it->decl_file_refs.end (); ++jt)
+ wr_error (jt->who)
<< "references .debug_line table, but CU DIE lacks DW_AT_stmt_list."
<< std::endl;
else if (_m_line == NULL
#include "check_debug_line_i.hh"
#include "check_debug_aranges_i.hh"
#include "sections_i.hh"
+#include "die_locus.hh"
+
+typedef ref_T<die_locus> ref;
+typedef ref_record_T<die_locus> ref_record;
struct cu_head
{
- uint64_t offset;
+ Dwarf_Off offset;
Dwarf_Off size; // Size of this CU.
Dwarf_Off head_size; // Size from begin to 1st byte of CU.
Dwarf_Off total_size; // size + head_size
- int offset_size; // Offset size in this CU.
- struct where where; // Where this section was defined.
+ int offset_size; // Offset size in this CU.
Dwarf_Off abbrev_offset; // Abbreviation section that this CU uses.
int version; // CU version
int address_size; // Address size in bytes on the target machine.
+
+ cu_locus where;
+
+ explicit cu_head (Dwarf_Off a_offset)
+ : offset (a_offset)
+ , size (0)
+ , head_size (0)
+ , total_size (0)
+ , offset_size (0)
+ , abbrev_offset (0)
+ , version (0)
+ , address_size (0)
+ , where (a_offset)
+ {}
};
struct cu
{
struct cu *next; // For compatibility with C level.
// xxx will probably go away eventually
- struct cu_head const *head;
+ cu_head const *head;
uint64_t cudie_offset;
uint64_t low_pc; // DW_AT_low_pc value of CU DIE, -1 if not present.
- struct ref stmt_list;
- struct addr_record die_addrs; // Addresses where DIEs begin in this CU.
- struct ref_record die_refs; // DIE references into other CUs from this CU.
- struct ref_record loc_refs; // references into .debug_loc from this CU.
- struct ref_record range_refs; // references into .debug_ranges from this CU.
- struct ref_record decl_file_refs; // values of DW_AT_decl_file in this CU.
+ ::ref stmt_list;
+ addr_record die_addrs; // Addresses where DIEs begin in this CU.
+ ref_record die_refs; // DIE references into other CUs from this CU.
+ ref_record loc_refs; // references into .debug_loc from this CU.
+ ref_record range_refs; // references into .debug_ranges from this CU.
+ ref_record decl_file_refs; // values of DW_AT_decl_file in this CU.
bool has_arange; // Whether we saw arange section pointing at this CU.
bool has_pubnames; // Likewise for pubnames.
bool has_pubtypes; // Likewise for pubtypes.
+
+ cu ()
+ : next (NULL)
+ , head (NULL)
+ , cudie_offset (0)
+ , low_pc (0)
+ , has_arange (false)
+ , has_pubnames (false)
+ , has_pubtypes (false)
+ {}
};
/** The pass for reading basic .debug_info data -- the layout of
Network licensing program, please visit www.openinventionnetwork.com
<http://www.openinventionnetwork.com>. */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include "check_debug_line.hh"
#include "check_debug_info.hh"
#include "sections.hh"
bool read_directory_index (include_directories_t &include_directories,
files_t &files, read_ctx *ctx,
const char *name, uint64_t *ptr,
- where *where, bool &retval)
+ locus const &loc, bool &retval)
{
size_t nfile = files.size () + 1;
if (!checked_read_uleb128 (ctx, ptr,
- where, "directory index"))
+ loc, "directory index"))
return false;
if (*name == '/' && *ptr != 0)
- wr_message (*where, mc_impact_2 | mc_line | mc_header)
+ wr_message (loc, mc_impact_2 | mc_line | mc_header)
<< "file #" << nfile
<< " has absolute pathname, but refers to directory != 0."
<< std::endl;
if (*ptr > include_directories.size ())
/* Not >=, dirs are indexed from 1. */
{
- wr_message (*where, mc_impact_4 | mc_line | mc_header)
+ wr_message (loc, mc_impact_4 | mc_line | mc_header)
<< "file #" << nfile
<< " refers to directory #" << *ptr
<< ", which wasn't defined." << std::endl;
bool
use_file (files_t &files, uint64_t file_idx,
- where *where, char const *msg = "")
+ locus const &loc, char const *msg = "")
{
if (file_idx == 0 || file_idx > files.size ())
{
- wr_error (*where)
+ wr_error (loc)
<< msg << "invalid file index " << file_idx << '.'
<< std::endl;
return false;
}
}
+namespace
+{
+ char const *
+ table_n ()
+ {
+ return "table";
+ }
+
+ typedef fixed_locus<sec_line, table_n,
+ locus_simple_fmt::dec> line_table_locus;
+}
+
check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint)
: _m_sec (lint.check (stack, _m_sec))
, _m_info (lint.toplev_check (stack, _m_info))
while (!read_ctx_eof (&ctx))
{
- struct where where = WHERE (_m_sec->sect.id, NULL);
uint64_t set_offset = read_ctx_get_offset (&ctx);
- where_reset_1 (&where, set_offset);
+ line_table_locus where (set_offset);
_m_line_tables.insert ((Dwarf_Off)set_offset);
const unsigned char *set_begin = ctx.ptr;
wr_error (where) << "can't read table length." << std::endl;
throw check_base::failed ();
}
- if (!read_size_extra (&ctx, size32, &size, &offset_size, &where))
+ if (!read_size_extra (&ctx, size32, &size, &offset_size, where))
throw check_base::failed ();
struct read_ctx sub_ctx;
success = false;
goto next;
}
- if (!supported_version (version, 2, &where, 2, 3))
+ if (!supported_version (version, 2, where, 2, 3))
goto skip;
/* Header length. */
uint64_t dir_idx;
if (!read_directory_index (include_directories, files,
- &sub_ctx, name, &dir_idx, &where, success))
+ &sub_ctx, name, &dir_idx, where, success))
goto skip;
/* Time of last modification. */
uint64_t timestamp;
if (!checked_read_uleb128 (&sub_ctx, ×tamp,
- &where, "timestamp of file entry"))
+ where, "timestamp of file entry"))
goto skip;
/* Size of the file. */
uint64_t file_size;
if (!checked_read_uleb128 (&sub_ctx, &file_size,
- &where, "file size of file entry"))
+ where, "file size of file entry"))
goto skip;
files.push_back ((struct file_t){name, dir_idx, false});
if (it->stmt_list.addr == set_offset)
{
found = true;
- for (size_t i = 0; i < it->decl_file_refs.size; ++i)
- if (!use_file (files,
- it->decl_file_refs.refs[i].addr,
- &it->decl_file_refs.refs[i].who))
+ for (ref_record::const_iterator
+ jt = it->decl_file_refs.begin ();
+ jt != it->decl_file_refs.end (); ++jt)
+ if (!use_file (files, jt->addr, jt->who))
success = false;
}
if (!found)
else if (sub_ctx.ptr < program_start)
{
/* Skip the rest of the header. */
- struct where wh = WHERE (sec_line, NULL);
uint64_t off_start, off_end;
if (read_check_zero_padding (&sub_ctx, &off_start, &off_end))
- wr_message_padding_0 (mc_line | mc_header, &wh,
+ wr_message_padding_0 (mc_line | mc_header, section_locus (sec_line),
off_start, off_end);
else
- wr_message_padding_n0 (mc_line | mc_header, &wh,
- off_start, program_start - sub_ctx.begin);
+ wr_message_padding_n0
+ (mc_line | mc_header, section_locus (sec_line),
+ off_start, program_start - sub_ctx.begin);
sub_ctx.ptr = program_start;
}
bool seen_opcode = false;
while (!read_ctx_eof (&sub_ctx))
{
- where_reset_2 (&where, read_ctx_get_offset (&sub_ctx));
+ section_locus op_where (sec_line, read_ctx_get_offset (&sub_ctx));
uint8_t opcode;
if (!read_ctx_read_ubyte (&sub_ctx, &opcode))
{
- wr_error (where) << "can't read opcode." << std::endl;
+ wr_error (op_where) << "can't read opcode." << std::endl;
goto skip;
}
case 0:
{
uint64_t skip_len;
- if (!checked_read_uleb128 (&sub_ctx, &skip_len, &where,
+ if (!checked_read_uleb128 (&sub_ctx, &skip_len, op_where,
"length of extended opcode"))
goto skip;
if (!read_ctx_need_data (&sub_ctx, skip_len))
{
- wr_error (where)
+ wr_error (op_where)
<< "not enough data to read an opcode of length "
<< skip_len << '.' << std::endl;
goto skip;
const unsigned char *next = sub_ctx.ptr + skip_len;
if (!read_ctx_read_ubyte (&sub_ctx, &extended))
{
- wr_error (where)
+ wr_error (op_where)
<< "can't read extended opcode." << std::endl;
goto skip;
}
uint64_t addr;
if (!read_ctx_read_offset (&sub_ctx, addr_64, &addr))
{
- wr_error (where)
+ wr_error (op_where)
<< "can't read operand of DW_LNE_set_address."
<< std::endl;
goto skip;
struct relocation *rel;
if ((rel = relocation_next (&_m_sec->sect.rel, ctx_offset,
- &where, skip_mismatched)))
+ op_where, skip_mismatched)))
relocate_one (&_m_sec->file, &_m_sec->sect.rel, rel,
- addr_64 ? 8 : 4,
- &addr, &where, rel_address, NULL);
+ addr_64 ? 8 : 4, &addr, op_where,
+ rel_target::rel_address, NULL);
else if (_m_sec->file.ehdr.e_type == ET_REL)
{
- wr_message (where, mc_impact_2 | mc_line | mc_reloc)
+ wr_message (op_where,
+ mc_impact_2 | mc_line | mc_reloc)
<< pri::lacks_relocation ("DW_LNE_set_address")
<< '.' << std::endl;
}
if (addr == 0)
- wr_message (where, mc_line | mc_impact_1)
+ wr_message (op_where, mc_line | mc_impact_1)
<< "DW_LNE_set_address with zero operand."
<< std::endl;
break;
/* XXX Is there anything interesting we should
check here? */
uint64_t disc;
- if (!checked_read_uleb128 (&sub_ctx, &disc, &where,
+ if (!checked_read_uleb128 (&sub_ctx, &disc, op_where,
"set_discriminator operand"))
goto skip;
sequence change. So setting to zero is never
necessary. */
if (disc == 0)
- wr_message (where, mc_line | mc_impact_1)
+ wr_message (op_where, mc_line | mc_impact_1)
<< "DW_LNE_set_discriminator with zero operand."
<< std::endl;
break;
const char *name;
if ((name = read_ctx_read_str (&sub_ctx)) == NULL)
{
- wr_error (where)
+ wr_error (op_where)
<< "can't read filename operand of DW_LNE_define_file."
<< std::endl;
goto skip;
uint64_t dir_idx;
if (!read_directory_index (include_directories,
files, &sub_ctx, name,
- &dir_idx, &where, success))
+ &dir_idx, op_where, success))
goto skip;
files.push_back
((struct file_t){name, dir_idx, false});
#undef ONE_KNOWN_DW_LNE
default:
/* No we don't, emit a warning. */
- wr_message (where, mc_impact_2 | mc_line)
+ wr_message (op_where, mc_impact_2 | mc_line)
<< "unknown extended opcode 0x"
<< std::hex << +extended << std::dec
<< '.' << std::endl;
if (sub_ctx.ptr > next)
{
- wr_error (where)
+ wr_error (op_where)
<< "opcode claims that it has a size of " << skip_len
<< ", but in fact it has a size of "
<< (skip_len + (next - sub_ctx.ptr)) << '.' << std::endl;
uint64_t off_start, off_end;
if (handled)
{
- struct where wh = WHERE (sec_line, NULL);
if (read_check_zero_padding (&sub_ctx,
&off_start, &off_end))
- wr_message_padding_0 (mc_line, &wh,
- off_start, off_end);
+ wr_message_padding_0
+ (mc_line, section_locus (sec_line),
+ off_start, off_end);
else
- wr_message_padding_n0 (mc_line, &wh,
- off_start,
- next - sub_ctx.begin);
+ wr_message_padding_n0
+ (mc_line, section_locus (sec_line),
+ off_start, next - sub_ctx.begin);
}
sub_ctx.ptr = next;
}
case DW_LNS_advance_line:
{
int64_t line_delta;
- if (!checked_read_sleb128 (&sub_ctx, &line_delta, &where,
+ if (!checked_read_sleb128 (&sub_ctx, &line_delta, op_where,
"DW_LNS_advance_line operand"))
goto skip;
}
uint16_t a;
if (!read_ctx_read_2ubyte (&sub_ctx, &a))
{
- wr_error (where)
+ wr_error (op_where)
<< "can't read operand of DW_LNS_fixed_advance_pc."
<< std::endl;
goto skip;
case DW_LNS_set_file:
{
uint64_t file_idx;
- if (!checked_read_uleb128 (&sub_ctx, &file_idx, &where,
+ if (!checked_read_uleb128 (&sub_ctx, &file_idx, op_where,
"DW_LNS_set_file operand"))
goto skip;
- if (!use_file (files, file_idx, &where, "DW_LNS_set_file: "))
+ if (!use_file (files, file_idx, op_where, "DW_LNS_set_file: "))
success = false;
first_file = false;
}
default:
if (opcode < opcode_base)
- wr_message (where, mc_impact_2 | mc_line)
+ wr_message (op_where, mc_impact_2 | mc_line)
<< "unknown standard opcode 0x"
<< std::hex << +opcode << std::dec
<< '.' << std::endl;
else
sprintf (buf, "operand #%d of DW_LNE_%s",
i, dwarf_line_extended_opcode_string (extended));
- if (!checked_read_uleb128 (&sub_ctx, &operand, &where, buf))
+ if (!checked_read_uleb128 (&sub_ctx, &operand, op_where, buf))
goto skip;
}
if (first_file)
{
- if (!use_file (files, 1, &where,
+ if (!use_file (files, 1, op_where,
"initial value of `file' register: "))
success = false;
first_file = false;
<< std::endl;
}
- struct where wh = WHERE (sec_line, NULL);
if (!terminated && seen_opcode)
wr_error (where)
<< "sequence of opcodes not terminated with DW_LNE_end_sequence."
{
uint64_t off_start, off_end;
if (read_check_zero_padding (&sub_ctx, &off_start, &off_end))
- wr_message_padding_0 (mc_line, &wh, off_start, off_end);
+ wr_message_padding_0
+ (mc_line, section_locus (sec_line), off_start, off_end);
else
- wr_message_padding_n0 (mc_line, &wh,
+ wr_message_padding_n0 (mc_line, section_locus (sec_line),
off_start, sub_ctx.end - sub_ctx.begin);
}
}
}
if (success)
- relocation_skip_rest (&_m_sec->sect.rel, _m_sec->sect.id);
+ relocation_skip_rest (&_m_sec->sect.rel, section_locus (_m_sec->sect.id));
else
throw check_base::failed ();
}
bool do_range_coverage = false; // currently no option
+global_opt<void_option>
+ opt_show_refs("\
+When validating .debug_loc and .debug_ranges, display information about \
+the DIE referring to the entry in consideration", "ref");
+
+std::string
+loc_range_locus::format (bool brief) const
+{
+ std::stringstream ss;
+ if (!brief)
+ ss << section_name[_m_sec] << ": ";
+
+ if (_m_sec == sec_loc)
+ ss << "loclist";
+ else
+ ss << "rangelist";
+
+ if (_m_offset != (Dwarf_Off)-1)
+ ss << " 0x" << std::hex << _m_offset;
+
+ if (opt_show_refs)
+ ss << ", ref. by " << _m_refby.format (true);
+
+ return ss.str ();
+}
+
checkdescriptor const *
check_debug_ranges::descriptor ()
{
struct hole_env
{
- struct where *where;
+ locus const &loc;
uint64_t address;
uint64_t end;
};
hole_env *env = (hole_env *)xenv;
char buf[128], buf2[128];
assert (h_length != 0);
- wr_error (env->where,
+ wr_error (&env->loc,
": portion %s of the range %s "
"doesn't fall into any ALLOC section.\n",
range_fmt (buf, sizeof buf,
{
struct coverage_map_hole_info *info = (struct coverage_map_hole_info *)user;
- struct where where = WHERE (info->info.section, NULL);
const char *scnname = sco->sec->name;
struct sec *sec = sco->sec;
return true;
char buf[128];
- wr_message (info->info.category | mc_acc_suboptimal | mc_impact_4, &where,
- ": addresses %s of section %s are not covered.\n",
- range_fmt (buf, sizeof buf, begin + base, end + base), scnname);
+ wr_message (section_locus (info->info.section),
+ info->info.category | mc_acc_suboptimal | mc_impact_4)
+ << "addresses " << range_fmt (buf, sizeof buf, begin + base, end + base)
+ << " of section " << scnname << " are not covered.\n";
return true;
}
coverage_map_add (struct coverage_map *coverage_map,
uint64_t address,
uint64_t length,
- struct where *where,
+ locus const &loc,
enum message_category cat)
{
bool found = false;
if (found && !crosses_boundary)
{
/* While probably not an error, it's very suspicious. */
- wr_message (cat | mc_impact_2, where,
+ wr_message (cat | mc_impact_2, &loc,
": the range %s crosses section boundaries.\n",
range_fmt (buf, sizeof buf, address, end));
crosses_boundary = true;
&& cov->is_overlap (cov_begin, cov_end - cov_begin))
{
/* Not a show stopper, this shouldn't derail high-level. */
- wr_message (*where, cat | mc_aranges | mc_impact_2 | mc_error)
+ wr_message (loc, cat | mc_aranges | mc_impact_2 | mc_error)
<< "the range " << range_fmt (buf, sizeof buf, address, end)
<< " overlaps with another one." << std::endl;
overlap = true;
}
if (sco->warn)
- wr_message (cat | mc_impact_2, where,
+ wr_message (cat | mc_impact_2, &loc,
": the range %s covers section %s.\n",
range_fmt (buf, sizeof buf, address, end), sco->sec->name);
if (!found)
/* Not a show stopper. */
- wr_error (where,
+ wr_error (&loc,
": couldn't find a section that the range %s covers.\n",
range_fmt (buf, sizeof buf, address, end));
else if (length > 0)
{
- hole_env env = {where, address, end};
+ hole_env env = {loc, address, end};
range_cov.find_holes (0, length, range_hole, &env);
}
}
struct coverage_map *coverage_map,
struct coverage *pc_coverage,
uint64_t addr,
- struct where const *wh,
+ locus const &loc,
enum message_category cat)
{
char buf[128]; // messages
read_ctx_init (&ctx, parent_ctx->data, file->other_byte_order);
if (!read_ctx_skip (&ctx, addr))
{
- wr_error (wh, ": invalid reference outside the section "
+ wr_error (&loc, ": invalid reference outside the section "
"%#" PRIx64 ", size only %#tx.\n",
addr, ctx.end - ctx.begin);
return false;
if (coverage->is_covered (addr, 1))
{
- wr_error (wh, ": reference to %#" PRIx64
+ wr_error (&loc, ": reference to %#" PRIx64
" points into another location or range list.\n", addr);
retval = false;
}
uint64_t base = cu->low_pc;
while (!read_ctx_eof (&ctx))
{
- struct where where = WHERE (sec->id, wh);
- where_reset_1 (&where, read_ctx_get_offset (&ctx));
+ uint64_t offset = read_ctx_get_offset (&ctx);
+ loc_range_locus where (sec->id, loc, offset);
#define HAVE_OVERLAP \
do { \
struct relocation *rel;
if ((rel = relocation_next (&sec->rel, begin_off,
- &where, skip_mismatched)))
+ where, skip_mismatched)))
{
begin_relocated = true;
relocate_one (file, &sec->rel, rel, cu->head->address_size,
- &begin_addr, &where, rel_value, &begin_symbol);
+ &begin_addr, where, rel_target::rel_value,
+ &begin_symbol);
}
/* end address */
}
if ((rel = relocation_next (&sec->rel, end_off,
- &where, skip_mismatched)))
+ where, skip_mismatched)))
{
end_relocated = true;
relocate_one (file, &sec->rel, rel, cu->head->address_size,
- &end_addr, &where, rel_value, &end_symbol);
+ &end_addr, where, rel_target::rel_value, &end_symbol);
if (begin_addr != escape)
{
if (!begin_relocated)
wr_message (cat | mc_impact_2 | mc_reloc, &where,
": end of address range is relocated, but the beginning wasn't.\n");
else
- check_range_relocations (cat, &where, file,
+ check_range_relocations (where, cat, file,
begin_symbol, end_symbol,
"begin and end address");
}
uint64_t address = begin_addr + base;
uint64_t length = end_addr - begin_addr;
if (coverage_map != NULL)
- coverage_map_add (coverage_map, address, length, &where, cat);
+ coverage_map_add (coverage_map, address, length, where, cat);
if (pc_coverage != NULL)
pc_coverage->add (address, length);
}
/* location expression itself */
uint64_t expr_start = read_ctx_get_offset (&ctx);
if (!check_location_expression
- (ver, *file, &ctx, cu, expr_start, &sec->rel, len, &where))
+ (ver, *file, &ctx, cu, expr_start, &sec->rel, len, where))
return false;
uint64_t expr_end = read_ctx_get_offset (&ctx);
if (!overlap
}
#undef HAVE_OVERLAP
- coverage->add (where.addr1, read_ctx_get_offset (&ctx) - where.addr1);
+ coverage->add (offset, read_ctx_get_offset (&ctx) - offset);
if (done)
break;
}
struct ref_cu
{
- struct ref ref;
- struct cu *cu;
- bool operator < (ref_cu const& other) const {
+ ::ref ref;
+ ::cu *cu;
+
+ bool
+ operator < (ref_cu const& other) const
+ {
return ref.addr < other.ref.addr;
}
};
&& (coverage_map
= coverage_map_alloc_XA (file, sec->id == sec_loc)) == NULL)
{
- wr_error (WHERE (sec->id, NULL))
+ wr_error (section_locus (sec->id))
<< "couldn't read ELF, skipping coverage analysis." << std::endl;
retval = false;
}
ref_cu_vect refs;
for (struct cu *cu = cu_chain; cu != NULL; cu = cu->next)
{
- struct ref_record *rec
+ ref_record *rec
= sec->id == sec_loc ? &cu->loc_refs : &cu->range_refs;
- for (size_t i = 0; i < rec->size; ++i)
+ for (ref_record::const_iterator it = rec->begin ();
+ it != rec->end (); ++it)
{
- ref_cu ref = {rec->refs[i], cu};
+ ref_cu ref = {*it, cu};
refs.push_back (ref);
}
}
{
if (off == last_off)
continue;
- struct where wh = WHERE (sec->id, NULL);
- relocation_skip (&sec->rel, off, &wh, skip_unref);
+ relocation_skip (&sec->rel, off, section_locus (sec->id),
+ skip_unref);
}
// xxx right now this is just so that we can ver->get_form
Perhaps that's undesirable. */
if (!check_loc_or_range_ref (ver, file, &ctx, it->cu, sec,
&coverage, coverage_map, pc_coverage,
- off, &it->ref.who, cat))
+ off, it->ref.who, cat))
retval = false;
last_off = off;
}
if (retval)
{
- relocation_skip_rest (&sec->rel, sec->id);
+ relocation_skip_rest (&sec->rel, section_locus (sec->id));
/* We check that all CUs have the same address size when building
the CU chain. So just take the address size of the first CU in
return true;
}
- static enum section_id
+ static rel_target
reloc_target_loc (uint8_t opcode)
{
switch (opcode)
return sec_info;
case DW_OP_addr:
- return rel_address;
+ return rel_target::rel_address;
case DW_OP_call_ref:
assert (!"Can't handle call_ref!");
std::cout << "XXX don't know how to handle opcode="
<< elfutils::dwarf::ops::name (opcode) << std::endl;
- return rel_value;
+ return rel_target::rel_value;
}
bool
form const *form,
uint64_t *valuep,
char const *str,
- struct where *where)
+ locus const &where)
{
if (form == NULL)
return true;
if (!read_generic_value (ctx, form->width (cu->head), storclass,
where, valuep, NULL))
{
- wr_error (*where)
+ wr_error (where)
<< "opcode \"" << elfutils::dwarf::ops::name (opcode)
<< "\": can't read " << str << " (form \""
<< *form << "\")." << std::endl;
cu->head->address_size, valuep, where,
reloc_target_loc (opcode), NULL);
else
- wr_error (where, ": relocation relocates a length field.\n");
+ wr_error (where) << "relocation relocates a length field.\n";
}
if (storclass == sc_block)
{
}
}
+class locexpr_locus
+ : public locus
+{
+ uint64_t _m_offset;
+ locus const *_m_context;
+
+public:
+ explicit locexpr_locus (uint64_t offset, locus const *context)
+ : _m_offset (offset)
+ , _m_context (context)
+ {}
+
+ std::string
+ format (bool) const
+ {
+ std::stringstream ss;
+ ss << _m_context
+ << " (location expression offset 0x" << std::hex << _m_offset << ")";
+ return ss.str ();
+ }
+};
+
bool
check_location_expression (dwarf_version const *ver,
elf_file const &file,
uint64_t init_off,
struct relocation_data *reloc,
size_t length,
- struct where *wh)
+ locus const &loc)
{
struct read_ctx ctx;
if (!read_ctx_init_sub (&ctx, parent_ctx, parent_ctx->ptr,
parent_ctx->ptr + length))
{
- wr_error (wh, PRI_NOT_ENOUGH, "location expression");
+ wr_error (&loc, PRI_NOT_ENOUGH, "location expression");
return false;
}
- struct ref_record oprefs;
- WIPE (oprefs);
-
- struct addr_record opaddrs;
- WIPE (opaddrs);
+ typedef ref_T<locexpr_locus> locexpr_ref;
+ typedef ref_record_T<locexpr_locus> locexpr_ref_record;
+ locexpr_ref_record oprefs;
+ addr_record opaddrs;
while (!read_ctx_eof (&ctx))
{
- struct where where = WHERE (sec_locexpr, wh);
uint64_t opcode_off = read_ctx_get_offset (&ctx) + init_off;
- where_reset_1 (&where, opcode_off);
- addr_record_add (&opaddrs, opcode_off);
+ locexpr_locus where (opcode_off, &loc);
+ opaddrs.add (opcode_off);
uint8_t opcode;
if (!read_ctx_read_ubyte (&ctx, &opcode))
uint64_t value1, value2;
if (!op_read_form (file, &ctx, cu, init_off, reloc,
- opcode, form1, &value1, "1st operand", &where)
+ opcode, form1, &value1, "1st operand", where)
|| !op_read_form (file, &ctx, cu, init_off, reloc,
- opcode, form2, &value2, "2st operand", &where))
+ opcode, form2, &value2, "2st operand", where))
goto out;
switch (opcode)
else
{
uint64_t off_after = read_ctx_get_offset (&ctx) + init_off;
- ref_record_add (&oprefs, off_after + skip, &where);
+ oprefs.push_back (locexpr_ref (off_after + skip, where));
}
break;
}
out:
- for (size_t i = 0; i < oprefs.size; ++i)
- {
- struct ref *ref = oprefs.refs + i;
- if (!addr_record_has_addr (&opaddrs, ref->addr))
- wr_error (&ref->who,
- ": unresolved reference to opcode at %#" PRIx64 ".\n",
- ref->addr);
- }
-
- addr_record_free (&opaddrs);
- ref_record_free (&oprefs);
+ for (locexpr_ref_record::const_iterator it = oprefs.begin ();
+ it != oprefs.end (); ++it)
+ if (!opaddrs.has_addr (it->addr))
+ wr_error (it->who) << "unresolved reference to opcode at "
+ << pri::hex (it->addr) << ".\n";
return true;
}
}
}
else
- {
- /* XXX: This actually lies when the unreferenced portion is
- composed of sequences of zeroes and non-zeroes. */
- struct where wh = WHERE (info->section, NULL);
- wr_message_padding_n0 (info->category, &wh, start, end);
- }
+ /* XXX: This actually lies when the unreferenced portion is
+ composed of sequences of zeroes and non-zeroes. */
+ wr_message_padding_n0 (info->category, section_locus (info->section),
+ start, end);
return true;
}
void
-check_range_relocations (enum message_category cat,
- struct where *where,
+check_range_relocations (locus const &loc,
+ enum message_category cat,
struct elf_file const *file,
GElf_Sym *begin_symbol,
GElf_Sym *end_symbol,
if (begin_symbol != NULL
&& end_symbol != NULL
&& begin_symbol->st_shndx != end_symbol->st_shndx)
- wr_message (cat | mc_impact_2 | mc_reloc, where,
+ wr_message (cat | mc_impact_2 | mc_reloc, &loc,
": %s relocated against different sections (%s and %s).\n",
description,
file->sec[begin_symbol->st_shndx].name,
/* Low-level checking of .debug_loc and .debug_range.
- Copyright (C) 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
#include "coverage.hh"
#include "dwarf_version_i.hh"
+class loc_range_locus
+ : public locus
+{
+ locus const &_m_refby;
+ Dwarf_Off _m_offset;
+ section_id _m_sec;
+
+public:
+ loc_range_locus (section_id sec, locus const &refby, Dwarf_Off offset = -1)
+ : _m_refby (refby)
+ , _m_offset (offset)
+ , _m_sec ((assert (sec == sec_loc || sec == sec_ranges), sec))
+ {}
+
+ std::string format (bool brief) const;
+};
+
struct section_coverage
{
struct sec *sec;
uint64_t init_off,
struct relocation_data *reloc,
size_t length,
- struct where *wh);
+ locus const &loc);
-void check_range_relocations (enum message_category cat,
- struct where *where,
+void check_range_relocations (locus const &loc,
+ enum message_category cat,
struct elf_file const *file,
GElf_Sym *begin_symbol,
GElf_Sym *end_symbol,
Network licensing program, please visit www.openinventionnetwork.com
<http://www.openinventionnetwork.com>. */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include "check_debug_pub.hh"
#include "check_debug_info.hh"
#include "sections.hh"
#include "messages.hh"
#include "misc.hh"
+namespace
+{
+ bool check_pub_structural (elf_file const &file, sec §,
+ check_debug_info *cus);
+}
+
template<section_id sec_id>
check_debug_pub<sec_id>::check_debug_pub (checkstack &stack, dwarflint &lint)
: _m_sec (lint.check (stack, _m_sec))
, _m_file (_m_sec->file)
, _m_cus (lint.toplev_check (stack, _m_cus))
{
- check_pub_structural ();
+ check_pub_structural (_m_file, _m_sec->sect, _m_cus);
}
static reg<check_debug_pubtypes> reg_debug_pubtypes;
-
-template <section_id sec_id>
-bool
-check_debug_pub<sec_id>::check_pub_structural ()
+namespace
{
- struct read_ctx ctx;
- read_ctx_init (&ctx, _m_sec->sect.data, _m_file.other_byte_order);
- bool retval = true;
-
- while (!read_ctx_eof (&ctx))
- {
- enum section_id sid = _m_sec->sect.id;
- struct where where = WHERE (sid, NULL);
- where_reset_1 (&where, read_ctx_get_offset (&ctx));
- const unsigned char *set_begin = ctx.ptr;
-
- /* Size. */
- uint32_t size32;
- uint64_t size;
- int offset_size;
- if (!read_ctx_read_4ubyte (&ctx, &size32))
- {
- wr_error (&where, ": can't read table length.\n");
- return false;
- }
- if (!read_size_extra (&ctx, size32, &size, &offset_size, &where))
- return false;
-
+ bool
+ check_pub_structural (elf_file const &file, sec §,
+ check_debug_info *cus)
+ {
+ struct read_ctx ctx;
+ read_ctx_init (&ctx, sect.data, file.other_byte_order);
+ bool retval = true;
+
+ while (!read_ctx_eof (&ctx))
{
- struct read_ctx sub_ctx;
- const unsigned char *set_end = ctx.ptr + size;
- if (!read_ctx_init_sub (&sub_ctx, &ctx, set_begin, set_end))
- goto not_enough;
- sub_ctx.ptr = ctx.ptr;
-
- /* Version. */
- uint16_t version;
- if (!read_ctx_read_2ubyte (&sub_ctx, &version))
- {
- wr_error (&where, ": can't read set version.\n");
- retval = false;
- goto next;
- }
- if (!supported_version (version, 1, &where, 2))
- {
- retval = false;
- goto next;
- }
+ enum section_id sid = sect.id;
+ section_locus where (sid, read_ctx_get_offset (&ctx));
+ const unsigned char *set_begin = ctx.ptr;
+
+ /* Size. */
+ uint32_t size32;
+ uint64_t size;
+ int offset_size;
+ if (!read_ctx_read_4ubyte (&ctx, &size32))
+ {
+ wr_error (&where, ": can't read table length.\n");
+ return false;
+ }
+ if (!read_size_extra (&ctx, size32, &size, &offset_size, where))
+ return false;
- /* CU offset. */
- uint64_t cu_offset; /* Offset of related CU. */
- uint64_t ctx_offset = sub_ctx.ptr - ctx.begin;
- if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_offset))
{
- wr_error (&where, ": can't read debug info offset.\n");
- retval = false;
- goto next;
- }
+ struct read_ctx sub_ctx;
+ const unsigned char *set_end = ctx.ptr + size;
+ if (!read_ctx_init_sub (&sub_ctx, &ctx, set_begin, set_end))
+ goto not_enough;
+ sub_ctx.ptr = ctx.ptr;
+
+ /* Version. */
+ uint16_t version;
+ if (!read_ctx_read_2ubyte (&sub_ctx, &version))
+ {
+ wr_error (&where, ": can't read set version.\n");
+ retval = false;
+ goto next;
+ }
+ if (!supported_version (version, 1, where, 2))
+ {
+ retval = false;
+ goto next;
+ }
- struct relocation *rel;
- if ((rel = relocation_next (&_m_sec->sect.rel, ctx_offset,
- &where, skip_mismatched)))
- relocate_one (&_m_file, &_m_sec->sect.rel, rel, offset_size,
- &cu_offset, &where, sec_info, NULL);
- else if (_m_file.ehdr.e_type == ET_REL)
- wr_message (mc_impact_2 | mc_pubtables | mc_reloc | mc_header, &where,
- PRI_LACK_RELOCATION, "debug info offset");
-
- struct cu *cu = NULL;
- if (_m_cus != NULL && (cu = _m_cus->find_cu (cu_offset)) == NULL)
- wr_error (where)
- << "unresolved reference to " << pri::CU (cu_offset)
- << '.' << std::endl;
- // xxx this can be checked even without CU
- if (cu != NULL)
- {
- where.ref = &cu->head->where;
- bool *has = _m_sec->sect.id == sec_pubnames
- ? &cu->has_pubnames : &cu->has_pubtypes;
- if (*has)
- wr_message (mc_impact_2 | mc_pubtables | mc_header, &where,
- ": there has already been section for this CU.\n");
- else
- *has = true;
- }
+ /* CU offset. */
+ uint64_t cu_offset; /* Offset of related CU. */
+ {
+ uint64_t ctx_offset = sub_ctx.ptr - ctx.begin;
+ if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_offset))
+ {
+ wr_error (&where, ": can't read debug info offset.\n");
+ retval = false;
+ goto next;
+ }
- /* Covered length. */
- uint64_t cu_len;
- if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_len))
- {
- wr_error (&where, ": can't read covered length.\n");
- retval = false;
- goto next;
- }
- if (cu != NULL && cu_len != cu->head->total_size)
- {
- wr_error (where)
- << "the table covers length " << cu_len << " but CU has length "
- << cu->head->total_size << '.' << std::endl;
- retval = false;
- goto next;
- }
+ struct relocation *rel;
+ if ((rel = relocation_next (§.rel, ctx_offset,
+ where, skip_mismatched)))
+ relocate_one (&file, §.rel, rel, offset_size,
+ &cu_offset, where, sec_info, NULL);
+ else if (file.ehdr.e_type == ET_REL)
+ wr_message (mc_impact_2 | mc_pubtables | mc_reloc | mc_header, &where,
+ PRI_LACK_RELOCATION, "debug info offset");
+ }
- /* Records... */
- while (!read_ctx_eof (&sub_ctx))
- {
- ctx_offset = sub_ctx.ptr - ctx.begin;
- where_reset_2 (&where, ctx_offset);
+ struct cu *cu = NULL;
+ if (cus != NULL && (cu = cus->find_cu (cu_offset)) == NULL)
+ wr_error (where)
+ << "unresolved reference to " << pri::CU (cu_offset)
+ << '.' << std::endl;
+ // xxx this can be checked even without CU
+ if (cu != NULL)
+ {
+ //where.ref = &cu->head->where;
+ bool *has = sect.id == sec_pubnames
+ ? &cu->has_pubnames : &cu->has_pubtypes;
+ if (*has)
+ wr_message (mc_impact_2 | mc_pubtables | mc_header, &where,
+ ": there has already been section for this CU.\n");
+ else
+ *has = true;
+ }
- uint64_t offset;
- if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &offset))
+ /* Covered length. */
+ uint64_t cu_len;
+ if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &cu_len))
{
- wr_error (&where, ": can't read offset field.\n");
+ wr_error (&where, ": can't read covered length.\n");
retval = false;
goto next;
}
- if (offset == 0)
- break;
-
- if (cu != NULL
- && !addr_record_has_addr (&cu->die_addrs,
- offset + cu->head->offset))
+ if (cu != NULL && cu_len != cu->head->total_size)
{
wr_error (where)
- << "unresolved reference to " << pri::DIE (offset)
- << '.' << std::endl;
+ << "the table covers length " << cu_len << " but CU has length "
+ << cu->head->total_size << '.' << std::endl;
retval = false;
goto next;
}
- // xxx read_ctx_read_str???
- uint8_t c;
- do
- if (!read_ctx_read_ubyte (&sub_ctx, &c))
- {
- wr_error (&where, ": can't read symbol name.\n");
- retval = false;
- goto next;
- }
- while (c);
- }
+ /* Records... */
+ while (!read_ctx_eof (&sub_ctx))
+ {
+ section_locus rec_where (sect.id, sub_ctx.ptr - ctx.begin);
+
+ uint64_t offset;
+ if (!read_ctx_read_offset (&sub_ctx, offset_size == 8, &offset))
+ {
+ wr_error (&rec_where, ": can't read offset field.\n");
+ retval = false;
+ goto next;
+ }
+ if (offset == 0)
+ break;
+
+ if (cu != NULL
+ && !cu->die_addrs.has_addr (offset + cu->head->offset))
+ {
+ wr_error (rec_where)
+ << "unresolved reference to " << pri::DIE (offset)
+ << '.' << std::endl;
+ retval = false;
+ goto next;
+ }
+
+ // xxx read_ctx_read_str???
+ uint8_t c;
+ do
+ if (!read_ctx_read_ubyte (&sub_ctx, &c))
+ {
+ wr_error (&rec_where, ": can't read symbol name.\n");
+ retval = false;
+ goto next;
+ }
+ while (c);
+ }
- sid = _m_sec->sect.id;
- struct where wh = WHERE (sid, NULL);
- if (sub_ctx.ptr != sub_ctx.end)
- {
- uint64_t off_start, off_end;
- if (read_check_zero_padding (&sub_ctx, &off_start, &off_end))
- wr_message_padding_0 (mc_pubtables, &wh, off_start, off_end);
- else
- {
- wr_message_padding_n0 (mc_pubtables | mc_error, &wh,
- off_start, off_start + size);
- retval = false;
- }
- }
- }
+ if (sub_ctx.ptr != sub_ctx.end)
+ {
+ uint64_t off_start, off_end;
+ if (read_check_zero_padding (&sub_ctx, &off_start, &off_end))
+ wr_message_padding_0 (mc_pubtables, section_locus (sect.id),
+ off_start, off_end);
+ else
+ {
+ wr_message_padding_n0 (mc_pubtables | mc_error,
+ section_locus (sect.id),
+ off_start, off_start + size);
+ retval = false;
+ }
+ }
+ }
- next:
- if (read_ctx_skip (&ctx, size))
- continue;
+ next:
+ if (read_ctx_skip (&ctx, size))
+ continue;
- not_enough:
- wr_error (&where, PRI_NOT_ENOUGH, "next set");
- return false;
- }
+ not_enough:
+ wr_error (&where, PRI_NOT_ENOUGH, "next set");
+ return false;
+ }
- if (retval)
- relocation_skip_rest (&_m_sec->sect.rel, _m_sec->sect.id);
+ if (retval)
+ relocation_skip_rest (§.rel, section_locus (sect.id));
- return retval;
+ return retval;
+ }
}
elf_file const &_m_file;
check_debug_info *_m_cus;
- bool check_pub_structural ();
-
public:
// instantiated in .cc for each subclass
check_debug_pub (checkstack &stack, dwarflint &lint);
decl_file = attrs.find (DW_AT_decl_file);
if (decl_column != attrs.end () && decl_line == attrs.end ())
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " has decl_column, but NOT decl_line" << std::endl;
if (decl_line != attrs.end () && decl_file == attrs.end ())
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " has decl_line, but NOT decl_file" << std::endl;
if (decl_file != attrs.end () && decl_line == attrs.end ())
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " has decl_file, but NOT decl_line" << std::endl;
call_file = attrs.find (DW_AT_call_file);
if (call_column != attrs.end () && call_line == attrs.end ())
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " has call_column, but NOT call_line" << std::endl;
if (call_line != attrs.end () && call_file == attrs.end ())
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " has call_line, but NOT call_file" << std::endl;
if (call_file != attrs.end () && call_line == attrs.end ())
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " has call_file, but NOT call_line" << std::endl;
}
if (! found)
- wr_message (to_where (entry), mc_impact_3 | mc_acc_suboptimal)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_suboptimal)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
<< " " << dwarf::attributes::name (pc.first) << "=0x"
r += reason;
}
- wr_error (to_where (*a_d_it))
+ wr_error (die_locus (*a_d_it))
<< "A check failed: " << (_m_cd->name () ?: "(nil)")
<< r << std::endl;
}
varinfo &i = old->second;
if ((declaration && i.decl != children.end ())
|| (!declaration && i.def != children.end ()))
- wr_message (to_where (*jt), mc_impact_3 | mc_die_other)
+ wr_message (die_locus (*jt), mc_impact_3 | mc_die_other)
.id (descriptor ())
<< "Re" << (declaration ? "declaration" : "definition")
<< " of variable '" << name << "', originally seen at "
<< pri::ref (declaration ? *i.decl : *i.def)
<< '.' << std::endl;
else
- wr_message (to_where (*jt), mc_impact_3 | mc_die_other)
+ wr_message (die_locus (*jt), mc_impact_3 | mc_die_other)
.id (descriptor ())
<< "Found "
<< (declaration ? "declaration" : "definition")
if ((at2 = m.find ((*at).first)) != m.end ()
&& ! duplicate_ok (entry.tag (), at2->first, attr.first,
referree.tag (), at2->second == (*at).second))
- wr_message (to_where (entry), mc_impact_3 | mc_acc_bloat | mc_die_rel)
+ wr_message (die_locus (entry), mc_impact_3 | mc_acc_bloat | mc_die_rel)
.id (descriptor ())
<< dwarf::tags::name (entry.tag ())
<< " attribute " << dwarf::attributes::name (at2->first)
void operator () (dwarf::compile_unit const &cu,
dwarf::debug_info_entry const &parent)
{
- struct where where = WHERE (sec_info, NULL);
- where_reset_1 (&where, cu.offset ());
- where_reset_2 (&where, parent.offset ());
+ die_locus where (parent);
int parent_tag = parent.tag ();
// XXX more specific class when <dwarf> has it
catch (std::runtime_error &exc)
{
- wr_error (WHERE (sec_info, NULL))
+ wr_error (section_locus (sec_info))
<< "Exception while checking expected trees: " << exc.what ()
<< std::endl;
throw check_base::failed ();
&& entry.tag () != DW_TAG_union_type)
|| attrs.find (DW_AT_name) != attrs.end ()))
{
- wr_message (to_where (entry),
+ wr_message (die_locus (entry),
mc_impact_3 | mc_acc_suboptimal | mc_die_other)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
if (attrs.find (DW_AT_declaration) == attrs.end ()
&& is_external (it))
{
- wr_message (to_where (entry),
+ wr_message (die_locus (entry),
mc_impact_3 | mc_acc_suboptimal | mc_die_other)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
{
// Global symbol in symbol table, not marked external.
// Always bad.
- wr_message (to_where (entry),
+ wr_message (die_locus (entry),
mc_impact_3 | mc_acc_suboptimal | mc_die_other)
.id (descriptor ())
<< elfutils::dwarf::tags::name (entry.tag ())
static checkdescriptor cd
(checkdescriptor::create ("check_matching_ranges")
.description (
-"Check that the ranges in .debug_aranges and .debug_ranges match.\n"
-));
+"Check that the ranges in .debug_aranges and .debug_ranges match.\n"));
return &cd;
}
try
{
- struct where where_ref = WHERE (sec_info, NULL);
- struct where where_ar = WHERE (sec_aranges, NULL);
- where_ar.ref = &where_ref;
- struct where where_r = WHERE (sec_ranges, NULL);
- where_r.ref = &where_ref;
char buf[128];
-
const dwarf::aranges_map &aranges = dw.aranges ();
for (dwarf::aranges_map::const_iterator i = aranges.begin ();
i != aranges.end (); ++i)
{
const dwarf::compile_unit &cu = i->first;
- where_reset_1 (&where_ref, 0);
- where_reset_2 (&where_ref, cu.offset ());
+ cudie_locus where_ref (cu);
+ loc_range_locus where_r (sec_ranges, where_ref);
+ arange_locus where_ar (where_ref);
std::set<dwarf::ranges::key_type>
cu_aranges = i->second,
// XXX more specific class when <dwarf> has it
catch (std::runtime_error &exc)
{
- wr_error (WHERE (sec_info, NULL))
+ wr_error (section_locus (sec_info))
<< "Exception while checking matching ranges: " << exc.what ()
<< std::endl;
throw check_base::failed ();
/* Pedantic checking of DWARF files
- Copyright (C) 2009,2010 Red Hat, Inc.
+ Copyright (C) 2009,2010,2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
private:
void not_available (section_id sec_id)
{
- wr_error (WHERE (sec_id, NULL))
+ wr_error (section_locus (sec_id))
<< "data not found." << std::endl;
}
#include "coverage.hh"
#include "pri.hh"
#include "check_debug_loc_range.hh"
-#include "misc.hh"
using elfutils::dwarf;
static void recursively_validate (dwarf::compile_unit const &cu,
dwarf::debug_info_entry const &die,
ranges_t const &ranges,
- where const &wh_parent);
+ locus const &wh_parent);
public:
static checkdescriptor const *descriptor () {
class dwarf::compile_units_type const &cus = dw.compile_units ();
ranges_t r;
r.push_back (std::make_pair (0, -1));
- where wh = WHERE (sec_info, NULL);
+ section_locus wh (sec_info);
for (dwarf::compile_units_type::const_iterator it = cus.begin ();
it != cus.end (); ++it)
recursively_validate (*it, *it, r, wh);
// XXX more specific class when <dwarf> has it
catch (std::runtime_error &exc)
{
- wr_error (WHERE (sec_info, NULL))
+ wr_error (section_locus (sec_info))
<< "Exception while checking ranges out of scope: " << exc.what ()
<< std::endl;
throw check_base::failed ();
(dwarf::compile_unit const &cu,
dwarf::debug_info_entry const &die,
ranges_t const &ranges,
- where const &wh_parent)
+ locus const &wh_parent)
{
- where wh = WHERE (sec_info, NULL);
- where_reset_1 (&wh, cu.offset ());
- where_reset_2 (&wh, die.offset ());
+ die_locus wh (die);
::Dwarf_Addr low_pc = 0;
::Dwarf_Addr high_pc = ::noaddr;
{
dwarf::debug_info_entry ref = *val.reference ();
if (ref.identity () == entry.identity ())
- wr_message (to_where (entry),
+ wr_message (die_locus (entry),
mc_impact_3 | mc_acc_suboptimal | mc_die_rel)
.id (descriptor ())
<< dwarf::tags::name (entry.tag ())
bool
read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep,
- int *offset_sizep, struct where *where)
+ int *offset_sizep, locus const &loc)
{
if (size32 == DWARF3_LENGTH_64_BIT)
{
if (!read_ctx_read_8ubyte (ctx, sizep))
{
- wr_error (where, ": can't read 64bit CU length.\n");
+ wr_error (loc) << "can't read 64bit CU length.\n";
return false;
}
}
else if (size32 >= DWARF3_LENGTH_MIN_ESCAPE_CODE)
{
- wr_error (where, ": unrecognized CU length escape value: "
- "%" PRIx32 ".\n", size32);
+ wr_error (loc)
+ << "unrecognized CU length escape value: " << size32 << ".\n";
return false;
}
else
}
error_code
-read_address_size (struct read_ctx *ctx,
- bool addr_64,
- int *address_sizep,
- struct where const *where)
+read_address_size (struct read_ctx *ctx, bool addr_64,
+ int *address_sizep, locus const &loc)
{
uint8_t address_size;
if (!read_ctx_read_ubyte (ctx, &address_size))
{
- wr_error (where, ": can't read address size.\n");
+ wr_error (loc) << "can't read address size.\n";
return err_fatal;
}
{
/* Keep going. Deduce the address size from ELF header, and try
to parse it anyway. */
- wr_error (where,
- ": invalid address size: %d (only 4 or 8 allowed).\n",
- address_size);
+ wr_error (loc) << "invalid address size: " << (int)address_size
+ << " (only 4 or 8 allowed).\n";
address_size = addr_64 ? 8 : 4;
ret = err_nohl;
}
else if ((address_size == 8) != addr_64)
{
/* Keep going, we may still be able to parse it. */
- wr_error (where,
- ": CU reports address size of %d in %d-bit ELF.\n",
- address_size, addr_64 ? 64 : 32);
+ wr_error (loc) << "CU reports address size of " << address_size
+ << " in " << (addr_64 ? 64 : 32) << "-bit ELF.\n";
ret = err_nohl;
}
bool
checked_read_uleb128 (read_ctx *ctx, uint64_t *ret,
- where const *where, const char *what)
+ locus const &loc, const char *what)
{
const unsigned char *ptr = ctx->ptr;
int st = read_ctx_read_uleb128 (ctx, ret);
if (st < 0)
- wr_error (where, ": can't read %s.\n", what);
+ wr_error (loc) << "can't read " << what << ".\n";
else if (st > 0)
{
char buf[19]; // 16 hexa digits, "0x", terminating zero
sprintf (buf, "%#" PRIx64, *ret);
- wr_format_leb128_message (where, what, buf, ptr, ctx->ptr);
+ wr_format_leb128_message (loc, what, buf, ptr, ctx->ptr);
}
return st >= 0;
}
bool
checked_read_sleb128 (read_ctx *ctx, int64_t *ret,
- where const *where, const char *what)
+ locus const &loc, const char *what)
{
const unsigned char *ptr = ctx->ptr;
int st = read_ctx_read_sleb128 (ctx, ret);
if (st < 0)
- wr_error (where, ": can't read %s.\n", what);
+ wr_error (loc) << "can't read " << what << ".\n";
else if (st > 0)
{
char buf[20]; // sign, "0x", 16 hexa digits, terminating zero
int64_t val = *ret;
sprintf (buf, "%s%#" PRIx64, val < 0 ? "-" : "", val < 0 ? -val : val);
- wr_format_leb128_message (where, what, buf, ptr, ctx->ptr);
+ wr_format_leb128_message (loc, what, buf, ptr, ctx->ptr);
}
return st >= 0;
}
bool
checked_read_leb128 (read_ctx *ctx, form_width_t width, uint64_t *ret,
- where const *where, const char *what)
+ locus const &loc, const char *what)
{
assert (width == fw_sleb || width == fw_uleb);
if (width == fw_sleb)
{
int64_t svalue;
- if (!checked_read_sleb128 (ctx, &svalue, where, what))
+ if (!checked_read_sleb128 (ctx, &svalue, loc, what))
return false;
*ret = (uint64_t) svalue;
return true;
}
else
- return checked_read_uleb128 (ctx, ret, where, what);
+ return checked_read_uleb128 (ctx, ret, loc, what);
}
bool
read_sc_value (uint64_t *valuep, form_width_t width,
- read_ctx *ctx, where const *where)
+ read_ctx *ctx, locus const &loc)
{
switch (width)
{
case fw_uleb:
case fw_sleb:
return checked_read_leb128 (ctx, width, valuep,
- where, "attribute value");
+ loc, "attribute value");
case fw_unknown:
;
bool
read_generic_value (read_ctx *ctx,
form_width_t width, storage_class_t storclass,
- where const *where, uint64_t *valuep, read_ctx *blockp)
+ locus const &loc, uint64_t *valuep, read_ctx *blockp)
{
uint64_t value;
if (storclass == sc_value
|| storclass == sc_block)
{
- if (!read_sc_value (&value, width, ctx, where))
+ if (!read_sc_value (&value, width, ctx, loc))
return false;
if (valuep != NULL)
*valuep = value;
#define DWARFLINT_CHECKED_READ_HH
#include "readctx.hh"
-#include "where.h"
+#include "locus.hh"
#include "dwarf_version.hh"
enum error_code
};
bool read_size_extra (read_ctx *ctx, uint32_t size32, uint64_t *sizep,
- int *offset_sizep, where *where);
+ int *offset_sizep, locus const &loc);
/// Read address size and return it via address_sizep and return 0.
/// Address size may be 4 or 8; for other values it's set depending or
/// addr_64, and err_nohl is returned.
-error_code read_address_size (read_ctx *ctx,
- bool addr_64,
- int *address_sizep,
- where const *where);
+error_code read_address_size (read_ctx *ctx, bool addr_64,
+ int *address_sizep, locus const &loc);
bool checked_read_uleb128 (read_ctx *ctx, uint64_t *ret,
- where const *where, const char *what);
+ locus const &loc, const char *what);
bool checked_read_sleb128 (read_ctx *ctx, int64_t *ret,
- where const *where, const char *what);
+ locus const &loc, const char *what);
bool checked_read_leb128 (read_ctx *ctx, form_width_t width, uint64_t *ret,
- where const *where, const char *what);
+ locus const &loc, const char *what);
/// Read value depending on the form width and storage class.
bool read_sc_value (uint64_t *valuep, form_width_t width,
- read_ctx *ctx, where const *where);
+ read_ctx *ctx, locus const &loc);
/// Read value depending on the form width and storage class.
/// Value is returned via VALUEP, if that is non-NULL; for block
/// itself.
bool read_generic_value (read_ctx *ctx,
form_width_t width, storage_class_t storclass,
- where const *where, uint64_t *valuep,
+ locus const &loc, uint64_t *valuep,
read_ctx *blockp);
#endif//DWARFLINT_CHECKED_READ_HH
#ifndef DWARFLINT_CHECKS_HH
#define DWARFLINT_CHECKS_HH
-#include "where.h"
+#include "locus.hh"
#include "dwarflint.hh"
#include "checkdescriptor.hh"
#include "messages.hh"
#endif
#include "coverage.hh"
-#include "misc.hh"
#include "pri.hh"
#include <stdbool.h>
Network licensing program, please visit www.openinventionnetwork.com
<http://www.openinventionnetwork.com>. */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include "cu_coverage.hh"
#include "check_debug_info.hh"
#include "check_debug_loc_range.hh"
--- /dev/null
+/*
+ Copyright (C) 2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat 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 a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "die_locus.hh"
+#include "pri.hh"
+
+char const *
+locus_simple_fmt::cu_n ()
+{
+ return "CU";
+}
+
+std::string
+die_locus::format (bool brief) const
+{
+ std::stringstream ss;
+ if (!brief)
+ ss << section_name[sec_info] << ": ";
+
+ ss << "DIE 0x" << std::hex << _m_offset;
+
+ if (_m_attrib_name != -1)
+ ss << ", attr. " << pri::attr_name (_m_attrib_name);
+
+ return ss.str ();
+}
+
--- /dev/null
+/*
+ Copyright (C) 2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat 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 a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifndef _DWARFLINT_DIE_LOCUS_H_
+#define _DWARFLINT_DIE_LOCUS_H_
+
+#include "locus.hh"
+#include "../libdw/c++/dwarf"
+
+namespace locus_simple_fmt
+{
+ char const *cu_n ();
+};
+
+typedef fixed_locus<sec_info,
+ locus_simple_fmt::cu_n,
+ locus_simple_fmt::dec> cu_locus;
+
+class die_locus
+ : public locus
+{
+ Dwarf_Off _m_offset;
+ int _m_attrib_name;
+
+public:
+ explicit die_locus (Dwarf_Off offset = -1, int attrib_name = -1)
+ : _m_offset (offset)
+ , _m_attrib_name (attrib_name)
+ {}
+
+ template <class T>
+ explicit die_locus (T const &die, int attrib_name = -1)
+ : _m_offset (die.offset ())
+ , _m_attrib_name (attrib_name)
+ {}
+
+ void
+ set_attrib_name (int attrib_name)
+ {
+ _m_attrib_name = attrib_name;
+ }
+
+ std::string format (bool brief = false) const;
+};
+
+#endif /* _DWARFLINT_DIE_LOCUS_H_ */
/* Pedantic checking of DWARF files.
- Copyright (C) 2008, 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
Elf_Data *data; /* May be NULL if data in this section are
missing or not substantial. */
enum section_id id;
+
+ sec ()
+ : scn (NULL)
+ , name (NULL)
+ , data (NULL)
+ , id (sec_invalid)
+ {}
};
struct elf_file
#endif
#include "checks.hh"
+#include "check_debug_info.hh"
+
#include "../libdw/c++/dwarf"
#include "../libdwfl/libdwfl.h"
{}
};
-template <class T>
-inline where
-to_where (T const &die)
-{
- where ret = WHERE (sec_info, NULL);
- where_reset_1 (&ret, 0);
- where_reset_2 (&ret, die.offset ());
- return ret;
-}
-
#endif//DWARFLINT_CHECKS_HIGH_HH
}
catch (::error const &e)
{
- struct where where = WHERE (sec_info, NULL);
- where_reset_1 (&where, it.cu ().offset ());
- where_reset_2 (&where, die.offset ());
- std::cerr << "error: " << where << ": "
+ std::cerr << "error: " << die_locus (die) << ": "
<< e.what () << '.' << std::endl;
continue;
}
--- /dev/null
+/* Pedantic checking of DWARF files
+ Copyright (C) 2008,2009,2010,2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat 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 a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "locus.hh"
+#include "section_id.hh"
+#include <sstream>
+#include <iostream>
+
+std::ostream &
+operator << (std::ostream &os, locus const &loc)
+{
+ os << loc.format ();
+ return os;
+}
+
+char const *
+locus_simple_fmt::offset_n ()
+{
+ return "offset";
+}
+
+void
+locus_simple_fmt::hex (std::ostream &ss, uint64_t off)
+{
+ ss << "0x" << std::hex << off;
+}
+
+void
+locus_simple_fmt::dec (std::ostream &ss, uint64_t off)
+{
+ ss << std::dec << off;
+}
+
+std::string
+simple_locus_aux::format_simple_locus (char const *(*N) (),
+ void (*F) (std::ostream &, uint64_t),
+ bool brief, section_id sec, uint64_t off)
+{
+ std::stringstream ss;
+ if (!brief)
+ ss << section_name[sec];
+ if (off != (uint64_t)-1)
+ {
+ if (!brief)
+ ss << ": ";
+ ss << N() << " ";
+ F (ss, off);
+ }
+ return ss.str ();
+}
--- /dev/null
+/* Pedantic checking of DWARF files
+ Copyright (C) 2009,2010,2011 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat 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 a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifndef DWARFLINT_WHERE_HH
+#define DWARFLINT_WHERE_HH
+
+#include "section_id.hh"
+
+#include <stdint.h>
+#include <iosfwd>
+#include <string>
+
+/// Instances of the locus subclasses are used as pointers into
+/// debuginfo for documentation purposes (messages and errors). They
+/// are usually tiny structures, and should be used as values, but we
+/// need the abstract interface to be able to format them, and copy
+/// them into ref_record.
+class locus
+{
+public:
+ virtual std::string format (bool brief = false) const = 0;
+ virtual ~locus () {}
+};
+
+std::ostream &operator << (std::ostream &os, locus const &loc);
+
+/// Helper class for simple_locus to reduce the template bloat.
+class simple_locus_aux
+{
+protected:
+ static std::string format_simple_locus (char const *(*N) (),
+ void (*F) (std::ostream &, uint64_t),
+ bool brief, section_id sec,
+ uint64_t off);
+};
+
+/// Template for quick construction of straightforward locus
+/// subclasses (one address, one way of formatting). N should be a
+/// function that returns the name of the argument.
+/// locus_simple_fmt::hex, locus_simple_fmt::dec would be candidate
+/// parameters for argument F.
+template<char const *(*N) (),
+ void (*F) (std::ostream &, uint64_t)>
+class simple_locus
+ : public locus
+ , private simple_locus_aux
+{
+ section_id _m_sec;
+ uint64_t _m_offset;
+
+public:
+ explicit simple_locus (section_id sec, uint64_t offset = -1)
+ : _m_sec (sec)
+ , _m_offset (offset)
+ {}
+
+ std::string
+ format (bool brief = false) const
+ {
+ return format_simple_locus (N, F, brief, _m_sec, _m_offset);
+ }
+};
+
+/// Constructor of simple_locus that fixes the section_id argument.
+template<section_id S,
+ char const *(*N) (),
+ void (*F) (std::ostream &, uint64_t)>
+class fixed_locus
+ : public simple_locus<N, F>
+{
+public:
+ explicit fixed_locus (uint64_t offset = -1)
+ : simple_locus<N, F> (S, offset)
+ {}
+};
+
+namespace locus_simple_fmt
+{
+ char const *offset_n ();
+ void hex (std::ostream &ss, uint64_t off);
+ void dec (std::ostream &ss, uint64_t off);
+}
+
+/// Straightforward locus for cases where either offset is not
+/// necessary at all, or if it is present, it's simply shown as
+/// "offset: 0xf00".
+typedef simple_locus<locus_simple_fmt::offset_n,
+ locus_simple_fmt::hex> section_locus;
+
+#endif//DWARFLINT_WHERE_HH
Network licensing program, please visit www.openinventionnetwork.com
<http://www.openinventionnetwork.com>. */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include "lowlevel_checks.hh"
#include "sections.hh"
#include "check_debug_info.hh"
global_opt<void_option>
be_tolerant ("Be somewhat more tolerant.", "tolerant");
-// xxx as soon as where is in c++, this can move there
-global_opt<void_option>
- opt_show_refs("\
-When validating .debug_loc and .debug_ranges, display information about \
-the DIE referring to the entry in consideration", "ref");
-extern "C" bool show_refs () { return (bool)opt_show_refs; }
-
int
main (int argc, char *argv[])
{
<http://www.openinventionnetwork.com>. */
#include "messages.hh"
-#include "misc.hh"
#include "coverage.hh"
#include "option.hh"
void
message_criteria::operator *= (message_criteria const &rhs)
{
- struct message_criteria ret;
- WIPE (ret);
-
+ message_criteria ret;
for (size_t i = 0; i < size (); ++i)
for (size_t j = 0; j < rhs.size (); ++j)
{
}
static void
-wr_verror (const struct where *wh, const char *format, va_list ap)
+wr_verror (locus const &loc, const char *format, va_list ap)
{
- printf ("error: %s", where_fmt (wh, NULL));
+ printf ("error: %s", loc.format ().c_str ());
vprintf (format, ap);
- where_fmt_chain (wh, "error");
++error_count;
}
static void
-wr_vwarning (const struct where *wh, const char *format, va_list ap)
+wr_vwarning (locus const &loc, const char *format, va_list ap)
{
- printf ("%s", where_fmt (wh, NULL));
+ printf ("%s", loc.format ().c_str ());
vprintf (format, ap);
- where_fmt_chain (wh, "warning");
++error_count;
}
void
-wr_error (const struct where *wh, const char *format, ...)
+wr_error (locus const *loc, const char *format, ...)
{
va_list ap;
va_start (ap, format);
- wr_verror (wh, format, ap);
+ wr_verror (*loc, format, ap);
va_end (ap);
}
void
-wr_message (unsigned long category, const struct where *wh,
+wr_message (unsigned long category, locus const *loc,
const char *format, ...)
{
va_list ap;
if (whether && message_accept (&warning_criteria, category))
{
if (message_accept (&error_criteria, category))
- wr_verror (wh, format, ap);
+ wr_verror (*loc, format, ap);
else
- wr_vwarning (wh, format, ap);
+ wr_vwarning (*loc, format, ap);
}
va_end (ap);
}
}
message_context::message_context (message_count_filter *filter,
- where const *where, char const *prefix)
+ locus const *loc, char const *prefix)
: _m_filter (filter)
- , _m_where (where)
+ , _m_loc (loc)
, _m_prefix (prefix)
{}
std::ostream &ret = get_stream ();
ret << _m_prefix;
- if (_m_where)
- ret << *_m_where << ": ";
+ if (_m_loc != NULL)
+ ret << _m_loc->format () << ": ";
return ret;
}
else
}
std::ostream &
-wr_error (where const &wh)
+wr_error (locus const &loc)
{
- return wr_error () << wh << ": ";
+ std::string fmt = loc.format ();
+ return wr_error () << fmt << ": ";
}
message_context
-message_context::filter_message (where const *wh, message_category category)
+message_context::filter_message (locus const *loc, message_category category)
{
if (!message_accept (&warning_criteria, category))
return message_context (NULL, NULL, NULL);
else if (message_accept (&error_criteria, category))
return message_context (message_count_filter::inst (),
- wh, "error: ");
+ loc, "error: ");
else
return message_context (message_count_filter::inst (),
- wh, "warning: ");
+ loc, "warning: ");
}
message_context
}
message_context
-wr_message (where const &wh, message_category category)
+wr_message (locus const &loc, message_category category)
{
- return message_context::filter_message (&wh, category);
+ return message_context::filter_message (&loc, category);
}
void
wr_format_padding_message (message_category category,
- struct where const *wh,
+ locus const &loc,
uint64_t start, uint64_t end, char const *kind)
{
char msg[128];
- wr_message (*wh, category)
+ wr_message (loc, category)
<< range_fmt (msg, sizeof msg, start, end)
<< ": " << kind << "." << std::endl;
}
void
-wr_format_leb128_message (struct where const *where,
+wr_format_leb128_message (locus const &loc,
const char *what,
const char *purpose,
const unsigned char *begin, const unsigned char *end)
char *ptr = buf;
for (; begin < end; ++begin)
ptr += sprintf (ptr, " %02x", *begin);
- wr_message (*where, category)
+ wr_message (loc, category)
<< what << ": value " << purpose << " encoded as `"
<< (buf + 1) << "'." << std::endl;
}
void
wr_message_padding_0 (message_category category,
- struct where const *wh,
+ locus const &loc,
uint64_t start, uint64_t end)
{
wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
- wh, start, end,
+ loc, start, end,
"unnecessary padding with zero bytes");
}
void
wr_message_padding_n0 (message_category category,
- struct where const *wh,
+ locus const &loc,
uint64_t start, uint64_t end)
{
wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
- wh, start, end,
+ loc, start, end,
"unreferenced non-zero bytes");
}
#ifndef DWARFLINT_MESSAGES_HH
#define DWARFLINT_MESSAGES_HH
-#include "where.h"
+#include "locus.hh"
#include "libdw.h"
#include <string>
#include <iosfwd>
message_criteria operator ! (message_term const &);
-extern void wr_error (const struct where *wh, const char *format, ...)
+extern void wr_error (locus const *wh, const char *format, ...)
__attribute__ ((format (printf, 2, 3)));
-extern void wr_message (unsigned long category, const struct where *wh,
+extern void wr_message (unsigned long category, locus const *loc,
const char *format, ...)
__attribute__ ((format (printf, 3, 4)));
extern void wr_format_padding_message (message_category category,
- struct where const *wh,
+ locus const &loc,
uint64_t start, uint64_t end,
char const *kind);
-extern void wr_format_leb128_message (struct where const *where,
+extern void wr_format_leb128_message (locus const &loc,
const char *what,
const char *purpose,
const unsigned char *begin,
const unsigned char *end);
extern void wr_message_padding_0 (message_category category,
- struct where const *wh,
+ locus const &loc,
uint64_t start, uint64_t end);
extern void wr_message_padding_n0 (message_category category,
- struct where const *wh,
+ locus const &loc,
uint64_t start, uint64_t end);
extern bool message_accept (struct message_criteria const *cri,
static bool _m_last_emitted;
message_count_filter *_m_filter;
- where const *_m_where;
+ locus const *_m_loc;
char const *_m_prefix;
- friend message_context wr_message (where const &wh, message_category cat);
+ friend message_context wr_message (locus const &loc, message_category cat);
friend message_context wr_message (message_category cat);
friend bool wr_prev_emitted ();
message_context (message_count_filter *filter,
- where const *where, char const *prefix);
+ locus const *loc, char const *prefix);
public:
- static message_context filter_message (where const *wh,
+ static message_context filter_message (locus const *loc,
message_category category);
std::ostream &operator << (char const *message);
std::ostream &when_prev () const;
};
-std::ostream &wr_error (where const &wh);
+std::ostream &wr_error (locus const &loc);
std::ostream &wr_error ();
-message_context wr_message (where const &wh, message_category cat);
+message_context wr_message (locus const &loc, message_category cat);
message_context wr_message (message_category cat);
void wr_reset_counters ();
bool wr_prev_emitted ();
/* Pedantic checking of DWARF files
- Copyright (C) 2008, 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
bool
supported_version (unsigned version,
- size_t num_supported, struct where *where, ...)
+ size_t num_supported, locus const &loc, ...)
{
bool retval = false;
va_list ap;
- va_start (ap, where);
+ va_start (ap, loc);
for (size_t i = 0; i < num_supported; ++i)
{
unsigned v = va_arg (ap, unsigned);
va_end (ap);
if (!retval)
- wr_error (where, ": unsupported version %d.\n", version);
+ wr_error (loc) << "unsupported version " << version << ".\n";
return retval;
}
#define DWARFLINT_MISC_HH
#include <cstring>
-#include "where.h"
+#include "locus.hh"
extern "C"
{
} \
} while (0)
-#define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ))
-
bool address_aligned (uint64_t addr, uint64_t align);
bool necessary_alignment (uint64_t start, uint64_t length,
uint64_t align);
bool supported_version (unsigned version,
- size_t num_supported, struct where *where, ...);
+ size_t num_supported, locus const &loc, ...);
#define UNREACHABLE assert (!"unreachable")
return os << "[" << pri::addr (obj.start)
<< ", " << pri::addr (obj.end) << ")";
}
+
+std::string
+pri::attr_name (int name)
+{
+ assert (name != -1);
+ return elfutils::dwarf::attributes::name (name);
+}
friend std::ostream &operator << (std::ostream &os, range const &obj);
};
std::ostream &operator << (std::ostream &os, range const &obj);
+
+ std::string attr_name (int name);
}
#endif//DWARFLINT_PRI_H
#include <stdbool.h>
#include "../libelf/libelf.h"
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
/* Functions and data structures related to bounds-checked
reading. */
bool read_check_zero_padding (struct read_ctx *ctx,
uint64_t *ret_off_start,
uint64_t *ret_off_end);
-#ifdef __cplusplus
-}
-#endif
#endif
#include "messages.hh"
#include "misc.hh"
#include "readctx.hh"
+#include "pri.hh"
#include <sstream>
#include <libebl.h>
#include <cassert>
-#include <inttypes.h>
+#include <cinttypes>
-static struct where
-where_from_reloc (struct relocation_data *reloc, struct where const *ref)
+namespace
{
- struct where where
- = WHERE (reloc->type == SHT_REL ? sec_rel : sec_rela, NULL);
- where_reset_1 (&where, reloc->rel[reloc->index].offset);
- where.ref = ref;
- return where;
+ class reloc_locus
+ : public locus
+ {
+ locus const &_m_ref;
+ size_t _m_index;
+ uint64_t _m_offset;
+ int _m_type;
+
+ public:
+ reloc_locus (int type, locus const &ref, uint64_t offset)
+ : _m_ref (ref)
+ , _m_index (-1)
+ , _m_offset (offset)
+ , _m_type (type)
+ {
+ }
+
+ reloc_locus (int type, locus const &ref, unsigned index)
+ : _m_ref (ref)
+ , _m_index (index)
+ , _m_offset (-1)
+ , _m_type (type)
+ {
+ }
+
+ void
+ set_offset (uint64_t offset)
+ {
+ _m_offset = offset;
+ }
+
+ virtual std::string
+ format (bool) const
+ {
+ std::stringstream ss;
+ ss << (_m_type == SHT_REL ? ".rel" : ".rela") << " ";
+ if (_m_offset != (uint64_t)-1)
+ ss << pri::hex (_m_offset);
+ else
+ {
+ assert (_m_index != (size_t)-1);
+ ss << "#" << _m_index;
+ }
+
+ // Do non-brief formatting of referee
+ ss << " of " << _m_ref.format ();
+ return ss.str ();
+ }
+ };
}
relocation *
relocation_next (relocation_data *reloc, uint64_t offset,
- struct where const *where, enum skip_type st)
+ locus const &loc, enum skip_type st)
{
if (reloc == NULL || reloc->rel == NULL)
return NULL;
{
if (st != skip_ok)
{
- struct where reloc_where = where_from_reloc (reloc, where);
- where_reset_2 (&reloc_where, rel->offset);
+ reloc_locus reloc_where (reloc->type, loc, rel->offset);
wr_error (reloc_where)
<< (st == skip_unref
? "relocation targets unreferenced portion of the section."
matching that offset is immediately yielded. */
void
relocation_skip (struct relocation_data *reloc, uint64_t offset,
- struct where const *where, enum skip_type st)
+ locus const &loc, enum skip_type st)
{
if (reloc != NULL && reloc->rel != NULL)
- relocation_next (reloc, offset - 1, where, st);
+ relocation_next (reloc, offset - 1, loc, st);
}
void
/* Skip all the remaining relocations. */
void
-relocation_skip_rest (struct relocation_data *reloc,
- enum section_id id)
+relocation_skip_rest (relocation_data *reloc,
+ locus const &loc)
{
if (reloc->rel != NULL)
- {
- where wh = WHERE (id, NULL);
- relocation_next (reloc, (uint64_t)-1, &wh,
- skip_mismatched);
- }
+ relocation_next (reloc, (uint64_t)-1, loc, skip_mismatched);
}
static void
relocation *rel,
unsigned rel_width,
uint64_t *value,
- where const &reloc_where,
- section_id offset_into,
+ reloc_locus const &reloc_where,
+ rel_target reltgt,
GElf_Sym *symbol,
GElf_Sym **symptr)
{
}
/* It's target value, not section offset. */
- if (offset_into == rel_value
- || offset_into == rel_address
- || offset_into == rel_exec)
+ if (reltgt == rel_target::rel_value
+ || reltgt == rel_target::rel_address
+ || reltgt == rel_target::rel_exec)
{
/* If a target value is what's expected, then complain if
it's not either SHN_ABS, an SHF_ALLOC section, or
SHN_UNDEF. For data forms of address_size, an SHN_UNDEF
reloc is acceptable, otherwise reject it. */
if (!(section_index == SHN_ABS
- || (offset_into == rel_address
+ || (reltgt == rel_target::rel_address
&& (section_index == SHN_UNDEF
|| section_index == SHN_COMMON))))
{
- if (offset_into != rel_address && section_index == SHN_UNDEF)
+ if (reltgt != rel_target::rel_address && section_index == SHN_UNDEF)
wr_error (&reloc_where,
- ": relocation of an address is formed using SHN_UNDEF symbol"
- " (symtab index %d).\n", rel->symndx);
+ ": relocation of an address is formed using SHN_UNDEF symbol"
+ " (symtab index %d).\n", rel->symndx);
else
{
require_valid_section_index;
wr_message (mc_reloc | mc_impact_3, &reloc_where,
": associated section %s isn't SHF_ALLOC.\n",
file->sec[section_index].name);
- if (offset_into == rel_exec
+ if (reltgt == rel_target::rel_exec
&& (shdr->sh_flags & SHF_EXECINSTR) != SHF_EXECINSTR)
/* This may still be kosher, but it's suspicious. */
wr_message (mc_reloc | mc_impact_2, &reloc_where,
else
{
require_valid_section_index;
- if (file->sec[section_index].id != offset_into)
+ section_id secid = file->sec[section_index].id;
+ if (reltgt != secid)
// If symtab[symndx].st_shndx does not match the expected
// debug section's index, complain.
wr_error (reloc_where)
<< "relocation references section "
<< (file->sec[section_index].name ?: "<invalid>") << ", but "
- << WHERE (offset_into, NULL) << " was expected." << std::endl;
+ << section_locus (secid) << " was expected." << std::endl;
}
/* Only do the actual relocation if we have ET_REL files. For
struct relocation_data *reloc,
struct relocation *rel,
unsigned width, uint64_t *value,
- struct where const *where,
- enum section_id offset_into, GElf_Sym **symptr)
+ locus const &loc,
+ rel_target reltgt,
+ GElf_Sym **symptr)
{
if (rel->invalid)
return;
- struct where reloc_where = where_from_reloc (reloc, where);
- where_reset_2 (&reloc_where, rel->offset);
- struct where reloc_ref_where = reloc_where;
- reloc_ref_where.next = where;
+ reloc_locus reloc_where (reloc->type, loc, rel->offset);
GElf_Sym symbol_mem, *symbol;
if (symptr != NULL)
else
symbol = &symbol_mem;
- if (offset_into == sec_invalid)
+ if (reltgt == sec_invalid)
{
- wr_message (mc_impact_3 | mc_reloc, &reloc_ref_where,
- ": relocates a datum that shouldn't be relocated.\n");
+ wr_message (reloc_where, mc_impact_3 | mc_reloc)
+ << "relocates a datum that shouldn't be relocated.\n";
return;
}
};
if (rel_width != width)
- wr_error (&reloc_ref_where,
- ": %d-byte relocation relocates %d-byte datum.\n",
- rel_width, width);
+ wr_error (reloc_where)
+ << rel_width << "-byte relocation relocates "
+ << width << "-byte datum.\n";
// Tolerate if we failed to obtain the symbol table.
if (reloc->symdata != NULL)
do_one_relocation (file, reloc, rel, rel_width, value,
- reloc_where, offset_into, symbol, symptr);
+ reloc_where, reltgt, symbol, symptr);
}
static GElf_Rela *
: (is_rela ? sizeof (Elf32_Rela) : sizeof (Elf32_Rel));
size_t count = reldata->d_size / entrysize;
- struct where parent = WHERE (sec->id, NULL);
- struct where where = WHERE (is_rela ? sec_rela : sec_rel, NULL);
- where.ref = &parent;
+ section_locus parent (sec->id);
for (unsigned i = 0; i < count; ++i)
{
- where_reset_1 (&where, i);
+ reloc_locus where (sec->rel.type, parent, i);
REALLOC (&sec->rel, rel);
struct relocation *cur = sec->rel.rel + sec->rel.size++;
- WIPE (*cur);
+ new (cur) relocation ();
GElf_Rela rela_mem, *rela
= get_rel_or_rela (reldata, i, &rela_mem, sec->rel.type);
cur->symndx = GELF_R_SYM (rela->r_info);
cur->type = cur_type;
- where_reset_2 (&where, cur->offset);
+ where.set_offset (cur->offset);
Elf_Type type = ebl_reloc_simple_type (file->ebl, cur->type);
int width;
/* Pedantic checking of DWARF files.
- Copyright (C) 2008, 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
#ifndef DWARFLINT_RELOC_H
#define DWARFLINT_RELOC_H
-#include "where.h"
+#include "locus.hh"
#include "elf_file_i.hh"
#include <libelf.h>
#include <gelf.h>
bool invalid; /* Whether this one relocation should be
ignored. Necessary so that we don't report
invalid & missing relocation twice. */
+
+ relocation ()
+ : offset (0)
+ , addend (0)
+ , symndx (0)
+ , type (0)
+ , invalid (false)
+ {}
};
struct relocation_data
size_t size;
size_t alloc;
size_t index; /* Current index. */
+
+ relocation_data ()
+ : symdata (NULL)
+ , type (SHT_NULL)
+ , rel (NULL)
+ , size (0)
+ , alloc (0)
+ , index (0)
+ {}
};
enum skip_type
skip_ok,
};
+struct rel_target
+{
+ enum target
+ {
+ rel_value, /* For relocations, this denotes that the
+ relocation is applied to target value, not a
+ section offset. */
+ rel_address, /* Same as above, but for addresses. */
+ rel_exec, /* Some as above, but we expect EXEC bit. */
+ };
+
+private:
+ bool _m_is_section;
+ union
+ {
+ section_id _m_section;
+ target _m_target;
+ };
+
+public:
+ rel_target (section_id sec)
+ : _m_is_section (true)
+ , _m_section (sec)
+ {}
+
+ rel_target (target t)
+ : _m_is_section (false)
+ , _m_target (t)
+ {}
+
+ bool
+ operator== (section_id sec)
+ {
+ return _m_is_section && _m_section == sec;
+ }
+
+ bool
+ operator== (target tgt)
+ {
+ return !_m_is_section && _m_target == tgt;
+ }
+
+ template<class T>
+ bool
+ operator!= (T t)
+ {
+ return !(*this == t);
+ }
+};
+
bool read_rel (struct elf_file *file, struct sec *sec,
Elf_Data *reldata, bool elf_64);
relocation *relocation_next (struct relocation_data *reloc,
uint64_t offset,
- struct where const *where,
+ locus const &loc,
enum skip_type st);
void relocation_reset (struct relocation_data *reloc);
void relocation_skip (struct relocation_data *reloc, uint64_t offset,
- struct where const *where, enum skip_type st);
+ locus const &loc, enum skip_type st);
void relocation_skip_rest (struct relocation_data *reloc,
- enum section_id id);
+ locus const &loc);
void relocate_one (struct elf_file const *file,
struct relocation_data *reloc,
struct relocation *rel,
unsigned width, uint64_t *value,
- struct where const *where,
- enum section_id offset_into, GElf_Sym **symptr);
+ locus const &loc,
+ rel_target reltgt,
+ GElf_Sym **symptr);
#define PRI_LACK_RELOCATION ": %s seems to lack a relocation.\n"
/* Pedantic checking of DWARF files
- Copyright (C) 2009, 2010 Red Hat, Inc.
+ Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
/* Debuginfo sections: */
#define SEC(n) sec_##n,
DEBUGINFO_SECTIONS
- count_debuginfo_sections,
#undef SEC
- /* Non-debuginfo sections: */
- sec_rel = count_debuginfo_sections,
- sec_rela,
-
- // XXX the following should really be split out to different enum
- /* Non-sections: */
- sec_locexpr, /* Not a section, but a portion of file that
- contains a location expression. */
- rel_value, /* For relocations, this denotes that the
- relocation is applied to taget value, not a
- section offset. */
- rel_address, /* Same as above, but for addresses. */
- rel_exec, /* Some as above, but we expect EXEC bit. */
+ count_debuginfo_sections
};
// section_name[0] is for sec_invalid. The last index is for
/* Section 0 is special, skip it. */
REALLOC (file, sec);
- file->sec[file->size++].id = sec_invalid;
+ new (file->sec + file->size++) sec ();
if (false)
{
REALLOC (file, sec);
size_t curndx = file->size++;
struct sec *cursec = file->sec + curndx;
+ new (cursec) sec ();
GElf_Shdr *shdr = gelf_getshdr (scn, &cursec->shdr);
if (shdr == NULL)
secentry *entry = secinfo.get (scnname);
cursec->scn = scn;
- cursec->id = entry != NULL ? entry->id : sec_invalid;
+ if (entry != NULL)
+ cursec->id = entry->id;
cursec->name = scnname;
- cursec->rel = (struct relocation_data){NULL, SHT_NULL, NULL, 0, 0, 0};
/* Dwarf section. */
if (entry != NULL)
struct sec *sec = file->sec + cur->secndx;
sec->rel.type = cur->reltype;
if (sec->data == NULL)
- wr_error (WHERE (sec->id, NULL))
+ wr_error (section_locus (sec->id))
<< "this data-less section has a relocation section."
<< std::endl;
else if (read_rel (file, sec, cur->reldata, file->addr_64))
if (secentry *str = secinfo.get (".debug_str"))
if (str->reldata != NULL)
- wr_message (WHERE (sec_str, NULL), mc_impact_2 | mc_elf)
+ wr_message (section_locus (sec_str), mc_impact_2 | mc_elf)
<< "there's a relocation section associated with this section."
<< std::endl;
}
testfiles DW_AT-later-version
testrun_compare ./dwarflint --nognu DW_AT-later-version <<EOF
-warning: .debug_abbrev: abbr. attribute 0x15: attribute DW_AT_endianity from later DWARF version.
+warning: .debug_abbrev: abbr. 0x11, attr. endianity: attribute from later DWARF version.
warning: .debug_info: DIE 0xb: DW_AT_low_pc value not below DW_AT_high_pc.
warning: .debug_info: DIE 0x29: variable has decl_file, but NOT decl_line
EOF
testrun_compare ./dwarflint empty-1 <<EOF
warning: .debug_info: DIE 0xb: DW_AT_low_pc value not below DW_AT_high_pc.
warning: .debug_line: table 0: no CU uses this line table.
-error: .debug_info: DIE 0x29 (abbr. attribute 0x13): references .debug_line table, but CU DIE lacks DW_AT_stmt_list.
+error: .debug_info: DIE 0x29, attr. decl_file: references .debug_line table, but CU DIE lacks DW_AT_stmt_list.
EOF
testrun_compare ./dwarflint garbage-1 <<EOF
testrun_compare ./dwarflint garbage-2 <<EOF
error: .debug_info: CU 0: toplevel DIE must be either compile_unit or partial_unit.
-error: .debug_info: DIE 0xab (abbreviation 113): DIE chain not terminated with null entry.
+error: .debug_info: DIE 0xab: DIE chain not terminated with null entry.
EOF
testrun_compare ./dwarflint --check=@low garbage-3 <<EOF
testrun_compare ./dwarflint garbage-4 <<EOF
error: .debug_info: DIE 0x6c: this DIE claims that its sibling is 0x80000085 but it's actually 0x85.
-error: .debug_info: DIE 0xab (abbreviation 113): DIE chain not terminated with null entry.
+error: .debug_info: DIE 0xab: DIE chain not terminated with null entry.
EOF
testrun_compare ./dwarflint garbage-5 <<EOF
-error: .debug_info: DIE 0xab (abbreviation 113): DIE chain not terminated with null entry.
+error: .debug_info: DIE 0xab: DIE chain not terminated with null entry.
error: .debug_line: offset 0x3e: not enough data to read an opcode of length 5.
-error: .debug_info: DIE 0xb (abbr. attribute 0xc): unresolved reference to .debug_line table 0x0.
+error: .debug_info: DIE 0xb, attr. stmt_list: unresolved reference to .debug_line table 0x0.
EOF
testrun_compare ./dwarflint garbage-6 <<EOF
error: .debug_info: CU 0: invalid address size: 9 (only 4 or 8 allowed).
error: .debug_info: couldn't load CU headers for processing .debug_abbrev; assuming latest DWARF flavor.
-error: .debug_abbrev: abbr. attribute 0xc: attribute stmt_list with invalid form data4.
-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.
+error: .debug_abbrev: abbr. 0x0, attr. stmt_list: attribute with invalid form DW_FORM_data4.
+error: .debug_abbrev: abbr. 0x13, attr. frame_base: attribute with invalid form DW_FORM_block1.
+error: .debug_abbrev: abbr. 0x2c, attr. location: attribute with invalid form DW_FORM_block1.
EOF
testrun_compare ./dwarflint garbage-7 <<EOF
warning: .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.
+error: .debug_abbrev: abbr. 0x7a, attr. 0x703: invalid form 0x0.
+error: .debug_abbrev: missing zero to mark end-of-table.
EOF
testrun_compare ./dwarflint garbage-8 <<EOF
-error: .debug_info: DIE 0x6c (abbr. attribute 0x43): DW_AT_sibling with a value of 0.
+error: .debug_info: DIE 0x6c, attr. sibling: has a value of 0.
error: .debug_info: DIE 0x6c: This DIE had children, but no DW_AT_sibling attribute.
-error: .debug_info: DIE 0xab (abbreviation 113): DIE chain not terminated with null entry.
+error: .debug_info: DIE 0xab: DIE chain not terminated with null entry.
EOF
testrun_compare ./dwarflint garbage-9 <<EOF
-error: .debug_info: DIE 0x84 (abbr. attribute 0x5f): invalid reference outside the CU: 0xef00ab.
+error: .debug_info: DIE 0x84, attr. type: invalid reference outside the CU: 0xef00ab.
error: .debug_info: DIE 0x6c: is the last sibling in chain, but has a DW_AT_sibling attribute.
-error: .debug_info: DIE 0xab (abbreviation 113): DIE chain not terminated with null entry.
+error: .debug_info: DIE 0xab: DIE chain not terminated with null entry.
EOF
testrun_compare ./dwarflint garbage-10 <<EOF
-warning: .rela.debug_info: offset 0xc: relocation formed using STT_SECTION symbol with non-zero value.
-error: .rela.debug_info: offset 0x11: couldn't obtain symbol #7208969: invalid section index.
+warning: .rela 0xc of .debug_info: DIE 0xb, attr. producer: relocation formed using STT_SECTION symbol with non-zero value.
+error: .rela 0x11 of .debug_info: DIE 0xb, attr. comp_dir: couldn't obtain symbol #7208969: invalid section index.
warning: .debug_info: DIE 0xb: DW_AT_low_pc value not below DW_AT_high_pc.
EOF
testrun_compare ./dwarflint garbage-11 <<EOF
-error: .rela.debug_info: offset 0x600: invalid relocation 2560 (<INVALID RELOC>).
-error: .rela.debug_info: offset 0xc00: invalid relocation 2560 (<INVALID RELOC>).
-error: .rela.debug_info: offset 0x1100: invalid relocation 2560 (<INVALID RELOC>).
-error: .rela.debug_info: offset 0x1500: invalid relocation 256 (<INVALID RELOC>).
-error: .rela.debug_info: offset 0x1d00: invalid relocation 256 (<INVALID RELOC>).
-error: .rela.debug_info: offset 0x2500: invalid relocation 2560 (<INVALID RELOC>).
-error: .rela.debug_info: offset 0x3600: invalid relocation 256 (<INVALID RELOC>).
+error: .rela 0x600 of .debug_info: invalid relocation 2560 (<INVALID RELOC>).
+error: .rela 0xc00 of .debug_info: invalid relocation 2560 (<INVALID RELOC>).
+error: .rela 0x1100 of .debug_info: invalid relocation 2560 (<INVALID RELOC>).
+error: .rela 0x1500 of .debug_info: invalid relocation 256 (<INVALID RELOC>).
+error: .rela 0x1d00 of .debug_info: invalid relocation 256 (<INVALID RELOC>).
+error: .rela 0x2500 of .debug_info: invalid relocation 2560 (<INVALID RELOC>).
+error: .rela 0x3600 of .debug_info: invalid relocation 256 (<INVALID RELOC>).
warning: .debug_info: CU 0: abbrev table offset seems to lack a relocation
-warning: .debug_info: DIE 0xb (abbr. attribute 0): strp seems to lack a relocation
-warning: .debug_info: DIE 0xb (abbr. attribute 0x4): strp seems to lack a relocation
-warning: .debug_info: DIE 0xb (abbr. attribute 0xa): data4 seems to lack a relocation
+warning: .debug_info: DIE 0xb, attr. producer: strp seems to lack a relocation
+warning: .debug_info: DIE 0xb, attr. comp_dir: strp seems to lack a relocation
+warning: .debug_info: DIE 0xb, attr. stmt_list: data4 seems to lack a relocation
warning: .debug_info: DIE 0xb: DW_AT_low_pc value not below DW_AT_high_pc.
error: .debug_line: table 0: header claims that it has a size of 542, but in fact it has a size of 30.
-error: .debug_info: DIE 0xb (abbr. attribute 0xa): unresolved reference to .debug_line table 0x0.
+error: .debug_info: DIE 0xb, attr. stmt_list: unresolved reference to .debug_line table 0x0.
EOF
testrun_compare ./dwarflint garbage-12 <<EOF
+++ /dev/null
-/* Pedantic checking of DWARF files
- Copyright (C) 2008,2009,2010,2011 Red Hat, Inc.
- This file is part of Red Hat elfutils.
-
- Red Hat elfutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by the
- Free Software Foundation; version 2 of the License.
-
- Red Hat 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 a copy of the GNU General Public License along
- with Red Hat elfutils; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
-
- Red Hat elfutils is an included package of the Open Invention Network.
- An included package of the Open Invention Network is a package for which
- Open Invention Network licensees cross-license their patents. No patent
- license is granted, either expressly or impliedly, by designation as an
- included package. Should you wish to participate in the Open Invention
- Network licensing program, please visit www.openinventionnetwork.com
- <http://www.openinventionnetwork.com>. */
-
-#include "where.h"
-
-#include <inttypes.h>
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-
-extern bool show_refs (void);
-
-struct section_info
-{
- const char *name;
- const char *addr1f;
- const char *addr2f;
- const char *addr3f;
-};
-
-static struct section_info section_names[] =
- {
- [sec_info] = {".debug_info", "CU %"PRId64, "DIE %#"PRIx64, NULL},
-
- [sec_abbrev] = {".debug_abbrev", "section %"PRId64,
- "abbreviation %"PRId64, "abbr. attribute %#"PRIx64},
-
- [sec_aranges] = {".debug_aranges", "table %"PRId64,
- "arange %#"PRIx64, NULL},
-
- [sec_pubnames] = {".debug_pubnames", "pubname table %"PRId64,
- "pubname %#"PRIx64, NULL},
-
- [sec_pubtypes] = {".debug_pubtypes", "pubtype table %"PRId64,
- "pubtype %#"PRIx64, NULL},
-
- [sec_str] = {".debug_str", "offset %#"PRIx64, NULL, NULL},
-
- [sec_line] = {".debug_line", "table %"PRId64, "offset %#"PRIx64, NULL},
-
- [sec_loc] = {".debug_loc", "loclist %#"PRIx64, "offset %#"PRIx64, NULL},
-
- [sec_mac] = {".debug_mac", NULL, NULL, NULL},
-
- [sec_ranges] = {".debug_ranges", "rangelist %#"PRIx64,
- "offset %#"PRIx64, NULL},
-
- [sec_locexpr] = {"location expression", "offset %#"PRIx64, NULL, NULL},
-
- [sec_rel] = {".rel", "relocation %"PRId64, "offset %#"PRIx64, NULL},
-
- [sec_rela] = {".rela", "relocation %"PRId64, "offset %#"PRIx64, NULL},
- };
-
-const char *
-where_fmt (const struct where *wh, char *ptr)
-{
- if (wh == NULL)
- return "";
-
- static char buf[256];
-
- static struct section_info special_formats[] =
- {
- [wf_cudie] = {".debug_info", "CU DIE %"PRId64, NULL, NULL}
- };
-
- assert (wh->section < sizeof (section_names) / sizeof (*section_names));
- struct section_info *inf
- = (wh->formatting == wf_plain)
- ? section_names + wh->section
- : special_formats + wh->formatting;
-
- assert (inf->name);
-
- assert ((wh->addr1 != (uint64_t)-1) ? inf->addr1f != NULL : true);
- assert ((wh->addr2 != (uint64_t)-1) ? inf->addr2f != NULL : true);
- assert ((wh->addr3 != (uint64_t)-1) ? inf->addr3f != NULL : true);
-
- assert ((wh->addr3 != (uint64_t)-1) ? (wh->addr2 != (uint64_t)-1) : true);
- assert ((wh->addr2 != (uint64_t)-1) ? (wh->addr1 != (uint64_t)-1) : true);
-
- /* GCC insists on checking format parameters and emits a warning
- when we don't use string literal. With -Werror this ends up
- being hard error. So instead we walk around this warning by
- using function pointer. */
- int (*x_asprintf)(char **strp, const char *fmt, ...) = asprintf;
-
-#define SETUP_ADDR(N) \
- char *addr##N##s; \
- bool free_s##N = false; \
- if (wh->addr##N == (uint64_t)-1) \
- addr##N##s = NULL; \
- else if (x_asprintf (&addr##N##s, inf->addr##N##f, wh->addr##N) >= 0) \
- free_s##N = true; \
- else \
- addr##N##s = "(fmt error)"
-
- SETUP_ADDR (1);
- SETUP_ADDR (2);
- SETUP_ADDR (3);
-#undef SETUP_ADDR
-
- char *orig = ptr;
- bool is_reloc = wh->section == sec_rel || wh->section == sec_rela;
- if (ptr == NULL)
- {
- ptr = stpcpy (buf, inf->name);
- if (is_reloc)
- {
- struct where const *ref = wh->ref;
- assert (ref != NULL);
- if (ref->section == sec_locexpr)
- {
- ref = ref->next;
- assert (ref != NULL);
- assert (ref->section != sec_locexpr);
- }
- ptr = stpcpy (ptr, section_names[ref->section].name);
- }
-
- if (addr1s != NULL)
- ptr = stpcpy (ptr, ": ");
- }
-
- if (addr3s != NULL)
- ptr = stpcpy (ptr, addr3s);
- else if (addr2s != NULL)
- ptr = stpcpy (ptr, addr2s);
- else if (addr1s != NULL)
- ptr = stpcpy (ptr, addr1s);
-
- if (free_s1)
- free (addr1s);
- if (free_s2)
- free (addr2s);
- if (free_s3)
- free (addr3s);
-
- if (wh->ref != NULL && !is_reloc)
- {
- ptr = stpcpy (ptr, " (");
- ptr = (char *)where_fmt (wh->ref, ptr);
- *ptr++ = ')';
- *ptr = 0;
- }
-
- if (orig == NULL)
- return buf;
- else
- return ptr;
-}
-
-void
-where_fmt_chain (const struct where *wh, const char *severity)
-{
- if (wh != NULL && show_refs ())
- for (struct where const *it = wh->next; it != NULL; it = it->next)
- printf ("%s: %s: caused by this reference.\n",
- severity, where_fmt (it, NULL));
-}
-
-void
-where_reset_1 (struct where *wh, uint64_t addr)
-{
- wh->addr1 = addr;
- wh->addr2 = wh->addr3 = (uint64_t)-1;
-}
-
-void
-where_reset_2 (struct where *wh, uint64_t addr)
-{
- wh->addr2 = addr;
- wh->addr3 = (uint64_t)-1;
-}
-
-void
-where_reset_3 (struct where *wh, uint64_t addr)
-{
- wh->addr3 = addr;
-}
+++ /dev/null
-/* Pedantic checking of DWARF files
- Copyright (C) 2009,2010,2011 Red Hat, Inc.
- This file is part of Red Hat elfutils.
-
- Red Hat elfutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by the
- Free Software Foundation; version 2 of the License.
-
- Red Hat 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 a copy of the GNU General Public License along
- with Red Hat elfutils; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
-
- Red Hat elfutils is an included package of the Open Invention Network.
- An included package of the Open Invention Network is a package for which
- Open Invention Network licensees cross-license their patents. No patent
- license is granted, either expressly or impliedly, by designation as an
- included package. Should you wish to participate in the Open Invention
- Network licensing program, please visit www.openinventionnetwork.com
- <http://www.openinventionnetwork.com>. */
-
-#ifndef DWARFLINT_WHERE_H
-#define DWARFLINT_WHERE_H
-
-#include "section_id.hh"
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#ifdef __cplusplus
-#include <iosfwd>
-extern "C"
-{
-#endif
-
- enum where_formatting
- {
- wf_plain = 0, /* Default formatting for given section. */
- wf_cudie,
- };
-
- struct where
- {
- enum section_id section;
- enum where_formatting formatting;
- uint64_t addr1; // E.g. a CU offset.
- uint64_t addr2; // E.g. a DIE address.
- uint64_t addr3; // E.g. an attribute.
- struct where const *ref; // Related reference, e.g. an abbrev
- // related to given DIE.
- struct where const *next; // For forming "caused-by" chains.
- };
-
- extern const char *where_fmt (const struct where *wh, char *ptr);
- extern void where_fmt_chain (const struct where *wh, const char *severity);
- extern void where_reset_1 (struct where *wh, uint64_t addr);
- extern void where_reset_2 (struct where *wh, uint64_t addr);
- extern void where_reset_3 (struct where *wh, uint64_t addr);
-
-#ifdef __cplusplus
-}
-
-#include <iostream>
-
-inline where
-WHERE (section_id sec, where const *next = NULL)
-{
- where ret = {sec, wf_plain,
- (uint64_t)-1,
- (uint64_t)-1,
- (uint64_t)-1,
- NULL, next};
- return ret;
-}
-
-
-inline std::ostream &
-operator << (std::ostream &os, where const &wh)
-{
- os << where_fmt (&wh, NULL);
- return os;
-}
-
-#endif
-
-#endif//DWARFLINT_WHERE_H