]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb/testsuite: also compile foll-exec.exp as C++
authorAndrew Burgess <aburgess@redhat.com>
Mon, 2 Jun 2025 13:58:51 +0000 (14:58 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 3 Jun 2025 18:58:44 +0000 (19:58 +0100)
For a long time, Fedora GDB has carried a test that performs some
basic testing that GDB can handle 'catch exec' related commands for a
C++ executable.

The exact motivation for this test has been lost in the mists of time,
but looking at the test script, the concern seems to be that GDB would
have problems inserting C++ related internal breakpoints if a non C++
process is execd from a C++ one.

There's no actual GDB fix associated with the Fedora test.  This
usually means that the issue was fixed upstream long ago.  This patch
does seem to date from around 2010ish (or maybe earlier).

Having a look through the upstream tests, I cannot see anything that
covers this sort of thing (C++ to C exec calls), and I figure it
cannot hurt to have some additional testing in this area, and so I
wrote this patch.

I've taken the existing foll-exec.exp test, which compiles a C
executable and then execs a different C executable, and split it into
two copies.

We now have foll-exec-c.exp and foll-exec-c++.exp.  These tests
compile a C and C++ executable respectively.  Then within each of
these scripts both a C and C++ helper application is built, which can
then be execd from the main test executable.

And so, we now cover 4 cases, the initial executable can be C or C++,
and the execd process can be C or C++.

As expected, everything passes.  This is just increasing test
coverage.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
gdb/testsuite/gdb.base/foll-exec-c++.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/foll-exec-c.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/foll-exec.c
gdb/testsuite/gdb.base/foll-exec.exp.tcl [moved from gdb/testsuite/gdb.base/foll-exec.exp with 83% similarity]

diff --git a/gdb/testsuite/gdb.base/foll-exec-c++.exp b/gdb/testsuite/gdb.base/foll-exec-c++.exp
new file mode 100644 (file)
index 0000000..d96310b
--- /dev/null
@@ -0,0 +1,24 @@
+# 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/>.
+
+# This file is part of the gdb testsuite
+
+# See foll-exec.exp.tcl for test details.  This file runs the test
+# using the C++ compiler.
+
+require allow_cplus_tests
+set lang c++
+
+source $srcdir/$subdir/foll-exec.exp.tcl
diff --git a/gdb/testsuite/gdb.base/foll-exec-c.exp b/gdb/testsuite/gdb.base/foll-exec-c.exp
new file mode 100644 (file)
index 0000000..67f62cc
--- /dev/null
@@ -0,0 +1,23 @@
+# 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/>.
+
+# This file is part of the gdb testsuite
+
+# See foll-exec.exp.tcl for test details.  This file runs the test
+# using the C compiler.
+
+set lang c
+
+source $srcdir/$subdir/foll-exec.exp.tcl
index a1c9b70b6d61270b1eee2921d5797bc576216ef3..548f045c789f4c080f4c318898884638981c1397 100644 (file)
@@ -19,7 +19,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-
+#include <libgen.h>
+#include <assert.h>
 #include <limits.h>
 
 int global_i = 100;
@@ -29,15 +30,23 @@ int main (int argc, char ** argv)
   int local_j = global_i + 1;
   int local_k = local_j + 1;
   char prog[PATH_MAX];
-  int len;
+  size_t len = PATH_MAX - 1;
+
+  printf ("foll-exec is about to execlp(%s)...\n", EXECD_PROG);
+
+  prog [len] = '\0';
+
+  strncpy (prog, dirname (argv[0]), len);
+  len -= strlen (prog);
+  assert (len > 0);
 
-  printf ("foll-exec is about to execlp(execd-prog)...\n");
+  strncat (prog, "/", len);
+  len -= 1;
+  assert (len > 0);
 
-  strcpy (prog, argv[0]);
-  len = strlen (prog);
-  /* Replace "foll-exec" with "execd-prog".  */
-  memcpy (prog + len - 9, "execd-prog", 10);
-  prog[len + 1] = 0;
+  strncat (prog, EXECD_PROG, len);
+  len -= strlen (EXECD_PROG);
+  assert (len > 0);
 
   /* In the following function call, maximum line length exceed the limit 80.
      This is intentional and required for clang compiler such that complete
@@ -45,7 +54,7 @@ int main (int argc, char ** argv)
      multi-line.  */
   execlp (prog, /* tbreak-execlp */ prog, "execlp arg1 from foll-exec", (char *) 0);
 
-  printf ("foll-exec is about to execl(execd-prog)...\n");
+  printf ("foll-exec is about to execl(%s)...\n", EXECD_PROG);
 
   /* In the following function call, maximum line length exceed the limit 80.
      This is intentional and required for clang compiler such that complete
@@ -61,7 +70,7 @@ int main (int argc, char ** argv)
 
     argv[0] = prog;
 
-    printf ("foll-exec is about to execv(execd-prog)...\n");
+    printf ("foll-exec is about to execv(%s)...\n", EXECD_PROG);
 
     execv (prog, argv); /* tbreak-execv */
   }
