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 <simon.marchi@efficios.com>
This commit is contained in:
Andrew Burgess
2025-06-02 14:58:51 +01:00
parent 4b42385c47
commit d462550c91
4 changed files with 126 additions and 48 deletions

View File

@@ -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

View File

@@ -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

View 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(execd-prog)...\n");
printf ("foll-exec is about to execlp(%s)...\n", EXECD_PROG);
strcpy (prog, argv[0]);
len = strlen (prog);
/* Replace "foll-exec" with "execd-prog". */
memcpy (prog + len - 9, "execd-prog", 10);
prog[len + 1] = 0;
prog [len] = '\0';
strncpy (prog, dirname (argv[0]), len);
len -= strlen (prog);
assert (len > 0);
strncat (prog, "/", len);
len -= 1;
assert (len > 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 */
}

View 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}]
set compile_options debug
# build the first test case
if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable $compile_options] != "" } {
untested "failed to compile"
return -1
}
if { [is_remote target] } {
gdb_remote_download target $binfile2
}
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $compile_options] != "" } {
untested "failed to compile"
return -1
}
proc do_exec_tests {} {
global binfile srcfile srcfile2 testfile 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
# 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]
set execee_flags debug
if { $execee_lang == "c++" } {
lappend execee_flags "c++"
}
if { [build_executable "failed to build $execee_testfile" $execee_testfile \
$srcfile2 $execee_flags] == -1 } {
return
}
if { [is_remote target] } {
gdb_remote_download target $execee_binfile
}
# 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
}