PR c++/9593:
	* thread.c (clear_thread_inferior_resources): Call
	delete_longjmp_breakpoint.
	* infrun.c (handle_inferior_event): Handle exception breakpoints.
	(handle_inferior_event): Likewise.
	(insert_exception_resume_breakpoint): New function.
	(check_exception_resume): Likewise.
	* inferior.h (delete_longjmp_breakpoint_cleanup): Declare.
	* infcmd.c (delete_longjmp_breakpoint_cleanup): No longer static.
	(step_1): Set thread's initiating frame.
	(until_next_continuation): New function.
	(until_next_command): Support exception breakpoints.
	(finish_command_continuation): Delete longjmp breakpoint.
	(finish_forward): Support exception breakpoints.
	* gdbthread.h (struct thread_info) <initiating_frame>: New field.
	* breakpoint.h (enum bptype) <bp_exception, bp_exception_resume,
	bp_exception_master>: New constants.
	(struct bpstat_what) <is_longjmp>: New field.
	(set_longjmp_breakpoint): Update.
	* breakpoint.c (create_exception_master_breakpoint): New function.
	(update_breakpoints_after_exec): Handle bp_exception_master.  Call
	create_exception_master_breakpoint.
	(print_it_typical): Handle bp_exception_master, bp_exception.
	(bpstat_stop_status): Handle bp_exception_master.
	(bpstat_what): Handle bp_exception_master, bp_exception,
	bp_exception_resume.
	(bptype_string): Likewise.
	(print_one_breakpoint_location): Likewise.
	(allocate_bp_location): Likewise.
	(set_longjmp_breakpoint): Handle exception breakpoints.  Change
	interface.
	(delete_longjmp_breakpoint): Handle exception breakpoints.
	(mention): Likewise.
	(struct until_break_command_continuation_args) <thread_num>: New
	field.
	(until_break_command_continuation): Call
	delete_longjmp_breakpoint.
	(until_break_command): Support exception breakpoints.
	(delete_command): Likewise.
	(breakpoint_re_set_one): Likewise.
	(breakpoint_re_set): Likewise.
gdb/testuite
	* gdb.java/jnpe.java: New file.
	* gdb.java/jnpe.exp: New file.
	* gdb.cp/nextoverthrow.exp: New file.
	* gdb.cp/nextoverthrow.cc: New file.
This commit is contained in:
Tom Tromey
2010-12-09 16:09:54 +00:00
parent 8b9a522f57
commit 186c406b19
13 changed files with 868 additions and 28 deletions

View File

@ -1,3 +1,47 @@
2010-12-09 Tom Tromey <tromey@redhat.com>
PR c++/9593:
* thread.c (clear_thread_inferior_resources): Call
delete_longjmp_breakpoint.
* infrun.c (handle_inferior_event): Handle exception breakpoints.
(handle_inferior_event): Likewise.
(insert_exception_resume_breakpoint): New function.
(check_exception_resume): Likewise.
* inferior.h (delete_longjmp_breakpoint_cleanup): Declare.
* infcmd.c (delete_longjmp_breakpoint_cleanup): No longer static.
(step_1): Set thread's initiating frame.
(until_next_continuation): New function.
(until_next_command): Support exception breakpoints.
(finish_command_continuation): Delete longjmp breakpoint.
(finish_forward): Support exception breakpoints.
* gdbthread.h (struct thread_info) <initiating_frame>: New field.
* breakpoint.h (enum bptype) <bp_exception, bp_exception_resume,
bp_exception_master>: New constants.
(struct bpstat_what) <is_longjmp>: New field.
(set_longjmp_breakpoint): Update.
* breakpoint.c (create_exception_master_breakpoint): New function.
(update_breakpoints_after_exec): Handle bp_exception_master. Call
create_exception_master_breakpoint.
(print_it_typical): Handle bp_exception_master, bp_exception.
(bpstat_stop_status): Handle bp_exception_master.
(bpstat_what): Handle bp_exception_master, bp_exception,
bp_exception_resume.
(bptype_string): Likewise.
(print_one_breakpoint_location): Likewise.
(allocate_bp_location): Likewise.
(set_longjmp_breakpoint): Handle exception breakpoints. Change
interface.
(delete_longjmp_breakpoint): Handle exception breakpoints.
(mention): Likewise.
(struct until_break_command_continuation_args) <thread_num>: New
field.
(until_break_command_continuation): Call
delete_longjmp_breakpoint.
(until_break_command): Support exception breakpoints.
(delete_command): Likewise.
(breakpoint_re_set_one): Likewise.
(breakpoint_re_set): Likewise.
2010-12-08 Doug Evans <dje@google.com> 2010-12-08 Doug Evans <dje@google.com>
* gdbtypes.h (TYPE_IS_OPAQUE): Reformat. * gdbtypes.h (TYPE_IS_OPAQUE): Reformat.

View File

