From 902866bfd07e34b3e2b86dce4e6a555b77621ab0 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 23 Aug 2018 11:27:17 +0100 Subject: [PATCH] Demangle c++ mangled function names when reporting gaps. Ignore small gaps. Merge ranges when one is wholly covered by another. Ignore gaps covered by _savegpr* or __x86.get_pc_thunk symbols. --- annocheck/annocheck.c | 27 +++++-- annocheck/annocheck.h | 1 + annocheck/hardened.c | 155 +++++++++++++++++++++++++--------------- autom4te.cache/output.0 | 8 +-- autom4te.cache/requests | 88 +++++++++++------------ config/gcc-plugin.m4 | 6 +- configure | 8 +-- 7 files changed, 174 insertions(+), 119 deletions(-) diff --git a/annocheck/annocheck.c b/annocheck/annocheck.c index 8275084..f8a5f28 100644 --- a/annocheck/annocheck.c +++ b/annocheck/annocheck.c @@ -874,13 +874,13 @@ follow_debuglink (annocheck_data * data, Dwarf * dwarf) free (canon_dir); - /* Now open the file.... */ + /* Now open the file... */ Dwarf * separate_debug_file = dwarf_begin (fd, DWARF_C_READ); - - einfo (VERBOSE, "%s: %s separate debug file: %s", - data->filename, - separate_debug_file == NULL ? "Failed to open" : "Found", - debugfile); + + if (separate_debug_file == NULL) + einfo (VERBOSE, "%s: Failed to open separate debug file: %s", data->filename, debugfile); + else + einfo (VERBOSE2, "%s: Opened separate debug file: %s", data->filename, debugfile); free (debugfile); return separate_debug_file; @@ -953,6 +953,18 @@ annocheck_walk_dwarf (annocheck_data * data, dwarf_walker func, void * ptr) /* -------------------------------------------------------------------- */ +static bool +ends_with (const char * string, const char * ending, const size_t end_len) +{ + size_t len = strlen (string); + + if (string == NULL + || len <= end_len + || ! streq (string + (len - end_len), ending)) + return false; + return true; +} + static const char * find_symbol_in (Elf * elf, Elf_Scn * sym_sec, ulong addr, Elf64_Shdr * sym_hdr, bool prefer_func) { @@ -981,6 +993,9 @@ find_symbol_in (Elf * elf, Elf_Scn * sym_sec, ulong addr, Elf64_Shdr * sym_hdr, break; } + if (ends_with (elf_strptr (elf, sym_hdr->sh_link, sym.st_name), "_end", strlen ("_end"))) + continue; + if (! use_saved) { memcpy (& saved_sym, & sym, sizeof sym); diff --git a/annocheck/annocheck.h b/annocheck/annocheck.h index f1b49f7..c3dba18 100644 --- a/annocheck/annocheck.h +++ b/annocheck/annocheck.h @@ -35,6 +35,7 @@ #include #include +#include #define PACKAGE "annocheck" diff --git a/annocheck/hardened.c b/annocheck/hardened.c index aa3db4a..0692c1d 100644 --- a/annocheck/hardened.c +++ b/annocheck/hardened.c @@ -319,8 +319,8 @@ skip_check (enum test_index check, const char * component_name) static void record_range (ulong start, ulong end) { - if (start == end) - return; + if (start >= end) + return; /* FIXME: We should ICE if start > end. */ if (next_free_range >= num_allocated_ranges) { @@ -338,24 +338,6 @@ record_range (ulong start, ulong end) next_free_range ++; } -static int -compare_range (const void * r1, const void * r2) -{ - hardened_note_data * n1 = (hardened_note_data *) r1; - hardened_note_data * n2 = (hardened_note_data *) r2; - - if (n1->end < n2->start) - return -1; - if (n1->start > n2->end) - return 1; - /* Overlap - we should merge the two ranges. */ - if (n1->start < n2->start) - return -1; - if (n1->end > n2->end) - return 1; - return 0; -} - /* Wrapper for einfo that avoids calling get_component_name() unless we know that the string will be needed. */ @@ -1044,9 +1026,11 @@ ignore_gap (annocheck_data * data, hardened_note_data * gap) if ((gap->end - gap->start) < text_section_alignment) return true; - /* If the gap starts in one section, but ends in a different section - then we ignore it. */ + /* We also ignore small gaps for now. */ + if ((gap->end - gap->start) < 32) + return true; + /* Find out where the gap starts and ends. */ if (data->is_32bit) { while ((scn = elf_nextscn (data->elf, scn)) != NULL) @@ -1088,17 +1072,17 @@ ignore_gap (annocheck_data * data, hardened_note_data * gap) } } + /* If the gap starts in one section, but ends in a different section then we ignore it. */ if (addr2_scn == NULL) return false; if (addr1_scn != addr2_scn) return true; - /* On the PowerPC64, the linker can insert PLT resolver stubs at - the end of the .text section. These will be unannotated, but - they can safely be ignored. + /* On the PowerPC64, the linker can insert PLT resolver stubs at the end of the .text section. + These will be unannotated, but they can safely be ignored. - We may not have the symbol table available however so check to - see if the gap ends at the end of the .text section. */ + We may not have the symbol table available however so check to see if the gap ends at the + end of the .text section. */ if (e_machine == EM_PPC64 && align (gap->end, 8) == align (scn_end, 8) && scn_name == text_section_name_index) @@ -1128,11 +1112,51 @@ ignore_gap (annocheck_data * data, hardened_note_data * gap) return false; } +static signed int +compare_range (const void * r1, const void * r2) +{ + hardened_note_data * n1 = (hardened_note_data *) r1; + hardened_note_data * n2 = (hardened_note_data *) r2; + + if (n1->end < n2->start) + return -1; + + if (n1->start > n2->end) + return 1; + + /* Overlap - we should merge the two ranges. */ + if (n1->start < n2->start) + return -1; + + if (n1->end > n2->end) + return 1; + + /* N1 is wholly covered by N2: + n2->start <= n1->start < n2->end + n2->start <= n1->end <= n2->end. + We adjust its range so that the gap detection code does not get confused. */ + n1->start = n2->start; + n1->end = n2->end; + return 0; +} + +/* Certain symbols can indicate that a gap can be safely ignored. */ + +static bool +skip_gap_sym (const char * sym) +{ + if (e_machine == EM_386 && const_strneq (sym, "__x86.get_pc_thunk")) + return true; + + if (e_machine == EM_PPC64 && const_strneq (sym, "_savegpr")) + return true; + + return false; +} + static void check_for_gaps (annocheck_data * data) { - bool gap_found = false; - assert (! ignore_gaps); if (next_free_range < 2) @@ -1144,6 +1168,7 @@ check_for_gaps (annocheck_data * data) hardened_note_data current = ranges[0]; /* Scan the ranges array. */ + bool gap_found = false; unsigned i; for (i = 1; i < next_free_range; i++) { @@ -1169,45 +1194,59 @@ check_for_gaps (annocheck_data * data) gap.start = current.end; gap.end = ranges[i].start; - if (! ignore_gap (data, & gap)) + /* We have found a gap, so reset the current range. */ + current = ranges[i]; + + if (ignore_gap (data, & gap)) + continue; + + const char * sym = annocheck_find_symbol_for_address_range (data, NULL, gap.start, gap.end, false); + + if ((sym == NULL || strstr (sym, ".end")) + && gap.start != align (gap.start, 16)) + { + sym = annocheck_find_symbol_for_address_range (data, NULL, align (gap.start, 16), gap.end, false); + if (sym) + gap.start = align (gap.start, 16); + } + + if (sym) + { + if (skip_check (TEST_MAX, sym)) + continue; + if (skip_gap_sym (sym)) + continue; + } + + gap_found = true; + if (! BE_VERBOSE) + break; + + if (sym) { - const char * sym = annocheck_find_symbol_for_address_range (data, NULL, gap.start, gap.end, false); + const char * cpsym = NULL; - if ((sym == NULL || strstr (sym, ".end")) - && gap.start != align (gap.start, 16)) + if (sym[0] == '_' && sym[1] == 'Z') { - sym = annocheck_find_symbol_for_address_range (data, NULL, align (gap.start, 16), gap.end, false); - if (sym) - gap.start = align (gap.start, 16); + cpsym = cplus_demangle (sym, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE); + if (cpsym != NULL) + sym = cpsym; } - if (sym && skip_check (TEST_MAX, sym)) - continue; - - gap_found = true; - if (! BE_VERBOSE) - break; + einfo (VERBOSE, "%s: gap: (%lx..%lx probable component: %s) in annobin notes", + data->filename, gap.start, gap.end, sym); - if (sym) - einfo (VERBOSE, "%s: gap: (%lx..%lx probable component: %s) in annobin notes", - data->filename, gap.start, gap.end, sym); - else - einfo (VERBOSE, "%s: gap: (%lx..%lx) in annobin notes", - data->filename, gap.start, gap.end); + free ((char *) cpsym); } - - /* We have found a gap, so reset the current range. */ - current = ranges[i]; + else + einfo (VERBOSE, "%s: gap: (%lx..%lx) in annobin notes", + data->filename, gap.start, gap.end); } } - if (!gap_found) - { - pass (data, "No gaps found"); - return; - } - - if (! BE_VERBOSE) + if (! gap_found) + pass (data, "No gaps found"); + else if (! BE_VERBOSE) fail (data, "Gaps were detected in the annobin coverage. Run with -v to list"); else fail (data, "Gaps were detected in the annobin coverage"); diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 index b4f0d1d..aee1f55 100644 --- a/autom4te.cache/output.0 +++ b/autom4te.cache/output.0 @@ -1427,7 +1427,7 @@ Optional Packages: both@:>@ --with-gnu-ld assume the C compiler uses GNU ld @<:@default=no@:>@ --with-gcc-plugin-dir=DIR - install ODB plugin into the GCC plugin directory + install annobin plugin into the GCC plugin directory Some influential environment variables: CC C compiler command @@ -16110,14 +16110,14 @@ $as_echo "yes" >&6; } CPPFLAGS="$CPPFLAGS -I$dir/include" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install ODB plugin into default GCC plugin directory" >&5 -$as_echo_n "checking whether to install ODB plugin into default GCC plugin directory... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install annobin plugin into default GCC plugin directory" >&5 +$as_echo_n "checking whether to install annobin plugin into default GCC plugin directory... " >&6; } case $gcc_plugin_dir in yes) gcc_plugin_dir=$dir ;; test) - # Only install into the GCC plugin dir if both GCC and ODB are + # Only install into the GCC plugin dir if both GCC and annobin are # installed into the same prefix. Testing whether $libdir or # $libexecdir is a prefix of the GCC plugin dir is a good # approximation. diff --git a/autom4te.cache/requests b/autom4te.cache/requests index 46f1d62..eb66078 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -15,63 +15,63 @@ 'configure.ac' ], { - 'AM_PROG_F77_C_O' => 1, - 'AM_SILENT_RULES' => 1, - 'm4_pattern_allow' => 1, - 'm4_pattern_forbid' => 1, - 'AC_SUBST_TRACE' => 1, - '_m4_warn' => 1, - 'AC_SUBST' => 1, + 'AM_PROG_CC_C_O' => 1, 'AC_FC_PP_SRCEXT' => 1, - 'AM_GNU_GETTEXT' => 1, - '_AM_COND_IF' => 1, - 'AM_ENABLE_MULTILIB' => 1, - 'AC_INIT' => 1, - 'AC_CONFIG_SUBDIRS' => 1, - 'AM_INIT_AUTOMAKE' => 1, - '_AM_SUBST_NOTMAKE' => 1, - 'sinclude' => 1, - 'AM_CONDITIONAL' => 1, + 'AC_CANONICAL_BUILD' => 1, + 'm4_pattern_allow' => 1, + 'm4_sinclude' => 1, + 'AC_PROG_LIBTOOL' => 1, 'AC_CANONICAL_TARGET' => 1, - 'AC_CONFIG_LINKS' => 1, - 'LT_SUPPORTED_TAG' => 1, - '_LT_AC_TAGCONFIG' => 1, + 'AC_FC_PP_DEFINE' => 1, + 'AM_PROG_AR' => 1, 'AC_CONFIG_HEADERS' => 1, + 'LT_INIT' => 1, + '_AM_COND_IF' => 1, 'LT_CONFIG_LTDL_DIR' => 1, - 'AC_CONFIG_FILES' => 1, - '_AM_MAKEFILE_INCLUDE' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'm4_sinclude' => 1, 'm4_include' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - 'AM_PROG_FC_C_O' => 1, - 'AC_REQUIRE_AUX_FILE' => 1, - 'AC_CANONICAL_HOST' => 1, - 'AC_CONFIG_AUX_DIR' => 1, - 'LT_INIT' => 1, + 'AM_GNU_GETTEXT' => 1, 'AM_PROG_MOC' => 1, - 'include' => 1, - 'AM_POT_TOOLS' => 1, + 'AM_PROG_CXX_C_O' => 1, '_AM_COND_ELSE' => 1, - 'AM_XGETTEXT_OPTION' => 1, - 'AC_FC_PP_DEFINE' => 1, + 'AM_CONDITIONAL' => 1, + '_m4_warn' => 1, + 'sinclude' => 1, + 'AC_CANONICAL_SYSTEM' => 1, + 'AM_ENABLE_MULTILIB' => 1, + 'AC_CONFIG_SUBDIRS' => 1, + 'AH_OUTPUT' => 1, 'AM_MAKEFILE_INCLUDE' => 1, + 'AC_SUBST_TRACE' => 1, + 'AM_POT_TOOLS' => 1, + '_LT_AC_TAGCONFIG' => 1, 'AC_LIBSOURCE' => 1, + 'AC_REQUIRE_AUX_FILE' => 1, + 'include' => 1, + 'AC_CONFIG_LINKS' => 1, + '_AM_COND_ENDIF' => 1, + 'AC_FC_FREEFORM' => 1, + 'AM_PROG_F77_C_O' => 1, + 'LT_SUPPORTED_TAG' => 1, + '_AM_MAKEFILE_INCLUDE' => 1, + 'AC_CONFIG_FILES' => 1, 'AM_MAINTAINER_MODE' => 1, - 'AC_CANONICAL_SYSTEM' => 1, + 'm4_pattern_forbid' => 1, + 'AM_XGETTEXT_OPTION' => 1, + 'AC_FC_SRCEXT' => 1, + 'AM_PROG_FC_C_O' => 1, + 'AC_SUBST' => 1, + 'AC_INIT' => 1, 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, - 'AC_FC_FREEFORM' => 1, - 'AM_PROG_CC_C_O' => 1, - '_AM_COND_ENDIF' => 1, - 'AC_CANONICAL_BUILD' => 1, - 'AH_OUTPUT' => 1, - 'AC_PROG_LIBTOOL' => 1, + 'AC_CONFIG_AUX_DIR' => 1, + 'AM_SILENT_RULES' => 1, 'AM_NLS' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + '_AM_SUBST_NOTMAKE' => 1, + 'AC_CANONICAL_HOST' => 1, + 'AM_PATH_GUILE' => 1, + 'AM_INIT_AUTOMAKE' => 1, 'AC_CONFIG_LIBOBJ_DIR' => 1, - 'AC_FC_SRCEXT' => 1, - 'AM_PROG_CXX_C_O' => 1, - 'AM_PROG_AR' => 1, - 'AM_PATH_GUILE' => 1 + 'AC_DEFINE_TRACE_LITERAL' => 1 } ], 'Autom4te::Request' ) ); diff --git a/config/gcc-plugin.m4 b/config/gcc-plugin.m4 index 625e7df..1c5c6e4 100644 --- a/config/gcc-plugin.m4 +++ b/config/gcc-plugin.m4 @@ -9,7 +9,7 @@ static_plugin=$enable_static AC_ARG_WITH( [gcc-plugin-dir], - [AC_HELP_STRING([--with-gcc-plugin-dir=DIR], [install ODB plugin into the GCC plugin directory])], + [AC_HELP_STRING([--with-gcc-plugin-dir=DIR], [install annobin plugin into the GCC plugin directory])], [gcc_plugin_dir=$withval], [gcc_plugin_dir=test]) @@ -54,13 +54,13 @@ else CPPFLAGS="$CPPFLAGS -I$dir/include" - AC_MSG_CHECKING([whether to install ODB plugin into default GCC plugin directory]) + AC_MSG_CHECKING([whether to install annobin plugin into default GCC plugin directory]) case $gcc_plugin_dir in yes) gcc_plugin_dir=$dir ;; test) - # Only install into the GCC plugin dir if both GCC and ODB are + # Only install into the GCC plugin dir if both GCC and annobin are # installed into the same prefix. Testing whether $libdir or # $libexecdir is a prefix of the GCC plugin dir is a good # approximation. diff --git a/configure b/configure index 52928dd..dc8ace7 100755 --- a/configure +++ b/configure @@ -1427,7 +1427,7 @@ Optional Packages: both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-gcc-plugin-dir=DIR - install ODB plugin into the GCC plugin directory + install annobin plugin into the GCC plugin directory Some influential environment variables: CC C compiler command @@ -16110,14 +16110,14 @@ $as_echo "yes" >&6; } CPPFLAGS="$CPPFLAGS -I$dir/include" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install ODB plugin into default GCC plugin directory" >&5 -$as_echo_n "checking whether to install ODB plugin into default GCC plugin directory... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install annobin plugin into default GCC plugin directory" >&5 +$as_echo_n "checking whether to install annobin plugin into default GCC plugin directory... " >&6; } case $gcc_plugin_dir in yes) gcc_plugin_dir=$dir ;; test) - # Only install into the GCC plugin dir if both GCC and ODB are + # Only install into the GCC plugin dir if both GCC and annobin are # installed into the same prefix. Testing whether $libdir or # $libexecdir is a prefix of the GCC plugin dir is a good # approximation. -- 2.43.5