dwarflint-messages.cc dwarflint-messages.h \
dwarflint-where.c dwarflint-where.h \
dwarflint-config.cc dwarflint-config.h \
- dwarflint-checks.cc dwarflint-checks.hh
+ dwarflint-checks.hh \
+ dwarflint-checks-low.cc dwarflint-checks-low.hh
readelf_SOURCES = readelf.c dwarfstrings.c
--- /dev/null
+/* Pedantic checking of DWARF files
+ Copyright (C) 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 "dwarflint-checks-low.hh"
+#include "dwarflint-low.h"
+#include <map>
+#include <sstream>
+#include <cstring>
+
+struct secentry
+{
+ Elf_Data *reldata; /* Relocation data if any found. */
+ size_t reltype; /* SHT_REL or SHT_RELA. We need this
+ temporary store to be able to resolve
+ relocation section appearing before
+ relocated section. */
+ size_t secndx; /* Index into file->sec or 0 if not yet loaded. */
+ section_id id; /* Section type. */
+
+ explicit secentry (section_id a_id = sec_invalid)
+ : reldata (NULL)
+ , reltype (0)
+ , secndx (0)
+ , id (a_id)
+ {}
+};
+
+struct secinfo_map
+ : public std::map <std::string, secentry>
+{
+ secentry *get (const char *name)
+ {
+ iterator it = find (std::string (name));
+ if (it == end ())
+ return NULL;
+ else
+ return &it->second;
+ }
+};
+
+bool
+elf_file_init (struct elf_file *file, Elf *elf)
+{
+ memset (file, 0, sizeof (*file));
+
+ file->elf = elf;
+ file->ebl = ebl_openbackend (elf);
+
+ if (file->ebl == NULL
+ || gelf_getehdr (elf, &file->ehdr) == NULL)
+ return false;
+
+ file->addr_64 = file->ehdr.e_ident[EI_CLASS] == ELFCLASS64;
+
+ /* Taken from dwarf_begin_elf.c. */
+ if ((BYTE_ORDER == LITTLE_ENDIAN
+ && file->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+ || (BYTE_ORDER == BIG_ENDIAN
+ && file->ehdr.e_ident[EI_DATA] == ELFDATA2LSB))
+ file->other_byte_order = true;
+
+ Elf_Scn *reloc_symtab = NULL;
+
+ secinfo_map secinfo;
+#define SEC(n) secinfo[".debug_" #n] = secentry (sec_##n);
+ DEBUGINFO_SECTIONS
+#undef SEC
+
+ /* Now find all necessary debuginfo sections and associated
+ relocation sections. */
+
+ /* Section 0 is special, skip it. */
+ REALLOC (file, sec);
+ file->sec[file->size++].id = sec_invalid;
+
+ bool check_rel = true;
+
+ for (Elf_Scn *scn = NULL; (scn = elf_nextscn (elf, scn)); )
+ {
+ REALLOC (file, sec);
+ size_t curndx = file->size++;
+ struct sec *cursec = file->sec + curndx;
+
+ GElf_Shdr *shdr = gelf_getshdr (scn, &cursec->shdr);
+ if (shdr == NULL)
+ {
+ invalid_elf:
+ wr_error (NULL, "Broken ELF.\n");
+ return false;
+ }
+
+ const char *scnname = elf_strptr (elf, file->ehdr.e_shstrndx,
+ shdr->sh_name);
+ if (scnname == NULL)
+ goto invalid_elf;
+
+ if (!address_aligned (shdr->sh_addr, shdr->sh_addralign))
+ {
+ std::ostringstream s;
+ s << "Base address of section " << scnname << ", "
+ << "0x" << std::hex << shdr->sh_addr
+ << ", should have an alignment of "
+ << std::dec << shdr->sh_addralign;
+ wr_error (NULL, "%s\n", s.str ().c_str ());
+ }
+
+ secentry *entry = secinfo.get (scnname);
+ cursec->scn = scn;
+ cursec->id = entry != NULL ? entry->id : sec_invalid;
+ cursec->name = scnname;
+ cursec->rel = (struct relocation_data){NULL, SHT_NULL, NULL, 0, 0, 0};
+
+ /* Dwarf section. */
+ if (entry != NULL)
+ {
+ if (unlikely (entry->secndx != 0))
+ wr_error (NULL, "Multiple occurrences of section %s.\n", scnname);
+ else
+ {
+ /* Haven't seen a section of that name yet. */
+ cursec->data = elf_getdata (scn, NULL);
+ if (cursec->data == NULL || cursec->data->d_buf == NULL)
+ /* Don't print out a warning, we'll get to that in
+ process_file. */
+ cursec->data = NULL;
+ entry->secndx = curndx;
+ }
+ }
+ /* Relocation section. */
+ else if (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL)
+ {
+ /* Get data of section that this REL(A) section relocates. */
+ Elf_Scn *relocated_scn = elf_getscn (elf, shdr->sh_info);
+ Elf_Scn *symtab_scn = elf_getscn (elf, shdr->sh_link);
+ if (relocated_scn == NULL || symtab_scn == NULL)
+ goto invalid_elf;
+
+ GElf_Shdr relocated_shdr_mem;
+ GElf_Shdr *relocated_shdr = gelf_getshdr (relocated_scn,
+ &relocated_shdr_mem);
+ if (relocated_shdr == NULL)
+ goto invalid_elf;
+
+ const char *relocated_scnname
+ = elf_strptr (elf, file->ehdr.e_shstrndx,
+ relocated_shdr->sh_name);
+
+ secentry *relocated = secinfo.get (relocated_scnname);
+
+ if (relocated != NULL)
+ {
+ if (relocated->reldata != NULL)
+ wr_error (NULL,
+ "Several relocation sections for debug section %s."
+ " Ignoring %s.\n",
+ relocated_scnname, scnname);
+ else
+ {
+ relocated->reldata = elf_getdata (scn, NULL);
+ if (unlikely (relocated->reldata == NULL
+ || relocated->reldata->d_buf == NULL))
+ {
+ wr_error (NULL,
+ "Data-less relocation section %s.\n", scnname);
+ relocated->reldata = NULL;
+ }
+ else
+ relocated->reltype = shdr->sh_type;
+ }
+
+ if (reloc_symtab == NULL)
+ reloc_symtab = symtab_scn;
+ else if (reloc_symtab != symtab_scn)
+ wr_error (NULL,
+ "Relocation sections use multiple symbol tables.\n");
+ }
+ }
+ }
+
+ for (secinfo_map::iterator it = secinfo.begin (); it != secinfo.end (); ++it)
+ if (it->second.secndx != 0)
+ file->debugsec[it->second.id] = file->sec + it->second.secndx;
+
+ if (check_rel)
+ {
+ Elf_Data *reloc_symdata = NULL;
+ if (reloc_symtab != NULL)
+ {
+ reloc_symdata = elf_getdata (reloc_symtab, NULL);
+ if (reloc_symdata == NULL)
+ /* Not a show stopper, we can check a lot of stuff even
+ without a symbol table. */
+ wr_error (NULL,
+ "Couldn't obtain symtab data.\n");
+ }
+
+ /* Check relocation sections that we've got. */
+ for (secinfo_map::iterator it = secinfo.begin (); it != secinfo.end (); ++it)
+ {
+ secentry *cur = &it->second;
+ if (cur->secndx != 0 && cur->reldata != NULL)
+ {
+ struct sec *sec = file->sec + cur->secndx;
+ sec->rel.type = cur->reltype;
+ if (sec->data == NULL)
+ {
+ where wh = WHERE (sec->id, NULL);
+ wr_error (&wh,
+ ": this data-less section has a relocation section.\n");
+ }
+ else if (read_rel (file, sec, cur->reldata, file->addr_64))
+ sec->rel.symdata = reloc_symdata;
+ }
+ }
+
+ if (secentry *str = secinfo.get (".debug_str"))
+ if (str->reldata != NULL)
+ {
+ where wh = WHERE (sec_str, NULL);
+ wr_message (mc_impact_2 | mc_elf, &wh,
+ ": there's a relocation section associated with this section.\n");
+ }
+ }
+
+ return true;
+}
+
+load_sections::load_sections (dwarflint &lint)
+{
+ elf_file_init (&file, lint.elf ());
+}
+
+sec &
+section_base::get_sec_or_throw (section_id secid)
+{
+ if (sec *s = sections->file.debugsec[secid])
+ return *s;
+
+ where wh = WHERE (secid, NULL);
+ std::stringstream ss;
+ ss << where_fmt (&wh) << ": data not found.";
+ throw check_base::failed (ss.str ());
+}
+
+section_base::section_base (dwarflint &lint, section_id secid)
+ : sections (lint.check (sections))
+ , sect (get_sec_or_throw (secid))
+ , file (sections->file)
+{
+}
+
+check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
+ : _m_sec_abbr (lint.check (_m_sec_abbr))
+{
+ read_ctx ctx;
+ read_ctx_init (&ctx, _m_sec_abbr->sect.data,
+ _m_sec_abbr->file.other_byte_order);
+
+ /* xxx wrap C routine before proper loading is in place. */
+ abbrev_table *chain = abbrev_table_load (&ctx);
+ if (chain == NULL)
+ throw check_base::failed (""); // xxx
+ for (abbrev_table *it = chain; it != NULL; it = it->next)
+ abbrevs[it->offset] = *it;
+ // abbrev_table_free (chain); xxx
+ abbrev_chain = chain;
+}
+
+check_debug_info::check_debug_info (dwarflint &lint)
+ : _m_sec_info (lint.check (_m_sec_info))
+ , _m_sec_abbrev (lint.check (_m_sec_abbrev))
+ , _m_sec_str (lint.check (_m_sec_str))
+ , _m_abbrevs (lint.check (_m_abbrevs))
+{
+ memset (&cu_cov, 0, sizeof (cu_cov));
+
+ /* xxx wrap C routine before proper loading is in place. */
+ cu *chain = check_info_structural
+ (&_m_sec_info->file, &_m_sec_info->sect,
+ _m_abbrevs->abbrev_chain, _m_sec_str->sect.data, &cu_cov);
+
+ if (chain == NULL)
+ throw check_base::failed (""); // xxx
+
+ for (cu *cu = chain; cu != NULL; cu = cu->next)
+ cus.push_back (*cu);
+ // cu_free (chain); xxx
+ cu_chain = chain;
+}
--- /dev/null
+#include "dwarflint-checks.hh"
+#include "dwarflint-low.h"
+
+class load_sections
+ : public check<load_sections>
+{
+public:
+ elf_file file;
+ explicit load_sections (dwarflint &lint);
+};
+
+class section_base
+{
+ load_sections *sections;
+ sec &get_sec_or_throw (section_id secid);
+public:
+ sec §
+ elf_file &file;
+ section_base (dwarflint &lint, section_id secid);
+};
+
+template<section_id sec_id>
+class section
+ : public section_base
+ , public check<section<sec_id> >
+{
+public:
+ explicit section (dwarflint &lint)
+ : section_base (lint, sec_id)
+ {}
+};
+
+class check_debug_abbrev
+ : public check<check_debug_abbrev>
+{
+ section<sec_abbrev> *_m_sec_abbr;
+
+public:
+ explicit check_debug_abbrev (dwarflint &lint);
+
+ // offset -> abbreviations
+ std::map < ::Dwarf_Off, abbrev_table> abbrevs;
+ struct abbrev_table *abbrev_chain; // xxx
+};
+static reg <check_debug_abbrev> reg_debug_abbrev;
+
+class check_debug_info
+ : public check<check_debug_info>
+{
+ section<sec_info> *_m_sec_info;
+ section<sec_abbrev> *_m_sec_abbrev;
+ section<sec_str> *_m_sec_str;
+ check_debug_abbrev *_m_abbrevs;
+
+public:
+ cu_coverage cu_cov;
+ std::vector <cu> cus;
+ cu *cu_chain; // xxx
+
+ explicit check_debug_info (dwarflint &lint);
+};
+static reg <check_debug_info> reg_debug_info;
-/* Pedantic checking of DWARF files
- Copyright (C) 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 "dwarflint-checks.hh"
-#include <map>
-#include <sstream>
-
-struct secentry
-{
- Elf_Data *reldata; /* Relocation data if any found. */
- size_t reltype; /* SHT_REL or SHT_RELA. We need this
- temporary store to be able to resolve
- relocation section appearing before
- relocated section. */
- size_t secndx; /* Index into file->sec or 0 if not yet loaded. */
- section_id id; /* Section type. */
-
- explicit secentry (section_id a_id = sec_invalid)
- : reldata (NULL)
- , reltype (0)
- , secndx (0)
- , id (a_id)
- {}
-};
-
-struct secinfo_map
- : public std::map <std::string, secentry>
-{
- secentry *get (const char *name)
- {
- iterator it = find (std::string (name));
- if (it == end ())
- return NULL;
- else
- return &it->second;
- }
-};
-
-bool
-elf_file_init (struct elf_file *file, Elf *elf)
-{
- WIPE (*file);
-
- file->elf = elf;
- file->ebl = ebl_openbackend (elf);
-
- if (file->ebl == NULL
- || gelf_getehdr (elf, &file->ehdr) == NULL)
- return false;
-
- file->addr_64 = file->ehdr.e_ident[EI_CLASS] == ELFCLASS64;
-
- /* Taken from dwarf_begin_elf.c. */
- if ((BYTE_ORDER == LITTLE_ENDIAN
- && file->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
- || (BYTE_ORDER == BIG_ENDIAN
- && file->ehdr.e_ident[EI_DATA] == ELFDATA2LSB))
- file->other_byte_order = true;
-
- Elf_Scn *reloc_symtab = NULL;
-
- secinfo_map secinfo;
-#define SEC(n) secinfo[".debug_" #n] = secentry (sec_##n);
- DEBUGINFO_SECTIONS
-#undef SEC
-
- /* Now find all necessary debuginfo sections and associated
- relocation sections. */
-
- /* Section 0 is special, skip it. */
- REALLOC (file, sec);
- file->sec[file->size++].id = sec_invalid;
-
- bool check_rel = true;
-
- for (Elf_Scn *scn = NULL; (scn = elf_nextscn (elf, scn)); )
- {
- REALLOC (file, sec);
- size_t curndx = file->size++;
- struct sec *cursec = file->sec + curndx;
-
- GElf_Shdr *shdr = gelf_getshdr (scn, &cursec->shdr);
- if (shdr == NULL)
- {
- invalid_elf:
- wr_error (NULL, "Broken ELF.\n");
- return false;
- }
-
- const char *scnname = elf_strptr (elf, file->ehdr.e_shstrndx,
- shdr->sh_name);
- if (scnname == NULL)
- goto invalid_elf;
-
- if (!address_aligned (shdr->sh_addr, shdr->sh_addralign))
- {
- std::ostringstream s;
- s << "Base address of section " << scnname << ", "
- << "0x" << std::hex << shdr->sh_addr
- << ", should have an alignment of "
- << std::dec << shdr->sh_addralign;
- wr_error (NULL, "%s\n", s.str ().c_str ());
- }
-
- secentry *entry = secinfo.get (scnname);
- cursec->scn = scn;
- cursec->id = entry != NULL ? entry->id : sec_invalid;
- cursec->name = scnname;
- cursec->rel = (struct relocation_data){NULL, SHT_NULL, NULL, 0, 0, 0};
-
- /* Dwarf section. */
- if (entry != NULL)
- {
- if (unlikely (entry->secndx != 0))
- wr_error (NULL, "Multiple occurrences of section %s.\n", scnname);
- else
- {
- /* Haven't seen a section of that name yet. */
- cursec->data = elf_getdata (scn, NULL);
- if (cursec->data == NULL || cursec->data->d_buf == NULL)
- /* Don't print out a warning, we'll get to that in
- process_file. */
- cursec->data = NULL;
- entry->secndx = curndx;
- }
- }
- /* Relocation section. */
- else if (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL)
- {
- /* Get data of section that this REL(A) section relocates. */
- Elf_Scn *relocated_scn = elf_getscn (elf, shdr->sh_info);
- Elf_Scn *symtab_scn = elf_getscn (elf, shdr->sh_link);
- if (relocated_scn == NULL || symtab_scn == NULL)
- goto invalid_elf;
-
- GElf_Shdr relocated_shdr_mem;
- GElf_Shdr *relocated_shdr = gelf_getshdr (relocated_scn,
- &relocated_shdr_mem);
- if (relocated_shdr == NULL)
- goto invalid_elf;
-
- const char *relocated_scnname
- = elf_strptr (elf, file->ehdr.e_shstrndx,
- relocated_shdr->sh_name);
-
- secentry *relocated = secinfo.get (relocated_scnname);
-
- if (relocated != NULL)
- {
- if (relocated->reldata != NULL)
- wr_error (NULL,
- "Several relocation sections for debug section %s."
- " Ignoring %s.\n",
- relocated_scnname, scnname);
- else
- {
- relocated->reldata = elf_getdata (scn, NULL);
- if (unlikely (relocated->reldata == NULL
- || relocated->reldata->d_buf == NULL))
- {
- wr_error (NULL,
- "Data-less relocation section %s.\n", scnname);
- relocated->reldata = NULL;
- }
- else
- relocated->reltype = shdr->sh_type;
- }
-
- if (reloc_symtab == NULL)
- reloc_symtab = symtab_scn;
- else if (reloc_symtab != symtab_scn)
- wr_error (NULL,
- "Relocation sections use multiple symbol tables.\n");
- }
- }
- }
-
- for (secinfo_map::iterator it = secinfo.begin (); it != secinfo.end (); ++it)
- if (it->second.secndx != 0)
- file->debugsec[it->second.id] = file->sec + it->second.secndx;
-
- if (check_rel)
- {
- Elf_Data *reloc_symdata = NULL;
- if (reloc_symtab != NULL)
- {
- reloc_symdata = elf_getdata (reloc_symtab, NULL);
- if (reloc_symdata == NULL)
- /* Not a show stopper, we can check a lot of stuff even
- without a symbol table. */
- wr_error (NULL,
- "Couldn't obtain symtab data.\n");
- }
-
- /* Check relocation sections that we've got. */
- for (secinfo_map::iterator it = secinfo.begin (); it != secinfo.end (); ++it)
- {
- secentry *cur = &it->second;
- if (cur->secndx != 0 && cur->reldata != NULL)
- {
- struct sec *sec = file->sec + cur->secndx;
- sec->rel.type = cur->reltype;
- if (sec->data == NULL)
- {
- where wh = WHERE (sec->id, NULL);
- wr_error (&wh,
- ": this data-less section has a relocation section.\n");
- }
- else if (read_rel (file, sec, cur->reldata, file->addr_64))
- sec->rel.symdata = reloc_symdata;
- }
- }
-
- if (secentry *str = secinfo.get (".debug_str"))
- if (str->reldata != NULL)
- {
- where wh = WHERE (sec_str, NULL);
- wr_message (mc_impact_2 | mc_elf, &wh,
- ": there's a relocation section associated with this section.\n");
- }
- }
-
- return true;
-}
-
-section_base::section_base (__attribute__ ((unused)) dwarflint &lint,
- __attribute__ ((unused)) section_id secid)
-{
-
-}
#include <string>
#include <iostream>
#include "dwarflint-where.h"
-#include "dwarflint-low.h"
#include "dwarflint-main.hh"
struct check_base
}
};
-struct section_base
- : public check<section_base>
- , public sec
-{
- section_base (dwarflint &lint, section_id secid);
-};
-
-template<section_id sec_id>
-class section
- : public section_base
-{
-public:
- explicit section (dwarflint &lint)
- : section_base (lint, sec_id)
- {}
-};
-
#endif//DWARFLINT_CHECKS_HH
/* Functions and data structures related to raw (i.e. unassisted by
libdw) Dwarf abbreviation handling. */
-struct abbrev
-{
- uint64_t code;
- struct where where;
-
- /* Attributes. */
- struct abbrev_attrib
- {
- struct where where;
- uint16_t name;
- uint8_t form;
- } *attribs;
- size_t size;
- size_t alloc;
-
- /* While ULEB128 can hold numbers > 32bit, these are not legal
- values of many enum types. So just use as large type as
- necessary to cover valid values. */
- uint16_t tag;
- bool has_children;
-
- /* Whether some DIE uses this abbrev. */
- bool used;
-};
-
-struct abbrev_table
-{
- struct abbrev_table *next;
- struct abbrev *abbr;
- uint64_t offset;
- size_t size;
- size_t alloc;
- bool used; /* There are CUs using this table. */
- bool skip_check; /* There were errors during loading one of the
- CUs that use this table. Check for unused
- abbrevs should be skipped. */
-};
-
/* Functions and data structures for address record handling. We use
that to check that all DIE references actually point to an existing
die, not somewhere mid-DIE, where it just happens to be
interpretable as a DIE. */
-struct addr_record
-{
- size_t size;
- size_t alloc;
- uint64_t *addrs;
-};
-
static size_t addr_record_find_addr (struct addr_record *ar, uint64_t addr);
static bool addr_record_has_addr (struct addr_record *ar, uint64_t addr);
static void addr_record_add (struct addr_record *ar, uint64_t addr);
the above, this is not stored as sorted set, but simply as an array
of records, because duplicates are unlikely. */
-struct ref
-{
- uint64_t addr; // Referree address
- struct where who; // Referrer
-};
-
-struct ref_record
-{
- size_t size;
- size_t alloc;
- struct ref *refs;
-};
-
static void ref_record_add (struct ref_record *rr, uint64_t addr, struct where *referrer);
static void ref_record_free (struct ref_record *rr);
-
-/* Functions and data structures for CU handling. */
-
-struct cu
-{
- struct cu *next;
- uint64_t offset;
- uint64_t cudie_offset;
- uint64_t length;
- uint64_t low_pc; // DW_AT_low_pc value of CU DIE, -1 if not present.
- struct addr_record die_addrs; // Addresses where DIEs begin in this CU.
- struct ref_record die_refs; // DIE references into other CUs from this CU.
- struct ref_record loc_refs; // references into .debug_loc from this CU.
- struct ref_record range_refs; // references into .debug_ranges from this CU.
- struct ref_record line_refs; // references into .debug_line from this CU.
- struct where where; // Where was this section defined.
- int address_size; // Address size in bytes on the target machine.
- int offset_size; // Offset size in this CU.
- int version; // CU version
- bool has_arange; // Whether we saw arange section pointing to this CU.
- bool has_pubnames; // Likewise for pubnames.
- bool has_pubtypes; // Likewise for pubtypes.
-};
-
static struct cu *cu_find_cu (struct cu *cu_chain, uint64_t offset);
static bool check_location_expression (struct elf_file *file,
struct cu_coverage *cu_coverage)
{
struct read_ctx ctx;
- read_ctx_init (&ctx, file, sec->data);
+ read_ctx_init (&ctx, sec->data, file->other_byte_order);
struct ref_record die_refs;
WIPE (die_refs);
struct coverage *coverage)
{
struct read_ctx ctx;
- read_ctx_init (&ctx, file, sec->data);
+ read_ctx_init (&ctx, sec->data, file->other_byte_order);
bool retval = true;
struct cu *cu_chain)
{
struct read_ctx ctx;
- read_ctx_init (&ctx, file, sec->data);
+ read_ctx_init (&ctx, sec->data, file->other_byte_order);
bool retval = true;
while (!read_ctx_eof (&ctx))
assert (coverage != NULL);
struct read_ctx ctx;
- read_ctx_init (&ctx, parent_ctx->file, parent_ctx->data);
+ read_ctx_init (&ctx, parent_ctx->data, file->other_byte_order);
if (!read_ctx_skip (&ctx, addr))
{
wr_error (wh, ": invalid reference outside the section "
assert (cu_chain != NULL);
struct read_ctx ctx;
- read_ctx_init (&ctx, file, sec->data);
+ read_ctx_init (&ctx, sec->data, file->other_byte_order);
bool retval = true;
bool is_rela = sec->rel.type == SHT_RELA;
struct read_ctx ctx;
- read_ctx_init (&ctx, file, sec->data);
+ read_ctx_init (&ctx, sec->data, file->other_byte_order);
size_t entrysize
= elf_64
uint64_t value;
if (width == 4)
value = dwarflint_read_4ubyte_unaligned
- (file, sec->data->d_buf + cur->offset);
+ (sec->data->d_buf + cur->offset, file->other_byte_order);
else
{
assert (width == 8);
value = dwarflint_read_8ubyte_unaligned
- (file, sec->data->d_buf + cur->offset);
+ (sec->data->d_buf + cur->offset, file->other_byte_order);
}
if (is_rela)
struct cu *cu_chain)
{
struct read_ctx ctx;
- read_ctx_init (&ctx, file, sec->data);
+ read_ctx_init (&ctx, sec->data, file->other_byte_order);
bool retval = true;
struct addr_record line_tables;
bool addr_64; /* True if it's 64-bit Elf. */
bool other_byte_order; /* True if the file has a byte order
different from the host. */
- // xxx add CUs etc here?
};
/* Check that .debug_aranges and .debug_ranges match. */
struct section_coverage *sco, void *data);
+ struct abbrev
+ {
+ uint64_t code;
+ struct where where;
+
+ /* Attributes. */
+ struct abbrev_attrib
+ {
+ struct where where;
+ uint16_t name;
+ uint8_t form;
+ } *attribs;
+ size_t size;
+ size_t alloc;
+
+ /* While ULEB128 can hold numbers > 32bit, these are not legal
+ values of many enum types. So just use as large type as
+ necessary to cover valid values. */
+ uint16_t tag;
+ bool has_children;
+
+ /* Whether some DIE uses this abbrev. */
+ bool used;
+ };
+
+ struct abbrev_table
+ {
+ struct abbrev_table *next;
+ struct abbrev *abbr;
+ uint64_t offset;
+ size_t size;
+ size_t alloc;
+ bool used; /* There are CUs using this table. */
+ bool skip_check; /* There were errors during loading one of the
+ CUs that use this table. Check for unused
+ abbrevs should be skipped. */
+ };
+
+ struct ref
+ {
+ uint64_t addr; // Referree address
+ struct where who; // Referrer
+ };
+
+ struct ref_record
+ {
+ size_t size;
+ size_t alloc;
+ struct ref *refs;
+ };
+
+ struct addr_record
+ {
+ size_t size;
+ size_t alloc;
+ uint64_t *addrs;
+ };
+
+ struct cu
+ {
+ struct cu *next;
+ uint64_t offset;
+ uint64_t cudie_offset;
+ uint64_t length;
+ uint64_t low_pc; // DW_AT_low_pc value of CU DIE, -1 if not present.
+ struct addr_record die_addrs; // Addresses where DIEs begin in this CU.
+ struct ref_record die_refs; // DIE references into other CUs from this CU.
+ struct ref_record loc_refs; // references into .debug_loc from this CU.
+ struct ref_record range_refs; // references into .debug_ranges from this CU.
+ struct ref_record line_refs; // references into .debug_line from this CU.
+ struct where where; // Where was this section defined.
+ int address_size; // Address size in bytes on the target machine.
+ int offset_size; // Offset size in this CU.
+ int version; // CU version
+ bool has_arange; // Whether we saw arange section pointing to this CU.
+ bool has_pubnames; // Likewise for pubnames.
+ bool has_pubtypes; // Likewise for pubtypes.
+ };
+
#ifdef __cplusplus
}
#endif
#include "dwarflint-main.hh"
#include "dwarflint-readctx.h"
#include "dwarflint-checks.hh"
+#include "dwarflint-checks-low.hh" // xxx
/* Bug report address. */
const char *argp_program_bug_address = PACKAGE_BUGREPORT;
return 0;
}
-dwarflint::dwarflint (Elf *elf)
+dwarflint::dwarflint (Elf *a_elf)
+ : _m_elf (a_elf)
{
check_registrar::inst ()->enroll (*this);
struct elf_file file;
- if (!elf_file_init (&file, elf))
+ if (!elf_file_init (&file, a_elf))
return;
- struct abbrev_table *abbrev_chain = NULL;
- struct cu *cu_chain = NULL;
- struct read_ctx ctx;
+ check_debug_info *check_info = check (check_info);
+ // xxx check_expected_trees
+ cu *cu_chain = check_info->cu_chain;
+ read_ctx ctx;
/* Don't attempt to do high-level checks if we couldn't initialize
high-level context. The wrapper takes care of printing out error
messages if any. */
- struct hl_ctx *hlctx = do_high_level ? hl_ctx_new (elf) : NULL;
+ struct hl_ctx *hlctx = do_high_level ? hl_ctx_new (a_elf) : NULL;
#define SEC(sec) (file.debugsec[sec_##sec])
#define HAS_SEC(sec) (SEC(sec) != NULL && SEC(sec)->data != NULL)
- if (likely (HAS_SEC(abbrev)))
- {
- read_ctx_init (&ctx, &file, SEC(abbrev)->data);
- abbrev_chain = abbrev_table_load (&ctx);
- }
- else if (!tolerate_nodebug)
- /* Hard error, not a message. We can't debug without this. */
- wr_error (NULL, ".debug_abbrev data not found.\n");
-
- Elf_Data *str_data = NULL;
- if (SEC(str) != NULL)
- {
- str_data = SEC(str)->data;
- if (str_data == NULL)
- {
- where wh = WHERE (sec_str, NULL);
- wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf, &wh,
- ": the section is present but empty.\n");
- }
- }
-
- struct cu_coverage *cu_coverage = NULL;
- if (abbrev_chain != NULL)
- {
- if (likely (HAS_SEC(info)))
- {
- cu_coverage
- = (struct cu_coverage *)calloc (1, sizeof (struct cu_coverage));
- cu_chain = check_info_structural (&file, SEC(info), abbrev_chain,
- str_data, cu_coverage);
- if (cu_chain != NULL && hlctx != NULL)
- check_expected_trees (hlctx);
- }
- else if (!tolerate_nodebug)
- /* Hard error, not a message. We can't debug without this. */
- wr_error (NULL, ".debug_info data not found.\n");
- }
-
bool ranges_sound;
if (HAS_SEC(ranges) && cu_chain != NULL)
ranges_sound = check_loc_or_range_structural (&file, SEC(ranges),
- cu_chain, cu_coverage);
+ cu_chain, &check_info->cu_cov);
else
ranges_sound = false;
if (HAS_SEC(aranges))
{
- read_ctx_init (&ctx, &file, SEC(aranges)->data);
+ read_ctx_init (&ctx, SEC(aranges)->data, file.other_byte_order);
/* If ranges were needed and not loaded, don't pass them down
for CU/aranges coverage analysis. */
struct coverage *cov
- = (cu_coverage != NULL
- && cu_coverage->need_ranges) ? NULL : &cu_coverage->cov;
+ = check_info->cu_cov.need_ranges ? NULL
+ : &check_info->cu_cov.cov;
if (check_aranges_structural (&file, SEC(aranges), cu_chain, cov)
&& ranges_sound && hlctx != NULL && !be_tolerant && !be_gnu)
}
cu_free (cu_chain);
- abbrev_table_free (abbrev_chain);
if (file.ebl != NULL)
ebl_closebackend (file.ebl);
free (file.sec);
#include <map>
#include <vector>
#include <stdexcept>
+#include "../libelf/libelf.h"
class dwarflint
{
typedef std::map <void const *, class check_base *> check_map;
check_map _m_checks;
+ Elf * _m_elf;
public:
struct check_registrar
};
dwarflint (Elf *elf);
+ Elf *elf () { return _m_elf; }
template <class T>
T *
template <class T>
T *
- check (T *fake)
+ check (__attribute__ ((unused)) T *fake)
{
return check<T> ();
}
} __attribute__ ((packed));
static uint16_t
-read_2ubyte_unaligned (struct elf_file *file, const void *p)
+read_2ubyte_unaligned (const void *p, bool other_byte_order)
{
const union unaligned *up = p;
- if (file->other_byte_order)
+ if (other_byte_order)
return bswap_16 (up->u2);
return up->u2;
}
/* Prefix with dwarflint_ for export, so that it doesn't get confused
with functions and macros in memory-access.h. */
uint32_t
-dwarflint_read_4ubyte_unaligned (struct elf_file *file, const void *p)
+dwarflint_read_4ubyte_unaligned (const void *p, bool other_byte_order)
{
const union unaligned *up = p;
- if (file->other_byte_order)
+ if (other_byte_order)
return bswap_32 (up->u4);
return up->u4;
}
uint64_t
-dwarflint_read_8ubyte_unaligned (struct elf_file *file, const void *p)
+dwarflint_read_8ubyte_unaligned (const void *p, bool other_byte_order)
{
const union unaligned *up = p;
- if (file->other_byte_order)
+ if (other_byte_order)
return bswap_64 (up->u8);
return up->u8;
}
-#define read_2ubyte_unaligned_inc(Dbg, Addr) \
- ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
- Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
- t_; })
+#define read_2ubyte_unaligned_inc(Addr, OtherByteOrder) \
+ ({ uint16_t t_ = read_2ubyte_unaligned (Addr, OtherByteOrder); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
+ t_; })
-#define read_4ubyte_unaligned_inc(Dbg, Addr) \
- ({ uint32_t t_ = dwarflint_read_4ubyte_unaligned (Dbg, Addr); \
- Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
- t_; })
+#define read_4ubyte_unaligned_inc(Addr, OtherByteOrder) \
+ ({ uint32_t t_ = dwarflint_read_4ubyte_unaligned (Addr, OtherByteOrder); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
+ t_; })
-#define read_8ubyte_unaligned_inc(Dbg, Addr) \
- ({ uint64_t t_ = dwarflint_read_8ubyte_unaligned (Dbg, Addr); \
- Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
- t_; })
+#define read_8ubyte_unaligned_inc(Addr, OtherByteOrder) \
+ ({ uint64_t t_ = dwarflint_read_8ubyte_unaligned (Addr, OtherByteOrder); \
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
+ t_; })
void
-read_ctx_init (struct read_ctx *ctx, struct elf_file *file, Elf_Data *data)
+read_ctx_init (struct read_ctx *ctx, Elf_Data *data, bool other_byte_order)
{
if (data == NULL)
abort ();
- ctx->file = file;
ctx->data = data;
ctx->begin = data->d_buf;
ctx->end = data->d_buf + data->d_size;
ctx->ptr = data->d_buf;
+ ctx->other_byte_order = other_byte_order;
}
bool
|| end > parent->end)
return false;
- ctx->file = parent->file;
ctx->data = parent->data;
ctx->begin = begin;
ctx->end = end;
ctx->ptr = begin;
+ ctx->other_byte_order = parent->other_byte_order;
return true;
}
{
if (!read_ctx_need_data (ctx, 2))
return false;
- uint16_t val = read_2ubyte_unaligned_inc (ctx->file, ctx->ptr);
+ uint16_t val = read_2ubyte_unaligned_inc (ctx->ptr, ctx->other_byte_order);
if (ret != NULL)
*ret = val;
return true;
{
if (!read_ctx_need_data (ctx, 4))
return false;
- uint32_t val = read_4ubyte_unaligned_inc (ctx->file, ctx->ptr);
+ uint32_t val = read_4ubyte_unaligned_inc (ctx->ptr, ctx->other_byte_order);
if (ret != NULL)
*ret = val;
return true;
{
if (!read_ctx_need_data (ctx, 8))
return false;
- uint64_t val = read_8ubyte_unaligned_inc (ctx->file, ctx->ptr);
+ uint64_t val = read_8ubyte_unaligned_inc (ctx->ptr, ctx->other_byte_order);
if (ret != NULL)
*ret = val;
return true;
struct read_ctx
{
- struct elf_file *file;
Elf_Data *data;
const unsigned char *ptr;
const unsigned char *begin;
const unsigned char *end;
+ bool other_byte_order;
};
-uint32_t dwarflint_read_4ubyte_unaligned (struct elf_file *file,
- const void *p);
-uint64_t dwarflint_read_8ubyte_unaligned (struct elf_file *file,
- const void *p);
+uint32_t dwarflint_read_4ubyte_unaligned (const void *p,
+ bool other_byte_order);
+uint64_t dwarflint_read_8ubyte_unaligned (const void *p,
+ bool other_byte_order);
void read_ctx_init (struct read_ctx *ctx,
- struct elf_file *file,
- Elf_Data *data);
+ Elf_Data *data,
+ bool other_byte_order);
bool read_ctx_init_sub (struct read_ctx *ctx,
struct read_ctx *parent,
const unsigned char *begin,