From 762dee7ef1ec28a798d40afe3ab5cec2a95432b8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 8 Oct 2009 20:00:15 +0200 Subject: [PATCH] dwarflint: Dissect dwarflint.c to modules --- src/Makefile.am | 11 +- src/dwarflint-coverage.cc | 4 - src/dwarflint-coverage.h | 21 +- src/dwarflint-hl.cc | 12 +- src/dwarflint-main.cc | 362 ++++++++++++++++++++++ src/dwarflint-messages.cc | 269 +++++++++++++++++ src/dwarflint-messages.h | 148 +++++++++ src/dwarflint-misc.h | 40 +++ src/dwarflint-where.h | 79 +++++ src/dwarflint.c | 622 +------------------------------------- src/dwarflint.h | 157 +--------- 11 files changed, 928 insertions(+), 797 deletions(-) create mode 100644 src/dwarflint-main.cc create mode 100644 src/dwarflint-messages.cc create mode 100644 src/dwarflint-messages.h create mode 100644 src/dwarflint-misc.h create mode 100644 src/dwarflint-where.h diff --git a/src/Makefile.am b/src/Makefile.am index 30bc3c364..87ece1937 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -78,10 +78,13 @@ dwarfcmp_test_CPPFLAGS = -DTEST dwarfcmp_test_SOURCES = $(dwarfcmp_SOURCES) dwarfcmp_test_LDADD = $(dwarfcmp_LDADD) -dwarflint_SOURCES = dwarflint.c dwarflint.h dwarflint-hl.cc \ - dwarflint-expected-at.cc dwarflint-expected.hh \ - dwarfstrings.c dwarflint-coverage.c dwarflint-coverage.h \ - dwarflint-readctx.c dwarflint-readctx.h +dwarflint_SOURCES = dwarfstrings.c \ + dwarflint-main.cc dwarflint.h dwarflint-misc.h \ + dwarflint.c \ + dwarflint-hl.cc dwarflint-expected-at.cc dwarflint-expected.hh \ + dwarflint-coverage.cc dwarflint-coverage.h \ + dwarflint-readctx.c dwarflint-readctx.h \ + dwarflint-messages.cc dwarflint-messages.h dwarflint-where.h readelf_SOURCES = readelf.c dwarfstrings.c diff --git a/src/dwarflint-coverage.cc b/src/dwarflint-coverage.cc index 4e4560292..fee57a158 100644 --- a/src/dwarflint-coverage.cc +++ b/src/dwarflint-coverage.cc @@ -29,10 +29,6 @@ #endif #include "dwarflint-coverage.hh" -extern "C" -{ -#include "../lib/system.h" -} #include #include diff --git a/src/dwarflint-coverage.h b/src/dwarflint-coverage.h index f21c55b19..28d86dd5d 100644 --- a/src/dwarflint-coverage.h +++ b/src/dwarflint-coverage.h @@ -32,25 +32,9 @@ #include #include -#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 = (typeof (_a->BUF)) \ - xrealloc (_a->BUF, \ - sizeof (*_a->BUF) * _a->alloc); \ - } \ - } while (0) - -#define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ)) +#include "dwarflint-misc.h" #ifdef __cplusplus -# define IF_CPLUSPLUS(X) X extern "C" { #endif @@ -122,8 +106,9 @@ bool coverage_find_ranges (struct coverage const *cov, void *data); #ifdef __cplusplus -# define IF_CPLUSPLUS(X) X } + +std::string range_fmt (uint64_t start, uint64_t end); #endif #endif//DWARFLINT_COVERAGE_H diff --git a/src/dwarflint-hl.cc b/src/dwarflint-hl.cc index d01acd757..9e7d16998 100644 --- a/src/dwarflint-hl.cc +++ b/src/dwarflint-hl.cc @@ -1,4 +1,4 @@ -/* Pedantic checking of DWARF files. +/* Pedantic checking of DWARF files. High level checks. Copyright (C) 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Petr Machata , 2009. @@ -46,16 +46,6 @@ using namespace elfutils; -namespace -{ - message_category cat (message_category c1, - message_category c2, - message_category c3 = mc_none) - { - return static_cast (c1 | c2 | c3); - } -} - class hl_ctx { Dwarf *handle; diff --git a/src/dwarflint-main.cc b/src/dwarflint-main.cc new file mode 100644 index 000000000..a9ecc2048 --- /dev/null +++ b/src/dwarflint-main.cc @@ -0,0 +1,362 @@ +/* Pedantic checking of DWARF files. Low-level checks. + Copyright (C) 2008,2009 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include "dwarflint.h" + +/* Bug report address. */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +#define ARGP_strict 300 +#define ARGP_gnu 301 +#define ARGP_tolerant 302 +#define ARGP_ref 303 +#define ARGP_nohl 304 +#define ARGP_dump_off 305 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { "strict", ARGP_strict, NULL, 0, + N_("Be extremely strict, flag level 2 features."), 0 }, + { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 }, + { "ignore-missing", 'i', NULL, 0, + N_("Don't complain if files have no DWARF at all"), 0 }, + { "gnu", ARGP_gnu, NULL, 0, + N_("Binary has been created with GNU toolchain and is therefore known to be \ +broken in certain ways"), 0 }, + { "tolerant", ARGP_tolerant, NULL, 0, + N_("Don't output certain common error messages"), 0 }, + { "ref", ARGP_ref, NULL, 0, + N_("When validating .debug_loc and .debug_ranges, display information about \ +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 }, + { "dump-offsets", ARGP_dump_off, NULL, 0, + N_("Dump DIE offsets to stderr as the tree is iterated."), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Short description of program. */ +static const char doc[] = N_("\ +Pedantic checking of DWARF stored in ELF files."); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_("FILE..."); + +/* If true, we accept silently files without debuginfo. */ +bool tolerate_nodebug = false; + +/* True if no message is to be printed if the run is succesful. */ +bool be_quiet = false; /* -q */ +bool be_verbose = false; /* -v */ +bool be_strict = false; /* --strict */ +bool be_gnu = false; /* --gnu */ +bool be_tolerant = false; /* --tolerant */ +bool show_refs = false; /* --ref */ +bool do_high_level = true; /* ! --nohl */ +bool dump_die_offsets = false; /* --dump-offsets */ + +/* Messages that are accepted (and made into warning). */ +struct message_criteria warning_criteria; + +/* Accepted (warning) messages, that are turned into errors. */ +struct message_criteria error_criteria; + + +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, NULL, NULL +}; + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg __attribute__ ((unused)), + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case ARGP_strict: + be_strict = true; + break; + + case ARGP_gnu: + be_gnu = true; + break; + + case ARGP_tolerant: + be_tolerant = true; + break; + + case ARGP_ref: + show_refs = true; + break; + + case ARGP_nohl: + do_high_level = false; + break; + + case ARGP_dump_off: + dump_die_offsets = true; + break; + + case 'i': + tolerate_nodebug = true; + break; + + case 'q': + be_quiet = true; + be_verbose = false; + break; + + case 'v': + be_quiet = false; + be_verbose = true; + break; + + case ARGP_KEY_NO_ARGS: + fputs (gettext ("Missing file name.\n"), stderr); + argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, + program_invocation_short_name); + exit (1); + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static int +layout_rel_file (Elf *elf) +{ + GElf_Ehdr ehdr; + if (gelf_getehdr (elf, &ehdr) == NULL) + return 1; + + if (ehdr.e_type != ET_REL) + return 0; + + /* Taken from libdwfl. */ + GElf_Addr base = 0; + GElf_Addr start = 0, end = 0, bias = 0; + + bool first = true; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (unlikely (shdr == NULL)) + return 1; + + if (shdr->sh_flags & SHF_ALLOC) + { + const GElf_Xword align = shdr->sh_addralign ?: 1; + const GElf_Addr next = (end + align - 1) & -align; + if (shdr->sh_addr == 0 + /* Once we've started doing layout we have to do it all, + unless we just layed out the first section at 0 when + it already was at 0. */ + || (bias == 0 && end > start && end != next)) + { + shdr->sh_addr = next; + if (end == base) + /* This is the first section assigned a location. + Use its aligned address as the module's base. */ + start = base = shdr->sh_addr; + else if (unlikely (base & (align - 1))) + { + /* If BASE has less than the maximum alignment of + any section, we eat more than the optimal amount + of padding and so make the module's apparent + size come out larger than it would when placed + at zero. So reset the layout with a better base. */ + + start = end = base = (base + align - 1) & -align; + Elf_Scn *prev_scn = NULL; + do + { + prev_scn = elf_nextscn (elf, prev_scn); + GElf_Shdr prev_shdr_mem; + GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn, + &prev_shdr_mem); + if (unlikely (prev_shdr == NULL)) + return 1; + if (prev_shdr->sh_flags & SHF_ALLOC) + { + const GElf_Xword prev_align + = prev_shdr->sh_addralign ?: 1; + + prev_shdr->sh_addr + = (end + prev_align - 1) & -prev_align; + end = prev_shdr->sh_addr + prev_shdr->sh_size; + + if (unlikely (! gelf_update_shdr (prev_scn, + prev_shdr))) + return 1; + } + } + while (prev_scn != scn); + continue; + } + + end = shdr->sh_addr + shdr->sh_size; + if (likely (shdr->sh_addr != 0) + && unlikely (! gelf_update_shdr (scn, shdr))) + return 1; + } + else + { + /* The address is already assigned. Just track it. */ + if (first || end < shdr->sh_addr + shdr->sh_size) + end = shdr->sh_addr + shdr->sh_size; + if (first || bias > shdr->sh_addr) + /* This is the lowest address in the module. */ + bias = shdr->sh_addr; + + if ((shdr->sh_addr - bias + base) & (align - 1)) + /* This section winds up misaligned using BASE. + Adjust BASE upwards to make it congruent to + the lowest section address in the file modulo ALIGN. */ + base = (((base + align - 1) & -align) + + (bias & (align - 1))); + } + + first = false; + } + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + /* Set locale. */ + setlocale (LC_ALL, ""); + + /* Initialize the message catalog. */ + textdomain (PACKAGE_TARNAME); + + /* Parse and process arguments. */ + int remaining; + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + /* Initialize warning & error criteria. */ + warning_criteria |= message_term (mc_none, mc_none); + + error_criteria |= message_term (mc_impact_4, mc_none); + error_criteria |= message_term (mc_error, mc_none); + + /* Configure warning & error criteria according to configuration. */ + if (tolerate_nodebug) + warning_criteria &= message_term (mc_none, mc_elf); + + if (be_gnu) + warning_criteria &= message_term (mc_none, mc_acc_bloat); + + if (!be_strict) + { + warning_criteria &= message_term (mc_none, mc_strings); + warning_criteria + &= message_term (cat (mc_line, mc_header, mc_acc_bloat), mc_none); + warning_criteria &= message_term (mc_none, mc_pubtypes); + } + + if (be_tolerant) + { + warning_criteria &= message_term (mc_none, mc_loc); + warning_criteria &= message_term (mc_none, mc_ranges); + } + + if (be_verbose) + { + std::cout << "warning criteria: " << warning_criteria.str () << std::endl; + std::cout << "error criteria: " << error_criteria.str () << std::endl; + } + + /* Before we start tell the ELF library which version we are using. */ + elf_version (EV_CURRENT); + + /* Now process all the files given at the command line. */ + bool only_one = remaining + 1 == argc; + do + { + /* Open the file. */ + int fd = open (argv[remaining], O_RDONLY); + if (fd == -1) + { + error (0, errno, gettext ("cannot open input file")); + continue; + } + + /* Create an `Elf' descriptor. */ + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL); + if (elf == NULL) + invalid_elf: + wr_error (NULL, + gettext ("Error processing ELF file: %s\n"), + elf_errmsg (-1)); + else + { + unsigned int prev_error_count = error_count; + if (layout_rel_file (elf)) + goto invalid_elf; + + process_file (elf, argv[remaining], only_one); + + elf_errno (); /* Clear errno. */ + elf_end (elf); + int err = elf_errno (); + if (err != 0) + wr_error (NULL, + gettext ("error while closing Elf descriptor: %s\n"), + elf_errmsg (err)); + + if (prev_error_count == error_count && !be_quiet) + puts (gettext ("No errors")); + } + + close (fd); + } + while (++remaining < argc); + + return error_count != 0; +} diff --git a/src/dwarflint-messages.cc b/src/dwarflint-messages.cc new file mode 100644 index 000000000..9539e642b --- /dev/null +++ b/src/dwarflint-messages.cc @@ -0,0 +1,269 @@ +#include "dwarflint-messages.h" +#include "dwarflint-misc.h" +#include "dwarflint-coverage.h" + +#include +#include +#include +#include + +unsigned error_count = 0; + +bool +message_accept (struct message_criteria const *cri, + unsigned long 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; +} + +namespace +{ + struct cat_to_str + : public std::vector + { + cat_to_str () + { +#define MC(CAT, ID) {reserve (ID); (*this)[ID] = #CAT;} + MESSAGE_CATEGORIES +#undef MC + } + }; +} + +std::string +message_term::str () const +{ + static cat_to_str names; + static size_t max = names.size (); + + std::ostringstream os; + os << '('; + + bool got = false; + for (size_t i = 0; i <= max; ++i) + { + size_t mask = 1u << i; + if ((positive & mask) != 0 + || (negative & mask) != 0) + { + if (got) + os << " & "; + if ((negative & (1u << i)) != 0) + os << '~'; + os << names[i]; + got = true; + } + } + + if (!got) + os << '1'; + + os << ')'; + return os.str (); +} + +std::string +message_criteria::str () const +{ + std::ostringstream os; + + for (size_t i = 0; i < size; ++i) + { + message_term const &t = terms[i]; + if (i > 0) + os << " | "; + os << t.str (); + } + + return os.str (); +} + +void +message_criteria::operator &= (message_term const &term) +{ + assert ((term.positive & term.negative) == 0); + for (size_t i = 0; i < size; ) + { + message_term &t = terms[i]; + t.positive |= term.positive; + t.negative |= term.negative; + if ((t.positive & t.negative) != 0) + /* A ^ ~A -> drop the term. */ + terms[i] = terms[--size]; + else + ++i; + } +} + +void +message_criteria::operator |= (message_term const &term) +{ + assert ((term.positive & term.negative) == 0); + REALLOC (this, terms); + terms[size++] = term; +} + +// xxx this one is inaccessible from the outside. Make it like &=, |= +// above +/* NEG(a&b&~c) -> (~a + ~b + c) */ +message_criteria +operator ! (message_term const &term) +{ + assert ((term.positive & term.negative) == 0); + + unsigned max = 0; +#define MC(CAT, ID) max = ID; + MESSAGE_CATEGORIES +#undef MC + + message_criteria ret; + for (size_t i = 0; i < max; ++i) + { + unsigned mask = 1u << i; + if ((term.positive & mask) != 0) + ret |= message_term (1u << i, mc_none); + else if ((term.negative & mask) != 0) + ret |= message_term (mc_none, 1u << i); + } + + return ret; +} + +// xxx this one is inaccessible from the outside. Make it like &=, |= +// above +/* MUL((a&b + c&d), (e&f + g&h)) -> (a&b&e&f + a&b&g&h + c&d&e&f + c&d&g&h) */ +void +message_cri_mul (struct message_criteria *cri, struct message_criteria *rhs) +{ + struct message_criteria ret; + WIPE (ret); + + for (size_t i = 0; i < cri->size; ++i) + for (size_t j = 0; j < rhs->size; ++j) + { + struct message_term t1 = cri->terms[i]; + struct message_term *t2 = rhs->terms + j; + t1.positive |= t2->positive; + t1.negative |= t2->negative; + if (t1.positive & t1.negative) + /* A ^ ~A -> drop the term. */ + continue; + ret |= t1; + } + + free (cri->terms); + *cri = ret; +} + +// xxx this one is inaccessible from the outside. Bind it properly +/* Reject message if TERM passes. */ +void +message_cri_and_not (message_criteria &cri, message_term const &term) +{ + message_criteria tmp = !message_term (term.negative, term.positive); + message_cri_mul (&cri, &tmp); +} + +static void +wr_verror (const struct where *wh, const char *format, va_list ap) +{ + printf ("error: %s", where_fmt (wh, NULL)); + vprintf (format, ap); + where_fmt_chain (wh, "error"); + ++error_count; +} + +static void +wr_vwarning (const struct where *wh, const char *format, va_list ap) +{ + printf ("warning: %s", where_fmt (wh, NULL)); + vprintf (format, ap); + where_fmt_chain (wh, "warning"); + ++error_count; +} + +void +wr_error (const struct where *wh, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + wr_verror (wh, format, ap); + va_end (ap); +} + +void +wr_warning (const struct where *wh, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + wr_vwarning (wh, format, ap); + va_end (ap); +} + +void +wr_message (unsigned long category, const struct where *wh, + const char *format, ...) +{ + va_list ap; + va_start (ap, format); + if (message_accept (&warning_criteria, category)) + { + if (message_accept (&error_criteria, category)) + wr_verror (wh, format, ap); + else + wr_vwarning (wh, format, ap); + } + va_end (ap); +} + +void +wr_format_padding_message (unsigned long category, + struct where *wh, + uint64_t start, uint64_t end, char const *kind) +{ + char msg[128]; + wr_message (category, wh, ": %s: %s.\n", + range_fmt (msg, sizeof msg, start, end), kind); +} + +void +wr_format_leb128_message (struct where *where, const char *what, + const char *purpose, + const unsigned char *begin, const unsigned char *end) +{ + unsigned long category = mc_leb128 | mc_acc_bloat | mc_impact_3; + char buf[(end - begin) * 3 + 1]; // 2 hexa digits+" " per byte, and term. 0 + char *ptr = buf; + for (; begin < end; ++begin) + ptr += sprintf (ptr, " %02x", *begin); + wr_message (category, where, + ": %s: value %s encoded as `%s'.\n", + what, purpose, buf + 1); +} + +void +wr_message_padding_0 (unsigned long category, + struct where *wh, + uint64_t start, uint64_t end) +{ + wr_format_padding_message (category | mc_acc_bloat | mc_impact_1, + wh, start, end, + "unnecessary padding with zero bytes"); +} + +void +wr_message_padding_n0 (unsigned long category, + struct where *wh, + uint64_t start, uint64_t end) +{ + wr_format_padding_message (category | mc_acc_bloat | mc_impact_1, + wh, start, end, + "unreferenced non-zero bytes"); +} diff --git a/src/dwarflint-messages.h b/src/dwarflint-messages.h new file mode 100644 index 000000000..3ae7c1642 --- /dev/null +++ b/src/dwarflint-messages.h @@ -0,0 +1,148 @@ +#ifndef DWARFLINT_MESSAGES_H +#define DWARFLINT_MESSAGES_H + +#include "dwarflint-where.h" + +#ifdef __cplusplus +# define IF_CPLUSPLUS(X) X +# include +extern "C" +{ +#endif + +#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, + +#define MC(CAT, ID)\ + mc_##CAT = 1u << ID, + MESSAGE_CATEGORIES +#undef MC + }; + + struct message_term + { + /* Given a term like A && !B && C && !D, we decompose it thus: */ + unsigned long positive; /* non-zero bits for plain predicates */ + unsigned long negative; /* non-zero bits for negated predicates */ + +#ifdef __cplusplus + message_term (unsigned long pos, unsigned long neg) + : positive (pos), negative (neg) + {} + std::string str () const; +#endif + }; + + struct message_criteria + { + struct message_term *terms; + size_t size; + size_t alloc; + +#ifdef __cplusplus + message_criteria () + : terms (NULL), size (0), alloc (0) + {} + ~message_criteria () + { + free (terms); + } + + void operator |= (message_term const &term); + void operator &= (message_term const &term); + std::string str () const; +#endif + }; + +#ifdef __cplusplus + message_criteria operator ! (message_term const &); +#endif + + extern void wr_error (const struct where *wh, const char *format, ...) + __attribute__ ((format (printf, 2, 3))); + + extern void wr_warning (const struct where *wh, const char *format, ...) + __attribute__ ((format (printf, 2, 3))); + + extern void wr_message (unsigned long category, const struct where *wh, + const char *format, ...) + __attribute__ ((format (printf, 3, 4))); + + extern void wr_format_padding_message (unsigned long category, + struct where *wh, + uint64_t start, uint64_t end, + char const *kind); + + extern void wr_format_leb128_message (struct where *where, const char *what, + const char *purpose, + const unsigned char *begin, + const unsigned char *end); + + extern void wr_message_padding_0 (unsigned long category, + struct where *wh, + uint64_t start, uint64_t end); + + extern void wr_message_padding_n0 (unsigned long category, + struct where *wh, + uint64_t start, uint64_t end); + + extern bool message_accept (struct message_criteria const *cri, + unsigned long cat); + + + extern unsigned error_count; + + /* Messages that are accepted (and made into warning). */ + extern struct message_criteria warning_criteria; + + /* Accepted (warning) messages, that are turned into errors. */ + extern struct message_criteria error_criteria; + +#ifdef __cplusplus +} + +inline message_category +cat (message_category c1, + message_category c2, + message_category c3 = mc_none, + message_category c4 = mc_none) +{ + return static_cast (c1 | c2 | c3 | c4); +} + +#endif + +#endif//DWARFLINT_MESSAGES_H diff --git a/src/dwarflint-misc.h b/src/dwarflint-misc.h new file mode 100644 index 000000000..bb6dd6da0 --- /dev/null +++ b/src/dwarflint-misc.h @@ -0,0 +1,40 @@ +#ifndef DWARFLINT_MISC_H +#define DWARFLINT_MISC_H + +#include + +#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 = (typeof (_a->BUF)) \ + xrealloc (_a->BUF, \ + sizeof (*_a->BUF) * _a->alloc); \ + } \ + } while (0) + +#define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ)) + +#ifdef __cplusplus +# define IF_CPLUSPLUS(X) X +#else +# define IF_CPLUSPLUS(X) /*X*/ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "../lib/system.h" + +#ifdef __cplusplus +} +#endif + +#endif//DWARFLINT_MISC_H diff --git a/src/dwarflint-where.h b/src/dwarflint-where.h new file mode 100644 index 000000000..245387aa9 --- /dev/null +++ b/src/dwarflint-where.h @@ -0,0 +1,79 @@ +#include +#include + +#ifdef __cplusplus +# define IF_CPLUSPLUS(X) X +extern "C" +{ +#else +# define IF_CPLUSPLUS(X) /*X*/ +#endif + +#define DEBUGINFO_SECTIONS \ + SEC (info) \ + SEC (abbrev) \ + SEC (aranges) \ + SEC (pubnames) \ + SEC (pubtypes) \ + SEC (str) \ + SEC (line) \ + SEC (loc) \ + SEC (mac) \ + SEC (ranges) + + enum section_id + { + sec_invalid = 0, + + /* Debuginfo sections: */ +#define SEC(n) sec_##n, + DEBUGINFO_SECTIONS + count_debuginfo_sections, +#undef SEC + + /* Non-debuginfo sections: */ + sec_rel = count_debuginfo_sections, + sec_rela, + + /* Non-sections: */ + sec_locexpr, /* Not a section, but a portion of file that + contains a location expression. */ + rel_value, /* For relocations, this denotes that the + relocation is applied to taget value, not a + section offset. */ + rel_address, /* Same as above, but for addresses. */ + rel_exec, /* Some as above, but we expect EXEC bit. */ + }; + + enum where_formatting + { + wf_plain = 0, /* Default formatting for given section. */ + wf_cudie, + }; + + struct where + { + enum section_id section; + enum where_formatting formatting; + uint64_t addr1; // E.g. a CU offset. + uint64_t addr2; // E.g. a DIE address. + uint64_t addr3; // E.g. an attribute. + struct where *ref; // Related reference, e.g. an abbrev related to given DIE. + struct where *next; // For forming "caused-by" chains. + }; + +# define WHERE(SECTION, NEXT) \ + ((struct where) \ + {(SECTION), wf_plain, \ + (uint64_t)-1, (uint64_t)-1, (uint64_t)-1, \ + NULL, NEXT}) + + extern const char *where_fmt (const struct where *wh, char *ptr IF_CPLUSPLUS (= NULL)); + extern void where_fmt_chain (const struct where *wh, const char *severity); + extern void where_reset_1 (struct where *wh, uint64_t addr); + extern void where_reset_2 (struct where *wh, uint64_t addr); + extern void where_reset_3 (struct where *wh, uint64_t addr); + +#ifdef __cplusplus +} +#endif diff --git a/src/dwarflint.c b/src/dwarflint.c index fd302c250..7361e8261 100644 --- a/src/dwarflint.c +++ b/src/dwarflint.c @@ -1,7 +1,6 @@ -/* Pedantic checking of DWARF files. +/* Pedantic checking of DWARF files Copyright (C) 2008,2009 Red Hat, Inc. This file is part of Red Hat elfutils. - Written by Petr Machata , 2008. 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 @@ -28,18 +27,15 @@ # include #endif -#include -#include -#include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -53,620 +49,14 @@ #include "dwarflint-readctx.h" #include "dwarf-opcodes.h" -/* Bug report address. */ -const char *argp_program_bug_address = PACKAGE_BUGREPORT; - -#define ARGP_strict 300 -#define ARGP_gnu 301 -#define ARGP_tolerant 302 -#define ARGP_ref 303 -#define ARGP_nohl 304 -#define ARGP_dump_off 305 - -/* Definitions of arguments for argp functions. */ -static const struct argp_option options[] = -{ - { "strict", ARGP_strict, NULL, 0, - N_("Be extremely strict, flag level 2 features."), 0 }, - { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 }, - { "ignore-missing", 'i', NULL, 0, - N_("Don't complain if files have no DWARF at all"), 0 }, - { "gnu", ARGP_gnu, NULL, 0, - N_("Binary has been created with GNU toolchain and is therefore known to be \ -broken in certain ways"), 0 }, - { "tolerant", ARGP_tolerant, NULL, 0, - N_("Don't output certain common error messages"), 0 }, - { "ref", ARGP_ref, NULL, 0, - N_("When validating .debug_loc and .debug_ranges, display information about \ -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 }, - { "dump-offsets", ARGP_dump_off, NULL, 0, - N_("Dump DIE offsets to stderr as the tree is iterated."), 0 }, - { NULL, 0, NULL, 0, NULL, 0 } -}; - -/* Short description of program. */ -static const char doc[] = N_("\ -Pedantic checking of DWARF stored in ELF files."); - -/* Strings for arguments in help texts. */ -static const char args_doc[] = N_("FILE..."); - -/* Prototype for option handler. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state); - -/* Data structure to communicate with argp functions. */ -static struct argp argp = -{ - options, parse_opt, args_doc, doc, NULL, NULL, NULL -}; - -/* If true, we accept silently files without debuginfo. */ -static bool tolerate_nodebug = false; - -static void process_file (Elf *elf, const char *fname, bool only_one); - -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 -{ - struct message_term *terms; - size_t size; - size_t alloc; -}; - -static bool -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) -{ - 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 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); - for (size_t i = 0; i < cri->size; ) - { - struct message_term *t = cri->terms + i; - t->positive |= term->positive; - t->negative |= term->negative; - if ((t->positive & t->negative) != 0) - /* A ^ ~A -> drop the term. */ - cri->terms[i] = cri->terms[--cri->size]; - else - ++i; - } -} - -static void -message_cri_or (struct message_criteria *cri, struct message_term *term) -{ - assert ((term->positive & term->negative) == 0); - REALLOC (cri, terms); - cri->terms[cri->size++] = *term; -} - -/* NEG(a&b&~c) -> (~a + ~b + c) */ -static struct message_criteria -message_cri_neg (struct message_term *term) -{ - assert ((term->positive & term->negative) == 0); - - unsigned max = 0; -#define MC(CAT, ID) max = ID; - MESSAGE_CATEGORIES -#undef MC - - struct message_criteria ret; - WIPE (ret); - for (size_t i = 0; i < max; ++i) - { - unsigned mask = 1u << i; - if ((term->positive & mask) != 0) - message_cri_or (&ret, &(struct message_term){1u << i, mc_none}); - else if ((term->negative & mask) != 0) - message_cri_or (&ret, &(struct message_term){mc_none, 1u << i}); - } - - return ret; -} - -/* MUL((a&b + c&d), (e&f + g&h)) -> (a&b&e&f + a&b&g&h + c&d&e&f + c&d&g&h) */ -static void -message_cri_mul (struct message_criteria *cri, struct message_criteria *rhs) -{ - struct message_criteria ret; - WIPE (ret); - - for (size_t i = 0; i < cri->size; ++i) - for (size_t j = 0; j < rhs->size; ++j) - { - struct message_term t1 = cri->terms[i]; - struct message_term *t2 = rhs->terms + j; - t1.positive |= t2->positive; - t1.negative |= t2->negative; - if (t1.positive & t1.negative) - /* A ^ ~A -> drop the term. */ - continue; - message_cri_or (&ret, &t1); - } - - free (cri->terms); - *cri = ret; -} - -/* Reject message if TERM passes. */ -static void -message_cri_and_not (struct message_criteria *cri, struct message_term *term) -{ - struct message_criteria tmp - = message_cri_neg (&(struct message_term) {term->negative, term->positive}); - message_cri_mul (cri, &tmp); - free (tmp.terms); -} - -/* 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 message_accept (&warning_criteria, cat); -} - -static void -wr_verror (const struct where *wh, const char *format, va_list ap) -{ - printf ("error: %s", where_fmt (wh, NULL)); - vprintf (format, ap); - where_fmt_chain (wh, "error"); - ++error_count; -} - -static void -wr_vwarning (const struct where *wh, const char *format, va_list ap) -{ - printf ("warning: %s", where_fmt (wh, NULL)); - vprintf (format, ap); - where_fmt_chain (wh, "warning"); - ++error_count; -} - -void -wr_error (const struct where *wh, const char *format, ...) -{ - va_list ap; - va_start (ap, format); - wr_verror (wh, format, ap); - va_end (ap); -} - -void -wr_warning (const struct where *wh, const char *format, ...) -{ - va_list ap; - va_start (ap, format); - wr_vwarning (wh, format, ap); - va_end (ap); -} - -void -wr_message (enum message_category category, const struct where *wh, - const char *format, ...) -{ - va_list ap; - va_start (ap, format); - if (message_accept (&warning_criteria, category)) - { - if (message_accept (&error_criteria, category)) - wr_verror (wh, format, ap); - else - wr_vwarning (wh, format, ap); - } - va_end (ap); -} - -void -wr_format_padding_message (enum message_category category, - struct where *wh, - uint64_t start, uint64_t end, char *kind) -{ - char msg[128]; - wr_message (category, wh, ": %s: %s.\n", - range_fmt (msg, sizeof msg, start, end), kind); -} - -void -wr_format_leb128_message (struct where *where, const char *what, - const char *purpose, - const unsigned char *begin, const unsigned char *end) -{ - enum message_category category = mc_leb128 | mc_acc_bloat | mc_impact_3; - char buf[(end - begin) * 3 + 1]; // 2 hexa digits+" " per byte, and term. 0 - char *ptr = buf; - for (; begin < end; ++begin) - ptr += sprintf (ptr, " %02x", *begin); - wr_message (category, where, - ": %s: value %s encoded as `%s'.\n", - what, purpose, buf + 1); -} - -void -wr_message_padding_0 (enum message_category category, - struct where *wh, - uint64_t start, uint64_t end) -{ - wr_format_padding_message (category | mc_acc_bloat | mc_impact_1, - wh, start, end, - "unnecessary padding with zero bytes"); -} - -void -wr_message_padding_n0 (enum message_category category, - struct where *wh, - uint64_t start, uint64_t end) -{ - wr_format_padding_message (category | mc_acc_bloat | mc_impact_1, - wh, start, end, - "unreferenced non-zero bytes"); -} - -/* True if no message is to be printed if the run is succesful. */ -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 */ -static bool show_refs = false; /* --ref */ -static bool do_high_level = true; /* ! --nohl */ -static bool dump_die_offsets = false; /* --dump-offsets */ - /* True if coverage analysis of .debug_ranges vs. ELF sections should be done. */ static const bool do_range_coverage = false; -static int -layout_rel_file (Elf *elf) -{ - GElf_Ehdr ehdr; - if (gelf_getehdr (elf, &ehdr) == NULL) - return 1; - - if (ehdr.e_type != ET_REL) - return 0; - - /* Taken from libdwfl. */ - GElf_Addr base = 0; - GElf_Addr start = 0, end = 0, bias = 0; - - bool first = true; - Elf_Scn *scn = NULL; - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (unlikely (shdr == NULL)) - return 1; - - if (shdr->sh_flags & SHF_ALLOC) - { - const GElf_Xword align = shdr->sh_addralign ?: 1; - const GElf_Addr next = (end + align - 1) & -align; - if (shdr->sh_addr == 0 - /* Once we've started doing layout we have to do it all, - unless we just layed out the first section at 0 when - it already was at 0. */ - || (bias == 0 && end > start && end != next)) - { - shdr->sh_addr = next; - if (end == base) - /* This is the first section assigned a location. - Use its aligned address as the module's base. */ - start = base = shdr->sh_addr; - else if (unlikely (base & (align - 1))) - { - /* If BASE has less than the maximum alignment of - any section, we eat more than the optimal amount - of padding and so make the module's apparent - size come out larger than it would when placed - at zero. So reset the layout with a better base. */ - - start = end = base = (base + align - 1) & -align; - Elf_Scn *prev_scn = NULL; - do - { - prev_scn = elf_nextscn (elf, prev_scn); - GElf_Shdr prev_shdr_mem; - GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn, - &prev_shdr_mem); - if (unlikely (prev_shdr == NULL)) - return 1; - if (prev_shdr->sh_flags & SHF_ALLOC) - { - const GElf_Xword prev_align - = prev_shdr->sh_addralign ?: 1; - - prev_shdr->sh_addr - = (end + prev_align - 1) & -prev_align; - end = prev_shdr->sh_addr + prev_shdr->sh_size; - - if (unlikely (! gelf_update_shdr (prev_scn, - prev_shdr))) - return 1; - } - } - while (prev_scn != scn); - continue; - } - - end = shdr->sh_addr + shdr->sh_size; - if (likely (shdr->sh_addr != 0) - && unlikely (! gelf_update_shdr (scn, shdr))) - return 1; - } - else - { - /* The address is already assigned. Just track it. */ - if (first || end < shdr->sh_addr + shdr->sh_size) - end = shdr->sh_addr + shdr->sh_size; - if (first || bias > shdr->sh_addr) - /* This is the lowest address in the module. */ - bias = shdr->sh_addr; - - if ((shdr->sh_addr - bias + base) & (align - 1)) - /* This section winds up misaligned using BASE. - Adjust BASE upwards to make it congruent to - the lowest section address in the file modulo ALIGN. */ - base = (((base + align - 1) & -align) - + (bias & (align - 1))); - } - - first = false; - } - } - return 0; -} - -int -main (int argc, char *argv[]) -{ - /* Set locale. */ - setlocale (LC_ALL, ""); - - /* Initialize the message catalog. */ - textdomain (PACKAGE_TARNAME); - - /* Parse and process arguments. */ - int remaining; - argp_parse (&argp, argc, argv, 0, &remaining, NULL); - - /* Initialize warning & error criteria. */ - message_cri_or (&warning_criteria, - &(struct message_term){mc_none, mc_none}); - - 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}); - - /* Configure warning & error criteria according to configuration. */ - if (tolerate_nodebug) - message_cri_and (&warning_criteria, - &(struct message_term){mc_none, mc_elf}); - - if (be_gnu) - { - 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_strings}); - message_cri_and_not (&warning_criteria, - &(struct message_term) - {mc_line | mc_header | mc_acc_bloat, mc_none}); - message_cri_and (&warning_criteria, - &(struct message_term){mc_none, mc_pubtypes}); - } - - if (be_tolerant) - { - 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); - - /* Now process all the files given at the command line. */ - bool only_one = remaining + 1 == argc; - do - { - /* Open the file. */ - int fd = open (argv[remaining], O_RDONLY); - if (fd == -1) - { - error (0, errno, gettext ("cannot open input file")); - continue; - } - - /* Create an `Elf' descriptor. */ - Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL); - if (elf == NULL) - invalid_elf: - wr_error (NULL, - gettext ("Error processing ELF file: %s\n"), - elf_errmsg (-1)); - else - { - unsigned int prev_error_count = error_count; - if (layout_rel_file (elf)) - goto invalid_elf; - - process_file (elf, argv[remaining], only_one); - - elf_errno (); /* Clear errno. */ - elf_end (elf); - int err = elf_errno (); - if (err != 0) - wr_error (NULL, - gettext ("error while closing Elf descriptor: %s\n"), - elf_errmsg (err)); - - if (prev_error_count == error_count && !be_quiet) - puts (gettext ("No errors")); - } - - close (fd); - } - while (++remaining < argc); - - return error_count != 0; -} - -/* Handle program arguments. */ -static error_t -parse_opt (int key, char *arg __attribute__ ((unused)), - struct argp_state *state __attribute__ ((unused))) +static bool +check_category (enum message_category cat) { - switch (key) - { - case ARGP_strict: - be_strict = true; - break; - - case ARGP_gnu: - be_gnu = true; - break; - - case ARGP_tolerant: - be_tolerant = true; - break; - - case ARGP_ref: - show_refs = true; - break; - - case ARGP_nohl: - do_high_level = false; - break; - - case ARGP_dump_off: - dump_die_offsets = true; - break; - - case 'i': - tolerate_nodebug = true; - break; - - case 'q': - be_quiet = true; - be_verbose = false; - break; - - case 'v': - be_quiet = false; - be_verbose = true; - break; - - case ARGP_KEY_NO_ARGS: - fputs (gettext ("Missing file name.\n"), stderr); - argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, - program_invocation_short_name); - exit (1); - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; + return message_accept (&warning_criteria, cat); } #define PRI_CU "CU 0x%" PRIx64 @@ -1219,7 +609,7 @@ elf_file_init (struct elf_file *file, Elf *elf) return true; } -static void +void process_file (Elf *elf, const char *fname, bool only_one) { if (!only_one) diff --git a/src/dwarflint.h b/src/dwarflint.h index b6b44efd9..22dd21904 100644 --- a/src/dwarflint.h +++ b/src/dwarflint.h @@ -29,14 +29,13 @@ #include "../libdw/libdw.h" #include "../libebl/libebl.h" #include "dwarflint-coverage.h" +#include "dwarflint-messages.h" #ifdef __cplusplus -# define IF_CPLUSPLUS(X) X # include extern "C" { #else -# define IF_CPLUSPLUS(X) /*X*/ # include #endif @@ -50,148 +49,18 @@ extern "C" extern bool check_matching_ranges (struct hl_ctx *hlctx); extern bool check_expected_trees (struct hl_ctx *hlctx); extern bool check_range_out_of_scope (struct hl_ctx *hlctx); - - - /* Functions and data structures describing location in Dwarf. */ - -#define DEBUGINFO_SECTIONS \ - SEC (info) \ - SEC (abbrev) \ - SEC (aranges) \ - SEC (pubnames) \ - SEC (pubtypes) \ - SEC (str) \ - SEC (line) \ - SEC (loc) \ - SEC (mac) \ - SEC (ranges) - - enum section_id - { - sec_invalid = 0, - - /* Debuginfo sections: */ -#define SEC(n) sec_##n, - DEBUGINFO_SECTIONS - count_debuginfo_sections, -#undef SEC - - /* Non-debuginfo sections: */ - sec_rel = count_debuginfo_sections, - sec_rela, - - /* Non-sections: */ - sec_locexpr, /* Not a section, but a portion of file that - contains a location expression. */ - rel_value, /* For relocations, this denotes that the - relocation is applied to taget value, not a - section offset. */ - rel_address, /* Same as above, but for addresses. */ - rel_exec, /* Some as above, but we expect EXEC bit. */ - }; - - enum where_formatting - { - wf_plain = 0, /* Default formatting for given section. */ - wf_cudie, - }; - - struct where - { - enum section_id section; - enum where_formatting formatting; - uint64_t addr1; // E.g. a CU offset. - uint64_t addr2; // E.g. a DIE address. - uint64_t addr3; // E.g. an attribute. - struct where *ref; // Related reference, e.g. an abbrev related to given DIE. - struct where *next; // For forming "caused-by" chains. - }; - -# define WHERE(SECTION, NEXT) \ - ((struct where) \ - {(SECTION), wf_plain, \ - (uint64_t)-1, (uint64_t)-1, (uint64_t)-1, \ - NULL, NEXT}) - - extern const char *where_fmt (const struct where *wh, char *ptr IF_CPLUSPLUS (= NULL)); - 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); - - - /* 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, - -#define MC(CAT, ID)\ - mc_##CAT = 1u << ID, - MESSAGE_CATEGORIES -#undef MC - }; - - extern void wr_error (const struct where *wh, const char *format, ...) - __attribute__ ((format (printf, 2, 3))); - - extern void wr_warning (const struct where *wh, const char *format, ...) - __attribute__ ((format (printf, 2, 3))); - - extern void wr_message (enum message_category category, const struct where *wh, - const char *format, ...) - __attribute__ ((format (printf, 3, 4))); - - extern void wr_format_padding_message (enum message_category category, - struct where *wh, - uint64_t start, uint64_t end, - char *kind); - - extern void wr_format_leb128_message (struct where *where, const char *what, - const char *purpose, - const unsigned char *begin, - const unsigned char *end); - - extern void wr_message_padding_0 (enum message_category category, - struct where *wh, - uint64_t start, uint64_t end); - - extern void wr_message_padding_n0 (enum message_category category, - struct where *wh, - uint64_t start, uint64_t end); + extern void process_file (Elf *elf, const char *fname, bool only_one); + + /* Whole-program options. */ + extern bool tolerate_nodebug; + extern bool be_quiet; /* -q */ + extern bool be_verbose; /* -v */ + extern bool be_strict; /* --strict */ + extern bool be_gnu; /* --gnu */ + extern bool be_tolerant; /* --tolerant */ + extern bool show_refs; /* --ref */ + extern bool do_high_level; /* ! --nohl */ + extern bool dump_die_offsets; /* --dump-offsets */ struct relocation { -- 2.47.3