From: Petr Machata Date: Tue, 20 Oct 2009 14:02:14 +0000 (+0200) Subject: dwarflint: Move more checks to the new dependency infrastructure X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5faacaffa6f300afa947c24b85dde317be2e7ac2;p=thirdparty%2Felfutils.git dwarflint: Move more checks to the new dependency infrastructure --- diff --git a/src/Makefile.am b/src/Makefile.am index 74ed80f4c..d89fb8e7f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,7 +87,8 @@ dwarflint_SOURCES = dwarfstrings.c \ 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 diff --git a/src/dwarflint-checks-low.cc b/src/dwarflint-checks-low.cc new file mode 100644 index 000000000..285045694 --- /dev/null +++ b/src/dwarflint-checks-low.cc @@ -0,0 +1,315 @@ +/* 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "dwarflint-checks-low.hh" +#include "dwarflint-low.h" +#include +#include +#include + +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 +{ + 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; +} diff --git a/src/dwarflint-checks-low.hh b/src/dwarflint-checks-low.hh new file mode 100644 index 000000000..587257044 --- /dev/null +++ b/src/dwarflint-checks-low.hh @@ -0,0 +1,62 @@ +#include "dwarflint-checks.hh" +#include "dwarflint-low.h" + +class load_sections + : public check +{ +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 +class section + : public section_base + , public check > +{ +public: + explicit section (dwarflint &lint) + : section_base (lint, sec_id) + {} +}; + +class check_debug_abbrev + : public check +{ + section *_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 reg_debug_abbrev; + +class check_debug_info + : public check +{ + section *_m_sec_info; + section *_m_sec_abbrev; + section *_m_sec_str; + check_debug_abbrev *_m_abbrevs; + +public: + cu_coverage cu_cov; + std::vector cus; + cu *cu_chain; // xxx + + explicit check_debug_info (dwarflint &lint); +}; +static reg reg_debug_info; diff --git a/src/dwarflint-checks.cc b/src/dwarflint-checks.cc index 126446e0c..e69de29bb 100644 --- a/src/dwarflint-checks.cc +++ b/src/dwarflint-checks.cc @@ -1,256 +0,0 @@ -/* 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 - . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "dwarflint-checks.hh" -#include -#include - -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 -{ - 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) -{ - -} diff --git a/src/dwarflint-checks.hh b/src/dwarflint-checks.hh index b22d02a61..4ca86e142 100644 --- a/src/dwarflint-checks.hh +++ b/src/dwarflint-checks.hh @@ -5,7 +5,6 @@ #include #include #include "dwarflint-where.h" -#include "dwarflint-low.h" #include "dwarflint-main.hh" struct check_base @@ -59,21 +58,4 @@ struct reg } }; -struct section_base - : public check - , public sec -{ - section_base (dwarflint &lint, section_id secid); -}; - -template -class section - : public section_base -{ -public: - explicit section (dwarflint &lint) - : section_base (lint, sec_id) - {} -}; - #endif//DWARFLINT_CHECKS_HH diff --git a/src/dwarflint-low.c b/src/dwarflint-low.c index 822fb84e0..502324c68 100644 --- a/src/dwarflint-low.c +++ b/src/dwarflint-low.c @@ -69,56 +69,11 @@ check_category (enum message_category cat) /* 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); @@ -130,46 +85,9 @@ static void addr_record_free (struct addr_record *ar); 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, @@ -2286,7 +2204,7 @@ check_info_structural (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); @@ -2548,7 +2466,7 @@ check_aranges_structural (struct elf_file *file, 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; @@ -2791,7 +2709,7 @@ check_pub_structural (struct elf_file *file, 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)) @@ -3129,7 +3047,7 @@ check_loc_or_range_ref (struct elf_file *file, 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 " @@ -3323,7 +3241,7 @@ check_loc_or_range_structural (struct elf_file *file, 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; @@ -3466,7 +3384,7 @@ read_rel (struct elf_file *file, 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 @@ -3559,12 +3477,12 @@ read_rel (struct elf_file *file, 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) @@ -3598,7 +3516,7 @@ check_line_structural (struct elf_file *file, 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; diff --git a/src/dwarflint-low.h b/src/dwarflint-low.h index 34e246f5c..3e60389a1 100644 --- a/src/dwarflint-low.h +++ b/src/dwarflint-low.h @@ -94,7 +94,6 @@ extern "C" 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. */ @@ -208,6 +207,85 @@ extern "C" 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 diff --git a/src/dwarflint-main.cc b/src/dwarflint-main.cc index b9706cb6d..131649387 100644 --- a/src/dwarflint-main.cc +++ b/src/dwarflint-main.cc @@ -40,6 +40,7 @@ #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; @@ -257,68 +258,32 @@ layout_rel_file (Elf *elf) 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; @@ -329,13 +294,13 @@ dwarflint::dwarflint (Elf *elf) 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) @@ -370,7 +335,6 @@ dwarflint::dwarflint (Elf *elf) } cu_free (cu_chain); - abbrev_table_free (abbrev_chain); if (file.ebl != NULL) ebl_closebackend (file.ebl); free (file.sec); diff --git a/src/dwarflint-main.hh b/src/dwarflint-main.hh index a6cd8b89d..d5a80744c 100644 --- a/src/dwarflint-main.hh +++ b/src/dwarflint-main.hh @@ -4,11 +4,13 @@ #include #include #include +#include "../libelf/libelf.h" class dwarflint { typedef std::map check_map; check_map _m_checks; + Elf * _m_elf; public: struct check_registrar @@ -42,6 +44,7 @@ public: }; dwarflint (Elf *elf); + Elf *elf () { return _m_elf; } template T * @@ -63,7 +66,7 @@ public: template T * - check (T *fake) + check (__attribute__ ((unused)) T *fake) { return check (); } diff --git a/src/dwarflint-readctx.c b/src/dwarflint-readctx.c index 3133f0acb..b1e3296d0 100644 --- a/src/dwarflint-readctx.c +++ b/src/dwarflint-readctx.c @@ -44,10 +44,10 @@ union unaligned } __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; } @@ -55,52 +55,52 @@ read_2ubyte_unaligned (struct elf_file *file, const void *p) /* 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 @@ -114,11 +114,11 @@ read_ctx_init_sub (struct read_ctx *ctx, struct read_ctx *parent, || 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; } @@ -217,7 +217,7 @@ read_ctx_read_2ubyte (struct read_ctx *ctx, uint16_t *ret) { 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; @@ -228,7 +228,7 @@ read_ctx_read_4ubyte (struct read_ctx *ctx, uint32_t *ret) { 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; @@ -239,7 +239,7 @@ read_ctx_read_8ubyte (struct read_ctx *ctx, uint64_t *ret) { 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; diff --git a/src/dwarflint-readctx.h b/src/dwarflint-readctx.h index 62112eb21..ab4839890 100644 --- a/src/dwarflint-readctx.h +++ b/src/dwarflint-readctx.h @@ -14,22 +14,22 @@ extern "C" 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,