From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29456 invoked by alias); 18 Nov 2013 12:51:20 -0000 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 Received: (qmail 29445 invoked by uid 89); 18 Nov 2013 12:51:20 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.2 required=5.0 tests=AWL,BAYES_50,RDNS_NONE,UNPARSEABLE_RELAY,URIBL_BLOCKED autolearn=no version=3.3.2 X-HELO: aserp1040.oracle.com Received: from Unknown (HELO aserp1040.oracle.com) (141.146.126.69) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Mon, 18 Nov 2013 12:51:15 +0000 Received: from acsinet22.oracle.com (acsinet22.oracle.com [141.146.126.238]) by aserp1040.oracle.com (Sentrion-MTA-4.3.1/Sentrion-MTA-4.3.1) with ESMTP id rAICp2qp019264 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 18 Nov 2013 12:51:02 GMT Received: from aserz7021.oracle.com (aserz7021.oracle.com [141.146.126.230]) by acsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id rAICp09F029544 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 18 Nov 2013 12:51:01 GMT Received: from abhmp0014.oracle.com (abhmp0014.oracle.com [141.146.116.20]) by aserz7021.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id rAICp01k016734; Mon, 18 Nov 2013 12:51:00 GMT Received: from termi.oracle.com (/10.175.53.2) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 18 Nov 2013 04:50:59 -0800 From: jose.marchesi@oracle.com (Jose E. Marchesi) To: Mark Kettenis Cc: brobecker@adacore.com, tromey@redhat.com, gdb-patches@sourceware.org Subject: Re: [PATCH] [SPARC64] Figure out where a longjmp will land References: <87y563k71b.fsf@oracle.com> <87d2nffr53.fsf@fleche.redhat.com> <87txgrjupm.fsf@oracle.com> <20131017055736.GC3302@adacore.com> <201310201926.r9KJQlD4017034@glazunov.sibelius.xs4all.nl> <87y55mwzou.fsf@oracle.com> <201310220821.r9M8LxKi011361@glazunov.sibelius.xs4all.nl> Date: Mon, 18 Nov 2013 14:02:00 -0000 In-Reply-To: <201310220821.r9M8LxKi011361@glazunov.sibelius.xs4all.nl> (Mark Kettenis's message of "Tue, 22 Oct 2013 10:21:59 +0200 (CEST)") Message-ID: <87iovpdg7e.fsf@oracle.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes X-SW-Source: 2013-11/txt/msg00463.txt.bz2 > Shall I address him directly? So yes, that might be a good idea. Your last diff is fine with me, so if Dave doesn't respond within a couple of days after you ping him, feel free to move ahead with this. I just committed the attached amended patch, reviewed by Mark and Dave off-list and authorized by Mark. 2013-10-08 Jose E. Marchesi * sparc-tdep.c (sparc_is_annulled_branch_insn): New function. * sparc-tdep.h: And its prototype. * sparc64-linux-tdep.c (sparc64_linux_get_longjmp_target): New function. (sparc64_linux_init_abi): Register the get_longjmp_target hook. diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index 880d276..4057d0d 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -121,6 +121,37 @@ sparc_is_unimp_insn (CORE_ADDR pc) return ((insn & 0xc1c00000) == 0); } +/* Return non-zero if the instruction corresponding to PC is an + "annulled" branch, i.e. the annul bit is set. */ + +int +sparc_is_annulled_branch_insn (CORE_ADDR pc) +{ + /* The branch instructions featuring an annul bit can be identified + by the following bit patterns: + + OP=0 + OP2=1: Branch on Integer Condition Codes with Prediction (BPcc). + OP2=2: Branch on Integer Condition Codes (Bcc). + OP2=5: Branch on FP Condition Codes with Prediction (FBfcc). + OP2=6: Branch on FP Condition Codes (FBcc). + OP2=3 && Bit28=0: + Branch on Integer Register with Prediction (BPr). + + This leaves out ILLTRAP (OP2=0), SETHI/NOP (OP2=4) and the V8 + coprocessor branch instructions (Op2=7). */ + + const unsigned long insn = sparc_fetch_instruction (pc); + const unsigned op2 = X_OP2 (insn); + + if ((X_OP (insn) == 0) + && ((op2 == 1) || (op2 == 2) || (op2 == 5) || (op2 == 6) + || ((op2 == 3) && ((insn & 0x10000000) == 0)))) + return X_A (insn); + else + return 0; +} + /* OpenBSD/sparc includes StackGhost, which according to the author's website http://stackghost.cerias.purdue.edu "... transparently and automatically protects applications' stack frames; more diff --git a/gdb/sparc-tdep.h b/gdb/sparc-tdep.h index cafc627..6fd7641 100644 --- a/gdb/sparc-tdep.h +++ b/gdb/sparc-tdep.h @@ -220,6 +220,8 @@ extern void sparc32_collect_fpregset (const struct sparc_fpregset *fpregset, const struct regcache *regcache, int regnum, void *fpregs); +extern int sparc_is_annulled_branch_insn (CORE_ADDR pc); + /* Functions and variables exported from sparc-sol2-tdep.c. */ /* Register offsets for Solaris 2. */ diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c index 3f53f6c..f6ddff0 100644 --- a/gdb/sparc64-linux-tdep.c +++ b/gdb/sparc64-linux-tdep.c @@ -233,6 +233,50 @@ sparc64_linux_get_syscall_number (struct gdbarch *gdbarch, } +/* Implement the "get_longjmp_target" gdbarch method. */ + +static int +sparc64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + CORE_ADDR jb_addr; + gdb_byte buf[8]; + + jb_addr = get_frame_register_unsigned (frame, SPARC_O0_REGNUM); + + /* setjmp and longjmp in SPARC64 are implemented in glibc using the + setcontext and getcontext system calls respectively. These + system calls operate on ucontext_t structures, which happen to + partially have the same structure than jmp_buf. However the + ucontext returned by getcontext, and thus the jmp_buf structure + returned by setjmp, contains the context of the trap instruction + in the glibc __[sig]setjmp wrapper, not the context of the user + code calling setjmp. + + %o7 in the jmp_buf structure is stored at offset 18*8 in the + mc_gregs array, which is itself located at offset 32 into + jmp_buf. See bits/setjmp.h. This register contains the address + of the 'call setjmp' instruction in user code. + + In order to determine the longjmp target address in the + initiating frame we need to examine the call instruction itself, + in particular whether the annul bit is set. If it is not set + then we need to jump over the instruction at the delay slot. */ + + if (target_read_memory (jb_addr + 32 + (18 * 8), buf, 8)) + return 0; + + *pc = extract_unsigned_integer (buf, 8, gdbarch_byte_order (gdbarch)); + + if (!sparc_is_annulled_branch_insn (*pc)) + *pc += 4; /* delay slot insn */ + *pc += 4; /* call insn */ + + return 1; +} + + static void sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -272,6 +316,9 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Make sure we can single-step over signal return system calls. */ tdep->step_trap = sparc64_linux_step_trap; + /* Make sure we can single-step over longjmp calls. */ + set_gdbarch_get_longjmp_target (gdbarch, sparc64_linux_get_longjmp_target); + set_gdbarch_write_pc (gdbarch, sparc64_linux_write_pc); /* Functions for 'catch syscall'. */