@ -2209,6 +2209,35 @@ create_std_terminate_master_breakpoint (const char *func_name)
do_cleanups (old_chain); do_cleanups (old_chain);
} }
/* Install a master breakpoint on the unwinder's debug hook. */
void
create_exception_master_breakpoint (void)
{
struct objfile *objfile;
ALL_OBJFILES (objfile)
{
struct minimal_symbol *debug_hook;
debug_hook = lookup_minimal_symbol ("_Unwind_DebugHook", NULL, objfile);
if (debug_hook != NULL)
{
struct breakpoint *b;
CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (debug_hook);
struct gdbarch *gdbarch = get_objfile_arch (objfile);
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
&current_target);
b = create_internal_breakpoint (gdbarch, addr, bp_exception_master);
b->addr_string = xstrdup ("_Unwind_DebugHook");
b->enable_state = bp_disabled;
}
}
update_global_location_list (1);
}
void void
update_breakpoints_after_exec (void) update_breakpoints_after_exec (void)
{ {
@ -2250,7 +2279,8 @@ update_breakpoints_after_exec (void)
/* Thread event breakpoints must be set anew after an exec(), /* Thread event breakpoints must be set anew after an exec(),
as must overlay event and longjmp master breakpoints. */ as must overlay event and longjmp master breakpoints. */
if (b->type == bp_thread_event || b->type == bp_overlay_event if (b->type == bp_thread_event || b->type == bp_overlay_event
|| b->type == bp_longjmp_master || b->type == bp_std_terminate_master) || b->type == bp_longjmp_master || b->type == bp_std_terminate_master
|| b->type == bp_exception_master)
{ {
delete_breakpoint (b); delete_breakpoint (b);
continue; continue;
@ -2265,7 +2295,8 @@ update_breakpoints_after_exec (void)
/* Longjmp and longjmp-resume breakpoints are also meaningless /* Longjmp and longjmp-resume breakpoints are also meaningless
after an exec. */ after an exec. */
if (b->type == bp_longjmp || b->type == bp_longjmp_resume) if (b->type == bp_longjmp || b->type == bp_longjmp_resume
|| b->type == bp_exception || b->type == bp_exception_resume)
{ {
delete_breakpoint (b); delete_breakpoint (b);
continue; continue;
@ -2327,6 +2358,7 @@ update_breakpoints_after_exec (void)
create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp");
create_std_terminate_master_breakpoint ("std::terminate()"); create_std_terminate_master_breakpoint ("std::terminate()");
create_exception_master_breakpoint ();
} }
int int
@ -3248,6 +3280,12 @@ print_it_typical (bpstat bs)
result = PRINT_NOTHING; result = PRINT_NOTHING;
break; break;
case bp_exception_master:
/* These should never be enabled. */
printf_filtered (_("Exception Master Breakpoint: gdb should not stop!\n"));
result = PRINT_NOTHING;
break;
case bp_watchpoint: case bp_watchpoint:
case bp_hardware_watchpoint: case bp_hardware_watchpoint:
annotate_watchpoint (b->number); annotate_watchpoint (b->number);
@ -3335,6 +3373,8 @@ print_it_typical (bpstat bs)
case bp_none: case bp_none:
case bp_longjmp: case bp_longjmp:
case bp_longjmp_resume: case bp_longjmp_resume:
case bp_exception:
case bp_exception_resume:
case bp_step_resume: case bp_step_resume:
case bp_watchpoint_scope: case bp_watchpoint_scope:
case bp_call_dummy: case bp_call_dummy:
@ -4121,7 +4161,8 @@ bpstat_stop_status (struct address_space *aspace,
if (b->type == bp_thread_event || b->type == bp_overlay_event if (b->type == bp_thread_event || b->type == bp_overlay_event
|| b->type == bp_longjmp_master || b->type == bp_longjmp_master
|| b->type == bp_std_terminate_master) || b->type == bp_std_terminate_master
|| b->type == bp_exception_master)
/* We do not stop for these. */ /* We do not stop for these. */
bs->stop = 0; bs->stop = 0;
else else
@ -4216,6 +4257,7 @@ bpstat_what (bpstat bs)
retval.main_action = BPSTAT_WHAT_KEEP_CHECKING; retval.main_action = BPSTAT_WHAT_KEEP_CHECKING;
retval.call_dummy = STOP_NONE; retval.call_dummy = STOP_NONE;
retval.is_longjmp = 0;
for (; bs != NULL; bs = bs->next) for (; bs != NULL; bs = bs->next)
{ {
@ -4271,10 +4313,14 @@ bpstat_what (bpstat bs)
} }
break; break;
case bp_longjmp: case bp_longjmp:
case bp_exception:
this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME; this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME;
retval.is_longjmp = bptype == bp_longjmp;
break; break;
case bp_longjmp_resume: case bp_longjmp_resume:
case bp_exception_resume:
this_action = BPSTAT_WHAT_CLEAR_LONGJMP_RESUME; this_action = BPSTAT_WHAT_CLEAR_LONGJMP_RESUME;
retval.is_longjmp = bptype == bp_longjmp_resume;
break; break;
case bp_step_resume: case bp_step_resume:
if (bs->stop) if (bs->stop)
@ -4290,6 +4336,7 @@ bpstat_what (bpstat bs)
case bp_overlay_event: case bp_overlay_event:
case bp_longjmp_master: case bp_longjmp_master:
case bp_std_terminate_master: case bp_std_terminate_master:
case bp_exception_master:
this_action = BPSTAT_WHAT_SINGLE; this_action = BPSTAT_WHAT_SINGLE;
break; break;
case bp_catchpoint: case bp_catchpoint:
@ -4483,6 +4530,8 @@ bptype_string (enum bptype type)
{bp_access_watchpoint, "acc watchpoint"}, {bp_access_watchpoint, "acc watchpoint"},
{bp_longjmp, "longjmp"}, {bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"}, {bp_longjmp_resume, "longjmp resume"},
{bp_exception, "exception"},
{bp_exception_resume, "exception resume"},
{bp_step_resume, "step resume"}, {bp_step_resume, "step resume"},
{bp_watchpoint_scope, "watchpoint scope"}, {bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"}, {bp_call_dummy, "call dummy"},
@ -4492,6 +4541,7 @@ bptype_string (enum bptype type)
{bp_overlay_event, "overlay events"}, {bp_overlay_event, "overlay events"},
{bp_longjmp_master, "longjmp master"}, {bp_longjmp_master, "longjmp master"},
{bp_std_terminate_master, "std::terminate master"}, {bp_std_terminate_master, "std::terminate master"},
{bp_exception_master, "exception master"},
{bp_catchpoint, "catchpoint"}, {bp_catchpoint, "catchpoint"},
{bp_tracepoint, "tracepoint"}, {bp_tracepoint, "tracepoint"},
{bp_fast_tracepoint, "fast tracepoint"}, {bp_fast_tracepoint, "fast tracepoint"},
@ -4630,6 +4680,8 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_finish: case bp_finish:
case bp_longjmp: case bp_longjmp:
case bp_longjmp_resume: case bp_longjmp_resume:
case bp_exception:
case bp_exception_resume:
case bp_step_resume: case bp_step_resume:
case bp_watchpoint_scope: case bp_watchpoint_scope:
case bp_call_dummy: case bp_call_dummy:
@ -4639,6 +4691,7 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_overlay_event: case bp_overlay_event:
case bp_longjmp_master: case bp_longjmp_master:
case bp_std_terminate_master: case bp_std_terminate_master:
case bp_exception_master:
case bp_tracepoint: case bp_tracepoint:
case bp_fast_tracepoint: case bp_fast_tracepoint:
case bp_static_tracepoint: case bp_static_tracepoint:
@ -5379,6 +5432,8 @@ allocate_bp_location (struct breakpoint *bpt)
case bp_finish: case bp_finish:
case bp_longjmp: case bp_longjmp:
case bp_longjmp_resume: case bp_longjmp_resume:
case bp_exception:
case bp_exception_resume:
case bp_step_resume: case bp_step_resume:
case bp_watchpoint_scope: case bp_watchpoint_scope:
case bp_call_dummy: case bp_call_dummy:
@ -5389,6 +5444,7 @@ allocate_bp_location (struct breakpoint *bpt)
case bp_jit_event: case bp_jit_event:
case bp_longjmp_master: case bp_longjmp_master:
case bp_std_terminate_master: case bp_std_terminate_master:
case bp_exception_master:
loc->loc_type = bp_loc_software_breakpoint; loc->loc_type = bp_loc_software_breakpoint;
break; break;
case bp_hardware_breakpoint: case bp_hardware_breakpoint:
@ -5605,13 +5661,14 @@ make_breakpoint_permanent (struct breakpoint *b)
} }
/* Call this routine when stepping and nexting to enable a breakpoint /* Call this routine when stepping and nexting to enable a breakpoint
if we do a longjmp() in THREAD. When we hit that breakpoint, call if we do a longjmp() or 'throw' in TP. FRAME is the frame which
set_longjmp_resume_breakpoint() to figure out where we are going. */ initiated the operation. */
void void
set_longjmp_breakpoint (int thread) set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
{ {
struct breakpoint *b, *temp; struct breakpoint *b, *temp;
int thread = tp->num;
/* To avoid having to rescan all objfile symbols at every step, /* To avoid having to rescan all objfile symbols at every step,
we maintain a list of continually-inserted but always disabled we maintain a list of continually-inserted but always disabled
@ -5619,13 +5676,16 @@ set_longjmp_breakpoint (int thread)
clones of those and enable them for the requested thread. */ clones of those and enable them for the requested thread. */
ALL_BREAKPOINTS_SAFE (b, temp) ALL_BREAKPOINTS_SAFE (b, temp)
if (b->pspace == current_program_space if (b->pspace == current_program_space
&& b->type == bp_longjmp_master) && (b->type == bp_longjmp_master
|| b->type == bp_exception_master))
{ {
struct breakpoint *clone = clone_momentary_breakpoint (b); struct breakpoint *clone = clone_momentary_breakpoint (b);
clone->type = bp_longjmp; clone->type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
clone->thread = thread; clone->thread = thread;
} }
tp->initiating_frame = frame;
} }
/* Delete all longjmp breakpoints from THREAD. */ /* Delete all longjmp breakpoints from THREAD. */
@ -5635,7 +5695,7 @@ delete_longjmp_breakpoint (int thread)
struct breakpoint *b, *temp; struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp) ALL_BREAKPOINTS_SAFE (b, temp)
if (b->type == bp_longjmp) if (b->type == bp_longjmp || b->type == bp_exception)
{ {
if (b->thread == thread) if (b->thread == thread)
delete_breakpoint (b); delete_breakpoint (b);
@ -6807,6 +6867,8 @@ mention (struct breakpoint *b)
case bp_finish: case bp_finish:
case bp_longjmp: case bp_longjmp:
case bp_longjmp_resume: case bp_longjmp_resume:
case bp_exception:
case bp_exception_resume:
case bp_step_resume: case bp_step_resume:
case bp_call_dummy: case bp_call_dummy:
case bp_std_terminate: case bp_std_terminate:
@ -6817,6 +6879,7 @@ mention (struct breakpoint *b)
case bp_jit_event: case bp_jit_event:
case bp_longjmp_master: case bp_longjmp_master:
case bp_std_terminate_master: case bp_std_terminate_master:
case bp_exception_master:
break; break;
} }
@ -8490,6 +8553,7 @@ struct until_break_command_continuation_args
{ {
struct breakpoint *breakpoint; struct breakpoint *breakpoint;
struct breakpoint *breakpoint2; struct breakpoint *breakpoint2;
int thread_num;
}; };
/* This function is called by fetch_inferior_event via the /* This function is called by fetch_inferior_event via the
@ -8504,6 +8568,7 @@ until_break_command_continuation (void *arg)
delete_breakpoint (a->breakpoint); delete_breakpoint (a->breakpoint);
if (a->breakpoint2) if (a->breakpoint2)
delete_breakpoint (a->breakpoint2); delete_breakpoint (a->breakpoint2);
delete_longjmp_breakpoint (a->thread_num);
} }
void void
@ -8515,6 +8580,8 @@ until_break_command (char *arg, int from_tty, int anywhere)
struct breakpoint *breakpoint; struct breakpoint *breakpoint;
struct breakpoint *breakpoint2 = NULL; struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain; struct cleanup *old_chain;
int thread;
struct thread_info *tp;
clear_proceed_status (); clear_proceed_status ();
@ -8553,6 +8620,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
old_chain = make_cleanup_delete_breakpoint (breakpoint); old_chain = make_cleanup_delete_breakpoint (breakpoint);
tp = inferior_thread ();
thread = tp->num;
/* Keep within the current frame, or in frames called by the current /* Keep within the current frame, or in frames called by the current
one. */ one. */
@ -8565,6 +8635,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
frame_unwind_caller_id (frame), frame_unwind_caller_id (frame),
bp_until); bp_until);
make_cleanup_delete_breakpoint (breakpoint2); make_cleanup_delete_breakpoint (breakpoint2);
set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
} }
proceed (-1, TARGET_SIGNAL_DEFAULT, 0); proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
@ -8581,6 +8654,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
args->breakpoint = breakpoint; args->breakpoint = breakpoint;
args->breakpoint2 = breakpoint2; args->breakpoint2 = breakpoint2;
args->thread_num = thread;
discard_cleanups (old_chain); discard_cleanups (old_chain);
add_continuation (inferior_thread (), add_continuation (inferior_thread (),
@ -9820,6 +9894,7 @@ delete_command (char *arg, int from_tty)
&& b->type != bp_overlay_event && b->type != bp_overlay_event
&& b->type != bp_longjmp_master && b->type != bp_longjmp_master
&& b->type != bp_std_terminate_master && b->type != bp_std_terminate_master
&& b->type != bp_exception_master
&& b->number >= 0) && b->number >= 0)
{ {
breaks_to_delete = 1; breaks_to_delete = 1;
@ -9841,6 +9916,7 @@ delete_command (char *arg, int from_tty)
&& b->type != bp_overlay_event && b->type != bp_overlay_event
&& b->type != bp_longjmp_master && b->type != bp_longjmp_master
&& b->type != bp_std_terminate_master && b->type != bp_std_terminate_master
&& b->type != bp_exception_master
&& b->number >= 0) && b->number >= 0)
delete_breakpoint (b); delete_breakpoint (b);
} }
@ -10301,6 +10377,7 @@ breakpoint_re_set_one (void *bint)
case bp_overlay_event: case bp_overlay_event:
case bp_longjmp_master: case bp_longjmp_master:
case bp_std_terminate_master: case bp_std_terminate_master:
case bp_exception_master:
delete_breakpoint (b); delete_breakpoint (b);
break; break;
@ -10324,6 +10401,8 @@ breakpoint_re_set_one (void *bint)
case bp_step_resume: case bp_step_resume:
case bp_longjmp: case bp_longjmp:
case bp_longjmp_resume: case bp_longjmp_resume:
case bp_exception:
case bp_exception_resume:
case bp_jit_event: case bp_jit_event:
break; break;
} }
@ -10367,6 +10446,7 @@ breakpoint_re_set (void)
create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp");
create_std_terminate_master_breakpoint ("std::terminate()"); create_std_terminate_master_breakpoint ("std::terminate()");
create_exception_master_breakpoint ();
} }
/* Reset the thread number of this breakpoint: /* Reset the thread number of this breakpoint:

View File

@ -57,6 +57,13 @@ enum bptype
bp_longjmp, /* secret breakpoint to find longjmp() */ bp_longjmp, /* secret breakpoint to find longjmp() */
bp_longjmp_resume, /* secret breakpoint to escape longjmp() */ bp_longjmp_resume, /* secret breakpoint to escape longjmp() */
/* An internal breakpoint that is installed on the unwinder's
debug hook. */
bp_exception,
/* An internal breakpoint that is set at the point where an
exception will land. */
bp_exception_resume,
/* Used by wait_for_inferior for stepping over subroutine calls, for /* Used by wait_for_inferior for stepping over subroutine calls, for
stepping over signal handlers, and for skipping prologues. */ stepping over signal handlers, and for skipping prologues. */
bp_step_resume, bp_step_resume,
@ -126,6 +133,9 @@ enum bptype
/* Master copies of std::terminate breakpoints. */ /* Master copies of std::terminate breakpoints. */
bp_std_terminate_master, bp_std_terminate_master,
/* Like bp_longjmp_master, but for exceptions. */
bp_exception_master,
bp_catchpoint, bp_catchpoint,
bp_tracepoint, bp_tracepoint,
@ -665,6 +675,11 @@ struct bpstat_what
continuing from a call dummy without popping the frame is not a continuing from a call dummy without popping the frame is not a
useful one). */ useful one). */
enum stop_stack_kind call_dummy; enum stop_stack_kind call_dummy;
/* Used for BPSTAT_WHAT_SET_LONGJMP_RESUME and
BPSTAT_WHAT_CLEAR_LONGJMP_RESUME. True if we are handling a
longjmp, false if we are handling an exception. */
int is_longjmp;
}; };
/* The possible return values for print_bpstat, print_it_normal, /* The possible return values for print_bpstat, print_it_normal,
@ -925,7 +940,8 @@ extern int detach_breakpoints (int);
this PSPACE anymore. */ this PSPACE anymore. */
extern void breakpoint_program_space_exit (struct program_space *pspace); extern void breakpoint_program_space_exit (struct program_space *pspace);
extern void set_longjmp_breakpoint (int thread); extern void set_longjmp_breakpoint (struct thread_info *tp,
struct frame_id frame);
extern void delete_longjmp_breakpoint (int thread); extern void delete_longjmp_breakpoint (int thread);
extern void enable_overlay_breakpoints (void); extern void enable_overlay_breakpoints (void);

