From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29291 invoked by alias); 7 Apr 2008 02:33:53 -0000 Received: (qmail 29245 invoked by uid 22791); 7 Apr 2008 02:33:49 -0000 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 07 Apr 2008 02:33:25 +0000 Received: (qmail 26132 invoked from network); 7 Apr 2008 02:33:22 -0000 Received: from unknown (HELO orlando.local) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 7 Apr 2008 02:33:22 -0000 From: Pedro Alves Subject: 3/5 - Rework stepping over longjmp support Date: Mon, 07 Apr 2008 02:34:00 -0000 User-Agent: KMail/1.9.6 (enterprise 0.20070907.709405) MIME-Version: 1.0 To: gdb-patches@sourceware.org Content-Type: Multipart/Mixed; boundary="Boundary-00=_ydY+HfBBDAx9Zoa" Message-Id: <200804070331.14538.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-04/txt/msg00126.txt.bz2 --Boundary-00=_ydY+HfBBDAx9Zoa Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Content-length: 4671 This rework was motivated by the non-stop mode. To handle stepping over longjmp, currently, we create internal disabled breakpoints on everything that looks like a longjmp : "longjmp", "_longjmp", "siglongjmp", and "_siglongjmp". These should cover all cases and all OSs. The basic idea it that when one of these breakpoints is hit, we look into the jmp_buf passed into longjmp, and extract the destination PC from it. We then set a breakpoint at that address, and let the inferior hit it. This handling is only desirable when the user is activelly doing a next or a step. We don't care for the inferior hitting a longjmp when the inferior is running freely -- if we left the breakpoint enabled all the time, even when not stepping (e.g., user did a continue, and no user breakpoints were hit, the inferior just runs uninterrupted), anytime the inferior called longjmp, it would hit the breakpoint, and then gdb would notice the inferior was not being stepped, so it should be resumed immediately. It is much more efficient to not hit that breakpoint at all in that case. So far, so good, this works OK in all-stop mode. Well, in theory, because the current implementation is broken. However, in non-stop mode, we can step more than one thread independenly and simultaneously. Having one thread finish a step, and disable the global longjmp breakpoint at that point, while another thread is still stepping is definitelly wrong. The other thread may happen to step a longjmp and it would go unnoticed. Basically, we need to associate the longjmp breakpoints with each stepping thread. Fortunally, the concept of per-thread breakpoints already exists in GDB. The current implementation sets a handling_longjmp variable when a longjmp is hit, and we insert a longjmp-resume breakpoint. If you look at infrun.c, you'll see there's always a FIXME associated with it. And it's right, because it's handling is broken. You can easilly see it breaking, by trying to step over something like this: #include jmp_buf env; int call_longjmp (jmp_buf *buf) { longjmp (*buf, 1); } int main () { if (setjmp (env) == 0) /* patt2 */ { call_longjmp (&env); <<<<<<<< try to step over this. } else { printf ("resumed\n"); } } Basically, the symptom is that GDB will not stop at the longjmp-resume address, instead the inferior will run to exit. Quite annoying. Instead of trying to explain deeply why the current implementation is broken (has to do with bad breakpoint handling, thread hopping, removing breakpoints at the wrong time, and the handling_longjmp variable getting in the way), I propose another implementation. We get rid of handling_longjmp, and instead, we handle a longjmp-resume breakpoint much like a step-resume breakpoint. It's natural to not have both set at the same time, and the current code already gets rid of the active step-resume breakpoint when inserting the longjmp-resume breakpoint. Setting step_resume_breakpoint to the new longjmp-resume breakpoint is exactly what we want. We want to keep stepping while it is set, we want to context switch it. We want to delete it everywhere a step-resume is being deleted. Of course, we could have a seperate per-thread context-switchable longjmp_resume_breakpoint instead, since we never have both a longjmp-resume and a step-resume breakpoint simulatenously (in a given thread), and it's handling would be equal everywhere else, it just feels better to overload step_resume_breakpoint. This patch implements the same behaviour that's in HEAD (if it weren't broken a lot of the times) where any longjmp hit while stepping, causes the step to stop. -- Pedro Alves P.S.: However, we could extend this to be smarter. E.g.: void hidden_longjmp (void) { if (setjmp (env) == 0) { longjmp (env, 1); } else { printf ("resumed\n"); } } int main () { hidden_longjmp (); <<<< step over this. } The longjmp inside hidden_longjmp is going to land inside hidden_longjmp. GDB could ignore it leave the step-resume breakpoint at the return of hidden_longjmp and pretend that longjmp was never seen. Think of stepping over a function in gdb's sources, and an exception being thrown and caught all somewhere inner to the function you're stepping. I've implemented a prototype patch that does this. Does anyone else think that behaviour is useful? (I'm aware that any smartness we add can be defeated by longjmp changing stacks, or stuff like debugging coroutines implemented with set/longjmp, but those feel like rare enough that a smart mode could be the default and useful most of (almost-all) the times.) --Boundary-00=_ydY+HfBBDAx9Zoa Content-Type: text/x-diff; charset="utf-8"; name="longjmp_rewrite.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="longjmp_rewrite.diff" Content-length: 21794 2008-04-07 Pedro Alves * breakpoint.c (update_breakpoints_after_exec): Delete bp_longjmp and bp_longjmp_resume breakpoints. (breakpoint_address_is_meaningful): Claim bp_longjmp_resume as meaningful. (create_longjmp_breakpoint): Don't create bp_longjmp_resume breakpoints. Create bp_longjmp breakpoints as momentary breakpoints. (enable_longjmp_breakpoint): Delete. (set_longjmp_breakpoint): New. (disable_longjmp_breakpoint): Delete. (delete_longjmp_breakpoint_thread, delete_longjmp_breakpoint): New. (set_longjmp_resume_breakpoint): Delete. (set_momentary_breakpoint_at_pc): New. (breakpoint_re_set_one): Don't delete bp_longjmp and bp_longjmp_resume breakpoints. (breakpoint_re_set): Don't create longjmp and longjmp-resume breakpoints. * infrun.c (step_resume_breakpoint): Add comment. (struct execution_control_state): Delete handling_longjmp member. (init_execution_control_state). Don't clear handling_longjmp. (context_switch): Don't context switch handling_longjmp. (handle_inferior_event): If handling a bp_longjmp breakpoint, create a bp_longjmp_resume breakpoint, and set it as current step_resume_breakpoint, then step over the longjmp breakpoint. If handling a bp_longjmp_resume breakpoint, don't delete the longjmp breakpoint, delete the longjmp-resume breakpoint, and stop stepping. (currently_stepping): Remove handling_longjmp from expression. (insert_step_resume_breakpoint_at_sal): Update comment. (insert_longjmp_resume_breakpoint): New. * breakpoint.h (set_momentary_breakpoint_at_pc): Declare. (enable_longjmp_breakpoint, disable_longjmp_breakpoint): Delete declarations. (set_longjmp_breakpoint, delete_longjmp_breakpoint) (delete_longjmp_breakpoint_thread): Declare. (set_longjmp_resume_breakpoint): Delete declaration. * gdbthread.h (save_infrun_state): Remove handling_longjmp parameter. (load_infrun_state): Delete *handling_longjmp parameter. * thread.c (save_infrun_state): Remove handling_longjmp parameter. Update body. (load_infrun_state): Delete *handling_longjmp parameter. Update body. * infcmd.c Include "gdbthread.h". (disable_longjmp_breakpoint_cleanup): Delete. (delete_longjmp_breakpoint_cleanup): New. (step_1): Call set_longjmp_breakpoint instead of enable_longjmp_breakpoint. Use delete_longjmp_breakpoint_cleanup instead of disable_longjmp_breakpoint_cleanup when making cleanup. * Makefile.in (infcmd.o): Update. --- gdb/Makefile.in | 2 gdb/breakpoint.c | 112 +++++++++++++++++++++---------------------------------- gdb/breakpoint.h | 9 ++-- gdb/gdbthread.h | 3 - gdb/infcmd.c | 26 ++++++++++-- gdb/infrun.c | 86 +++++++++++++++++++++++++++++------------- gdb/thread.c | 4 - 7 files changed, 131 insertions(+), 111 deletions(-) Index: src/gdb/breakpoint.c =================================================================== --- src.orig/gdb/breakpoint.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/breakpoint.c 2008-04-07 02:28:24.000000000 +0100 @@ -149,8 +149,6 @@ static int watchpoint_check (void *); static void maintenance_info_breakpoints (char *, int); -static void create_longjmp_breakpoint (char *); - static void create_overlay_event_breakpoint (char *); static int hw_breakpoint_used_count (void); @@ -1430,6 +1428,14 @@ update_breakpoints_after_exec (void) continue; } + /* Longjmp and longjmp-resume breakpoints are also meaningless + after an exec. */ + if (b->type == bp_longjmp || b->type == bp_longjmp_resume) + { + delete_breakpoint (b); + continue; + } + /* Don't delete an exec catchpoint, because else the inferior won't stop when it ought! @@ -3968,7 +3974,6 @@ set_default_breakpoint (int valid, CORE_ bp_read_watchpoint bp_access_watchpoint bp_catch_exec - bp_longjmp_resume bp_catch_fork bp_catch_vork */ @@ -3982,7 +3987,6 @@ breakpoint_address_is_meaningful (struct && type != bp_read_watchpoint && type != bp_access_watchpoint && type != bp_catch_exec - && type != bp_longjmp_resume && type != bp_catch_fork && type != bp_catch_vfork); } @@ -4349,20 +4353,9 @@ create_longjmp_breakpoint (char *func_na struct breakpoint *b; struct minimal_symbol *m; - if (func_name == NULL) - b = create_internal_breakpoint (0, bp_longjmp_resume); - else - { - if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL) - return; - - b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp); - } - - b->enable_state = bp_disabled; - b->silent = 1; - if (func_name) - b->addr_string = xstrdup (func_name); + if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL) + return; + set_momentary_breakpoint_at_pc (SYMBOL_VALUE_ADDRESS (m), bp_longjmp); } /* Call this routine when stepping and nexting to enable a breakpoint @@ -4370,30 +4363,31 @@ create_longjmp_breakpoint (char *func_na set_longjmp_resume_breakpoint() to figure out where we are going. */ void -enable_longjmp_breakpoint (void) +set_longjmp_breakpoint (void) { struct breakpoint *b; - ALL_BREAKPOINTS (b) - if (b->type == bp_longjmp) + if (gdbarch_get_longjmp_target_p (current_gdbarch)) { - b->enable_state = bp_enabled; - check_duplicates (b); + create_longjmp_breakpoint ("longjmp"); + create_longjmp_breakpoint ("_longjmp"); + create_longjmp_breakpoint ("siglongjmp"); + create_longjmp_breakpoint ("_siglongjmp"); } } +/* Delete all longjmp breakpoints from PTID. */ void -disable_longjmp_breakpoint (void) +delete_longjmp_breakpoint (int thread) { - struct breakpoint *b; + struct breakpoint *b, *temp; - ALL_BREAKPOINTS (b) - if (b->type == bp_longjmp - || b->type == bp_longjmp_resume) - { - b->enable_state = bp_disabled; - check_duplicates (b); - } + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->type == bp_longjmp) + { + if (b->thread == thread) + delete_breakpoint (b); + } } static void @@ -4679,30 +4673,6 @@ hw_watchpoint_used_count (enum bptype ty return i; } -/* Call this after hitting the longjmp() breakpoint. Use this to set - a new breakpoint at the target of the jmp_buf. - - FIXME - This ought to be done by setting a temporary breakpoint - that gets deleted automatically... */ - -void -set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_id frame_id) -{ - struct breakpoint *b; - - ALL_BREAKPOINTS (b) - if (b->type == bp_longjmp_resume) - { - b->loc->requested_address = pc; - b->loc->address = adjust_breakpoint_address (b->loc->requested_address, - b->type); - b->enable_state = bp_enabled; - b->frame_id = frame_id; - check_duplicates (b); - return; - } -} - void disable_watchpoints_before_interactive_call_start (void) { @@ -4764,6 +4734,19 @@ set_momentary_breakpoint (struct symtab_ return b; } + +struct breakpoint * +set_momentary_breakpoint_at_pc (CORE_ADDR pc, enum bptype type) +{ + struct symtab_and_line sal; + + sal = find_pc_line (pc, 0); + sal.pc = pc; + sal.section = find_pc_overlay (pc); + sal.explicit_pc = 1; + + return set_momentary_breakpoint (sal, null_frame_id, type); +} /* Tell the user we have just set a breakpoint B. */ @@ -7423,10 +7406,8 @@ breakpoint_re_set_one (void *bint) default: printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type); /* fall through */ - /* Delete longjmp and overlay event breakpoints; they will be - reset later by breakpoint_re_set. */ - case bp_longjmp: - case bp_longjmp_resume: + /* Delete overlay event breakpoints; they will be reset later by + breakpoint_re_set. */ case bp_overlay_event: delete_breakpoint (b); break; @@ -7448,6 +7429,8 @@ breakpoint_re_set_one (void *bint) case bp_watchpoint_scope: case bp_call_dummy: case bp_step_resume: + case bp_longjmp: + case bp_longjmp_resume: break; } @@ -7475,15 +7458,6 @@ breakpoint_re_set (void) } set_language (save_language); input_radix = save_input_radix; - - if (gdbarch_get_longjmp_target_p (current_gdbarch)) - { - create_longjmp_breakpoint ("longjmp"); - create_longjmp_breakpoint ("_longjmp"); - create_longjmp_breakpoint ("siglongjmp"); - create_longjmp_breakpoint ("_siglongjmp"); - create_longjmp_breakpoint (NULL); - } create_overlay_event_breakpoint ("_ovly_debug_event"); } Index: src/gdb/infrun.c =================================================================== --- src.orig/gdb/infrun.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/infrun.c 2008-04-07 02:41:01.000000000 +0100 @@ -271,6 +271,7 @@ struct regcache *stop_registers; static int stop_print_frame; +/* Step-resume or longjmp-resume breakpoint. */ static struct breakpoint *step_resume_breakpoint = NULL; /* This is a cached copy of the pid/waitstatus of the last event @@ -947,7 +948,6 @@ struct execution_control_state struct symtab_and_line sal; int current_line; struct symtab *current_symtab; - int handling_longjmp; /* FIXME */ ptid_t ptid; ptid_t saved_inferior_ptid; int step_after_step_resume_breakpoint; @@ -969,6 +969,8 @@ static void insert_step_resume_breakpoin static void insert_step_resume_breakpoint_at_caller (struct frame_info *); static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, struct frame_id sr_id); +static void insert_longjmp_resume_breakpoint (CORE_ADDR); + static void stop_stepping (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs); static void keep_going (struct execution_control_state *ecs); @@ -1118,7 +1120,6 @@ init_execution_control_state (struct exe ecs->stepping_over_breakpoint = 0; ecs->random_signal = 0; ecs->step_after_step_resume_breakpoint = 0; - ecs->handling_longjmp = 0; /* FIXME */ ecs->stepping_through_solib_after_catch = 0; ecs->stepping_through_solib_catchpoints = NULL; ecs->sal = find_pc_line (prev_pc, 0); @@ -1173,7 +1174,7 @@ context_switch (struct execution_control stepping_over_breakpoint, step_resume_breakpoint, step_range_start, step_range_end, &step_frame_id, - ecs->handling_longjmp, ecs->stepping_over_breakpoint, + ecs->stepping_over_breakpoint, ecs->stepping_through_solib_after_catch, ecs->stepping_through_solib_catchpoints, ecs->current_line, ecs->current_symtab); @@ -1183,7 +1184,7 @@ context_switch (struct execution_control &stepping_over_breakpoint, &step_resume_breakpoint, &step_range_start, &step_range_end, &step_frame_id, - &ecs->handling_longjmp, &ecs->stepping_over_breakpoint, + &ecs->stepping_over_breakpoint, &ecs->stepping_through_solib_after_catch, &ecs->stepping_through_solib_catchpoints, &ecs->current_line, &ecs->current_symtab); @@ -2106,38 +2107,50 @@ process_event_stop_test: switch (what.main_action) { case BPSTAT_WHAT_SET_LONGJMP_RESUME: - /* If we hit the breakpoint at longjmp, disable it for the - duration of this command. Then, install a temporary - breakpoint at the target of the jmp_buf. */ - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n"); - disable_longjmp_breakpoint (); + /* If we hit the breakpoint at longjmp while stepping, we + install a momentary breakpoint at the target of the + jmp_buf. */ + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n"); + + ecs->stepping_over_breakpoint = 1; + if (!gdbarch_get_longjmp_target_p (current_gdbarch) || !gdbarch_get_longjmp_target (current_gdbarch, get_current_frame (), &jmp_buf_pc)) { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "\ +infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); keep_going (ecs); return; } - /* Need to blow away step-resume breakpoint, as it - interferes with us */ + /* We're going to replace the current step-resume breakpoint + with a longjmp-resume breakpoint. */ if (step_resume_breakpoint != NULL) - { - delete_step_resume_breakpoint (&step_resume_breakpoint); - } + delete_step_resume_breakpoint (&step_resume_breakpoint); + + /* Insert a breakpoint at resume address. */ + insert_longjmp_resume_breakpoint (jmp_buf_pc); - set_longjmp_resume_breakpoint (jmp_buf_pc, null_frame_id); - ecs->handling_longjmp = 1; /* FIXME */ keep_going (ecs); return; case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); - disable_longjmp_breakpoint (); - ecs->handling_longjmp = 0; /* FIXME */ - break; + fprintf_unfiltered (gdb_stdlog, + "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); + + gdb_assert (step_resume_breakpoint != NULL); + delete_step_resume_breakpoint (&step_resume_breakpoint); + + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; case BPSTAT_WHAT_SINGLE: if (debug_infrun) @@ -2704,9 +2717,8 @@ process_event_stop_test: static int currently_stepping (struct execution_control_state *ecs) { - return ((!ecs->handling_longjmp - && ((step_range_end && step_resume_breakpoint == NULL) - || stepping_over_breakpoint)) + return (((step_range_end && step_resume_breakpoint == NULL) + || stepping_over_breakpoint) || ecs->stepping_through_solib_after_catch || bpstat_should_step ()); } @@ -2793,8 +2805,8 @@ static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, struct frame_id sr_id) { - /* There should never be more than one step-resume breakpoint per - thread, so we should never be setting a new + /* There should never be more than one step-resume or longjmp-resume + breakpoint per thread, so we should never be setting a new step_resume_breakpoint when one is already active. */ gdb_assert (step_resume_breakpoint == NULL); @@ -2862,6 +2874,28 @@ insert_step_resume_breakpoint_at_caller insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame)); } +/* Insert a "longjmp-resume" breakpoint at PC. This is used to set a + new breakpoint at the target of a jmp_buf. The handling of + longjmp-resume uses the same mechanisms used for handling + "step-resume" breakpoints. */ + +static void +insert_longjmp_resume_breakpoint (CORE_ADDR pc) +{ + /* There should never be more than one step-resume or longjmp-resume + breakpoint per thread, so we should never be setting a new + longjmp_resume_breakpoint when one is already active. */ + gdb_assert (step_resume_breakpoint == NULL); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: inserting longjmp-resume breakpoint at 0x%s\n", + paddr_nz (pc)); + + step_resume_breakpoint = + set_momentary_breakpoint_at_pc (pc, bp_longjmp_resume); +} + static void stop_stepping (struct execution_control_state *ecs) { Index: src/gdb/breakpoint.h =================================================================== --- src.orig/gdb/breakpoint.h 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/breakpoint.h 2008-04-07 02:28:24.000000000 +0100 @@ -686,6 +686,9 @@ extern int ep_is_exception_catchpoint (s extern struct breakpoint *set_momentary_breakpoint (struct symtab_and_line, struct frame_id, enum bptype); +extern struct breakpoint *set_momentary_breakpoint_at_pc + (CORE_ADDR pc, enum bptype type); + extern void set_ignore_count (int, int, int); extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int); @@ -756,12 +759,12 @@ extern void update_breakpoints_after_exe inferior_ptid. */ extern int detach_breakpoints (int); -extern void enable_longjmp_breakpoint (void); -extern void disable_longjmp_breakpoint (void); +extern void set_longjmp_breakpoint (void); +extern void delete_longjmp_breakpoint (int thread); + extern void enable_overlay_breakpoints (void); extern void disable_overlay_breakpoints (void); -extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_id); /* These functions respectively disable or reenable all currently enabled watchpoints. When disabled, the watchpoints are marked call_disabled. When reenabled, they are marked enabled. Index: src/gdb/gdbthread.h =================================================================== --- src.orig/gdb/gdbthread.h 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/gdbthread.h 2008-04-07 02:28:24.000000000 +0100 @@ -50,7 +50,6 @@ struct thread_info int current_line; struct symtab *current_symtab; int trap_expected; - int handling_longjmp; int stepping_over_breakpoint; /* This is set TRUE when a catchpoint of a shared library event @@ -123,7 +122,6 @@ extern void save_infrun_state (ptid_t pt CORE_ADDR step_range_start, CORE_ADDR step_range_end, const struct frame_id *step_frame_id, - int handling_longjmp, int another_trap, int stepping_through_solib_after_catch, bpstat stepping_through_solib_catchpoints, @@ -139,7 +137,6 @@ extern void load_infrun_state (ptid_t pt CORE_ADDR *step_range_start, CORE_ADDR *step_range_end, struct frame_id *step_frame_id, - int *handling_longjmp, int *another_trap, int *stepping_through_solib_affter_catch, bpstat *stepping_through_solib_catchpoints, Index: src/gdb/thread.c =================================================================== --- src.orig/gdb/thread.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/thread.c 2008-04-07 02:28:24.000000000 +0100 @@ -316,7 +316,6 @@ load_infrun_state (ptid_t ptid, CORE_ADDR *step_range_start, CORE_ADDR *step_range_end, struct frame_id *step_frame_id, - int *handling_longjmp, int *stepping_over_breakpoint, int *stepping_through_solib_after_catch, bpstat *stepping_through_solib_catchpoints, @@ -337,7 +336,6 @@ load_infrun_state (ptid_t ptid, *step_range_start = tp->step_range_start; *step_range_end = tp->step_range_end; *step_frame_id = tp->step_frame_id; - *handling_longjmp = tp->handling_longjmp; *stepping_over_breakpoint = tp->stepping_over_breakpoint; *stepping_through_solib_after_catch = tp->stepping_through_solib_after_catch; @@ -357,7 +355,6 @@ save_infrun_state (ptid_t ptid, CORE_ADDR step_range_start, CORE_ADDR step_range_end, const struct frame_id *step_frame_id, - int handling_longjmp, int stepping_over_breakpoint, int stepping_through_solib_after_catch, bpstat stepping_through_solib_catchpoints, @@ -378,7 +375,6 @@ save_infrun_state (ptid_t ptid, tp->step_range_start = step_range_start; tp->step_range_end = step_range_end; tp->step_frame_id = (*step_frame_id); - tp->handling_longjmp = handling_longjmp; tp->stepping_over_breakpoint = stepping_over_breakpoint; tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch; tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints; Index: src/gdb/infcmd.c =================================================================== --- src.orig/gdb/infcmd.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/infcmd.c 2008-04-07 02:28:24.000000000 +0100 @@ -49,6 +49,7 @@ #include "target-descriptions.h" #include "user-regs.h" #include "exceptions.h" +#include "gdbthread.h" /* Functions exported for general use, in inferior.h: */ @@ -689,9 +690,11 @@ nexti_command (char *count_string, int f } static void -disable_longjmp_breakpoint_cleanup (void *ignore) +delete_longjmp_breakpoint_cleanup (void *arg) { - disable_longjmp_breakpoint (); + int thread = * (int *) arg; + xfree (arg); + delete_longjmp_breakpoint (thread); } static void @@ -724,11 +727,24 @@ step_1 (int skip_subroutines, int single if (!single_inst || skip_subroutines) /* leave si command alone */ { - enable_longjmp_breakpoint (); + struct cleanup *old_chain; + int *thread; + + thread = xmalloc (sizeof (int)); + old_chain = make_cleanup (xfree, thread); + + if (in_thread_list (inferior_ptid)) + *thread = pid_to_thread_id (inferior_ptid); + else + *thread = -1; + + set_longjmp_breakpoint (); + + discard_cleanups (old_chain); if (!target_can_async_p ()) - cleanups = make_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); + cleanups = make_cleanup (delete_longjmp_breakpoint_cleanup, thread); else - make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); + make_exec_cleanup (delete_longjmp_breakpoint_cleanup, thread); } /* In synchronous case, all is well, just use the regular for loop. */ Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2008-04-07 02:28:11.000000000 +0100 +++ src/gdb/Makefile.in 2008-04-07 02:41:05.000000000 +0100 @@ -2291,7 +2291,7 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_strin $(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \ $(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \ $(solib_h) $(gdb_assert_h) $(observer_h) $(target_descriptions_h) \ - $(user_regs_h) $(exceptions_h) + $(user_regs_h) $(exceptions_h) $(gdbthread_h) inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \ $(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) \ $(language_h) --Boundary-00=_ydY+HfBBDAx9Zoa--