diff options
Diffstat (limited to 'gdb/testsuite/gdb.threads')
-rw-r--r-- | gdb/testsuite/gdb.threads/step-over-exec-execd.c | 30 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/step-over-exec.c | 90 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/step-over-exec.exp | 113 |
3 files changed, 233 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.threads/step-over-exec-execd.c b/gdb/testsuite/gdb.threads/step-over-exec-execd.c new file mode 100644 index 0000000..5f3835c --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-exec-execd.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020 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/>. */ + +int a_variable_in_execd = 1212; + +static void +foo (void) +{ +} + +int +main (void) +{ + foo (); + return a_variable_in_execd; +} diff --git a/gdb/testsuite/gdb.threads/step-over-exec.c b/gdb/testsuite/gdb.threads/step-over-exec.c new file mode 100644 index 0000000..a043e8d --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-exec.c @@ -0,0 +1,90 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020 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 <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#include "../lib/my-syscalls.h" + +#if (!defined(LEADER_DOES_EXEC) && !defined(OTHER_DOES_EXEC) \ + || defined(LEADER_DOES_EXEC) && defined(OTHER_DOES_EXEC)) +# error "Exactly one of LEADER_DOES_EXEC and OTHER_DOES_EXEC must be defined." +#endif + + +static char *argv0; +static pthread_barrier_t barrier; + +static void +do_the_exec (void) +{ + char *execd_path = (char *) malloc (strlen (argv0) + sizeof ("-execd")); + sprintf (execd_path, "%s-execd", argv0); + char *argv[] = { execd_path, NULL }; + + printf ("Exec-ing %s\n", execd_path); + + extern char **environ; + my_execve (execd_path, argv, environ); + + printf ("Exec failed :(\n"); + abort (); +} + +static void * +thread_func (void *arg) +{ + pthread_barrier_wait (&barrier); +#ifdef OTHER_DOES_EXEC + printf ("Other going in exec.\n"); + do_the_exec (); +#endif + + /* Just make sure the thread does not exit when the leader does the exec. */ + pthread_barrier_wait (&barrier); + + return NULL; +} + +int +main (int argc, char *argv[]) +{ + argv0 = argv[0]; + + int ret = pthread_barrier_init (&barrier, NULL, 2); + if (ret != 0) + abort (); + + pthread_t thread; + ret = pthread_create (&thread, NULL, thread_func, argv[0]); + if (ret != 0) + abort (); + + pthread_barrier_wait (&barrier); + +#ifdef LEADER_DOES_EXEC + printf ("Leader going in exec.\n"); + do_the_exec (); +#endif + + pthread_join (thread, NULL); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/step-over-exec.exp b/gdb/testsuite/gdb.threads/step-over-exec.exp new file mode 100644 index 0000000..411980c --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-over-exec.exp @@ -0,0 +1,113 @@ +# Copyright 2020 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 stepping over an exec syscall instruction in a multi-threaded program. + +standard_testfile .c -execd.c + +set syscalls_src $srcdir/lib/my-syscalls.S + +# EXECR_THREAD is "leader" or "other", and decides which thread does the exec. +# +# If DIFFERENT_TEXT_SEGMENTS is true, the exec'er and exec'd program are +# compiled with different, explicit text segment addresses. This makes it so +# the address of the displaced stepping buffer in the old executable is likely +# not accessible in the new executable. This might catch cases where GDB tries +# (wrongfully) to restore the bytes saved from the old executable in the new +# executable. +# +# DISPLACED_STEPPING is "auto" or "off" and controls the value of "set +# displaced-stepping". + +proc do_test { execr_thread different_text_segments displaced_stepping } { + global srcdir subdir srcfile srcfile2 binfile + global syscalls_src + global decimal hex + + set execr_srcs [list $srcdir/$subdir/$srcfile $syscalls_src] + set execd_srcs [list $srcdir/$subdir/$srcfile2] + + # Generate unique filenames for each case. + set execr_binfile $binfile-execr-thread-$execr_thread-diff-text-segs-$different_text_segments + set execd_binfile $execr_binfile-execd + + set execr_opts [list debug] + set execd_opts [list debug] + + if { $different_text_segments } { + lappend execr_opts "ldflags=-Wl,-Ttext-segment=0x600000" + lappend execd_opts "ldflags=-Wl,-Ttext-segment=0x800000" + } + + if { $execr_thread == "leader" } { + lappend execr_opts "additional_flags=-DLEADER_DOES_EXEC" + } elseif { $execr_thread == "other" } { + lappend execr_opts "additional_flags=-DOTHER_DOES_EXEC" + } else { + error "Invalid execr_thread value: $execr_thread." + } + + # Compile execr binary (the one that does the exec). + if {[gdb_compile_pthreads $execr_srcs $execr_binfile executable $execr_opts] != "" } { + return -1 + } + + # Compile the second binary (the one that gets exec'd). + if {[gdb_compile $execd_srcs $execd_binfile executable $execd_opts] != "" } { + return -1 + } + + clean_restart ${execr_binfile} + + gdb_test_no_output "set displaced-stepping $displaced_stepping" + + if ![runto_main] { + return + } + + # Leave breakpoint main inserted, we expect to hit it after exec. + + # This breakpoint will be stepped by whatever thread does the exec. + gdb_test "break my_execve_syscall if 0" "Breakpoint $decimal at $hex.*" + + # Continue across exec to main. + if { [target_is_gdbserver] } { + setup_kfail gdb/27020 "*-*-*" + } + set failed [gdb_test "continue" \ + "process $decimal is executing new program: .* hit Breakpoint $decimal, main .*" \ + "continue across exec"] + if { $failed } { + return + } + + # Just to confirm we are indeed in the execd program. + gdb_test "print a_variable_in_execd" " = 1212" + + # Continue execution to make sure we can step over the breakpoint on main. + # It would be nice to use gdb_continue_to_end to ensure the program can + # exit properly, but it hangs due to PR gdb/26995. + gdb_breakpoint foo + gdb_test "continue" "Breakpoint $decimal, foo .*" \ + "continue to foo" +} + +foreach_with_prefix displaced_stepping {auto off} { + foreach_with_prefix different_text_segments {true false} { + foreach_with_prefix execr_thread {leader other} { + do_test $execr_thread $different_text_segments $displaced_stepping + } + } +} |