From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5225 invoked by alias); 16 Nov 2009 15:05:47 -0000 Received: (qmail 5211 invoked by uid 22791); 16 Nov 2009 15:05:45 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 16 Nov 2009 15:04:50 +0000 Received: (qmail 29592 invoked from network); 16 Nov 2009 15:04:48 -0000 Received: from unknown (HELO orlando) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 16 Nov 2009 15:04:48 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Re: RFC: Longjmp vs LD_POINTER_GUARD revisited Date: Mon, 16 Nov 2009 15:05:00 -0000 User-Agent: KMail/1.9.10 Cc: Daniel Jacobowitz , Paul Pluzhnikov , Ulrich Weigand References: <20091115173429.GB23483@caradoc.them.org> <20091116143613.GA9703@caradoc.them.org> <200911161453.50890.pedro@codesourcery.com> In-Reply-To: <200911161453.50890.pedro@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Message-Id: <200911161504.50279.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: 2009-11/txt/msg00358.txt.bz2 On Monday 16 November 2009 14:53:50, Pedro Alves wrote: > =A0- I've tried a similar hack as yours and found that I had > =A0 =A0to add several more "functions still within longjmp" special > =A0 =A0cases. =A0I had tried it on netbsd and Windows too. =A0NetBSD > =A0 =A0was also bad at needing special casing. =A0I'll post the relevant > =A0 =A0bits of the patch in a bit, when I find it :-) >=20 Here they are... --=20 Pedro Alves Index: src/gdb/infrun.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src.orig/gdb/infrun.c 2009-07-25 16:47:07.000000000 +0100 +++ src/gdb/infrun.c 2009-07-25 18:28:50.000000000 +0100 @@ -1330,6 +1330,9 @@ clear_proceed_status_thread (struct thre =20 tp->proceed_to_finish =3D 0; =20 + tp->stepping_through_longjmp =3D 0; + tp->longjmp_frame =3D null_frame_id; + /* Discard any remaining commands or status from previous stop. */ bpstat_clear (&tp->stop_bpstat); } @@ -3248,7 +3251,8 @@ targets should add new threads to the th =3D !(bpstat_explains_signal (ecs->event_thread->stop_bpstat) || ecs->event_thread->trap_expected || (ecs->event_thread->step_range_end - && ecs->event_thread->step_resume_breakpoint =3D=3D NULL)); + && ecs->event_thread->step_resume_breakpoint =3D=3D NULL) + || ecs->event_thread->stepping_through_longjmp); else { ecs->random_signal =3D !bpstat_explains_signal (ecs->event_thread->stop= _bpstat); @@ -3374,7 +3378,6 @@ process_event_stop_test: =20 /* Handle cases caused by hitting a breakpoint. */ { - CORE_ADDR jmp_buf_pc; struct bpstat_what what; =20 what =3D bpstat_what (ecs->event_thread->stop_bpstat); @@ -3387,33 +3390,19 @@ process_event_stop_test: switch (what.main_action) { case BPSTAT_WHAT_SET_LONGJMP_RESUME: - /* If we hit the breakpoint at longjmp while stepping, we - install a momentary breakpoint at the target of the - jmp_buf. */ - + /* If we hit the breakpoint at longjmp while stepping, prepare + to step all the way through it. */ if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n"); =20 + /* Step over this longjmp breakpoint. */ ecs->event_thread->stepping_over_breakpoint =3D 1; =20 - if (!gdbarch_get_longjmp_target_p (gdbarch) - || !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"); - keep_going (ecs); - 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); - + /* Store longjmp's frame id. We'll single-step until an outer + frame becomes current. */ + ecs->event_thread->longjmp_frame =3D get_frame_id (get_current_frame ()); + ecs->event_thread->stepping_through_longjmp =3D 1; keep_going (ecs); return; =20 @@ -3641,6 +3630,135 @@ infrun: not switching back to stepped th return; } =20 + if (ecs->event_thread->stepping_through_longjmp) + { + struct thread_info *tp =3D ecs->event_thread; + struct frame_info *frame =3D get_current_frame (); + struct gdbarch *gdbarch =3D get_frame_arch (frame); + struct minimal_symbol *msymbol; + + /* While we're still inside longjmp, in most implementations, + matching by frame id won't work, unfortunately, either + because unwind info is missing the correct annotations, or + because the frame parsers have a hard time with the PC, SP, + and FP juggling going on inside longjmp. Libc + implementations that apply some form of mangling to + jmp_buf's are the worse offenders. There's another caveat + here: if we find ourselves in code that has no symbol info + whatsoever, we don't really know if we're still inside + longjmp, or, if we've reached a setjmp landing site that had + no debug info. We're assuming the former. */ + + if (in_solib_dynsym_resolve_code (get_frame_pc (frame))) + { + CORE_ADDR pc_after_resolver =3D + gdbarch_skip_solib_resolver (get_frame_arch (frame), get_frame_pc (f= rame)); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: stepped into dynsym resolve= code\n"); + + if (pc_after_resolver) + { + /* Set up a step-resume breakpoint at the address + indicated by SKIP_SOLIB_RESOLVER. */ + struct symtab_and_line sr_sal; + init_sal (&sr_sal); + sr_sal.pc =3D pc_after_resolver; + + insert_step_resume_breakpoint_at_sal (gdbarch, + sr_sal, null_frame_id); + } + + keep_going (ecs); + return; + } + + msymbol =3D lookup_minimal_symbol_by_pc (get_frame_pc (frame)); + if (msymbol =3D=3D NULL) + { + /* We're still supposedly in longjmp, keep going. Should + perhaps check if we're still in the same module (that + is, catch going out of libc.so?) */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stepping through longjmp (in ??\?)\n"); + keep_going (ecs); + return; + } + else if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), "longjmp") =3D=3D 0 + || strcmp (SYMBOL_LINKAGE_NAME (msymbol), "_longjmp") =3D=3D 0 + || strcmp (SYMBOL_LINKAGE_NAME (msymbol), "siglongjmp") =3D=3D 0 + || strcmp (SYMBOL_LINKAGE_NAME (msymbol), "_siglongjmp") =3D=3D 0) + { + /* Update the recorded frame id, as it is likely to not be + stable (in a perfect world, it would be, though). */ + tp->longjmp_frame =3D get_frame_id (frame); + + /* We're still in longjmp, keep going. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stepping through longjmp (in longjmp)\n"); + keep_going (ecs); + return; + } + /* Make this an uglier than ugly architecture specific callback + "un-unwindable functions that are called by longjmp, and + can't be longjmp landing sites" list? Sigh... */ + else if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), + "__pthread_cleanup_upto") =3D=3D 0 /* linux */ + /* openbsd */ + || strcmp (SYMBOL_LINKAGE_NAME (msymbol), "sigsetmask") =3D=3D 0) + { + /* We're still waiting for the longjmp, keep going. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stepping through longjmp (in callee)\n"); + keep_going (ecs); + return; + } + else if (frame_find_by_id (tp->longjmp_frame) !=3D NULL) + { + /* We still have the longjmp frame in the frame chain, keep + going. In theory, we would only need this check. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stepping through longjmp (in frame chain)\n"); + keep_going (ecs); + return; + } + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: got out of longjmp\n"); + + /* We made it. */ + tp->stepping_through_longjmp =3D 0; + + /* If there's a step-resume breakpoint set, decide if we should + keep stepping to the step-resume breakpoint, or if the + longjmp took us outermost already, hence the step-resume + breakpoint will never be hit, and we should stop now. */ + if (ecs->event_thread->step_resume_breakpoint) + { + if (!frame_id_eq (get_frame_id (frame), + tp->step_resume_breakpoint->frame_id) + && frame_find_by_id (tp->step_resume_breakpoint->frame_id)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "\ +infrun: longjmp-resume inner than step-resume\n"); + } + else + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: step-resume overran by longjmp\n"); + delete_step_resume_breakpoint (ecs->event_thread); + stop_stepping (ecs); + return; + } + } + } + if (ecs->event_thread->step_resume_breakpoint) { if (debug_infrun) @@ -4165,7 +4283,8 @@ currently_stepping (struct thread_info * return ((tp->step_range_end && tp->step_resume_breakpoint =3D=3D NULL) || tp->trap_expected || tp->stepping_through_solib_after_catch - || bpstat_should_step ()); + || bpstat_should_step () + || tp->stepping_through_longjmp); } =20 /* Returns true if any thread *but* the one passed in "data" is in the @@ -4179,7 +4298,8 @@ currently_stepping_or_nexting_callback ( =20 return (tp->step_range_end || tp->trap_expected - || tp->stepping_through_solib_after_catch); + || tp->stepping_through_solib_after_catch + || tp->stepping_through_longjmp); } =20 /* Inferior has stepped into a subroutine call with source code that Index: src/gdb/gdbthread.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src.orig/gdb/gdbthread.h 2009-07-25 16:47:07.000000000 +0100 +++ src/gdb/gdbthread.h 2009-07-25 17:06:40.000000000 +0100 @@ -185,6 +185,12 @@ struct thread_info /* True if this thread has been explicitly requested to stop. */ int stop_requested; =20 + /* True if a longjmp call was detected while stepping, and we're + single-stepping until we reach the other end. */ + int stepping_through_longjmp; + /* The frame of the longjmp we're currently handling. */ + struct frame_id longjmp_frame; + /* Private data used by the target vector implementation. */ struct private_thread_info *private; }; Index: src/gdb/breakpoint.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src.orig/gdb/breakpoint.c 2009-07-25 16:47:07.000000000 +0100 +++ src/gdb/breakpoint.c 2009-07-25 17:06:40.000000000 +0100 @@ -1532,9 +1532,6 @@ create_longjmp_master_breakpoint (char * struct breakpoint *b; struct minimal_symbol *m; =20 - if (!gdbarch_get_longjmp_target_p (get_objfile_arch (objfile))) - continue; - m =3D lookup_minimal_symbol_text (func_name, objfile); if (m =3D=3D NULL) continue; Index: src/gdb/testsuite/gdb.base/longjmp.exp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src.orig/gdb/testsuite/gdb.base/longjmp.exp 2009-07-25 16:47:07.0000000= 00 +0100 +++ src/gdb/testsuite/gdb.base/longjmp.exp 2009-07-25 17:06:40.000000000 +0= 100 @@ -127,4 +127,4 @@ gdb_test "break $bp_start_test_3" \ "breakpoint at pattern 3 start" gdb_test "continue" "patt3.*" "continue to breakpoint at pattern 3 start" =20 -gdb_test "next" "longjmp caught.*" "next over patt3" +gdb_test "next" "patt_end3.*" "next over patt3"