From: Petr Machata Date: Thu, 5 Mar 2009 16:22:45 +0000 (+0100) Subject: dwarflint: Better message filtering system X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a271bd417ff450df8f1f15475ecd749d4cd07633;p=thirdparty%2Felfutils.git dwarflint: Better message filtering system --- diff --git a/src/dwarflint.c b/src/dwarflint.c index 1a632f9cb..04295cd65 100644 --- a/src/dwarflint.c +++ b/src/dwarflint.c @@ -81,6 +81,8 @@ broken in certain ways"), 0 }, the DIE referring to the entry in consideration"), 0 }, { "nohl", ARGP_nohl, NULL, 0, N_("Don't run high-level tests"), 0 }, + { "verbose", 'v', NULL, 0, + N_("Be verbose"), 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; @@ -105,32 +107,154 @@ static bool tolerate_nodebug = false; static void process_file (Dwarf *dwarf, const char *fname, bool only_one); +#define REALLOC(A, BUF) \ + do { \ + typeof ((A)) _a = (A); \ + if (_a->size == _a->alloc) \ + { \ + if (_a->alloc == 0) \ + _a->alloc = 8; \ + else \ + _a->alloc *= 2; \ + _a->BUF = xrealloc (_a->BUF, \ + sizeof (*_a->BUF) * _a->alloc); \ + } \ + } while (0) + +struct message_term +{ + /* Given a term like A && !B && C && !D, we decompose it thus: */ + enum message_category positive; /* non-zero bits for plain predicates */ + enum message_category negative; /* non-zero bits for negated predicates */ +}; + struct message_criteria { - enum message_category accept; /* cat & accept must be != 0 */ - enum message_category reject; /* cat & reject must be == 0 */ + struct message_term *terms; + size_t size; + size_t alloc; }; static bool -accept_message (struct message_criteria *crit, enum message_category cat) +message_accept (struct message_criteria *cri, enum message_category cat) +{ + for (size_t i = 0; i < cri->size; ++i) + { + struct message_term *t = cri->terms + i; + if ((t->positive & cat) == t->positive + && (t->negative & cat) == 0) + return true; + } + return false; +} + +static const char * +message_term_str (struct message_term *t) { - assert (crit != NULL); - return (crit->accept & cat) != 0 - && (crit->reject & cat) == 0; + static char *names[] = { +#define MC(CAT, ID) [ID] = #CAT, + MESSAGE_CATEGORIES +#undef MC + }; + + unsigned max = 0; +#define MC(CAT, ID) max = ID; + MESSAGE_CATEGORIES +#undef MC + + static char buf[512]; + char *ptr = buf; + ptr = stpcpy (ptr, "("); + + bool got = false; + for (unsigned i = 0; i <= max; ++i) + { + unsigned mask = 1u << i; + if ((t->positive & mask) != 0 + || (t->negative & mask) != 0) + { + if (got) + ptr = stpcpy (ptr, " & "); + if ((t->negative & (1u << i)) != 0) + ptr = stpcpy (ptr, "~"); + ptr = stpcpy (ptr, names[i]); + got = true; + } + } + + if (ptr == buf + 1) + ptr = stpcpy (ptr, "1"); + ptr = stpcpy (ptr, ")"); + return buf; } -static struct message_criteria warning_criteria - = {mc_all & ~(mc_strings), - mc_pubtypes}; -static struct message_criteria error_criteria - = {mc_impact_4 | mc_error, - mc_none}; +static const char * +message_cri_str (struct message_criteria *cri) +{ + static char buf[512]; + char *ptr = buf; + *ptr = 0; + + for (size_t i = 0; i < cri->size; ++i) + { + struct message_term *t = cri->terms + i; + if (i > 0) + ptr = stpcpy (ptr, " | "); + ptr = stpcpy (ptr, message_term_str (t)); + } + + return buf; +} + +static void +message_cri_and (struct message_criteria *cri, struct message_term term) +{ + assert ((term.positive & term.negative) == 0); + //printf ("message_cri_and(%s)\n : %s\n", message_term_str (&term), message_cri_str (cri)); + for (size_t i = 0; i < cri->size; ) + { + struct message_term *t = cri->terms + i; + //struct message_term orig = *t; + t->positive |= term.positive; + t->negative |= term.negative; + if ((t->positive & t->negative) != 0) + { + /* A ^ ~A -> drop the term. */ + /* + printf ("(eliminate %s)\n", message_term_str (&orig)); + printf ("(became %s)\n", message_term_str (t)); + */ + cri->terms[i] = cri->terms[--cri->size]; + } + else + ++i; + } + //printf (" : %s\n", message_cri_str (cri)); +} + +static void +message_cri_or (struct message_criteria *cri, struct message_term term) +{ + assert ((term.positive & term.negative) == 0); + //printf ("message_cri_or(%s)\n : %s\n", message_term_str (&term), message_cri_str (cri)); + REALLOC (cri, terms); + cri->terms[cri->size++] = term; + //printf (" : %s\n", message_cri_str (cri)); +} + + +/* Messages that are accepted (and made into warning). */ +static struct message_criteria warning_criteria; + +/* Accepted (warning) messages, that are turned into errors. */ +static struct message_criteria error_criteria; + static unsigned error_count = 0; static bool check_category (enum message_category cat) { - return accept_message (&warning_criteria, cat); + return message_accept (&warning_criteria, cat); } static void @@ -175,9 +299,9 @@ wr_message (enum message_category category, const struct where *wh, { va_list ap; va_start (ap, format); - if (accept_message (&warning_criteria, category)) + if (message_accept (&warning_criteria, category)) { - if (accept_message (&error_criteria, category)) + if (message_accept (&error_criteria, category)) wr_verror (wh, format, ap); else wr_vwarning (wh, format, ap); @@ -230,7 +354,8 @@ wr_message_padding_n0 (enum message_category category, } /* True if no message is to be printed if the run is succesful. */ -static bool be_quiet; +static bool be_quiet = false; /* -q */ +static bool be_verbose = false; /* -v */ static bool be_strict = false; /* --strict */ static bool be_gnu = false; /* --gnu */ static bool be_tolerant = false; /* --tolerant */ @@ -250,18 +375,46 @@ main (int argc, char *argv[]) int remaining; argp_parse (&argp, argc, argv, 0, &remaining, NULL); + /* Initialize warning & error criteria. */ + message_cri_or (&error_criteria, + (struct message_term){mc_impact_4, mc_none}); + message_cri_or (&error_criteria, + (struct message_term){mc_error, mc_none}); + + message_cri_or (&warning_criteria, + (struct message_term){mc_none, mc_strings}); + + /* Configure warning & error criteria according to configuration. */ if (tolerate_nodebug) - warning_criteria.reject |= mc_elf; + message_cri_and (&warning_criteria, + (struct message_term){mc_none, mc_elf}); + if (be_gnu) - warning_criteria.reject |= mc_acc_bloat | mc_pubtypes; - if (be_strict) { - warning_criteria.accept |= mc_strings; - if (!be_gnu) - warning_criteria.reject &= ~mc_pubtypes; + message_cri_and (&warning_criteria, + (struct message_term){mc_none, mc_acc_bloat}); + if (!be_strict) + message_cri_and (&warning_criteria, + (struct message_term){mc_none, mc_pubtypes}); } + + if (be_strict) + message_cri_and (&warning_criteria, + (struct message_term){mc_strings, mc_none}); + if (be_tolerant) - warning_criteria.reject |= mc_loc | mc_ranges; + { + message_cri_and (&warning_criteria, + (struct message_term){mc_none, mc_loc}); + message_cri_and (&warning_criteria, + (struct message_term){mc_none, mc_ranges}); + } + + if (be_verbose) + { + printf ("warning criteria: %s\n", message_cri_str (&warning_criteria)); + printf ("error criteria: %s\n", message_cri_str (&error_criteria)); + } /* Before we start tell the ELF library which version we are using. */ elf_version (EV_CURRENT); @@ -354,6 +507,12 @@ parse_opt (int key, char *arg __attribute__ ((unused)), case 'q': be_quiet = true; + be_verbose = false; + break; + + case 'v': + be_quiet = false; + be_verbose = true; break; case ARGP_KEY_NO_ARGS: @@ -368,20 +527,6 @@ parse_opt (int key, char *arg __attribute__ ((unused)), return 0; } -#define REALLOC(A, BUF) \ - do { \ - typeof ((A)) _a = (A); \ - if (_a->size == _a->alloc) \ - { \ - if (_a->alloc == 0) \ - _a->alloc = 8; \ - else \ - _a->alloc *= 2; \ - _a->BUF = xrealloc (_a->BUF, \ - sizeof (*_a->BUF) * _a->alloc); \ - } \ - } while (0) - #define PRI_CU "CU 0x%" PRIx64 #define PRI_DIE "DIE 0x%" PRIx64 #define PRI_NOT_ENOUGH ": not enough data for %s.\n" @@ -4898,14 +5043,14 @@ check_line_structural (struct section_data *data, for (size_t i = 0; i < include_directories.size; ++i) if (!include_directories.dirs[i].used) - wr_message (mc_impact_3 | mc_acc_bloat | mc_line, &where, - ": the include #%zd `%s' is not used.\n", + wr_message (mc_impact_3 | mc_acc_bloat | mc_line, + &where, ": the include #%zd `%s' is not used.\n", i + 1, include_directories.dirs[i].name); for (size_t i = 0; i < files.size; ++i) if (!files.files[i].used) - wr_message (mc_impact_3 | mc_acc_bloat | mc_line, &where, - ": the file #%zd `%s' is not used.\n", + wr_message (mc_impact_3 | mc_acc_bloat | mc_line, + &where, ": the file #%zd `%s' is not used.\n", i + 1, files.files[i].name); if (!terminated) diff --git a/src/dwarflint.h b/src/dwarflint.h index 335226755..2c6bc7073 100644 --- a/src/dwarflint.h +++ b/src/dwarflint.h @@ -74,44 +74,46 @@ extern "C" /* Functions and data structures for emitting various types of messages. */ +#define MESSAGE_CATEGORIES \ + /* Severity: */ \ + MC (impact_1, 0) /* no impact on the consumer */ \ + MC (impact_2, 1) /* still no impact, but suspicious or worth mentioning */ \ + MC (impact_3, 2) /* some impact */ \ + MC (impact_4, 3) /* high impact */ \ + \ + /* Accuracy: */ \ + MC (acc_bloat, 4) /* unnecessary constructs (e.g. unreferenced strings) */ \ + MC (acc_suboptimal, 5) /* suboptimal construct (e.g. lack of siblings) */ \ + \ + /* Various: */ \ + MC (error, 6) /* turn the message into an error */ \ + \ + /* Area: */ \ + MC (leb128, 7) /* ULEB/SLEB storage */ \ + MC (abbrevs, 8) /* abbreviations and abbreviation tables */ \ + MC (die_rel, 9) /* DIE relationship */ \ + MC (die_other, 10) /* other messages related to DIEs */ \ + MC (info, 11) /* messages related to .debug_info, but not particular DIEs */ \ + MC (strings, 12) /* string table */ \ + MC (aranges, 13) /* address ranges table */ \ + MC (elf, 14) /* ELF structure, e.g. missing optional sections */ \ + MC (pubtables, 15) /* table of public names/types */ \ + MC (pubtypes, 16) /* .debug_pubtypes presence */ \ + MC (loc, 17) /* messages related to .debug_loc */ \ + MC (ranges, 18) /* messages related to .debug_ranges */ \ + MC (line, 19) /* messages related to .debug_line */ \ + MC (reloc, 20) /* messages related to relocation handling */ \ + MC (header, 21) /* messages related to header portions in general */ \ + MC (other, 31) /* messages unrelated to any of the above */ + enum message_category { mc_none = 0, - /* Severity: */ - mc_impact_1 = 0x1, // no impact on the consumer - mc_impact_2 = 0x2, // still no impact, but suspicious or worth mentioning - mc_impact_3 = 0x4, // some impact - mc_impact_4 = 0x8, // high impact - mc_impact_all= 0xf, // all severity levels - mc_impact_2p = 0xe, // 2+ - mc_impact_3p = 0xc, // 3+ - - /* Accuracy: */ - mc_acc_bloat = 0x10, // unnecessary constructs (e.g. unreferenced strings) - mc_acc_suboptimal= 0x20, // suboptimal construct (e.g. lack of siblings) - mc_acc_all = 0x30, // all accuracy options - - /* Various: */ - mc_error = 0x40, // turn the message into an error - - /* Area: */ - mc_leb128 = 0x100, // ULEB/SLEB storage - mc_abbrevs = 0x200, // abbreviations and abbreviation tables - mc_die_rel = 0x400, // DIE relationship - mc_die_other = 0x800, // other messages related to DIEs - mc_info = 0x1000, // messages related to .debug_info, but not particular DIEs - mc_strings = 0x2000, // string table - mc_aranges = 0x4000, // address ranges table - mc_elf = 0x8000, // ELF structure, e.g. missing optional sections - mc_pubtables = 0x10000, // table of public names/types - mc_pubtypes = 0x20000, // .debug_pubtypes presence - mc_loc = 0x40000, // messages related to .debug_loc - mc_ranges = 0x80000, // messages related to .debug_ranges - mc_line = 0x1000000, // messages related to .debug_line - mc_reloc = 0x40000000, // messages related to relocation handling - mc_other = 0x80000000, // messages unrelated to any of the above - mc_all = 0xffffff00, // all areas +#define MC(CAT, ID)\ + mc_##CAT = 1u << ID, + MESSAGE_CATEGORIES +#undef MC }; extern void wr_error (const struct where *wh, const char *format, ...)