similarity index 83%
rename from gdb/testsuite/gdb.base/foll-exec.exp
rename to gdb/testsuite/gdb.base/foll-exec.exp.tcl
index ad4c3516576c53f112fe123162edeefb091b3c1f..8f96a55fda468ac0926f2c5dc1b9364cb12e8f6b 100644 (file)
@@ -22,33 +22,55 @@ require {istarget "*-linux*"}
 
 standard_testfile foll-exec.c
 
-set testfile2 "execd-prog"
-set srcfile2 ${testfile2}.c
-set binfile2 [standard_output_file ${testfile2}]
+# Compile a program that performs an exec as EXECER_LANG, and a
+# program that will be exec'd as EXECEE_LANG.  Either language can be
+# 'c' or 'c++'.  Then run various test associated with 'catch exec'
+# using the compiled programs.
+proc do_exec_tests { execer_lang execee_lang } {
+   global srcfile testfile
+   global gdb_prompt
 
-set compile_options debug
+   # First compile the program to be exec'd, the execee.
+   set execee_base_filename "execd-prog"
+   set srcfile2 ${execee_base_filename}.c
+   set execee_testfile "execd-prog-${execee_lang}"
+   set execee_testfile_re [string_to_regexp $execee_testfile]
+   set execee_binfile [standard_output_file $execee_testfile]
 
-# build the first test case
-if  { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable $compile_options] != "" } {
-     untested "failed to compile"
-     return -1
-}
+   set execee_flags debug
+   if { $execee_lang == "c++" } {
+       lappend execee_flags "c++"
+   }
 
-if { [is_remote target] } {
-    gdb_remote_download target $binfile2
-}
+   if { [build_executable "failed to build $execee_testfile" $execee_testfile \
+            $srcfile2 $execee_flags] == -1 } {
+       return
+   }
 
-if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $compile_options] != "" } {
-     untested "failed to compile"
-     return -1
-}
+   if { [is_remote target] } {
+       gdb_remote_download target $execee_binfile
+   }
 
