mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-18 08:38:10 +08:00
gdb
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:
@ -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.
|
||||||
|
@ -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,
|
||||||
|
¤t_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:
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
34
gdb/infcmd.c
34
gdb/infcmd.c
@ -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));
|
||||||
|
@ -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);
|
||||||
|
194
gdb/infrun.c
194
gdb/infrun.c
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
203
gdb/testsuite/gdb.cp/nextoverthrow.cc
Normal file
203
gdb/testsuite/gdb.cp/nextoverthrow.cc
Normal 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
|
||||||
|
}
|
||||||
|
|
153
gdb/testsuite/gdb.cp/nextoverthrow.exp
Normal file
153
gdb/testsuite/gdb.cp/nextoverthrow.exp
Normal 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
|
74
gdb/testsuite/gdb.java/jnpe.exp
Normal file
74
gdb/testsuite/gdb.java/jnpe.exp
Normal 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"
|
40
gdb/testsuite/gdb.java/jnpe.java
Normal file
40
gdb/testsuite/gdb.java/jnpe.java
Normal 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
|
||||||
|
}
|
||||||
|
}
|
19
gdb/thread.c
19
gdb/thread.c
@ -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
|
||||||
|
Reference in New Issue
Block a user