View File

@ -40,6 +40,9 @@ struct thread_control_state
/* Step-resume or longjmp-resume breakpoint. */ /* Step-resume or longjmp-resume breakpoint. */
struct breakpoint *step_resume_breakpoint; struct breakpoint *step_resume_breakpoint;
/* Exception-resume breakpoint. */
struct breakpoint *exception_resume_breakpoint;
/* Range to single step within. /* Range to single step within.
If this is nonzero, respond to a single-step signal by continuing If this is nonzero, respond to a single-step signal by continuing
@ -207,6 +210,10 @@ struct thread_info
/* True if this thread has been explicitly requested to stop. */ /* True if this thread has been explicitly requested to stop. */
int stop_requested; int stop_requested;
/* The initiating frame of a nexting operation, used for deciding
which exceptions to intercept. */
struct frame_id initiating_frame;
/* Private data used by the target vector implementation. */ /* Private data used by the target vector implementation. */
struct private_thread_info *private; struct private_thread_info *private;
@ -243,6 +250,9 @@ extern void delete_thread_silent (ptid_t);
/* Delete a step_resume_breakpoint from the thread database. */ /* Delete a step_resume_breakpoint from the thread database. */
extern void delete_step_resume_breakpoint (struct thread_info *); extern void delete_step_resume_breakpoint (struct thread_info *);
/* Delete an exception_resume_breakpoint from the thread database. */
extern void delete_exception_resume_breakpoint (struct thread_info *);
/* Translate the integer thread id (GDB's homegrown id, not the system's) /* Translate the integer thread id (GDB's homegrown id, not the system's)
into a "pid" (which may be overloaded with extra thread information). */ into a "pid" (which may be overloaded with extra thread information). */
extern ptid_t thread_id_to_pid (int); extern ptid_t thread_id_to_pid (int);