-proc do_exec_tests {} {
-   global binfile srcfile srcfile2 testfile testfile2
-   global gdb_prompt
+
+   # Now compile the program to do the exec, the execer.
+   set execer_testfile "$testfile-${execee_lang}"
+   set execer_binfile [standard_output_file $execer_testfile]
+
+   set execer_flags debug
+   if { $execer_lang == "c++" } {
+       lappend execer_flags "c++"
+   }
+   lappend execer_flags "additional_flags=-DEXECD_PROG=\"${execee_testfile}\""
+
+   if { [build_executable "failed to build $execer_testfile" $execer_testfile \
+            $srcfile $execer_flags] == -1 } {
+       return
+   }
+
+   # Now we can start running the tests.
+   clean_restart $execer_binfile
 
    # Start the program running, and stop at main.
-   #
    if {![runto_main]} {
      return
    }
@@ -71,7 +93,7 @@ proc do_exec_tests {} {
      return
    }
 
-   clean_restart $binfile
+   clean_restart $execer_binfile
 
    # Start the program running, and stop at main.
    #
@@ -120,7 +142,7 @@ proc do_exec_tests {} {
    set execd_line [gdb_get_line_number "after-exec" $srcfile2]
    send_gdb "next\n"
    gdb_expect {
-     -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
+     -re ".*xecuting new program: .*${execee_testfile_re}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
                      {pass "step through execlp call"}
      -re "$gdb_prompt $" {fail "step through execlp call"}
      timeout         {fail "(timeout) step through execlp call"}
@@ -160,7 +182,7 @@ proc do_exec_tests {} {
 
    # Explicitly kill this program, or a subsequent rerun actually runs
    # the exec'd program, not the original program...
-   clean_restart $binfile
+   clean_restart $execer_binfile
 
    # Start the program running, and stop at main.
    #
@@ -193,7 +215,7 @@ proc do_exec_tests {} {
 
    send_gdb "continue\n"
    gdb_expect {
-     -re ".*xecuting new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*$gdb_prompt $"\
+     -re ".*xecuting new program:.*${execee_testfile_re}.*Catchpoint .*(exec\'d .*${execee_testfile_re}).*$gdb_prompt $"\
                      {pass "hit catch exec"}
      -re "$gdb_prompt $" {fail "hit catch exec"}
      timeout         {fail "(timeout) hit catch exec"}
@@ -210,7 +232,7 @@ proc do_exec_tests {} {
    #
    set msg "info shows catchpoint exec pathname"
    gdb_test_multiple "info breakpoints" $msg {
-       -re ".*catchpoint.*keep y.*exec, program \".*${testfile2}\".*$gdb_prompt $" {
+       -re ".*catchpoint.*keep y.*exec, program \".*${execee_testfile_re}\".*$gdb_prompt $" {
            pass $msg
        }
    }
@@ -228,7 +250,7 @@ proc do_exec_tests {} {
 
    # Explicitly kill this program, or a subsequent rerun actually runs
    # the exec'd program, not the original program...
-   clean_restart $binfile
+   clean_restart $execer_binfile
 
    # Start the program running, and stop at main.
    #
@@ -269,7 +291,7 @@ proc do_exec_tests {} {
    #
    send_gdb "next 2\n"
    gdb_expect {
-     -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
+     -re ".*xecuting new program: .*${execee_testfile_re}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
                      {pass "step through execl call"}
      -re "$gdb_prompt $" {fail "step through execl call"}
      timeout         {fail "(timeout) step through execl call"}
@@ -295,7 +317,7 @@ proc do_exec_tests {} {
 
    # Explicitly kill this program, or a subsequent rerun actually runs
    # the exec'd program, not the original program...
-   clean_restart $binfile
+   clean_restart $execer_binfile
 
    # Start the program running, and stop at main.
    #
@@ -330,7 +352,7 @@ proc do_exec_tests {} {
    }
    send_gdb "next\n"
    gdb_expect {
-     -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
+     -re ".*xecuting new program: .*${execee_testfile_re}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
                      {pass "step through execv call"}
      -re "$gdb_prompt $" {fail "step through execv call"}
      timeout         {fail "(timeout) step through execv call"}
@@ -356,7 +378,7 @@ proc do_exec_tests {} {
 
    # Explicitly kill this program, or a subsequent rerun actually runs
    # the exec'd program, not the original program...
-   clean_restart $binfile
+   clean_restart $execer_binfile
 
    # Start the program running, and stop at main.
    #
@@ -370,13 +392,13 @@ proc do_exec_tests {} {
    #
    send_gdb "continue\n"
    gdb_expect {
-     -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
+     -re ".*xecuting new program: .*${execee_testfile_re}.*${srcfile2}:${execd_line}.*int  local_j = argc;.*$gdb_prompt $"\
                      {pass "continue through exec"}
      -re "$gdb_prompt $" {fail "continue through exec"}
      timeout         {fail "(timeout) continue through exec"}
    }
 }
 
-clean_restart $binfile
-
-do_exec_tests
+foreach_with_prefix execee_lang { c c++ } {
+    do_exec_tests $lang $execee_lang
+}