From d462550c91cfd5293bcc47610454a381ab5825e3 Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Mon, 2 Jun 2025 14:58:51 +0100 Subject: [PATCH] gdb/testsuite: also compile foll-exec.exp as C++ 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 --- gdb/testsuite/gdb.base/foll-exec-c++.exp | 24 +++++ gdb/testsuite/gdb.base/foll-exec-c.exp | 23 +++++ gdb/testsuite/gdb.base/foll-exec.c | 29 +++--- .../{foll-exec.exp => foll-exec.exp.tcl} | 90 ++++++++++++------- 4 files changed, 122 insertions(+), 44 deletions(-) create mode 100644 gdb/testsuite/gdb.base/foll-exec-c++.exp create mode 100644 gdb/testsuite/gdb.base/foll-exec-c.exp rename gdb/testsuite/gdb.base/{foll-exec.exp => foll-exec.exp.tcl} (83%) diff --git a/gdb/testsuite/gdb.base/foll-exec-c++.exp b/gdb/testsuite/gdb.base/foll-exec-c++.exp new file mode 100644 index 00000000000..d96310bc55f --- /dev/null +++ b/gdb/testsuite/gdb.base/foll-exec-c++.exp @@ -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 . + +# 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 index 00000000000..67f62ccd786 --- /dev/null +++ b/gdb/testsuite/gdb.base/foll-exec-c.exp @@ -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 . + +# 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 diff --git a/gdb/testsuite/gdb.base/foll-exec.c b/gdb/testsuite/gdb.base/foll-exec.c index a1c9b70b6d6..548f045c789 100644 --- a/gdb/testsuite/gdb.base/foll-exec.c +++ b/gdb/testsuite/gdb.base/foll-exec.c @@ -19,7 +19,8 @@ #include #include #include - +#include +#include #include 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 */ } diff --git a/gdb/testsuite/gdb.base/foll-exec.exp b/gdb/testsuite/gdb.base/foll-exec.exp.tcl similarity index 83% rename from gdb/testsuite/gdb.base/foll-exec.exp rename to gdb/testsuite/gdb.base/foll-exec.exp.tcl index ad4c3516576..8f96a55fda4 100644 --- a/gdb/testsuite/gdb.base/foll-exec.exp +++ b/gdb/testsuite/gdb.base/foll-exec.exp.tcl @@ -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 +} -- 2.39.5