View File

@ -822,7 +822,7 @@ nexti_command (char *count_string, int from_tty)
step_1 (1, 1, count_string); step_1 (1, 1, count_string);
} }
static void void
delete_longjmp_breakpoint_cleanup (void *arg) delete_longjmp_breakpoint_cleanup (void *arg)
{ {
int thread = * (int *) arg; int thread = * (int *) arg;
@ -862,10 +862,12 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
if (!single_inst || skip_subroutines) /* leave si command alone */ if (!single_inst || skip_subroutines) /* leave si command alone */
{ {
struct thread_info *tp = inferior_thread ();
if (in_thread_list (inferior_ptid)) if (in_thread_list (inferior_ptid))
thread = pid_to_thread_id (inferior_ptid); thread = pid_to_thread_id (inferior_ptid);
set_longjmp_breakpoint (thread); set_longjmp_breakpoint (tp, get_frame_id (get_current_frame ()));
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
} }
@ -1220,6 +1222,16 @@ signal_command (char *signum_exp, int from_tty)
proceed ((CORE_ADDR) -1, oursig, 0); proceed ((CORE_ADDR) -1, oursig, 0);
} }
/* A continuation callback for until_next_command. */
static void
until_next_continuation (void *arg)
{
struct thread_info *tp = arg;
delete_longjmp_breakpoint (tp->num);
}
/* Proceed until we reach a different source line with pc greater than /* Proceed until we reach a different source line with pc greater than
our current one or exit the function. We skip calls in both cases. our current one or exit the function. We skip calls in both cases.
@ -1236,6 +1248,8 @@ until_next_command (int from_tty)
struct symbol *func; struct symbol *func;
struct symtab_and_line sal; struct symtab_and_line sal;
struct thread_info *tp = inferior_thread (); struct thread_info *tp = inferior_thread ();
int thread = tp->num;
struct cleanup *old_chain;
clear_proceed_status (); clear_proceed_status ();
set_step_frame (); set_step_frame ();
@ -1271,7 +1285,18 @@ until_next_command (int from_tty)
tp->step_multi = 0; /* Only one call to proceed */ tp->step_multi = 0; /* Only one call to proceed */
set_longjmp_breakpoint (tp, get_frame_id (frame));
old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
if (target_can_async_p () && is_running (inferior_ptid))
{
discard_cleanups (old_chain);
add_continuation (tp, until_next_continuation, tp, NULL);
}
else
do_cleanups (old_chain);
} }
static void static void
@ -1464,6 +1489,7 @@ finish_command_continuation (void *arg)
if (bs != NULL && tp->control.proceed_to_finish) if (bs != NULL && tp->control.proceed_to_finish)
observer_notify_normal_stop (bs, 1 /* print frame */); observer_notify_normal_stop (bs, 1 /* print frame */);
delete_breakpoint (a->breakpoint); delete_breakpoint (a->breakpoint);
delete_longjmp_breakpoint (inferior_thread ()->num);
} }
static void static void
@ -1548,6 +1574,7 @@ finish_forward (struct symbol *function, struct frame_info *frame)
struct breakpoint *breakpoint; struct breakpoint *breakpoint;
struct cleanup *old_chain; struct cleanup *old_chain;
struct finish_command_continuation_args *cargs; struct finish_command_continuation_args *cargs;
int thread = tp->num;
sal = find_pc_line (get_frame_pc (frame), 0); sal = find_pc_line (get_frame_pc (frame), 0);
sal.pc = get_frame_pc (frame); sal.pc = get_frame_pc (frame);
@ -1558,6 +1585,9 @@ finish_forward (struct symbol *function, struct frame_info *frame)
old_chain = make_cleanup_delete_breakpoint (breakpoint); old_chain = make_cleanup_delete_breakpoint (breakpoint);
set_longjmp_breakpoint (tp, get_frame_id (frame));
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
/* We want stop_registers, please... */ /* We want stop_registers, please... */
tp->control.proceed_to_finish = 1; tp->control.proceed_to_finish = 1;
cargs = xmalloc (sizeof (*cargs)); cargs = xmalloc (sizeof (*cargs));

