reloc.cc reloc.hh \
section_id.cc section_id.hh \
sections.cc sections.hh sections_i.hh \
- where.c where.h \
+ where.cc where.h \
wrap.cc wrap.hh \
\
check_debug_abbrev.cc check_debug_abbrev.hh check_debug_abbrev_i.hh \
files.cc files.hh \
option.cc option.hh option_i.hh \
pri.cc pri.hh \
- where.c where.h
+ where.cc where.h
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
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);
-}
/* 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 <vector>
+
#include "where.h"
-#ifdef __cplusplus
-extern "C"
+
+/* 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. */
+
+struct addr_record
+{
+ size_t size;
+ size_t alloc;
+ uint64_t *addrs;
+};
+
+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);
+
+/* 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. */
+
+struct ref
+{
+ uint64_t addr; // Referree address
+ ::where who; // Referrer
+
+ ref ()
+ : addr (-1)
+ , who ()
+ {}
+
+ ref (uint64_t a_addr, where const &a_who)
+ : addr (a_addr)
+ , who (a_who)
+ {}
+};
+
+class ref_record
+ : private std::vector<struct ref>
{
-#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. */
-
- struct addr_record
- {
- size_t size;
- size_t alloc;
- uint64_t *addrs;
- };
-
- 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);
-
- /* 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. */
-
- struct ref
- {
- uint64_t addr; // Referree address
- struct where who; // Referrer
- };
-
- struct ref_record
- {
- size_t size;
- size_t alloc;
- struct ref *refs;
- };
-
- void ref_record_add (struct ref_record *rr, uint64_t addr,
- struct where *referrer);
- void ref_record_free (struct ref_record *rr);
-
-#ifdef __cplusplus
-}
-#endif
+ typedef std::vector<struct ref> _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"
+class ll_where
+ : public locus
+{
+};
+
checkdescriptor const *
check_debug_abbrev::descriptor ()
{
struct abbrev_table *section = NULL;
uint64_t first_attr_off = 0;
- struct where where = WHERE (sec_abbrev, NULL);
+ section_id const sec_id = sec_abbrev;
+ where where = WHERE (sec_id, NULL);
// Tolerate failure here.
dwarf_version const *ver = NULL;
static dwarf_version const *latest_ver = dwarf_version::get_latest ();
- where.addr1 = 0;
+ where_reset_1 (&where, 0);
bool failed = false;
while (true)
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, where, "abbrev code"))
throw check_base::failed ();
/* Note: we generally can't tell the difference between
if (zero_seq_off != (uint64_t)-1)
{
- struct where wh = WHERE (where.section, NULL);
+ struct where wh = WHERE (sec_id, NULL);
wr_message_padding_0 (mc_abbrevs | mc_header,
- &wh, zero_seq_off, abbr_off);
+ wh, zero_seq_off, abbr_off);
}
}
else
cur = &fake;
WIPE (*cur);
+ new (&cur->where) class where ();
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)
where_reset_3 (&where, attr_off);
/* Load attribute name and form. */
- if (!checked_read_uleb128 (&ctx, &attrib_name, &where,
+ if (!checked_read_uleb128 (&ctx, &attrib_name, where,
"attribute name"))
throw check_base::failed ();
- if (!checked_read_uleb128 (&ctx, &attrib_form, &where,
+ if (!checked_read_uleb128 (&ctx, &attrib_form, where,
"attribute form"))
throw check_base::failed ();
struct abbrev_attrib *acur = cur->attribs + cur->size++;
WIPE (*acur);
+ new (&acur->where) class where ();
acur->name = attrib_name;
acur->form = attrib_form;
acur->where = where;
}
while (!null_attrib);
- where_reset_2 (&where, where.addr2); // drop addr 3
+ where_reset_3 (&where, -1); // 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."
while (!read_ctx_eof (&ctx))
{
- struct where where = WHERE (sec_aranges, NULL);
+ section_id const sec_id = sec_aranges;
+ struct where where = WHERE (sec_id, NULL);
where_reset_1 (&where, read_ctx_get_offset (&ctx));
const unsigned char *atab_begin = ctx.ptr;
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;
+ class cudie_locus
+ : public locus
+ {
+ uint64_t _m_offset;
+
+ public:
+ cudie_locus (uint64_t offset)
+ : _m_offset (offset)
+ {}
+
+ std::string
+ format (bool) const
+ {
+ std::stringstream ss;
+ if (_m_offset != (uint64_t)-1)
+ ss << "CU DIE " << _m_offset;
+ else
+ ss << "unknown CU";
+ return ss.str ();
+ }
+ };
+
+ cudie_locus cudie_loc (cu != NULL ? cu->cudie_offset : -1);
+ where.ref = &cudie_loc;
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;
if (cu->has_arange)
wr_error (where)
<< "there has already been arange section for this CU."
if (sub_ctx.ptr != sub_ctx.end)
{
uint64_t start, end;
- struct where wh = WHERE (where.section, NULL);
+ struct where wh = WHERE (sec_id, NULL);
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;
}
struct 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 (!addr_record_has_addr (&cu->die_addrs, 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 (addr_record_has_addr (&jt->die_addrs, 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;
}
{
const unsigned char *cu_begin = ctx.ptr;
struct where where = WHERE (sec_info, NULL);
- where_reset_1 (&where, read_ctx_get_offset (&ctx));
+ uint64_t offset = read_ctx_get_offset (&ctx);
+ where_reset_1 (&where, offset);
cu_head head;
- head.offset = where.addr1;
+ head.offset = offset;
head.where = where;
/* Reading CU head is a bit tricky, because we don't know if
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, where,
off_start, off_end);
break;
}
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, where,
off_start, off_end);
break;
}
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. */
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.
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 \
{
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
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.
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;
}
Elf_Data *const strings = _m_sec_str->sect.data;
struct ref_record die_refs;
- WIPE (die_refs);
bool success = true;
{
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);
}
}
that's not necessary anymore. */
check_global_die_references (!cus.empty () ? &cus.front () : NULL);
- ref_record_free (&die_refs);
if (strings_coverage != NULL)
{
{
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);
- }
+ addr_record_free (&it->die_addrs);
}
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
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.
+ ::where where; // Where this section was defined.
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_head ()
+ : offset (0)
+ , size (0)
+ , head_size (0)
+ , total_size (0)
+ , offset_size (0)
+ , where ()
+ , abbrev_offset (0)
+ , version (0)
+ , address_size (0)
+ {}
};
struct cu
{
size_t nfile = files.size () + 1;
if (!checked_read_uleb128 (ctx, ptr,
- where, "directory index"))
+ *where, "directory index"))
return false;
if (*name == '/' && *ptr != 0)
bool
use_file (files_t &files, uint64_t file_idx,
- where *where, char const *msg = "")
+ where const &where, char const *msg = "")
{
if (file_idx == 0 || file_idx > files.size ())
{
- wr_error (*where)
+ wr_error (where)
<< msg << "invalid file index " << file_idx << '.'
<< std::endl;
return false;
/* 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)
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, wh,
off_start, off_end);
else
- wr_message_padding_n0 (mc_line | mc_header, &wh,
+ wr_message_padding_n0 (mc_line | mc_header, wh,
off_start, program_start - sub_ctx.begin);
sub_ctx.ptr = program_start;
}
case 0:
{
uint64_t skip_len;
- if (!checked_read_uleb128 (&sub_ctx, &skip_len, &where,
+ if (!checked_read_uleb128 (&sub_ctx, &skip_len, where,
"length of extended opcode"))
goto skip;
if (!read_ctx_need_data (&sub_ctx, skip_len))
/* 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, where,
"set_discriminator operand"))
goto skip;
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,
+ wr_message_padding_0 (mc_line, wh,
off_start, off_end);
else
- wr_message_padding_n0 (mc_line, &wh,
+ wr_message_padding_n0 (mc_line, wh,
off_start,
next - sub_ctx.begin);
}
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, where,
"DW_LNS_advance_line operand"))
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, 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, where, "DW_LNS_set_file: "))
success = false;
first_file = false;
}
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, where, buf))
goto skip;
}
if (first_file)
{
- if (!use_file (files, 1, &where,
+ if (!use_file (files, 1, where,
"initial value of `file' register: "))
success = false;
first_file = false;
{
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, wh, off_start, off_end);
else
- wr_message_padding_n0 (mc_line, &wh,
+ wr_message_padding_n0 (mc_line, wh,
off_start, sub_ctx.end - sub_ctx.begin);
}
}
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);
+ where_reset_1 (&where, offset);
#define HAVE_OVERLAP \
do { \
}
#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_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);
}
}
form const *form,
uint64_t *valuep,
char const *str,
- struct where *where)
+ struct where 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;
struct relocation *rel;
if ((rel = relocation_next (reloc, off,
- where, skip_mismatched)))
+ &where, skip_mismatched)))
{
if (storclass != sc_block)
relocate_one (&file, reloc, rel,
- cu->head->address_size, valuep, where,
+ 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)
{
uint64_t off_block_end = read_ctx_get_offset (ctx) + init_off - 1;
- relocation_next (reloc, off_block_end, where, skip_ok);
+ relocation_next (reloc, off_block_end, &where, skip_ok);
}
return true;
return false;
}
- struct ref_record oprefs;
- WIPE (oprefs);
+ ref_record oprefs;
struct addr_record opaddrs;
WIPE (opaddrs);
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 (ref (off_after + skip, where));
}
break;
}
out:
- for (size_t i = 0; i < oprefs.size; ++i)
+ for (ref_record::const_iterator it = oprefs.begin ();
+ it != oprefs.end (); ++it)
{
- 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);
+ if (!addr_record_has_addr (&opaddrs, it->addr))
+ wr_error (it->who) << "unresolved reference to opcode at "
+ << pri::hex (it->addr) << ".\n";
}
addr_record_free (&opaddrs);
- ref_record_free (&oprefs);
return true;
}
&& (length < info->align)))
{
struct where wh = WHERE (info->section, NULL);
- wr_message_padding_0 (info->category, &wh, start, end);
+ wr_message_padding_0 (info->category, wh, start, end);
}
}
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);
+ wr_message_padding_n0 (info->category, wh, start, end);
}
return true;
{
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);
+ wr_message_padding_0 (mc_pubtables, wh, off_start, off_end);
else
{
- wr_message_padding_n0 (mc_pubtables | mc_error, &wh,
+ wr_message_padding_n0 (mc_pubtables | mc_error, wh,
off_start, off_start + size);
retval = false;
}
{
if (!read_ctx_read_8ubyte (ctx, sizep))
{
- wr_error (where, ": can't read 64bit CU length.\n");
+ wr_error (*where) << "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 (*where)
+ << "unrecognized CU length escape value: " << size32 << ".\n";
return false;
}
else
uint8_t address_size;
if (!read_ctx_read_ubyte (ctx, &address_size))
{
- wr_error (where, ": can't read address size.\n");
+ wr_error (*where) << "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 (*where) << "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 (*where) << "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;
where const *where);
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
*this *= tmp;
}
+extern "C" bool show_refs ();
static void
-wr_verror (const struct where *wh, const char *format, va_list ap)
+format_chain (locus const &loc, char const *severity)
{
- printf ("error: %s", where_fmt (wh, NULL));
+ if (show_refs ())
+ for (locus const *it = loc.next (); it != NULL; it = it->next ())
+ printf ("%s: %s: caused by this reference.\n",
+ severity, it->format ().c_str ());
+}
+
+static void
+wr_verror (locus const &loc, const char *format, va_list ap)
+{
+ printf ("error: %s", loc.format ().c_str ());
vprintf (format, ap);
- where_fmt_chain (wh, "error");
+ format_chain (loc, "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 ("warning: %s", where_fmt (wh, NULL));
+ printf ("warning: %s", loc.format ().c_str ());
vprintf (format, ap);
- where_fmt_chain (wh, "warning");
+ format_chain (loc, "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 (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");
}
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
va_end (ap);
if (!retval)
- wr_error (where, ": unsupported version %d.\n", version);
+ wr_error (*where) << "unsupported version " << version << ".\n";
return retval;
}
#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 *
{
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, *where, rel->offset);
wr_error (reloc_where)
<< (st == skip_unref
? "relocation targets unreferenced portion of the section."
relocation *rel,
unsigned rel_width,
uint64_t *value,
- where const &reloc_where,
+ reloc_locus const &reloc_where,
section_id offset_into,
GElf_Sym *symbol,
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, *where, rel->offset);
GElf_Sym symbol_mem, *symbol;
if (symptr != NULL)
if (offset_into == 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)
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;
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++;
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) 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
#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: */
rel_exec, /* Some as above, but we expect EXEC bit. */
};
+static const unsigned num_section_ids = rel_exec + 1;
+
// section_name[0] is for sec_invalid. The last index is for
// count_debuginfo_sections and is NULL.
extern char const *section_name[];
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 (abbr. attribute 0): relocation formed using STT_SECTION symbol with non-zero value.
+error: .rela 0x11 of .debug_info: DIE 0xb (abbr. attribute 0x4): 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
+++ /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) 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 <cinttypes>
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <array>
+
+class where::simple_formatter
+ : public where::formatter
+{
+ char const *_m_name;
+ char const *_m_fmt1;
+ char const *_m_fmt2;
+ char const *_m_fmt3;
+
+public:
+ simple_formatter (char const *name = NULL,
+ char const *fmt1 = NULL,
+ char const *fmt2 = NULL,
+ char const *fmt3 = NULL)
+ : _m_name (name)
+ , _m_fmt1 (fmt1)
+ , _m_fmt2 (fmt2)
+ , _m_fmt3 (fmt3)
+ {}
+
+ virtual std::string
+ format (where const &wh, bool brief) const
+ {
+ std::string ret;
+
+ brief = brief || _m_name == NULL;
+ if (!brief)
+ ret += _m_name;
+
+ char const *const *formats = &_m_fmt1;
+ uint64_t const *addrs = &wh._m_addr1;
+
+ for (size_t i = 3; i > 0; --i)
+ {
+ size_t idx = i - 1;
+ if (addrs[idx] == (uint64_t)-1)
+ continue;
+
+ assert (formats[idx] != NULL);
+
+ /* 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;
+
+ if (!brief)
+ ret += ": ";
+ char *buf;
+ if (x_asprintf (&buf, formats[idx], addrs[idx]) >= 0)
+ {
+ ret += buf;
+ free (buf);
+ }
+ else
+ ret += formats[idx];
+
+ break;
+ }
+
+ if (wh.ref != NULL)
+ {
+ ret += " (";
+ ret += wh.ref->format (true);
+ ret += ')';
+ }
+
+ return ret;
+ }
+};
+
+namespace
+{
+ template<size_t size>
+ class simple_formatters
+ : public std::array<where::simple_formatter, size>
+ {
+ protected:
+ void
+ add (section_id id, char const *name,
+ char const *addr1f = NULL,
+ char const *addr2f = NULL,
+ char const *addr3f = NULL)
+ {
+ (*this)[id] = where::simple_formatter (name, addr1f, addr2f, addr3f);
+ }
+ };
+
+ class section_formatters
+ : public simple_formatters<num_section_ids>
+ {
+ public:
+ section_formatters ()
+ {
+ add (sec_info, ".debug_info", "CU %"PRId64, "DIE %#"PRIx64);
+
+ add (sec_abbrev, ".debug_abbrev",
+ "section %"PRId64, "abbreviation %"PRId64, "abbr. attribute %#"PRIx64);
+
+ add (sec_aranges, ".debug_aranges",
+ "table %"PRId64, "arange %#"PRIx64);
+
+ add (sec_pubnames, ".debug_pubnames",
+ "pubname table %"PRId64, "pubname %#"PRIx64);
+
+ add (sec_pubtypes, ".debug_pubtypes",
+ "pubtype table %"PRId64, "pubtype %#"PRIx64);
+
+ add (sec_str, ".debug_str", "offset %#"PRIx64);
+
+ add (sec_line, ".debug_line", "table %"PRId64, "offset %#"PRIx64);
+
+ add (sec_loc, ".debug_loc", "loclist %#"PRIx64, "offset %#"PRIx64);
+
+ add (sec_mac, ".debug_mac");
+
+ add (sec_ranges, ".debug_ranges", "rangelist %#"PRIx64, "offset %#"PRIx64);
+
+ add (sec_locexpr, "location expression", "offset %#"PRIx64);
+ }
+ } const section_names;
+}
+
+namespace
+{
+ where::formatter const *
+ wf_for_section (section_id sec)
+ {
+ return §ion_names[sec];
+ }
+}
+
+where
+WHERE (section_id sec, where const *next)
+{
+ where::formatter const *fmt = wf_for_section (sec);
+ return where (fmt, next);
+}
+
+where::where (formatter const *fmt, locus const *nxt)
+ : _m_formatter (fmt)
+ , _m_addr1 ((uint64_t)-1)
+ , _m_addr2 ((uint64_t)-1)
+ , _m_addr3 ((uint64_t)-1)
+ , ref (NULL)
+ , _m_next (nxt)
+{
+}
+
+where &
+where::operator= (where const ©)
+{
+ _m_formatter = copy._m_formatter;
+
+ _m_addr1 = copy._m_addr1;
+ _m_addr2 = copy._m_addr2;
+ _m_addr3 = copy._m_addr3;
+
+ ref = copy.ref;
+ _m_next = copy._m_next;
+
+ return *this;
+}
+
+std::string
+where::format (bool brief) const
+{
+ assert (_m_formatter != NULL);
+ return _m_formatter->format (*this, brief);
+}
+
+void
+where_reset_1 (struct where *wh, uint64_t addr)
+{
+ wh->_m_addr1 = addr;
+ wh->_m_addr2 = wh->_m_addr3 = (uint64_t)-1;
+}
+
+void
+where_reset_2 (struct where *wh, uint64_t addr)
+{
+ wh->_m_addr2 = addr;
+ wh->_m_addr3 = (uint64_t)-1;
+}
+
+void
+where_reset_3 (struct where *wh, uint64_t addr)
+{
+ wh->_m_addr3 = addr;
+}
#include <stdint.h>
#include <stdlib.h>
-
-#ifdef __cplusplus
#include <iosfwd>
-extern "C"
+#include <iostream>
+#include <cassert>
+
+class locus
{
-#endif
+public:
+ virtual std::string format (bool brief = false) const = 0;
- enum where_formatting
+ virtual locus const *next () const
{
- wf_plain = 0, /* Default formatting for given section. */
- wf_cudie,
- };
+ return NULL;
+ }
+
+ virtual ~locus () {}
+};
- struct where
+struct where
+ : public locus
+{
+ class formatter
{
- 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.
+ public:
+ virtual ~formatter () {}
+ virtual std::string format (where const &wh, bool brief = false) const = 0;
};
- 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);
+ class simple_formatter;
-#ifdef __cplusplus
-}
+private:
+ formatter const *_m_formatter;
-#include <iostream>
+ uint64_t _m_addr1; // E.g. a CU offset.
+ uint64_t _m_addr2; // E.g. a DIE address.
+ uint64_t _m_addr3; // E.g. an attribute.
-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;
-}
+public:
+ locus const *ref; // Related reference, e.g. an abbrev related to
+ // given DIE.
+ locus const *_m_next; // For forming "caused-by" chains.
+ explicit where (formatter const *fmt = NULL,
+ locus const *nxt = NULL);
+
+ where &operator= (where const ©);
+
+ std::string format (bool brief = false) const;
+
+ locus const *
+ next () const
+ {
+ return _m_next;
+ }
+
+ void
+ set_next (locus const *nxt)
+ {
+ assert (_m_next == NULL);
+ _m_next = nxt;
+ }
+
+ friend void where_reset_1 (struct where *wh, uint64_t addr);
+ friend void where_reset_2 (struct where *wh, uint64_t addr);
+ friend void where_reset_3 (struct where *wh, uint64_t addr);
+};
+
+void where_reset_1 (struct where *wh, uint64_t addr);
+void where_reset_2 (struct where *wh, uint64_t addr);
+void where_reset_3 (struct where *wh, uint64_t addr);
+
+where WHERE (section_id sec, where const *next = NULL);
inline std::ostream &
operator << (std::ostream &os, where const &wh)
{
- os << where_fmt (&wh, NULL);
+ os << wh.format ();
return os;
}
-#endif
-
#endif//DWARFLINT_WHERE_H