]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: restore warning when core file and executable don't match
authorAndrew Burgess <aburgess@redhat.com>
Fri, 17 Oct 2025 13:19:54 +0000 (14:19 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Fri, 17 Oct 2025 15:25:52 +0000 (16:25 +0100)
Consider the following GDB session:

  (gdb) file /path/to/program
  (gdb) core /path/to/corefile
  warning: core file may not match specified executable file.
  ... etc ...
  (gdb)

Notice the warning.  GDB produces this warning when one of the
following conditions is true:

  + The build-id for the core file doesn't match the build-id of the
    executable, or

  + The filename of the executable doesn't match the partial filename
    stored in the PRPSINFO note from the core file.

Unfortunately, this warning was broken by the following two commits:

  commit c97e57bc9d2e081b7c842742933b7262f1d7ce39
  Date:   Wed Oct 8 11:18:07 2025 +0100

      gdb: move core file bfd from program_space into core_target

  commit 84f8be0d9c8ce30bf56eb9e14ce6fe012125fa53
  Date:   Wed Sep 10 11:04:45 2025 +0100

      gdb: remove program_space::core_bfd member function

These commits changed how the validate_files function (in corefile.c),
which is where the warning is emitted, find the core file BFD object.
Prior to the above commits, the core file BFD was stored in the
program_space, and was set by the time validate_files was called.

After the above commits the core file BFD is stored in the inferior's
core_target, and can only be accessed if the core_target has been
pushed onto the inferior's target stack.

Unfortunately, validate_files is called just before core_target is
pushed.  As a result, in validate_files it appears as if there is no
core file loaded, and so no validation is performed.

This commit fixes that by moving the call to validate_files to after
the core_target is pushed.  The warning is now restored.

I was surprised that this wasn't caught in testing.  I was sure we had
a test for that warning.  But, when I look now, I cannot find any such
test, so this commit adds one.

While I'm adding the test, validate_files also has a warning that it
can emit if the core file is older than the executable.  I've made
sure that the test covers this warning too.

Approved-By: Tom Tromey <tom@tromey.com>
gdb/corelow.c
gdb/testsuite/gdb.base/corefile-exec-mismatch.c [new file with mode: 0644]
gdb/testsuite/gdb.base/corefile-exec-mismatch.exp [new file with mode: 0644]

index 8f7a07b516320f2ed476229788c5efc7b79ff238..65a672bbaa30eb3bc9ffdbffcaaaa064831e0829 100644 (file)
@@ -1055,10 +1055,12 @@ core_target_open (const char *arg, int from_tty)
   /* Own the target until it is successfully pushed.  */
   target_ops_up target_holder (target);
 
-  validate_files ();
-
   current_inferior ()->push_target (std::move (target_holder));
 
+  /* Validate files after pushing the core_target, this allows the
+     validate_files function to see the newly loaded core file.  */
+  validate_files ();
+
   switch_to_no_thread ();
 
   /* Need to flush the register cache (and the frame cache) from a
diff --git a/gdb/testsuite/gdb.base/corefile-exec-mismatch.c b/gdb/testsuite/gdb.base/corefile-exec-mismatch.c
new file mode 100644 (file)
index 0000000..a52b2a3
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2025 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 <stdlib.h>
+
+#ifdef GEN_CORE
+static int
+crashfunc (void)
+{
+  abort ();
+  return 0;
+}
+#endif
+
+int
+main (void)
+{
+#ifdef GEN_CORE
+  int ret = crashfunc ();
+#else
+  int ret = 0;
+#endif
+  return ret;
+}
diff --git a/gdb/testsuite/gdb.base/corefile-exec-mismatch.exp b/gdb/testsuite/gdb.base/corefile-exec-mismatch.exp
new file mode 100644 (file)
index 0000000..dbd652d
--- /dev/null
@@ -0,0 +1,188 @@
+# Copyright 2025 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/>.
+
+# Test that when loading a core file, if the current executable
+# doesn't match the expected executable for this core file, then GDB
+# should give a warning.
+#
+# We only check the build-id based verification as the name only based
+# verification relies on the name held in the PRPSINFO note, which is
+# only 80 characters long, as a result, when running the testsuite,
+# this string usually only holds the path to the testsuite build
+# directory, which might be the same for every core file created.
+#
+# In addition, as the check is in a similar area of GDB, we check that
+# if the executable is newer than the core file, GDB gives a warning.
+
+# The core file management in this script only works if the host
+# machine is local.
+require {!is_remote host}
+
+standard_testfile .c
+
+# Build an executable with a build id.
+if { [build_executable "build" $testfile $srcfile \
+         { debug build-id additional_flags=-DGEN_CORE } ] } {
+    return
+}
+
+# Build an alternative executable.  This is different than
+# TESTFILE, and so has a different build-id.
+set alt_testfile "alt-with-build-id"
+set alt_binfile [standard_output_file $alt_testfile]
+if { [build_executable "build" $alt_testfile $srcfile \
+         { debug build-id } ] } {
+    return
+}
+
+# Do we expect the build-id for BINFILE to appear in a core file
+# generated from BINFILE?  If not then this test isn't going to
+# work.
+if { ![expect_build_id_in_core_file $binfile] } {
+    unsupported "build-id will not appear in core file"
+    return
+}
+
+# Create a core file by running BINFILE.
+set corefile [core_find $binfile {}]
+if {$corefile == ""} {
+    untested "unable to create corefile"
+    return
+}
+
+# Start GDB using a completely different executable (than was used
+# to generate the core file); this has a different filename and
+# build-id.
+clean_restart $alt_testfile
+
+# Load the core file.  GDB should warn because the build-id of the
+# executable doesn't match the expected build-id pulled from the
+# core file.
+set saw_mismatch_warning false
+gdb_test_multiple "core $corefile" "load core file, different exec name" {
+    -re "^core \[^\r\n\]+\r\n" {
+       exp_continue
+    }
+    -re "^warning: core file may not match specified executable file\\.\r\n" {
+       set saw_mismatch_warning true
+       exp_continue
+    }
+    -re "^$gdb_prompt $" {
+       gdb_assert { $saw_mismatch_warning } $gdb_test_name
+    }
+    -re "^\[^\r\n\]*\r\n" {
+       exp_continue
+    }
+}
+
+# Cleanup before the next test.
+unset saw_mismatch_warning
+gdb_exit
+
+# Touch TESTFILE (via its full filename) so that it is newer than
+# the core file.
+sleep 1
+remote_exec host "touch ${binfile}"
+
+# Start GDB using the correct executable, but this file is newer than
+# the core file, we expect GDB to warn about this.
+clean_restart $testfile
+
+# Load the core file.  GDB should warn that the executable is
+# newer than the core file.
+#
+# NOTE: In this case the build-ids match, so maybe GDB should
+# ignore the fact that the core file is older than the executable?
+# If we every make that change to GDB, and this test starts to
+# fail, then the test should be updated to build executables
+# without build-ids so that this warning is still tested.
+#
+# The reason I didn't do this initially is that, if there are any
+# build-ids in the core file, from any shared library at all, then
+# GDB will use this as "the" build-id for the core file, and
+# compare this to the build-id of the executable.  I say GDB here,
+# but some of this logic is in BFD.  Anyway, if GDB thinks that
+# the core file has a build-id, but the executable doesn't, then
+# GDB gives the generic "core file may not match specified
+# executable file" warning instead of the "exec file is newer than
+# core file" warning, which is what we want.
+#
+# For now then, I just check for the age based warning when we
+# also have full build-ids.
+set saw_age_warning false
+gdb_test_multiple "core $corefile" "load core file, exec is newer" {
+    -re "^core \[^\r\n\]+\r\n" {
+       exp_continue
+    }
+    -re "^warning: exec file is newer than core file\\.\r\n" {
+       set saw_age_warning true
+       exp_continue
+    }
+    -re "^$gdb_prompt $" {
+       gdb_assert { $saw_age_warning } $gdb_test_name
+    }
+    -re "^\[^\r\n\]*\r\n" {
+       exp_continue
+    }
+}
+
+# Cleanup before the next test.
+unset saw_age_warning
+gdb_exit
+
+# Replace BINFILE with ALT_BINFILE, a file with a different
+# build-id.
+remote_exec host "mv $binfile ${binfile}-hidden"
+remote_exec host "cp $alt_binfile $binfile"
+
+# Ensure COREFILE is newer than BINFILE.
+sleep 1
+remote_exec host "touch ${corefile}"
+
+# Start GDB using the filename that now points to the replacement
+# file.
+clean_restart $testfile
+
+# Load the core file.  GDB should use the build-id to warn the
+# user that the executable doesn't match the core file.  We'll
+# also get a warning that the build-id of the executable doesn't
+# match while processing the mapped file information in the core
+# file.
+set saw_mismatch_warning false
+set saw_build_id_warning false
+gdb_test_multiple "core $corefile" "load core file, same exec name" {
+    -re "^core \[^\r\n\]+\r\n" {
+       exp_continue
+    }
+    -re "^warning: File [string_to_regexp $binfile] doesn't match build-id from core-file during file-backed mapping processing" {
+       set saw_build_id_warning true
+       exp_continue
+    }
+    -re "^warning: core file may not match specified executable file\\.\r\n" {
+       set saw_mismatch_warning true
+       exp_continue
+    }
+    -re "^$gdb_prompt $" {
+       gdb_assert { $saw_mismatch_warning \
+                        && $saw_build_id_warning } $gdb_test_name
+    }
+    -re "^\[^\r\n\]*\r\n" {
+       exp_continue
+    }
+}
+
+unset saw_mismatch_warning
+unset saw_build_id_warning
+gdb_exit