From: Petr Machata Date: Fri, 16 Oct 2009 14:18:43 +0000 (+0200) Subject: dwarflint: More restructuring of checks X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=572aef63f4fbdd90c700d7bbee34226f5d427ea0;p=thirdparty%2Felfutils.git dwarflint: More restructuring of checks --- diff --git a/src/Makefile.am b/src/Makefile.am index 9ffa18719..74ed80f4c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,7 +87,7 @@ dwarflint_SOURCES = dwarfstrings.c \ dwarflint-messages.cc dwarflint-messages.h \ dwarflint-where.c dwarflint-where.h \ dwarflint-config.cc dwarflint-config.h \ - dwarflnit-checks.hh + dwarflint-checks.cc dwarflint-checks.hh readelf_SOURCES = readelf.c dwarfstrings.c diff --git a/src/dwarflint-checks.cc b/src/dwarflint-checks.cc new file mode 100644 index 000000000..126446e0c --- /dev/null +++ b/src/dwarflint-checks.cc @@ -0,0 +1,256 @@ +/* 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 37f569b20..b22d02a61 100644 --- a/src/dwarflint-checks.hh +++ b/src/dwarflint-checks.hh @@ -1,10 +1,11 @@ #ifndef DWARFLINT_CHECKS_HH #define DWARFLINT_CHECKS_HH -#include #include #include +#include #include "dwarflint-where.h" +#include "dwarflint-low.h" #include "dwarflint-main.hh" struct check_base @@ -14,8 +15,7 @@ struct check_base { failed (std::string const &msg) : std::runtime_error (msg) - { - } + {} }; }; @@ -30,20 +30,6 @@ public: } }; -template -struct reg - : public dwarflint::check_registrar::item -{ - reg () - { - dwarflint::check_registrar::inst ()->add (this); - } - - virtual void run (dwarflint &lint) { - lint.toplev_check (); - } -}; - template void toplev_check (dwarflint &lint) @@ -58,4 +44,36 @@ toplev_check (dwarflint &lint) } } +template +struct reg + : public dwarflint::check_registrar::item +{ + reg () + { + dwarflint::check_registrar::inst ()->add (this); + } + + virtual void run (dwarflint &lint) + { + toplev_check (lint); + } +}; + +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 6f099f696..822fb84e0 100644 --- a/src/dwarflint-low.c +++ b/src/dwarflint-low.c @@ -180,219 +180,18 @@ static bool check_location_expression (struct elf_file *file, size_t length, struct where *wh); -static bool read_rel (struct elf_file *file, - struct sec *sec, - Elf_Data *reldata, - bool elf_64); - -static bool +bool address_aligned (uint64_t addr, uint64_t align) { return align < 2 || (addr % align == 0); } -static bool +bool necessary_alignment (uint64_t start, uint64_t length, uint64_t align) { return address_aligned (start + length, align) && length < align; } -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; - - struct secinfo - { - const char *name; - 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. */ - enum section_id id; /* Section type. */ - }; - struct secinfo secinfo[] = { -#define SEC(n) {".debug_" #n, NULL, 0, 0, sec_##n}, - DEBUGINFO_SECTIONS -#undef SEC - }; - - Elf_Scn *reloc_symtab = NULL; - - struct secinfo *find_secentry (const char *secname) - { - for (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i) - if (strcmp (secinfo[i].name, secname) == 0) - return secinfo + i; - return NULL; - } - - /* 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)) - wr_error (NULL, "Base address of section %s, %#" PRIx64 - ", should have an alignment of %" PRId64 ".\n", - scnname, shdr->sh_addr, shdr->sh_addralign); - - struct secinfo *secentry = find_secentry (scnname); - cursec->scn = scn; - cursec->id = secentry != NULL ? secentry->id : sec_invalid; - cursec->name = scnname; - cursec->rel = (struct relocation_data){NULL, SHT_NULL, NULL, 0, 0, 0}; - - /* Dwarf section. */ - if (secentry != NULL) - { - if (unlikely (secentry->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; - secentry->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); - - struct secinfo *relocated - = find_secentry (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 (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i) - if (secinfo[i].secndx != 0) - file->debugsec[secinfo[i].id] = file->sec + secinfo[i].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 (size_t i = 0; i < sizeof (secinfo) / sizeof (*secinfo); ++i) - { - struct secinfo *cur = secinfo + i; - if (cur->secndx != 0 && cur->reldata != NULL) - { - struct sec *sec = file->sec + cur->secndx; - sec->rel.type = cur->reltype; - if (sec->data == NULL) - wr_error (&WHERE (sec->id, NULL), - ": 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 (find_secentry (".debug_str")->reldata != NULL) - wr_message (mc_impact_2 | mc_elf, &WHERE (sec_str, NULL), - ": there's a relocation section associated with this section.\n"); - } - - return true; -} - static bool checked_read_uleb128 (struct read_ctx *ctx, uint64_t *ret, struct where *where, const char *what) @@ -3656,7 +3455,7 @@ get_rel_or_rela (Elf_Data *data, int ndx, } } -static bool +bool read_rel (struct elf_file *file, struct sec *sec, Elf_Data *reldata, diff --git a/src/dwarflint-low.h b/src/dwarflint-low.h index cecd6ab5d..34e246f5c 100644 --- a/src/dwarflint-low.h +++ b/src/dwarflint-low.h @@ -105,11 +105,16 @@ extern "C" extern bool check_range_out_of_scope (struct hl_ctx *hlctx); extern bool elf_file_init (struct elf_file *file, Elf *elf); - // xxx will go away + // xxx some of that will go away extern struct abbrev_table * abbrev_table_load (struct read_ctx *ctx); extern void abbrev_table_free (struct abbrev_table *abbr); extern struct abbrev *abbrev_table_find_abbrev (struct abbrev_table *abbrevs, uint64_t abbrev_code); + extern bool read_rel (struct elf_file *file, struct sec *sec, + Elf_Data *reldata, bool elf_64); + extern bool address_aligned (uint64_t addr, uint64_t align); + extern bool necessary_alignment (uint64_t start, uint64_t length, + uint64_t align); struct section_coverage { diff --git a/src/dwarflint-main.cc b/src/dwarflint-main.cc index 249da8c15..b9706cb6d 100644 --- a/src/dwarflint-main.cc +++ b/src/dwarflint-main.cc @@ -39,6 +39,7 @@ #include "dwarflint-config.h" #include "dwarflint-main.hh" #include "dwarflint-readctx.h" +#include "dwarflint-checks.hh" /* Bug report address. */ const char *argp_program_bug_address = PACKAGE_BUGREPORT; diff --git a/src/dwarflint-where.h b/src/dwarflint-where.h index 245387aa9..7aa3ee2ec 100644 --- a/src/dwarflint-where.h +++ b/src/dwarflint-where.h @@ -1,3 +1,6 @@ +#ifndef DWARFLINT_WHERE_H +#define DWARFLINT_WHERE_H + #include #include @@ -77,3 +80,5 @@ extern "C" #ifdef __cplusplus } #endif + +#endif//DWARFLINT_WHERE_H