ChangeLog:

* infrun.c (handle_inferior_event): Handle presence of single-step
	breakpoints for TARGET_WAITKIND_FORKED and TARGET_WAITKIND_VFORKED.
	Cancel single-step breakpoints for TARGET_WAITKIND_EXITED,
	TARGET_WAITKIND_SIGNALED, and TARGET_WAITKIND_EXECD.
	* breakpoint.c (detach_single_step_breakpoints): New function.
	(detach_breakpoints): Call it.
	(cancel_single_step_breakpoints): New function.
	* breakpoint.h (cancel_single_step_breakpoints): Add prototype.

	* spu-tdep.c (spu_memory_remove_breakpoint): New function.
	(spu_gdbarch_init): Install it.

testsuite/ChangeLog:

	* gdb.cell/fork.exp: New file.
	* gdb.cell/fork.c: Likewise.
	* gdb.cell/fork-spu.c: Likewise.
This commit is contained in:
Ulrich Weigand 2010-06-23 12:46:37 +00:00
parent 61e8a5ea17
commit d03285ec7b
9 changed files with 315 additions and 0 deletions

View File

@ -1,3 +1,17 @@
2010-06-23 Ulrich Weigand <uweigand@de.ibm.com>
* infrun.c (handle_inferior_event): Handle presence of single-step
breakpoints for TARGET_WAITKIND_FORKED and TARGET_WAITKIND_VFORKED.
Cancel single-step breakpoints for TARGET_WAITKIND_EXITED,
TARGET_WAITKIND_SIGNALED, and TARGET_WAITKIND_EXECD.
* breakpoint.c (detach_single_step_breakpoints): New function.
(detach_breakpoints): Call it.
(cancel_single_step_breakpoints): New function.
* breakpoint.h (cancel_single_step_breakpoints): Add prototype.
* spu-tdep.c (spu_memory_remove_breakpoint): New function.
(spu_gdbarch_init): Install it.
2010-06-23 Jan Kratochvil <jan.kratochvil@redhat.com>
* configure.ac: Always set RDYNAMIC at least as `-rdynamic'.

View File

@ -196,6 +196,8 @@ static void tcatch_command (char *arg, int from_tty);
static void ep_skip_leading_whitespace (char **s);
static void detach_single_step_breakpoints (void);
static int single_step_breakpoint_inserted_here_p (struct address_space *,
CORE_ADDR pc);
@ -2383,6 +2385,10 @@ detach_breakpoints (int pid)
if (b->inserted)
val |= remove_breakpoint_1 (b, mark_inserted);
}
/* Detach single-step breakpoints as well. */
detach_single_step_breakpoints ();
do_cleanups (old_chain);
return val;
}
@ -10491,6 +10497,39 @@ remove_single_step_breakpoints (void)
}
}
/* Delete software single step breakpoints without removing them from
the inferior. This is intended to be used if the inferior's address
space where they were inserted is already gone, e.g. after exit or
exec. */
void
cancel_single_step_breakpoints (void)
{
int i;
for (i = 0; i < 2; i++)
if (single_step_breakpoints[i])
{
xfree (single_step_breakpoints[i]);
single_step_breakpoints[i] = NULL;
single_step_gdbarch[i] = NULL;
}
}
/* Detach software single-step breakpoints from INFERIOR_PTID without
removing them. */
static void
detach_single_step_breakpoints (void)
{
int i;
for (i = 0; i < 2; i++)
if (single_step_breakpoints[i])
target_remove_breakpoint (single_step_gdbarch[i],
single_step_breakpoints[i]);
}
/* Check whether a software single-step breakpoint is inserted at PC. */
static int

View File

@ -985,6 +985,7 @@ extern int remove_hw_watchpoints (void);
extern void insert_single_step_breakpoint (struct gdbarch *,
struct address_space *, CORE_ADDR);
extern void remove_single_step_breakpoints (void);
extern void cancel_single_step_breakpoints (void);
/* Manage manual breakpoints, separate from the normal chain of
breakpoints. These functions are used in murky target-specific

View File

@ -3165,6 +3165,7 @@ handle_inferior_event (struct execution_control_state *ecs)
gdb_flush (gdb_stdout);
target_mourn_inferior ();
singlestep_breakpoints_inserted_p = 0;
cancel_single_step_breakpoints ();
stop_print_frame = 0;
stop_stepping (ecs);
return;
@ -3188,6 +3189,7 @@ handle_inferior_event (struct execution_control_state *ecs)
print_stop_reason (SIGNAL_EXITED, ecs->ws.value.sig);
singlestep_breakpoints_inserted_p = 0;
cancel_single_step_breakpoints ();
stop_stepping (ecs);
return;
@ -3225,6 +3227,13 @@ handle_inferior_event (struct execution_control_state *ecs)
detach_breakpoints (child_pid);
}
if (singlestep_breakpoints_inserted_p)
{
/* Pull the single step breakpoints out of the target. */
remove_single_step_breakpoints ();
singlestep_breakpoints_inserted_p = 0;
}
/* In case the event is caught by a catchpoint, remember that
the event is to be followed at the next resume of the thread,
and not immediately. */
@ -3314,6 +3323,9 @@ handle_inferior_event (struct execution_control_state *ecs)
reinit_frame_cache ();
}
singlestep_breakpoints_inserted_p = 0;
cancel_single_step_breakpoints ();
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
/* Do whatever is necessary to the parent branch of the vfork. */

View File

@ -1494,6 +1494,39 @@ spu_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr, int *lenptr)
return breakpoint;
}
static int
spu_memory_remove_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
/* We work around a problem in combined Cell/B.E. debugging here. Consider
that in a combined application, we have some breakpoints inserted in SPU
code, and now the application forks (on the PPU side). GDB common code
will assume that the fork system call copied all breakpoints into the new
process' address space, and that all those copies now need to be removed
(see breakpoint.c:detach_breakpoints).
While this is certainly true for PPU side breakpoints, it is not true
for SPU side breakpoints. fork will clone the SPU context file
descriptors, so that all the existing SPU contexts are in accessible
in the new process. However, the contents of the SPU contexts themselves
are *not* cloned. Therefore the effect of detach_breakpoints is to
remove SPU breakpoints from the *original* SPU context's local store
-- this is not the correct behaviour.
The workaround is to check whether the PID we are asked to remove this
breakpoint from (i.e. ptid_get_pid (inferior_ptid)) is different from the
PID of the current inferior (i.e. current_inferior ()->pid). This is only
true in the context of detach_breakpoints. If so, we simply do nothing.
[ Note that for the fork child process, it does not matter if breakpoints
remain inserted, because those SPU contexts are not runnable anyway --
the Linux kernel allows only the original process to invoke spu_run. */
if (ptid_get_pid (inferior_ptid) != current_inferior ()->pid)
return 0;
return default_memory_remove_breakpoint (gdbarch, bp_tgt);
}
/* Software single-stepping support. */
@ -2638,6 +2671,7 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Breakpoints. */
set_gdbarch_decr_pc_after_break (gdbarch, 4);
set_gdbarch_breakpoint_from_pc (gdbarch, spu_breakpoint_from_pc);
set_gdbarch_memory_remove_breakpoint (gdbarch, spu_memory_remove_breakpoint);
set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
set_gdbarch_software_single_step (gdbarch, spu_software_single_step);
set_gdbarch_get_longjmp_target (gdbarch, spu_get_longjmp_target);

View File

@ -1,3 +1,9 @@
2010-06-23 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* gdb.cell/fork.exp: New file.
* gdb.cell/fork.c: Likewise.
* gdb.cell/fork-spu.c: Likewise.
2010-06-22 Pierre Muller <muller@ics.u-strasbg.fr>
* lib/gdb.exp (banned_variables_traced): New global variable.

View File

@ -0,0 +1,47 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2010 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/>.
Contributed by Ulrich Weigand <uweigand@de.ibm.com> */
#include <spu_mfcio.h>
int var;
void
func (void)
{
}
int
main (unsigned long long speid, unsigned long long argp,
unsigned long long envp)
{
/* Signal to PPU side that it should fork now. */
spu_write_out_intr_mbox (0);
/* Wait until fork completed. */
spu_read_in_mbox ();
/* Trigger watchpoint. */
var = 1;
/* Now call some function to trigger breakpoint. */
func ();
return 0;
}

View File

@ -0,0 +1,77 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2010 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/>.
Contributed by Ulrich Weigand <uweigand@de.ibm.com> */
#include <stdio.h>
#include <stdlib.h>
#include <libspe2.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern spe_program_handle_t fork_spu;
void *
spe_thread (void * arg)
{
int flags = 0;
unsigned int entry = SPE_DEFAULT_ENTRY;
spe_context_ptr_t *ctx = (spe_context_ptr_t *) arg;
spe_program_load (*ctx, &fork_spu);
spe_context_run (*ctx, &entry, flags, NULL, NULL, NULL);
pthread_exit (NULL);
}
int
main (void)
{
pthread_t pts;
spe_context_ptr_t ctx;
unsigned int value;
unsigned int pid;
ctx = spe_context_create (0, NULL);
pthread_create (&pts, NULL, &spe_thread, &ctx);
/* Wait until the SPU thread is running. */
spe_out_intr_mbox_read (ctx, &value, 1, SPE_MBOX_ALL_BLOCKING);
pid = fork ();
if (pid == 0)
{
/* This is the child. Just exit immediately. */
exit (0);
}
else
{
/* This is the parent. Wait for the child to exit. */
waitpid (pid, NULL, 0);
}
/* Tell SPU to continue. */
spe_in_mbox_write (ctx, &value, 1, SPE_MBOX_ALL_BLOCKING);
pthread_join (pts, NULL);
spe_context_destroy (ctx);
return 0;
}

View File

@ -0,0 +1,85 @@
# Copyright 2010 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/>.
#
# Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
#
# Testsuite for Cell Broadband Engine combined debugger
# This testcases tests support for PPU-side fork during SPU debugging
load_lib cell.exp
set testfile "fork"
set ppu_file "fork"
set ppu_src ${srcdir}/${subdir}/${ppu_file}.c
set ppu_bin ${objdir}/${subdir}/${ppu_file}
set spu_file "fork-spu"
set spu_src ${srcdir}/${subdir}/${spu_file}.c
set spu_bin ${objdir}/${subdir}/${spu_file}
if {[skip_cell_tests]} {
return 0
}
# Compile SPU binary.
if { [gdb_compile_cell_spu $spu_src $spu_bin executable {debug}] != "" } {
unsupported "Compiling spu binary failed."
return -1
}
# Compile PPU binary.
if { [gdb_cell_embedspu $spu_bin $spu_bin-embed.o {debug}] != "" } {
unsupported "Embedding spu binary failed."
return -1
}
if { [gdb_compile_cell_ppu [list $ppu_src $spu_bin-embed.o] $ppu_bin executable {debug}] != "" } {
unsupported "Compiling ppu binary failed."
return -1
}
if [get_compiler_info ${ppu_bin}] {
return -1
}
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${ppu_bin}
if ![runto_main] then {
fail "Can't run to main"
return 0
}
gdb_test_no_output "set spu stop-on-load" "set spu stop-on-load"
gdb_test "continue" "Continuing\\..*Temporary breakpoint \[0-9\]+, main \\(speid=.*, argp=.*, envp=.*\\) at .*$spu_file\\.c:.*spu_write_out_intr_mbox.*" \
"run until SPU main"
gdb_test "break func" "Breakpoint \[0-9\]+ at.* file .*$spu_file.c, line \[0-9\]+\\." "break func"
gdb_test "watch var" "Watchpoint \[0-9\]+: var" "watch var"
gdb_test "continue" "Continuing\\..*Watchpoint.*Old value = 0.*New value = 1.*" \
"run until watchpoint hit"
gdb_test_no_output "delete \$bpnum" "delete watchpoint"
gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, func \\(\\) at .*$spu_file.c:.*" \
"run until breakpoint hit"
gdb_test "continue" "Continuing\\..*Program exited normally.*" \
"run until end"
gdb_exit
return 0