From 9ad0e8f75afe140eaeabd472ba1aac8f11cf985c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 27 Nov 2009 16:41:10 +0100 Subject: [PATCH] dwarflint: Move Elf* out of dwarflint class * instead implement opening in highlevel_check and lowlevel_check separately. We need to open highlevel check through dwfl, which does its own Elf opening. --- src/Makefile.am | 2 +- src/dwarflint/check_highlevel.cc | 47 ++++++++++ src/dwarflint/checks-high.hh | 17 +++- src/dwarflint/checks-low.cc | 151 ++++++++++++++++++++++++++++++- src/dwarflint/dwarflint.cc | 4 +- src/dwarflint/dwarflint.hh | 6 +- src/dwarflint/main.cc | 136 ++-------------------------- 7 files changed, 222 insertions(+), 141 deletions(-) create mode 100644 src/dwarflint/check_highlevel.cc diff --git a/src/Makefile.am b/src/Makefile.am index 4a1c07eb1..976af4948 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -95,7 +95,7 @@ dwarflint_SOURCES = dwarfstrings.c \ dwarflint/reloc.cc dwarflint/reloc.h \ dwarflint/tables.cc dwarflint/tables.hh dwarflint/tables.h \ dwarflint/all-dies-it.hh \ - dwarflint/checks-high.hh \ + dwarflint/check_highlevel.cc dwarflint/checks-high.hh \ dwarflint/check_debug_abbrev.cc \ dwarflint/check_debug_info.cc \ dwarflint/check_debug_line.cc \ diff --git a/src/dwarflint/check_highlevel.cc b/src/dwarflint/check_highlevel.cc new file mode 100644 index 000000000..68309d477 --- /dev/null +++ b/src/dwarflint/check_highlevel.cc @@ -0,0 +1,47 @@ +/* Initialization of high-level check context + 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 + . */ + + // xxx this will throw an exception on or + // failure. We need to catch it and convert to check_base::failed. + +#include "checks-high.hh" // xxx rename +#include "../libdwfl/libdwfl.h" + +Dwarf * +dwarf_handle_loader::get_dwarf_handle (int fd) +{ + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + /* + static const Dwfl_Callbacks callbacks = + { + .section_address = dwfl_offline_section_address, + .find_debuginfo = find_no_debuginfo + }; + Dwfl *dwfl = dwfl_begin (&callbacks); + if (unlikely (dwfl == NULL)) + throw check_base::failed (); + */ + return dwarf_begin_elf (elf, DWARF_C_READ, NULL); +} diff --git a/src/dwarflint/checks-high.hh b/src/dwarflint/checks-high.hh index 6e1a63ec9..5361e5e8a 100644 --- a/src/dwarflint/checks-high.hh +++ b/src/dwarflint/checks-high.hh @@ -23,13 +23,26 @@ Network licensing program, please visit www.openinventionnetwork.com . */ +#ifndef DWARFLINT_CHECKS_HIGH_HH +#define DWARFLINT_CHECKS_HIGH_HH + +#ifdef HAVE_CONFIG_H +# include +#endif + #include "checks-low.hh" #include "config.h" #include "c++/dwarf" +struct dwarf_handle_loader +{ + Dwarf *get_dwarf_handle (int fd); +}; + template class highlevel_check : public check > + , private dwarf_handle_loader { ::Dwarf *_m_handle; @@ -39,7 +52,7 @@ public: // xxx this will throw an exception on or // failure. We need to catch it and convert to check_base::failed. explicit highlevel_check (dwarflint &lint) - : _m_handle (dwarf_begin_elf (lint.elf (), DWARF_C_READ, NULL)) + : _m_handle (get_dwarf_handle (lint.fd ())) , dw (_m_handle) { if (!do_high_level) @@ -61,3 +74,5 @@ to_where (T const &die) where_reset_2 (&ret, die.offset ()); return ret; } + +#endif//DWARFLINT_CHECKS_HIGH_HH diff --git a/src/dwarflint/checks-low.cc b/src/dwarflint/checks-low.cc index 9350d92b4..a4247db2e 100644 --- a/src/dwarflint/checks-low.cc +++ b/src/dwarflint/checks-low.cc @@ -67,9 +67,136 @@ struct secinfo_map } }; -bool -elf_file_init (struct elf_file *file, Elf *elf) +namespace +{ +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; +} + + Elf * + open_elf (int fd) + { + Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL); + if (unlikely (elf == NULL)) + { + wr_error () + << "Error opening file: " << elf_errmsg (-1) << std::endl; + throw check_base::failed (); + } + + if (layout_rel_file (elf)) + { + wr_error () + << "Couldn't layout ET_REL file." << std::endl; + throw check_base::failed (); + } + + return elf; + } + +Elf * +elf_file_init (struct elf_file *file, int fd) { + Elf *elf = open_elf (fd); + assert (elf != NULL); memset (file, 0, sizeof (*file)); file->elf = elf; @@ -115,7 +242,7 @@ elf_file_init (struct elf_file *file, Elf *elf) { invalid_elf: wr_error () << "Broken ELF." << std::endl; - return false; + goto close_and_out; } const char *scnname = elf_strptr (elf, file->ehdr.e_shstrndx, @@ -245,12 +372,26 @@ elf_file_init (struct elf_file *file, Elf *elf) << std::endl; } - return true; + return elf; + + close_and_out: + if (elf != NULL) + { + elf_errno (); // clear errno + elf_end (elf); + int err = elf_errno (); + if (err != 0) + wr_error () + << "error while closing Elf descriptor: " + << elf_errmsg (err) << std::endl; + } + return NULL; +} } load_sections::load_sections (dwarflint &lint) { - elf_file_init (&file, lint.elf ()); + elf_file_init (&file, lint.fd ()); } load_sections::~load_sections () diff --git a/src/dwarflint/dwarflint.cc b/src/dwarflint/dwarflint.cc index 72f23c89b..27f51f181 100644 --- a/src/dwarflint/dwarflint.cc +++ b/src/dwarflint/dwarflint.cc @@ -1,7 +1,7 @@ #include "dwarflint.hh" -dwarflint::dwarflint (Elf *a_elf) - : _m_elf (a_elf) +dwarflint::dwarflint (int a_fd) + : _m_fd (a_fd) { check_registrar::inst ()->enroll (*this); } diff --git a/src/dwarflint/dwarflint.hh b/src/dwarflint/dwarflint.hh index f1684ecaf..6d256a7e8 100644 --- a/src/dwarflint/dwarflint.hh +++ b/src/dwarflint/dwarflint.hh @@ -10,7 +10,7 @@ class dwarflint { typedef std::map check_map; check_map _m_checks; - Elf * _m_elf; + int _m_fd; public: struct check_registrar @@ -43,8 +43,8 @@ public: std::vector _m_items; }; - dwarflint (Elf *elf); - Elf *elf () { return _m_elf; } + explicit dwarflint (int fd); + int fd () { return _m_fd; } template T *check (); diff --git a/src/dwarflint/main.cc b/src/dwarflint/main.cc index 38fd1b2c7..f544635a9 100644 --- a/src/dwarflint/main.cc +++ b/src/dwarflint/main.cc @@ -156,108 +156,6 @@ parse_opt (int key, char *arg __attribute__ ((unused)), 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[]) { @@ -320,33 +218,13 @@ main (int argc, char *argv[]) } /* 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; - - if (!only_one) - std::cout << std::endl << argv[remaining] << ":" << std::endl; - dwarflint lint (elf); - - 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")); - } + unsigned int prev_error_count = error_count; + if (!only_one) + std::cout << std::endl << argv[remaining] << ":" << std::endl; + dwarflint lint (fd); + + if (prev_error_count == error_count && !be_quiet) + puts (gettext ("No errors")); close (fd); } -- 2.47.2