View File

@ -279,6 +279,8 @@ extern void interrupt_target_command (char *args, int from_tty);
extern void interrupt_target_1 (int all_threads); extern void interrupt_target_1 (int all_threads);
extern void delete_longjmp_breakpoint_cleanup (void *arg);
extern void detach_command (char *, int); extern void detach_command (char *, int);
extern void notice_new_inferior (ptid_t, int, int); extern void notice_new_inferior (ptid_t, int, int);

View File

@ -45,6 +45,8 @@
#include "language.h" #include "language.h"
#include "solib.h" #include "solib.h"
#include "main.h" #include "main.h"
#include "dictionary.h"
#include "block.h"
#include "gdb_assert.h" #include "gdb_assert.h"
#include "mi/mi-common.h" #include "mi/mi-common.h"
#include "event-top.h" #include "event-top.h"
@ -377,6 +379,7 @@ follow_fork (void)
parent thread structure's run control related fields, not just these. parent thread structure's run control related fields, not just these.
Initialized to avoid "may be used uninitialized" warnings from gcc. */ Initialized to avoid "may be used uninitialized" warnings from gcc. */
struct breakpoint *step_resume_breakpoint = NULL; struct breakpoint *step_resume_breakpoint = NULL;
struct breakpoint *exception_resume_breakpoint = NULL;
CORE_ADDR step_range_start = 0; CORE_ADDR step_range_start = 0;
CORE_ADDR step_range_end = 0; CORE_ADDR step_range_end = 0;
struct frame_id step_frame_id = { 0 }; struct frame_id step_frame_id = { 0 };
@ -429,6 +432,8 @@ follow_fork (void)
step_range_start = tp->control.step_range_start; step_range_start = tp->control.step_range_start;
step_range_end = tp->control.step_range_end; step_range_end = tp->control.step_range_end;
step_frame_id = tp->control.step_frame_id; step_frame_id = tp->control.step_frame_id;
exception_resume_breakpoint
= clone_momentary_breakpoint (tp->control.exception_resume_breakpoint);
/* For now, delete the parent's sr breakpoint, otherwise, /* For now, delete the parent's sr breakpoint, otherwise,
parent/child sr breakpoints are considered duplicates, parent/child sr breakpoints are considered duplicates,
@ -439,6 +444,7 @@ follow_fork (void)
tp->control.step_range_start = 0; tp->control.step_range_start = 0;
tp->control.step_range_end = 0; tp->control.step_range_end = 0;
tp->control.step_frame_id = null_frame_id; tp->control.step_frame_id = null_frame_id;
delete_exception_resume_breakpoint (tp);
} }
parent = inferior_ptid; parent = inferior_ptid;
@ -481,6 +487,8 @@ follow_fork (void)
tp->control.step_range_start = step_range_start; tp->control.step_range_start = step_range_start;
tp->control.step_range_end = step_range_end; tp->control.step_range_end = step_range_end;
tp->control.step_frame_id = step_frame_id; tp->control.step_frame_id = step_frame_id;
tp->control.exception_resume_breakpoint
= exception_resume_breakpoint;
} }
else else
{ {
@ -534,6 +542,9 @@ follow_inferior_reset_breakpoints (void)
if (tp->control.step_resume_breakpoint) if (tp->control.step_resume_breakpoint)
breakpoint_re_set_thread (tp->control.step_resume_breakpoint); breakpoint_re_set_thread (tp->control.step_resume_breakpoint);
if (tp->control.exception_resume_breakpoint)
breakpoint_re_set_thread (tp->control.exception_resume_breakpoint);
/* Reinsert all breakpoints in the child. The user may have set /* Reinsert all breakpoints in the child. The user may have set
breakpoints after catching the fork, in which case those breakpoints after catching the fork, in which case those
were never set in the child, but only in the parent. This makes were never set in the child, but only in the parent. This makes
@ -771,6 +782,7 @@ follow_exec (ptid_t pid, char *execd_pathname)
/* If there was one, it's gone now. We cannot truly step-to-next /* If there was one, it's gone now. We cannot truly step-to-next
statement through an exec(). */ statement through an exec(). */
th->control.step_resume_breakpoint = NULL; th->control.step_resume_breakpoint = NULL;
th->control.exception_resume_breakpoint = NULL;
th->control.step_range_start = 0; th->control.step_range_start = 0;
th->control.step_range_end = 0; th->control.step_range_end = 0;
@ -2219,6 +2231,8 @@ static void insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch,
struct symtab_and_line sr_sal, struct symtab_and_line sr_sal,
struct frame_id sr_id); struct frame_id sr_id);
static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
static void check_exception_resume (struct execution_control_state *,
struct frame_info *, struct symbol *);
static void stop_stepping (struct execution_control_state *ecs); static void stop_stepping (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs);
@ -2340,6 +2354,7 @@ delete_step_resume_breakpoint_callback (struct thread_info *info, void *data)
return 0; return 0;
delete_step_resume_breakpoint (info); delete_step_resume_breakpoint (info);
delete_exception_resume_breakpoint (info);
return 0; return 0;
} }
@ -2364,6 +2379,7 @@ delete_step_thread_step_resume_breakpoint (void)
struct thread_info *tp = inferior_thread (); struct thread_info *tp = inferior_thread ();
delete_step_resume_breakpoint (tp); delete_step_resume_breakpoint (tp);
delete_exception_resume_breakpoint (tp);
} }
else else
/* In all-stop mode, delete all step-resume and longjmp-resume /* In all-stop mode, delete all step-resume and longjmp-resume
@ -4112,23 +4128,33 @@ process_event_stop_test:
ecs->event_thread->stepping_over_breakpoint = 1; ecs->event_thread->stepping_over_breakpoint = 1;
if (!gdbarch_get_longjmp_target_p (gdbarch) if (what.is_longjmp)
|| !gdbarch_get_longjmp_target (gdbarch, frame, &jmp_buf_pc))
{ {
if (debug_infrun) if (!gdbarch_get_longjmp_target_p (gdbarch)
fprintf_unfiltered (gdb_stdlog, "\ || !gdbarch_get_longjmp_target (gdbarch,
frame, &jmp_buf_pc))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "\
infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
keep_going (ecs); keep_going (ecs);
return; return;
}
/* We're going to replace the current step-resume breakpoint
with a longjmp-resume breakpoint. */
delete_step_resume_breakpoint (ecs->event_thread);
/* Insert a breakpoint at resume address. */
insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
} }
else
{
struct symbol *func = get_frame_function (frame);
/* We're going to replace the current step-resume breakpoint if (func)
with a longjmp-resume breakpoint. */ check_exception_resume (ecs, frame, func);
delete_step_resume_breakpoint (ecs->event_thread); }
/* Insert a breakpoint at resume address. */
insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
keep_going (ecs); keep_going (ecs);
return; return;
@ -4137,9 +4163,54 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
fprintf_unfiltered (gdb_stdlog, fprintf_unfiltered (gdb_stdlog,
"infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
gdb_assert (ecs->event_thread->control.step_resume_breakpoint if (what.is_longjmp)
!= NULL); {
delete_step_resume_breakpoint (ecs->event_thread); gdb_assert (ecs->event_thread->control.step_resume_breakpoint
!= NULL);
delete_step_resume_breakpoint (ecs->event_thread);
}
else
{
/* There are several cases to consider.
1. The initiating frame no longer exists. In this case
we must stop, because the exception has gone too far.
2. The initiating frame exists, and is the same as the
current frame. We stop, because the exception has been
caught.
3. The initiating frame exists and is different from
the current frame. This means the exception has been
caught beneath the initiating frame, so keep going. */
struct frame_info *init_frame
= frame_find_by_id (ecs->event_thread->initiating_frame);
gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
!= NULL);
delete_exception_resume_breakpoint (ecs->event_thread);
if (init_frame)
{
struct frame_id current_id
= get_frame_id (get_current_frame ());
if (frame_id_eq (current_id,
ecs->event_thread->initiating_frame))
{
/* Case 2. Fall through. */
}
else
{
/* Case 3. */
keep_going (ecs);
return;
}
}
/* For Cases 1 and 2, remove the step-resume breakpoint,
if it exists. */
delete_step_resume_breakpoint (ecs->event_thread);
}
ecs->event_thread->control.stop_step = 1; ecs->event_thread->control.stop_step = 1;
print_end_stepping_range_reason (); print_end_stepping_range_reason ();
@ -5109,6 +5180,97 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume); set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume);
} }
/* Insert an exception resume breakpoint. TP is the thread throwing
the exception. The block B is the block of the unwinder debug hook
function. FRAME is the frame corresponding to the call to this
function. SYM is the symbol of the function argument holding the
target PC of the exception. */
static void
insert_exception_resume_breakpoint (struct thread_info *tp,
struct block *b,
struct frame_info *frame,
struct symbol *sym)
{
struct gdb_exception e;
/* We want to ignore errors here. */
TRY_CATCH (e, RETURN_MASK_ERROR)
{
struct symbol *vsym;
struct value *value;
CORE_ADDR handler;
struct breakpoint *bp;
vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
value = read_var_value (vsym, frame);
/* If the value was optimized out, revert to the old behavior. */
if (! value_optimized_out (value))
{
handler = value_as_address (value);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: exception resume at %lx\n",
(unsigned long) handler);
bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
handler, bp_exception_resume);
bp->thread = tp->num;
inferior_thread ()->control.exception_resume_breakpoint = bp;
}
}
}
/* This is called when an exception has been intercepted. Check to
see whether the exception's destination is of interest, and if so,
set an exception resume breakpoint there. */
static void
check_exception_resume (struct execution_control_state *ecs,
struct frame_info *frame, struct symbol *func)
{
struct gdb_exception e;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
struct block *b;
struct dict_iterator iter;
struct symbol *sym;
int argno = 0;
/* The exception breakpoint is a thread-specific breakpoint on
the unwinder's debug hook, declared as:
void _Unwind_DebugHook (void *cfa, void *handler);
The CFA argument indicates the frame to which control is
about to be transferred. HANDLER is the destination PC.
We ignore the CFA and set a temporary breakpoint at HANDLER.
This is not extremely efficient but it avoids issues in gdb
with computing the DWARF CFA, and it also works even in weird
cases such as throwing an exception from inside a signal
handler. */
b = SYMBOL_BLOCK_VALUE (func);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
if (!SYMBOL_IS_ARGUMENT (sym))
continue;
if (argno == 0)
++argno;
else
{
insert_exception_resume_breakpoint (ecs->event_thread,
b, frame, sym);
break;
}
}
}
}
static void static void
stop_stepping (struct execution_control_state *ecs) stop_stepping (struct execution_control_state *ecs)
{ {

View File

@ -1,3 +1,10 @@
2010-12-09 Tom Tromey <tromey@redhat.com>
* gdb.java/jnpe.java: New file.
* gdb.java/jnpe.exp: New file.
* gdb.cp/nextoverthrow.exp: New file.
* gdb.cp/nextoverthrow.cc: New file.
2010-12-07 Doug Evans <dje@google.com> 2010-12-07 Doug Evans <dje@google.com>
* gdb.base/catch-syscall.exp (do_syscall_tests): Remove setting * gdb.base/catch-syscall.exp (do_syscall_tests): Remove setting

View File

@ -0,0 +1,203 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2008, 2009, 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/>.
*/
#include <iostream>
using namespace std;
void dummy ()
{
}
class NextOverThrowDerivates
{
public:
// Single throw an exception in this function.
void function1 (int val)
{
throw val;
}
// Throw an exception in another function.
void function2 (int val)
{
function1 (val);
}
// Throw an exception in another function, but handle it
// locally.
void function3 (int val)
{
{
try
{
function1 (val);
}
catch (...)
{
cout << "Caught and handled function1 exception" << endl;
}
}
}
void rethrow (int val)
{
try
{
function1 (val);
}
catch (...)
{
throw;
}
}
void finish (int val)
{
// We use this to test that a "finish" here does not end up in
// this frame, but in the one above.
try
{
function1 (val);
}
catch (int x)
{
}
function1 (val); // marker for until
}
void until (int val)
{
function1 (val);
function1 (val); // until here
}
};
NextOverThrowDerivates next_cases;
int main ()
{
int testval = -1;
try
{
next_cases.function1 (0); // Start: first test
}
catch (int val)
{
dummy ();
testval = val; // End: first test
}
try
{
next_cases.function2 (1); // Start: nested throw
}
catch (int val)
{
dummy ();
testval = val; // End: nested throw
}
try
{
// This is duplicated so we can next over one but step into
// another.
next_cases.function2 (2); // Start: step in test
}
catch (int val)
{
dummy ();
testval = val; // End: step in test
}
next_cases.function3 (3); // Start: next past catch
dummy ();
testval = 3; // End: next past catch
try
{
next_cases.rethrow (4); // Start: rethrow
}
catch (int val)
{
dummy ();
testval = val; // End: rethrow
}
try
{
// Another duplicate so we can test "finish".
next_cases.function2 (5); // Start: first finish
}
catch (int val)
{
dummy ();
testval = val; // End: first finish
}
// Another test for "finish".
try
{
next_cases.finish (6); // Start: second finish
}
catch (int val)
{
dummy ();
testval = val; // End: second finish
}
// Test of "until".
try
{
next_cases.finish (7); // Start: first until
}
catch (int val)
{
dummy ();
testval = val; // End: first until
}
// Test of "until" with an argument.
try
{
next_cases.until (8); // Start: second until
}
catch (int val)
{
dummy ();
testval = val; // End: second until
}
// Test of "advance".
try
{
next_cases.until (9); // Start: advance
}
catch (int val)
{
dummy ();
testval = val; // End: advance
}
testval = 32; // done
}

View File

@ -0,0 +1,153 @@
# Copyright 2008, 2009, 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/>.
if $tracelevel then {
strace $tracelevel
}
if { [skip_cplus_tests] } { continue }
set testfile "nextoverthrow"
set srcfile ${testfile}.cc
set binfile $objdir/$subdir/$testfile
# Create and source the file that provides information about the compiler
# used to compile the test case.
if [get_compiler_info ${binfile} "c++"] {
untested nextoverthrow.exp
return -1
}
if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
return -1
}
if ![runto_main] then {
perror "couldn't run to main"
continue
}
# See whether we have the needed unwinder hooks.
set ok 1
gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
-re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" {
pass "check for unwinder hook"
}
-re "No symbol .* in current context.\r\n$gdb_prompt $" {
# Pass the test so we don't get bogus fails in the results.
pass "check for unwinder hook"
set ok 0
}
}
if {!$ok} {
unsupported "nextoverthrow.exp could not find _Unwind_DebugHook"
return -1
}
# Set a temporary breakpoint and then continue to it.
# The breakpoint is set according to a marker in the file.
proc tbreak_and_cont {text} {
global testfile
set line [gdb_get_line_number $text $testfile.cc]
gdb_breakpoint "$testfile.cc:$line" temporary
gdb_test "continue" "Temporary breakpoint.*" "continuing to $text"
}
# Verify the value of testval.
proc verify_testval {name value} {
gdb_test "print testval == $value" " = true" $name
}
# See http://sourceware.org/bugzilla/show_bug.cgi?id=9593
# Our general approach here is to do some operation, verify
# that testval has not changed, continue to the location at
# which the next test starts, and verify testval again.
# This works around platform differences in debuginfo that
# make looking at the source line unreliable.
# A simple test of next over a throw.
tbreak_and_cont "Start: first test"
gdb_test "next" ".*" "next over a throw 1"
tbreak_and_cont "End: first test"
verify_testval "pre-check - next over a throw 1" -1
tbreak_and_cont "Start: nested throw"
verify_testval "post-check - next over a throw 1" 0
gdb_test "next" ".*" "next over a throw 2"
tbreak_and_cont "End: nested throw"
verify_testval "pre-check - next over a throw 2" 0
tbreak_and_cont "Start: step in test"
verify_testval "post-check - next over a throw 2" 1
gdb_test "step" "function1().*" "step into function2 1"
gdb_test "next" ".*" "next over a throw 3"
tbreak_and_cont "End: step in test"
verify_testval "pre-check - next over a throw 3" 1
tbreak_and_cont "Start: next past catch"
verify_testval "post-check - next over a throw 3" 2
gdb_test "next" ".*" "next past catch"
tbreak_and_cont "End: next past catch"
verify_testval "pre-check - next past catch" 2
tbreak_and_cont "Start: rethrow"
verify_testval "post-check - next past catch" 3
gdb_test "next" ".*" "next over a throw 4"
tbreak_and_cont "End: rethrow"
verify_testval "pre-check - next over a throw 4" 3
tbreak_and_cont "Start: first finish"
verify_testval "post-check - next over a throw 4" 4
gdb_test "step" "function1().*" "step into function2 2"
gdb_test "finish" ".*" "finish 1"
tbreak_and_cont "End: first finish"
verify_testval "pre-check - finish 1" 4
tbreak_and_cont "Start: second finish"
verify_testval "post-check - finish 1" 5
gdb_test "step" "function1 ().*" "step into finish method"
gdb_test "finish" ".*" "finish 2"
tbreak_and_cont "End: second finish"
verify_testval "pre-check - finish 2" 5
tbreak_and_cont "Start: first until"
verify_testval "post-check - finish 2" 6
gdb_test "step" ".*" "step into finish, for until"
gdb_test "until" ".*" "until with no argument 1"
set line [gdb_get_line_number "marker for until" $testfile.cc]
gdb_test "until $line" "function1 ().*" "next past catch 6"
gdb_test "until" ".*" "until with no argument 2"
tbreak_and_cont "End: first until"
verify_testval "pre-check - until 1" 6
tbreak_and_cont "Start: second until"
verify_testval "post-check - until 1" 7
set line [gdb_get_line_number "until here" $testfile.cc]
gdb_test "step" "function1 ().*" "step into until"
gdb_test "until $line" ".*" "until-over-throw"
tbreak_and_cont "End: second until"
verify_testval "pre-check - until 2" 7
tbreak_and_cont "Start: advance"
verify_testval "post-check - until 2" 8
gdb_test "step" "function1 ().*" "step into until, for advance"
gdb_test "advance $line" ".*" "advance-over-throw"
tbreak_and_cont "End: advance"
verify_testval "pre-check - advance" 8
tbreak_and_cont "done"
verify_testval "post-check - advance" 9

