From: Petr Machata Date: Tue, 12 Apr 2011 19:24:35 +0000 (+0200) Subject: dwarflint: Revamp where, step 1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ded5901e3ed7ba76424f9641619907d7216b3050;p=thirdparty%2Felfutils.git dwarflint: Revamp where, step 1 --- diff --git a/dwarflint/Makefile.am b/dwarflint/Makefile.am index 56e261152..e3f518d49 100644 --- a/dwarflint/Makefile.am +++ b/dwarflint/Makefile.am @@ -69,7 +69,7 @@ dwarflint_SOURCES = \ 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 \ @@ -96,7 +96,7 @@ locstats_SOURCES = \ 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 diff --git a/dwarflint/addr-record.cc b/dwarflint/addr-record.cc index ec31eba2e..c2f68be1c 100644 --- a/dwarflint/addr-record.cc +++ b/dwarflint/addr-record.cc @@ -1,5 +1,5 @@ /* 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 @@ -81,19 +81,3 @@ 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); -} diff --git a/dwarflint/addr-record.hh b/dwarflint/addr-record.hh index 1542ff314..e22ae6500 100644 --- a/dwarflint/addr-record.hh +++ b/dwarflint/addr-record.hh @@ -1,5 +1,5 @@ /* 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 @@ -28,55 +28,57 @@ #include #include +#include + #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 { -#else -# include -#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 _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 diff --git a/dwarflint/check_debug_abbrev.cc b/dwarflint/check_debug_abbrev.cc index 3b5e3bab6..771c506d5 100644 --- a/dwarflint/check_debug_abbrev.cc +++ b/dwarflint/check_debug_abbrev.cc @@ -43,6 +43,11 @@ #include "messages.hh" #include "misc.hh" +class ll_where + : public locus +{ +}; + checkdescriptor const * check_debug_abbrev::descriptor () { @@ -153,12 +158,13 @@ namespace 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) @@ -184,7 +190,7 @@ namespace 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 @@ -212,9 +218,9 @@ namespace 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); } } @@ -308,13 +314,14 @@ namespace 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) @@ -362,11 +369,11 @@ namespace 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 (); @@ -377,6 +384,7 @@ namespace 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; @@ -458,7 +466,7 @@ namespace } 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." diff --git a/dwarflint/check_debug_aranges.cc b/dwarflint/check_debug_aranges.cc index b95597022..7373626ec 100644 --- a/dwarflint/check_debug_aranges.cc +++ b/dwarflint/check_debug_aranges.cc @@ -196,7 +196,8 @@ check_aranges_structural (struct elf_file *file, 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; @@ -268,13 +269,32 @@ check_aranges_structural (struct elf_file *file, 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." @@ -395,12 +415,12 @@ check_aranges_structural (struct elf_file *file, 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; } diff --git a/dwarflint/check_debug_info.cc b/dwarflint/check_debug_info.cc index 46d4ec512..2ee494c31 100644 --- a/dwarflint/check_debug_info.cc +++ b/dwarflint/check_debug_info.cc @@ -114,17 +114,15 @@ namespace 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; } @@ -133,12 +131,12 @@ namespace { 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; @@ -146,9 +144,9 @@ namespace 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) @@ -156,8 +154,8 @@ namespace 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; } @@ -179,10 +177,11 @@ namespace { 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 @@ -192,7 +191,7 @@ namespace 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; } @@ -211,7 +210,7 @@ namespace 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; } @@ -426,15 +425,15 @@ namespace 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. */ @@ -479,7 +478,7 @@ namespace << "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. */ @@ -497,13 +496,13 @@ namespace 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. @@ -571,7 +570,7 @@ namespace 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 \ @@ -688,7 +687,7 @@ namespace { 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 @@ -843,7 +842,7 @@ namespace 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. @@ -1033,7 +1032,7 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, 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); @@ -1052,8 +1051,7 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, 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, @@ -1071,7 +1069,6 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, else if (!check_die_references (cu, &local_die_refs)) retval = false; - ref_record_free (&local_die_refs); return retval; } @@ -1088,7 +1085,6 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) Elf_Data *const strings = _m_sec_str->sect.data; struct ref_record die_refs; - WIPE (die_refs); bool success = true; @@ -1137,13 +1133,13 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) { 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); } } @@ -1200,7 +1196,6 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) that's not necessary anymore. */ check_global_die_references (!cus.empty () ? &cus.front () : NULL); - ref_record_free (&die_refs); if (strings_coverage != NULL) { @@ -1224,13 +1219,7 @@ check_debug_info::~check_debug_info () { for (std::vector::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 * @@ -1276,8 +1265,9 @@ check_debug_info_refs::check_debug_info_refs (checkstack &stack, 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 diff --git a/dwarflint/check_debug_info.hh b/dwarflint/check_debug_info.hh index 2c93f09c7..d71f1a2a1 100644 --- a/dwarflint/check_debug_info.hh +++ b/dwarflint/check_debug_info.hh @@ -43,11 +43,23 @@ struct cu_head 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 diff --git a/dwarflint/check_debug_line.cc b/dwarflint/check_debug_line.cc index 93637238e..7dc722ab3 100644 --- a/dwarflint/check_debug_line.cc +++ b/dwarflint/check_debug_line.cc @@ -101,7 +101,7 @@ namespace { size_t nfile = files.size () + 1; if (!checked_read_uleb128 (ctx, ptr, - where, "directory index")) + *where, "directory index")) return false; if (*name == '/' && *ptr != 0) @@ -128,11 +128,11 @@ namespace 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; @@ -316,13 +316,13 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) /* 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}); @@ -340,10 +340,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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) @@ -371,10 +371,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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; } @@ -400,7 +400,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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)) @@ -466,7 +466,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) /* 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; @@ -533,10 +533,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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); } @@ -550,7 +550,7 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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; } @@ -572,10 +572,10 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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; } @@ -616,13 +616,13 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) 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; @@ -670,9 +670,9 @@ check_debug_line::check_debug_line (checkstack &stack, dwarflint &lint) { 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); } } diff --git a/dwarflint/check_debug_loc_range.cc b/dwarflint/check_debug_loc_range.cc index 74b4d272e..6719c3087 100644 --- a/dwarflint/check_debug_loc_range.cc +++ b/dwarflint/check_debug_loc_range.cc @@ -392,7 +392,8 @@ namespace 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 { \ @@ -542,7 +543,7 @@ namespace } #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; } @@ -602,9 +603,10 @@ namespace { 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); } } @@ -785,7 +787,7 @@ namespace form const *form, uint64_t *valuep, char const *str, - struct where *where) + struct where const &where) { if (form == NULL) return true; @@ -797,7 +799,7 @@ namespace 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; @@ -810,19 +812,19 @@ namespace 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; @@ -847,8 +849,7 @@ check_location_expression (dwarf_version const *ver, return false; } - struct ref_record oprefs; - WIPE (oprefs); + ref_record oprefs; struct addr_record opaddrs; WIPE (opaddrs); @@ -879,9 +880,9 @@ check_location_expression (dwarf_version const *ver, 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) @@ -908,7 +909,7 @@ check_location_expression (dwarf_version const *ver, 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; @@ -937,17 +938,15 @@ check_location_expression (dwarf_version const *ver, } 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; } @@ -974,7 +973,7 @@ found_hole (uint64_t start, uint64_t length, void *data) && (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 @@ -982,7 +981,7 @@ found_hole (uint64_t start, uint64_t length, void *data) /* 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; diff --git a/dwarflint/check_debug_pub.cc b/dwarflint/check_debug_pub.cc index c44cab4b0..7bd9a7f59 100644 --- a/dwarflint/check_debug_pub.cc +++ b/dwarflint/check_debug_pub.cc @@ -231,10 +231,10 @@ check_debug_pub::check_pub_structural () { 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; } diff --git a/dwarflint/checked_read.cc b/dwarflint/checked_read.cc index 14831ecb1..a4df0222a 100644 --- a/dwarflint/checked_read.cc +++ b/dwarflint/checked_read.cc @@ -45,7 +45,7 @@ read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep, { 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; } @@ -53,8 +53,8 @@ read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep, } 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 @@ -75,7 +75,7 @@ read_address_size (struct read_ctx *ctx, 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; } @@ -84,18 +84,16 @@ read_address_size (struct read_ctx *ctx, { /* 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; } @@ -105,59 +103,59 @@ read_address_size (struct read_ctx *ctx, 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) { @@ -174,7 +172,7 @@ read_sc_value (uint64_t *valuep, form_width_t width, case fw_uleb: case fw_sleb: return checked_read_leb128 (ctx, width, valuep, - where, "attribute value"); + loc, "attribute value"); case fw_unknown: ; @@ -185,13 +183,13 @@ read_sc_value (uint64_t *valuep, form_width_t width, 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; diff --git a/dwarflint/checked_read.hh b/dwarflint/checked_read.hh index 1e0deda8c..3f4f5984b 100644 --- a/dwarflint/checked_read.hh +++ b/dwarflint/checked_read.hh @@ -49,17 +49,17 @@ error_code read_address_size (read_ctx *ctx, 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 @@ -68,7 +68,7 @@ bool read_sc_value (uint64_t *valuep, form_width_t width, /// 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 diff --git a/dwarflint/messages.cc b/dwarflint/messages.cc index a803a50a3..7ea65d280 100644 --- a/dwarflint/messages.cc +++ b/dwarflint/messages.cc @@ -246,35 +246,45 @@ message_criteria::and_not (message_term const &term) *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; @@ -282,9 +292,9 @@ wr_message (unsigned long category, const struct where *wh, 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); } @@ -330,9 +340,9 @@ message_count_filter::should_emit (void const *key) } 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) {} @@ -347,8 +357,8 @@ message_context::when (bool whether) const 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 @@ -405,22 +415,23 @@ wr_error () } 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 @@ -430,24 +441,24 @@ wr_message (message_category category) } 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) @@ -457,28 +468,28 @@ wr_format_leb128_message (struct where const *where, 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"); } diff --git a/dwarflint/messages.hh b/dwarflint/messages.hh index 6e85d4299..fe9a9d154 100644 --- a/dwarflint/messages.hh +++ b/dwarflint/messages.hh @@ -114,30 +114,30 @@ std::ostream &operator<< (std::ostream &o, message_criteria const &criteria); 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, @@ -191,18 +191,18 @@ class message_context 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); @@ -231,9 +231,9 @@ public: 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 (); diff --git a/dwarflint/misc.cc b/dwarflint/misc.cc index 497ee114e..82359bc1f 100644 --- a/dwarflint/misc.cc +++ b/dwarflint/misc.cc @@ -1,5 +1,5 @@ /* 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 @@ -62,7 +62,7 @@ supported_version (unsigned version, va_end (ap); if (!retval) - wr_error (where, ": unsupported version %d.\n", version); + wr_error (*where) << "unsupported version " << version << ".\n"; return retval; } diff --git a/dwarflint/reloc.cc b/dwarflint/reloc.cc index 2e23248b8..e4a702254 100644 --- a/dwarflint/reloc.cc +++ b/dwarflint/reloc.cc @@ -31,20 +31,64 @@ #include "messages.hh" #include "misc.hh" #include "readctx.hh" +#include "pri.hh" #include #include #include -#include +#include -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 * @@ -71,8 +115,7 @@ relocation_next (relocation_data *reloc, uint64_t offset, { 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." @@ -126,7 +169,7 @@ do_one_relocation (elf_file const *file, 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) @@ -263,10 +306,7 @@ relocate_one (struct elf_file const *file, 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) @@ -279,8 +319,8 @@ relocate_one (struct elf_file const *file, 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; } @@ -314,9 +354,9 @@ relocate_one (struct elf_file const *file, }; 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) @@ -372,12 +412,10 @@ read_rel (struct elf_file *file, 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++; @@ -405,7 +443,7 @@ read_rel (struct elf_file *file, 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; diff --git a/dwarflint/section_id.hh b/dwarflint/section_id.hh index 4b937d7fd..ec9c4daea 100644 --- a/dwarflint/section_id.hh +++ b/dwarflint/section_id.hh @@ -1,5 +1,5 @@ /* 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 @@ -49,8 +49,6 @@ enum section_id #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: */ @@ -63,6 +61,8 @@ enum section_id 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[]; diff --git a/dwarflint/tests/run-bad.sh b/dwarflint/tests/run-bad.sh index 3080f3e9a..bbaf95b58 100755 --- a/dwarflint/tests/run-bad.sh +++ b/dwarflint/tests/run-bad.sh @@ -105,19 +105,19 @@ error: .debug_info: DIE 0xab (abbreviation 113): DIE chain not terminated with n EOF testrun_compare ./dwarflint garbage-10 <). -error: .rela.debug_info: offset 0xc00: invalid relocation 2560 (). -error: .rela.debug_info: offset 0x1100: invalid relocation 2560 (). -error: .rela.debug_info: offset 0x1500: invalid relocation 256 (). -error: .rela.debug_info: offset 0x1d00: invalid relocation 256 (). -error: .rela.debug_info: offset 0x2500: invalid relocation 2560 (). -error: .rela.debug_info: offset 0x3600: invalid relocation 256 (). +error: .rela 0x600 of .debug_info: invalid relocation 2560 (). +error: .rela 0xc00 of .debug_info: invalid relocation 2560 (). +error: .rela 0x1100 of .debug_info: invalid relocation 2560 (). +error: .rela 0x1500 of .debug_info: invalid relocation 256 (). +error: .rela 0x1d00 of .debug_info: invalid relocation 256 (). +error: .rela 0x2500 of .debug_info: invalid relocation 2560 (). +error: .rela 0x3600 of .debug_info: invalid relocation 256 (). 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 diff --git a/dwarflint/where.c b/dwarflint/where.c deleted file mode 100644 index e7547f7a6..000000000 --- a/dwarflint/where.c +++ /dev/null @@ -1,204 +0,0 @@ -/* 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 - . */ - -#include "where.h" - -#include -#include -#include -#include -#include - -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; -} diff --git a/dwarflint/where.cc b/dwarflint/where.cc new file mode 100644 index 000000000..cd11b015c --- /dev/null +++ b/dwarflint/where.cc @@ -0,0 +1,223 @@ +/* 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 + . */ + +#include "where.h" + +#include +#include +#include +#include +#include +#include + +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 + class simple_formatters + : public std::array + { + 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 + { + 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; +} diff --git a/dwarflint/where.h b/dwarflint/where.h index fb1dd47a5..7087827ca 100644 --- a/dwarflint/where.h +++ b/dwarflint/where.h @@ -30,61 +30,83 @@ #include #include - -#ifdef __cplusplus #include -extern "C" +#include +#include + +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 + 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