Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Lancelot SIX via Gdb-patches <gdb-patches@sourceware.org>
To: Kevin Buettner <kevinb@redhat.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH 2/2] BFD error message suppression test case
Date: Tue, 6 Sep 2022 10:29:08 +0000	[thread overview]
Message-ID: <20220906102908.qrvisybbnyg4idhp@ubuntu.lan> (raw)
In-Reply-To: <20220903004759.2082950-3-kevinb@redhat.com>

Hi,

When applying this patch, I have:

    Applying: BFD error message suppression test case
    [...]/rebase-apply/patch:269: trailing whitespace.
    # in the dynamic linker/loader due to using a mangled shared object. 
    warning: 1 line adds whitespace errors.

Also, on my systems (ubuntu 22.04 and ubuntu 20.04), the test fails:

    (gdb) catch load bfd-errors-lib
    Catchpoint 1 (load)
    (gdb) PASS: gdb.base/bfd-errors.exp: catch load bfd-errors-lib
    run 
    Starting program: .../gdb/testsuite/outputs/gdb.base/bfd-errors/bfd-errors-main 
    .../gdb/testsuite/outputs/gdb.base/bfd-errors/bfd-errors-main: symbol lookup error: .../gdb/testsuite/outputs/gdb.base/bfd-errors/bfd-errors-main: undefined symbol: foo4
    [Inferior 1 (process 19165) exited with code 0177]
    (gdb) FAIL: gdb.base/bfd-errors.exp: run to catchpoint (the program exited)
    PASS: gdb.base/bfd-errors.exp: consolidated bfd errors
    FAIL: gdb.base/bfd-errors.exp: print all unique bfd error

I have not really looked at the errors in detail.

I also have minor comments inlined in the patch.