View File

@ -0,0 +1,74 @@
# Copyright 2009, 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/>.
if $tracelevel then {
strace $tracelevel
}
load_lib "java.exp"
set testfile "jnpe"
set srcfile ${testfile}.java
set binfile ${objdir}/${subdir}/${testfile}
if { [compile_java_from_source ${srcdir}/$subdir/${srcfile} ${binfile} "-g"] != "" } {
untested "Couldn't compile ${srcdir}/$subdir/${srcfile}"
return -1
}
# Start with a fresh gdb.
clean_restart $testfile
set line [gdb_get_line_number "break here" $testfile.java]
if ![runto "$testfile.java:$line"] then {
perror "couldn't run to jnpe.main"
continue
}
# See whether we have the needed unwinder hooks.
set ok 1
gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook in java" {
-re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" {
pass "check for unwinder hook in java"
}
-re "No symbol .* in current context.?\r\n$gdb_prompt $" {
# Pass the test so we don't get bogus fails in the results.
setup_xfail *-*-*
fail "check for unwinder hook in java"
set ok 0
}
}
if {!$ok} {
unsupported "jnpe.exp could not find _Unwind_DebugHook"
return -1
}
gdb_test "handle SIGSEGV nostop noprint" \
"SIGSEGV.*fault" \
"disable SIGSEGV for next-over-NPE"
# The line where we stop differs according to gcj; just check that we
# did not already execute the catch point. This is done in a somewhat
# funny way due to other gcj debuginfo oddities that don't
# meaningfully affect the user's experience.
gdb_test "next" \
".*" \
"next over NPE"
set line [gdb_get_line_number "stop point"]
gdb_breakpoint $line
gdb_test "continue" "Continuing.\[\r\n\]*success\[\r\n\]*Breakpoint .*:$line\[\r\n\]*.*// stop point\[\r\n\]*" \
"continue to success for next-over-NPE"

