From 7bad71a0b853ca065a50c243de4d81e6f83fa33d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 6 Sep 2010 17:44:16 +0200 Subject: [PATCH] dwarflint: Extract cu_coverage to separate check pass - if the data is incomplete or unavailable, the pass fails just like any other pass --- dwarflint/Makefile.am | 3 +- dwarflint/check_debug_aranges.cc | 22 +++++-------- dwarflint/check_debug_aranges.hh | 4 +++ dwarflint/check_debug_info.cc | 21 +++++++----- dwarflint/check_debug_info.hh | 18 +++++++--- dwarflint/check_debug_loc_range.cc | 38 ++++++++++----------- dwarflint/check_debug_loc_range.hh | 9 +++-- dwarflint/check_debug_loc_range.ii | 3 ++ dwarflint/cu_coverage.cc | 53 ++++++++++++++++++++++++++++++ dwarflint/cu_coverage.hh | 50 ++++++++++++++++++++++++++++ dwarflint/cu_coverage.ii | 1 + dwarflint/dwarflint.hh | 11 +++++++ dwarflint/low.h | 10 ------ 13 files changed, 184 insertions(+), 59 deletions(-) create mode 100644 dwarflint/check_debug_loc_range.ii create mode 100644 dwarflint/cu_coverage.cc create mode 100644 dwarflint/cu_coverage.hh create mode 100644 dwarflint/cu_coverage.ii diff --git a/dwarflint/Makefile.am b/dwarflint/Makefile.am index a79b8cfb3..90ce5b050 100644 --- a/dwarflint/Makefile.am +++ b/dwarflint/Makefile.am @@ -57,11 +57,12 @@ dwarflint_SOURCES = \ checks.cc checks.hh checks.ii \ sections.cc sections.hh sections.ii \ highlevel_check.cc highlevel_check.hh \ + cu_coverage.cc cu_coverage.hh cu_coverage.ii \ check_debug_abbrev.cc check_debug_abbrev.hh check_debug_abbrev.ii \ check_debug_info.cc check_debug_info.hh check_debug_info.ii \ check_debug_line.cc \ check_debug_pub.cc \ - check_debug_loc_range.cc check_debug_loc_range.hh \ + check_debug_loc_range.cc check_debug_loc_range.hh check_debug_loc_range.ii \ check_debug_aranges.cc check_debug_aranges.hh \ check_matching_ranges.cc \ check_range_out_of_scope.cc \ diff --git a/dwarflint/check_debug_aranges.cc b/dwarflint/check_debug_aranges.cc index 440d5465a..4d87b4022 100644 --- a/dwarflint/check_debug_aranges.cc +++ b/dwarflint/check_debug_aranges.cc @@ -32,6 +32,7 @@ #include "check_debug_aranges.hh" #include "check_debug_info.hh" #include "check_debug_loc_range.hh" +#include "cu_coverage.hh" static reg reg_debug_aranges; @@ -42,6 +43,8 @@ check_debug_aranges::descriptor () (checkdescriptor::create ("check_debug_aranges") .groups ("@low") .prereq () + .prereq () + .prereq () .description ( "Checks for low-level structure of .debug_aranges. In addition it\n" "checks:\n" @@ -57,24 +60,15 @@ check_debug_aranges::descriptor () check_debug_aranges::check_debug_aranges (checkstack &stack, dwarflint &lint) : _m_sec_aranges (lint.check (stack, _m_sec_aranges)) + , _m_info (lint.toplev_check (stack, _m_info)) + , _m_cu_coverage (lint.toplev_check (stack, _m_cu_coverage)) { - check_debug_info *info = lint.toplev_check (stack); - coverage *cov = NULL; - if (info != NULL) - { - // xxx If need_ranges is true, we have to load ranges first. - // That's a flaw in design of checks, that data should have been - // stored in check_ranges, and that should have been requested - // explicitly. But for the time being... - if (info->cu_cov.need_ranges) - lint.toplev_check (stack); - if (!info->cu_cov.need_ranges) - cov = &info->cu_cov.cov; - } + coverage *cov = _m_cu_coverage != NULL ? &_m_cu_coverage->cov : NULL; if (!check_aranges_structural (&_m_sec_aranges->file, &_m_sec_aranges->sect, - info != NULL ? &info->cus.front () : NULL, + _m_info != NULL + ? &_m_info->cus.front () : NULL, cov)) throw check_base::failed (); } diff --git a/dwarflint/check_debug_aranges.hh b/dwarflint/check_debug_aranges.hh index d4427b495..993a221ad 100644 --- a/dwarflint/check_debug_aranges.hh +++ b/dwarflint/check_debug_aranges.hh @@ -29,11 +29,15 @@ #include "low.h" #include "checks.hh" #include "sections.ii" +#include "check_debug_info.ii" +#include "cu_coverage.ii" class check_debug_aranges : public check { section *_m_sec_aranges; + check_debug_info *_m_info; + cu_coverage *_m_cu_coverage; public: static checkdescriptor descriptor (); diff --git a/dwarflint/check_debug_info.cc b/dwarflint/check_debug_info.cc index 2d510d718..25ff93351 100644 --- a/dwarflint/check_debug_info.cc +++ b/dwarflint/check_debug_info.cc @@ -380,7 +380,8 @@ namespace struct ref_record *local_die_refs; Elf_Data *strings; struct coverage *strings_coverage; - struct cu_coverage *cu_coverage; + struct coverage *pc_coverage; + bool *need_rangesp; }; typedef void (*value_check_cb_t) (uint64_t addr, @@ -451,7 +452,7 @@ namespace wr_message (*ctx->where, cat (mc_ranges, mc_impact_2)) << "rangeptr value " << pri::hex (value) << " not aligned to CU address size." << std::endl; - ctx->cu_coverage->need_ranges = true; + *ctx->need_rangesp = true; ref_record_add (&ctx->cu->range_refs, value, ctx->where); } @@ -496,7 +497,8 @@ namespace struct ref_record *local_die_refs, struct coverage *strings_coverage, struct relocation_data *reloc, - struct cu_coverage *cu_coverage) + struct coverage *pc_coverage, + bool *need_rangesp) { bool got_die = false; uint64_t sibling_addr = 0; @@ -509,7 +511,8 @@ namespace ctx, &where, cu, local_die_refs, strings, strings_coverage, - cu_coverage + pc_coverage, + need_rangesp }; while (!read_ctx_eof (ctx)) @@ -986,7 +989,7 @@ namespace cu->low_pc = value; if (low_pc != (uint64_t)-1 && high_pc != (uint64_t)-1) - coverage_add (&cu_coverage->cov, low_pc, high_pc - low_pc); + coverage_add (pc_coverage, low_pc, high_pc - low_pc); } } where.ref = NULL; @@ -1011,7 +1014,7 @@ namespace int st = read_die_chain (ver, file, ctx, cu, abbrevs, strings, local_die_refs, strings_coverage, reloc, - cu_coverage); + pc_coverage, need_rangesp); if (st == -1) return -1; else if (st == 0) @@ -1074,7 +1077,7 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx, if (read_die_chain (ver, _m_file, ctx, cu, &abbrevs, strings, &local_die_refs, strings_coverage, (reloc != NULL && reloc->size > 0) ? reloc : NULL, - &cu_cov) < 0) + &_m_cov, &_m_need_ranges) < 0) { _m_abbr_skip.push_back (abbrevs.offset); retval = false; @@ -1226,7 +1229,7 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint) , _m_abbrevs (lint.check (stack, _m_abbrevs)) , _m_cu_headers (lint.check (stack, _m_cu_headers)) { - memset (&cu_cov, 0, sizeof (cu_cov)); + memset (&_m_cov, 0, sizeof (_m_cov)); check_info_structural (); // re-link CUs so that they form a chain again. This is to @@ -1257,7 +1260,7 @@ check_debug_info::~check_debug_info () ref_record_free (&it->loc_refs); ref_record_free (&it->decl_file_refs); } - coverage_free (&cu_cov.cov); + coverage_free (&_m_cov); } cu * diff --git a/dwarflint/check_debug_info.hh b/dwarflint/check_debug_info.hh index 7b33499e9..2e2e8fef7 100644 --- a/dwarflint/check_debug_info.hh +++ b/dwarflint/check_debug_info.hh @@ -44,6 +44,7 @@ public: read_cu_headers (checkstack &stack, dwarflint &lint); }; +/** The pass for in-depth structural analysis of .debug_info. */ class check_debug_info : public check { @@ -58,6 +59,15 @@ class check_debug_info // validation. Check for unused abbrevs should be skipped. std::vector< ::Dwarf_Off> _m_abbr_skip; + // The check pass adds all low_pc/high_pc ranges loaded from DIE + // tree into this coverage structure. + coverage _m_cov; + + // If, during the check, we find any rangeptr-class attributes, we + // set need_ranges to true. cu_ranges pass then uses this as a hint + // whether to request .debug_ranges or not. + bool _m_need_ranges; + bool check_cu_structural (struct read_ctx *ctx, struct cu *const cu, Elf_Data *strings, @@ -69,10 +79,10 @@ class check_debug_info public: static checkdescriptor descriptor (); - // The check pass adds all low_pc/high_pc ranges loaded from DIE - // tree into this following cu_cov structure. If it finds any - // rangeptr-class attributes, it sets cu_cov.need_ranges to true. - cu_coverage cu_cov; + coverage const &cov () const { return _m_cov; } + bool need_ranges () const { return _m_need_ranges; } + + // This is where the loaded CUs are stored. std::vector cus; check_debug_info (checkstack &stack, dwarflint &lint); diff --git a/dwarflint/check_debug_loc_range.cc b/dwarflint/check_debug_loc_range.cc index b9310db0e..e1b397183 100644 --- a/dwarflint/check_debug_loc_range.cc +++ b/dwarflint/check_debug_loc_range.cc @@ -54,7 +54,7 @@ check_debug_ranges::descriptor () (checkdescriptor::create ("check_debug_ranges") .groups ("@low") .prereq () - .prereq () + .prereq () .description ( "Checks for low-level structure of .debug_ranges. In addition it\n" "checks:\n" @@ -79,7 +79,7 @@ check_debug_loc::descriptor () (checkdescriptor::create ("check_debug_loc") .groups ("@low") .prereq () - .prereq () + .prereq () .description ( "Checks for low-level structure of .debug_loc. In addition it\n" "makes the same checks as .debug_ranges. For location expressions\n" @@ -388,7 +388,7 @@ namespace struct sec *sec, struct coverage *coverage, struct coverage_map *coverage_map, - struct cu_coverage *cu_coverage, + struct coverage *pc_coverage, uint64_t addr, struct where const *wh, enum message_category cat) @@ -523,14 +523,14 @@ namespace /* Skip coverage analysis if we have errors or have no base (or just don't do coverage analysis at all). */ else if (base < (uint64_t)-2 && retval - && (coverage_map != NULL || cu_coverage != NULL)) + && (coverage_map != NULL || pc_coverage != NULL)) { uint64_t address = begin_addr + base; uint64_t length = end_addr - begin_addr; if (coverage_map != NULL) coverage_map_add (coverage_map, address, length, &where, cat); - if (cu_coverage != NULL) - coverage_add (&cu_coverage->cov, address, length); + if (pc_coverage != NULL) + coverage_add (pc_coverage, address, length); } if (contains_locations) @@ -601,7 +601,7 @@ namespace check_loc_or_range_structural (struct elf_file *file, struct sec *sec, struct cu *cu_chain, - struct cu_coverage *cu_coverage) + struct coverage *pc_coverage) { assert (sec->id == sec_loc || sec->id == sec_ranges); assert (cu_chain != NULL); @@ -666,8 +666,7 @@ namespace ranges get recorded, not only those belonging to CUs. Perhaps that's undesirable. */ if (!check_loc_or_range_ref (file, &ctx, it->cu, sec, - &coverage, coverage_map, - sec->id == sec_ranges ? cu_coverage : NULL, + &coverage, coverage_map, pc_coverage, off, &it->ref.who, cat)) retval = false; last_off = off; @@ -699,33 +698,34 @@ namespace coverage_free (&coverage); coverage_map_free_XA (coverage_map); - if (retval && cu_coverage != NULL) - /* Only drop the flag if we were successful, so that the coverage - analysis isn't later done against incomplete data. */ - cu_coverage->need_ranges = false; - return retval; } } check_debug_ranges::check_debug_ranges (checkstack &stack, dwarflint &lint) : _m_sec_ranges (lint.check (stack, _m_sec_ranges)) - , _m_cus (lint.check (stack, _m_cus)) + , _m_info (lint.check (stack, _m_info)) { + memset (&_m_cov, 0, sizeof (_m_cov)); if (!::check_loc_or_range_structural (&_m_sec_ranges->file, &_m_sec_ranges->sect, - &_m_cus->cus.front (), - &_m_cus->cu_cov)) + &_m_info->cus.front (), + &_m_cov)) throw check_base::failed (); } +check_debug_ranges::~check_debug_ranges () +{ + coverage_free (&_m_cov); +} + check_debug_loc::check_debug_loc (checkstack &stack, dwarflint &lint) : _m_sec_loc (lint.check (stack, _m_sec_loc)) - , _m_cus (lint.check (stack, _m_cus)) + , _m_info (lint.check (stack, _m_info)) { if (!::check_loc_or_range_structural (&_m_sec_loc->file, &_m_sec_loc->sect, - &_m_cus->cus.front (), + &_m_info->cus.front (), NULL)) throw check_base::failed (); } diff --git a/dwarflint/check_debug_loc_range.hh b/dwarflint/check_debug_loc_range.hh index d48aebfca..c3737e1ce 100644 --- a/dwarflint/check_debug_loc_range.hh +++ b/dwarflint/check_debug_loc_range.hh @@ -28,23 +28,28 @@ #include "sections.ii" #include "check_debug_info.ii" #include "messages.h" +#include "coverage.hh" class check_debug_ranges : public check { section *_m_sec_ranges; - check_debug_info *_m_cus; + check_debug_info *_m_info; + coverage _m_cov; public: static checkdescriptor const &descriptor (); + + coverage const &cov () const { return _m_cov; } check_debug_ranges (checkstack &stack, dwarflint &lint); + ~check_debug_ranges (); }; class check_debug_loc : public check { section *_m_sec_loc; - check_debug_info *_m_cus; + check_debug_info *_m_info; public: static checkdescriptor const &descriptor (); diff --git a/dwarflint/check_debug_loc_range.ii b/dwarflint/check_debug_loc_range.ii new file mode 100644 index 000000000..a5926e127 --- /dev/null +++ b/dwarflint/check_debug_loc_range.ii @@ -0,0 +1,3 @@ +class check_debug_ranges; +class check_debug_loc; +struct hole_info; diff --git a/dwarflint/cu_coverage.cc b/dwarflint/cu_coverage.cc new file mode 100644 index 000000000..8fabcda81 --- /dev/null +++ b/dwarflint/cu_coverage.cc @@ -0,0 +1,53 @@ +/* Pedantic checking of DWARF files + Copyright (C) 2010 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 + . */ + +#include "cu_coverage.hh" +#include "check_debug_info.hh" +#include "check_debug_loc_range.hh" + +checkdescriptor const & +cu_coverage::descriptor () +{ + static checkdescriptor cd + (checkdescriptor::create ("cu_coverage") + .prereq () + .prereq ()); + return cd; +} + +cu_coverage::cu_coverage (checkstack &stack, dwarflint &lint) + : _m_info (lint.check (stack, _m_info)) + , _m_ranges (lint.check_if (_m_info->need_ranges (), stack, _m_ranges)) +{ + memset (&cov, 0, sizeof (cov)); + coverage_add_all (&cov, &_m_info->cov ()); + if (_m_ranges) + coverage_add_all (&cov, &_m_ranges->cov ()); +} + +cu_coverage::~cu_coverage () +{ + coverage_free (&cov); +} diff --git a/dwarflint/cu_coverage.hh b/dwarflint/cu_coverage.hh new file mode 100644 index 000000000..00767e922 --- /dev/null +++ b/dwarflint/cu_coverage.hh @@ -0,0 +1,50 @@ +/* Pedantic checking of DWARF files + Copyright (C) 2010 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 + . */ + +#ifndef DWARFLINT_CU_COVERAGE_HH +#define DWARFLINT_CU_COVERAGE_HH + +#include "check_debug_info.ii" +#include "check_debug_loc_range.ii" +#include "coverage.hh" +#include "checks.hh" + +/** The pass for finalizing cu_coverage. */ +class cu_coverage + : public check +{ + check_debug_info *_m_info; + check_debug_ranges *_m_ranges; + +public: + static checkdescriptor const &descriptor (); + + coverage cov; + + cu_coverage (checkstack &stack, dwarflint &lint); + ~cu_coverage (); +}; + +#endif//DWARFLINT_CU_COVERAGE_HH diff --git a/dwarflint/cu_coverage.ii b/dwarflint/cu_coverage.ii new file mode 100644 index 000000000..01d567f35 --- /dev/null +++ b/dwarflint/cu_coverage.ii @@ -0,0 +1 @@ +class cu_coverage; diff --git a/dwarflint/dwarflint.hh b/dwarflint/dwarflint.hh index 0e30d2a18..518c33bf0 100644 --- a/dwarflint/dwarflint.hh +++ b/dwarflint/dwarflint.hh @@ -127,6 +127,17 @@ public: template T *toplev_check (checkstack &stack, __attribute__ ((unused)) T *fake = NULL); + + template + T * + check_if (bool whether, checkstack &stack, + __attribute__ ((unused)) T *fake = NULL) + { + if (whether) + return check (stack); + else + return NULL; + } }; #endif//DWARFLINT_HH diff --git a/dwarflint/low.h b/dwarflint/low.h index 27c336501..13f2a9f76 100644 --- a/dwarflint/low.h +++ b/dwarflint/low.h @@ -130,16 +130,6 @@ extern "C" bool allow_overlap; }; - struct cu_coverage - { - struct coverage cov; - bool need_ranges; /* If all CU DIEs have high_pc/low_pc - attribute pair, we don't need separate - range pass. Otherwise we do. As soon as - ranges are projected into cov, the flag - is set to false again. */ - }; - // xxx low-level check entry points, will go away struct cu; extern bool check_aranges_structural (struct elf_file *file, -- 2.47.3