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
#endif
#include "dwarflint-coverage.hh"
-extern "C"
-{
-#include "../lib/system.h"
-}
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#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
void *data);
#ifdef __cplusplus
-# define IF_CPLUSPLUS(X) X
}
+
+std::string range_fmt (uint64_t start, uint64_t end);
#endif
#endif//DWARFLINT_COVERAGE_H
-/* 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 <pmachata@redhat.com>, 2009.
using namespace elfutils;
-namespace
-{
- message_category cat (message_category c1,
- message_category c2,
- message_category c3 = mc_none)
- {
- return static_cast<message_category> (c1 | c2 | c3);
- }
-}
-
class hl_ctx
{
Dwarf *handle;
--- /dev/null
+/* 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
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <argp.h>
+#include <libintl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <error.h>
+
+#include <iostream>
+
+#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;
+}
--- /dev/null
+#include "dwarflint-messages.h"
+#include "dwarflint-misc.h"
+#include "dwarflint-coverage.h"
+
+#include <vector>
+#include <sstream>
+#include <cassert>
+#include <cstdarg>
+
+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<std::string>
+ {
+ 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");
+}
--- /dev/null
+#ifndef DWARFLINT_MESSAGES_H
+#define DWARFLINT_MESSAGES_H
+
+#include "dwarflint-where.h"
+
+#ifdef __cplusplus
+# define IF_CPLUSPLUS(X) X
+# include <string>
+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<message_category> (c1 | c2 | c3 | c4);
+}
+
+#endif
+
+#endif//DWARFLINT_MESSAGES_H
--- /dev/null
+#ifndef DWARFLINT_MISC_H
+#define DWARFLINT_MISC_H
+
+#include <string.h>
+
+#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
--- /dev/null
+#include <stdint.h>
+#include <stdlib.h>
+
+#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
-/* 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 <pmachata@redhat.com>, 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
# include <config.h>
#endif
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <argp.h>
#include <assert.h>
#include <error.h>
-#include <fcntl.h>
#include <gelf.h>
#include <inttypes.h>
#include <libintl.h>
#include <locale.h>
#include <stdarg.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <system.h>
#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
return true;
}
-static void
+void
process_file (Elf *elf, const char *fname, bool only_one)
{
if (!only_one)
#include "../libdw/libdw.h"
#include "../libebl/libebl.h"
#include "dwarflint-coverage.h"
+#include "dwarflint-messages.h"
#ifdef __cplusplus
-# define IF_CPLUSPLUS(X) X
# include <string>
extern "C"
{
#else
-# define IF_CPLUSPLUS(X) /*X*/
# include <stdbool.h>
#endif
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
{