View File

@ -0,0 +1,40 @@
// Test next-over-NPE.
/* This testcase is part of GDB, the GNU debugger.
Copyright 2009, 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/>.
*/
public class jnpe
{
public static String npe ()
{
return ((Object) null).toString();
}
public static void main (String[] args)
{
try
{
System.out.println (npe ()); // break here
}
catch (NullPointerException n)
{
System.out.println ("success");
}
System.out.println ("blah"); // stop point
}
}

View File

@ -90,6 +90,16 @@ delete_step_resume_breakpoint (struct thread_info *tp)
} }
} }
void
delete_exception_resume_breakpoint (struct thread_info *tp)
{
if (tp && tp->control.exception_resume_breakpoint)
{
delete_breakpoint (tp->control.exception_resume_breakpoint);
tp->control.exception_resume_breakpoint = NULL;
}
}
static void static void
clear_thread_inferior_resources (struct thread_info *tp) clear_thread_inferior_resources (struct thread_info *tp)
{ {
@ -103,10 +113,19 @@ clear_thread_inferior_resources (struct thread_info *tp)
tp->control.step_resume_breakpoint = NULL; tp->control.step_resume_breakpoint = NULL;
} }
if (tp->control.exception_resume_breakpoint)
{
tp->control.exception_resume_breakpoint->disposition
= disp_del_at_next_stop;
tp->control.exception_resume_breakpoint = NULL;
}
bpstat_clear (&tp->control.stop_bpstat); bpstat_clear (&tp->control.stop_bpstat);
discard_all_intermediate_continuations_thread (tp); discard_all_intermediate_continuations_thread (tp);
discard_all_continuations_thread (tp); discard_all_continuations_thread (tp);
delete_longjmp_breakpoint (tp->num);
} }
static void static void