On Fri, Sep 02, 2022 at 05:47:59PM -0700, Kevin Buettner via Gdb-patches wrote:
> This commit adds a GDB test case which tests GDB's BFD error handler
> hook for suppressing output of all but the first identical messages.
> 
> See the comment at the beginning of bfd-errors.exp for details about
> this new test.
> 
> I've tested this test for both 32- and 64-bit ELF files and also
> on both little endian and big endian machines.  It also works for
> both native and remote targets.  The only major restriction is that
> it only works for ELF targets.
> ---
>  gdb/testsuite/gdb.base/bfd-errors-lib.c  |  44 +++++
>  gdb/testsuite/gdb.base/bfd-errors-main.c |  31 ++++
>  gdb/testsuite/gdb.base/bfd-errors.exp    | 211 +++++++++++++++++++++++
>  3 files changed, 286 insertions(+)
>  create mode 100644 gdb/testsuite/gdb.base/bfd-errors-lib.c
>  create mode 100644 gdb/testsuite/gdb.base/bfd-errors-main.c
>  create mode 100644 gdb/testsuite/gdb.base/bfd-errors.exp
> 
> diff --git a/gdb/testsuite/gdb.base/bfd-errors-lib.c b/gdb/testsuite/gdb.base/bfd-errors-lib.c
> new file mode 100644
> index 00000000000..2b582d14c58
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/bfd-errors-lib.c
> @@ -0,0 +1,44 @@
> +/* Copyright 2022 Free Software Foundation, Inc.
> +   This program 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; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include <stdio.h>
> +
> +void
> +foo1 ()
> +{
> +  printf ("foo1 in lib\n");
> +  return;
> +}
> +
> +void
> +foo2()
> +{
> +  printf ("foo2 in lib\n");
> +  return;
> +}
> +
> +void
> +foo3()
> +{
> +  printf ("foo3 in lib\n");
> +  return;
> +}
> +
> +void
> +foo4()
> +{
> +  printf ("foo4 in lib\n");
> +  return;
> +}
> diff --git a/gdb/testsuite/gdb.base/bfd-errors-main.c b/gdb/testsuite/gdb.base/bfd-errors-main.c
> new file mode 100644
> index 00000000000..153f29704eb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/bfd-errors-main.c
> @@ -0,0 +1,31 @@
> +/* Copyright 2022 Free Software Foundation, Inc.
> +   This program 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; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include <stdio.h>
> +
> +extern void foo1();
> +extern void foo2();
> +extern void foo3();
> +extern void foo4();
> +
> +int main ()
> +{
> +  printf ("in main\n");
> +  foo1 ();
> +  foo2 ();
> +  foo3 ();
> +  foo4 ();
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/bfd-errors.exp b/gdb/testsuite/gdb.base/bfd-errors.exp
> new file mode 100644
> index 00000000000..6d5a9428dc0
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/bfd-errors.exp
> @@ -0,0 +1,211 @@
> +# Copyright 2022 Free Software Foundation, Inc.
> +# This program 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; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Tools which use the BFD library will output error messages of the
> +# form "BFD: some messsage" when a problem with the file upon which it
> +# operating is found.  E.g. an actual message (modulo some shortening
> +# of the pathname) from this test is:
> +#
> +# BFD: bfd-errors-lib.so: invalid string offset 1154 >= 154 for section `.dynstr'
> +#
> +# For some problems with executable files or libraries, BFD will
> +# attempt to output many identical messages.  Code has been added to
> +# GDB to suppress messages which are identical to earlier messages
> +# that have already been printed.
> +#
> +# This test makes sure that (all but the first) identical BFD messages
> +# are suppresssed and also that differing messages are output at least
> +# once.
> +#
> +# To accomplish this, a shared object with at least four symbols is
> +# created.  The .dynsym section is extracted and offsets which should
> +# refer to strings in the .dynstr section are changed to be
> +# larger than the size of the .dynstr section.  Only two (different)
> +# offsets are used; thus BFD will attempt to output at least two pairs
> +# of identical messages.  (And it would do this too if not intercepted
> +# by the hook placed by GDB.)  After modifying the extracted section,
> +# the mangled section is placed back into the shared object.
> +#
> +# This test then sets a catchpoint on the shared library load
> +# operation and GDB is run to that catchpoint.  On the way to running
> +# to the catchpoint, the test observes and records the BFD errors that
> +# were output.  Finally, data collected while running to the
> +# catchpoint are examined to make sure that identical messages were
> +# suppressed while also making sure that at least two messages have
> +# been printed.
> +
> +# This test can't be run on targets lacking shared library support
> +# or for non-ELF targets.
> +if { [skip_shlib_tests] || ![is_elf_target] } {
> +    return 0
> +}
> +
> +# Library file names and flags:
> +set lib_basename ${::gdb_test_file_name}-lib
> +set srcfile_lib ${srcdir}/${subdir}/${lib_basename}.c
> +set binfile_lib [standard_output_file ${lib_basename}.so]
> +set lib_flags [list debug ldflags=-Wl,-Bsymbolic]
> +
> +# Main executable names and flags:
> +set main_basename ${::gdb_test_file_name}-main
> +set srcfile ${srcdir}/${subdir}/${main_basename}.c
> +set binfile [standard_output_file ${main_basename}]
> +set bin_flags [list debug shlib=${binfile_lib}]
> +
> +# Compile shared library and main executable:
> +if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != ""
> +     || [gdb_compile ${srcfile} ${binfile} executable $bin_flags] != "" } {
> +    untested "failed to compile"
> +    return -1
> +}
> +
> +# Open the shared library and determine some basic facts.  The key
> +# things that we need to learn are 1) whether the solib is 32-bit or
> +# 64-bit ELF file, and 2) the endianness.
> +set solib_fp [open ${binfile_lib} r]
> +fconfigure $solib_fp -translation binary
> +
> +# Read and check EI_MAG to verify that it's really an ELF file.
> +set data [read $solib_fp 4]
> +if { ![string equal $data "\x7fELF"] } {
> +    untested "shared library is not an ELF file"
> +    return -1
> +}
> +
> +# Read EI_CLASS for ELF32 versus ELF64.
> +set data [read $solib_fp 1]
> +set is_elf64 [string equal $data "\x02"]
> +
> +# Read EI_DATA to determine data encoding (byte order).
> +set data [read $solib_fp 1]
> +set is_big_endian [string equal $data "\x02"]
> +
> +close $solib_fp
> +
> +set objcopy_program [gdb_find_objcopy]
> +
> +# Extract the .dynsym and .dynstr section from the shared object.
> +if {[run_on_host \
> +	"objcopy dump-section" \
> +	${objcopy_program} \
> +	"--dump-section .dynsym=${binfile_lib}.dynsym --dump-section .dynstr=${binfile_lib}.dynstr ${binfile_lib}"]} {
> +    untested "failed objcopy dump-section"
> +    return -1
> +}
> +
> +# Determine length of .dynstr.  We'll use the length for creating invalid
> +# offsets into .dynstr.
> +set dynstr_fp [open ${binfile_lib}.dynstr r]
> +fconfigure $dynstr_fp -translation binary
> +set dynstr_len [string length [read $dynstr_fp]]
> +close $dynstr_fp
> +
> +# Open the file containing .dynsym and determine its length.  In this
> +# case, we want to know the length in order to compute the total number
> +# of symbols that it contains.  We also leave the file open for a
> +# while so that we can write invalid offsets to it.
> +set dynsym_fp [open ${binfile_lib}.dynsym r+]
> +fconfigure $dynsym_fp -translation binary
> +set dynsym_len [string length [read $dynsym_fp]]
> +
> +# SZ is the size of the Elf32_Sym / Elf64_Sym struct.  OFF is the
> +# offset into the file.  CNT is one greater than the number of symbols
> +# left to mangle.  Note that, in the loop below, the first symbol is
> +# skipped.  This is intentional since the first symbol is defined by
> +# the ELF specification to be the undefined symbol.
> +set off 0
> +if { $is_elf64 } {
> +    set sz 24
> +} else {
> +    set sz 16
> +}
> +set cnt [expr $dynsym_len / $sz]
> +
> +# Create patterns (bad offsets) to write into the st_name area.
> +if { $is_big_endian } {
> +    set pat(0) [binary format I [expr $dynstr_len + 1000]]
> +    set pat(1) [binary format I [expr $dynstr_len + 2000]]
> +} else {
> +    set pat(0) [binary format i [expr $dynstr_len + 1000]]
> +    set pat(1) [binary format i [expr $dynstr_len + 2000]]
> +}
> +
> +# Mangle st_name for the symbols following the first (STN_UNDEF) entry.
> +while { [incr cnt -1] > 0 } {
> +    seek $dynsym_fp [incr off $sz]
> +    puts $dynsym_fp $pat([expr $cnt % 2])
> +}
> +
> +close $dynsym_fp
> +
> +# Replace .dynsym section in shared object with the mangled version.
> +if {[run_on_host \
> +	"objcopy update-section" \
> +	${objcopy_program} \
> +	"--update-section .dynsym=${binfile_lib}.dynsym ${binfile_lib}"]} {
> +    untested "failed objcopy update-section"
> +    return -1
> +}
> +
> +gdb_start
> +gdb_reinitialize_dir $srcdir/$subdir
> +gdb_load ${binfile}
> +gdb_load_shlib $binfile_lib
> +
> +# We don't run to main because doing so will sometimes cause a SIGSEGV
> +# in the dynamic linker/loader due to using a mangled shared object. 
> +# Instead, we'll stop at the shared library load.
> +gdb_test "catch load ${lib_basename}" "Catchpoint.*load.*"
> +
> +gdb_run_cmd
> +
> +# Count number of distinct BFD error messages via 'bfd_error_count'
> +# array while running to the catchpoint.
> +set testname "run to catchpoint"
> +gdb_test_multiple "" $testname {
> +    -re "(BFD:\[^\r\n\]*)\[\r\n\]+" {
> +	incr bfd_error_count($expect_out(1,string))
> +	exp_continue
> +    }
> +    -re "Catchpoint .*${lib_basename}.*$gdb_prompt $" {
> +	pass $testname

You could use $gdb_test_name here.  This would avoid the need of the
testname variable.

> +    }
> +}
> +
> +# Examine counts recorded in the 'bfd_error_count' array to see if any
> +# message was printed multiple times.
> +set testname "consolidated bfd errors"
> +set more_than_one 0
> +foreach index [array names bfd_error_count] {
> +    if { $bfd_error_count($index) > 1 } {
> +	incr more_than_one
> +    }
> +}
> +if { $more_than_one > 0 } {
> +    fail $testname
> +} else {
> +    pass $testname
> +}
> +

I guess you could use

    gdb_assert { $more_than_one > 0 } "consolidated bfd errors"

> +# There should have been at least two distinct BFD errors printed.
> +set testname "print all unique bfd errors"
> +if { [array size bfd_error_count] >= 2 } {
> +    pass $testname
> +} else {
> +    fail $testname
> +}

Similarly, I think gdb_assert would be more concise.

Best,
Lancelot.

> +
> +gdb_exit
> +
> +return 0
> -- 
> 2.37.2
> 

  reply	other threads:[~2022-09-06 10:29 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-03  0:47 [PATCH 0/2] Suppress printing of superfluous BFD error messages Kevin Buettner via Gdb-patches
2022-09-03  0:47 ` [PATCH 1/2] " Kevin Buettner via Gdb-patches
2022-09-06 10:09   ` Lancelot SIX via Gdb-patches
2022-09-03  0:47 ` [PATCH 2/2] BFD error message suppression test case Kevin Buettner via Gdb-patches
2022-09-06 10:29   ` Lancelot SIX via Gdb-patches [this message]
2022-09-06 23:21     ` Kevin Buettner via Gdb-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220906102908.qrvisybbnyg4idhp@ubuntu.lan \
    --to=gdb-patches@sourceware.org \
    --cc=kevinb@redhat.com \
    --cc=lsix@lancelotsix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox