From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10433 invoked by alias); 28 Mar 2007 22:49:12 -0000 Received: (qmail 10350 invoked by uid 22791); 28 Mar 2007 22:49:09 -0000 X-Spam-Check-By: sourceware.org Received: from nile.gnat.com (HELO nile.gnat.com) (205.232.38.5) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 28 Mar 2007 23:49:03 +0100 Received: from localhost (localhost [127.0.0.1]) by filtered-nile.gnat.com (Postfix) with ESMTP id 277F148CE31 for ; Wed, 28 Mar 2007 18:49:02 -0400 (EDT) Received: from nile.gnat.com ([127.0.0.1]) by localhost (nile.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 08221-01-4 for ; Wed, 28 Mar 2007 18:49:02 -0400 (EDT) Received: from joel.gnat.com (unknown [70.71.0.212]) by nile.gnat.com (Postfix) with ESMTP id 6FE2548CDCE for ; Wed, 28 Mar 2007 18:49:01 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 8B353E7B43; Wed, 28 Mar 2007 18:50:13 -0400 (EDT) Date: Wed, 28 Mar 2007 22:49:00 -0000 From: Joel Brobecker To: gdb-patches@sourceware.org Subject: [RFA/sparc] Add handling of stack-check probes Message-ID: <20070328225013.GN3866@adacore.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="yNb1oOkm5a9FJOVX" Content-Disposition: inline User-Agent: Mutt/1.4.2.2i 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: 2007-03/txt/msg00297.txt.bz2 --yNb1oOkm5a9FJOVX Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1627 Hello, GDB is currently unable to unwind past stack-check probes that are inserted by the compiler when compiling with -stack-check. The attached patch adds handling for the sequences currently emitted by GCC. Eric Botcazou told us that they can take 3 forms: 1. A single probe sethi ,%g1 sub %sp, %g1, %g1 clr [%g1 - some immediate] 2. A small number of probes (at most 5) sethi ,%g1 sub %sp, %g1, %g1 clr [%g1] add %g1, -, %g1 clr [%g1] [...] add %g1, -, %g1 clr [%g1] clr [%g1 - some immediate] 3. A probing loop sethi ,%g1 sub %sp, %g1, %g1 sethi , %g4 sub %g1, %g4, %g4 cmp %g1, %g4 be add %g1, -, %g1 ba clr [%g1] clr [%g4 - some immediate] 2007-03-28 Joel Brobecker * sparc-tdep.c (X_RS2): New macro. (sparc_skip_stack_check): New function. (sparc_analyze_prologue): Adjust PC past stack probing sequence if necessary. Tested on sparc-solaris, no regression. OK to apply? Thanks, -- Joel PS: Do other people think that it is simpler for the human brain to understand if (pc >= current_pc) than if (current_pc <= pc) In other words, the boundary value is put on the rhs of the condition, and the variable value is put on the lhs... It's just an aesthetic consideration, but I can change it if others agree. --yNb1oOkm5a9FJOVX Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="stack-check.diff" Content-length: 5934 Index: sparc-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/sparc-tdep.c,v retrieving revision 1.178 diff -u -p -r1.178 sparc-tdep.c --- sparc-tdep.c 27 Feb 2007 20:17:19 -0000 1.178 +++ sparc-tdep.c 28 Mar 2007 22:44:30 -0000 @@ -82,6 +82,7 @@ struct regset; #define X_IMM22(i) ((i) & 0x3fffff) #define X_OP3(i) (((i) >> 19) & 0x3f) #define X_RS1(i) (((i) >> 14) & 0x1f) +#define X_RS2(i) ((i) & 0x1f) #define X_I(i) (((i) >> 13) & 1) /* Sign extension macros. */ #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000) @@ -571,6 +572,156 @@ sparc_alloc_frame_cache (void) return cache; } +/* GCC generates several well-known sequences of instructions at the begining + of each function prologue when compiling with -fstack-check. If one of + such sequences starts at START_PC, then return the address of the + instruction immediately past this sequence. Otherwise, return START_PC. */ + +static CORE_ADDR +sparc_skip_stack_check (const CORE_ADDR start_pc) +{ + CORE_ADDR pc = start_pc; + unsigned long insn; + int offset_stack_checking_sequence = 0; + + /* With GCC, all stack checking sequences begin with the same two + instructions. */ + + /* sethi ,%g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1)) + return start_pc; + + /* sub %sp, %g1, %g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1)) + return start_pc; + + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + + /* First possible sequence: + [first two instructions above] + clr [%g1 - some immediate] */ + + /* clr [%g1 - some immediate] */ + if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 0) + { + /* Valid stack-check sequence, return the new PC. */ + return pc; + } + + /* Second possible sequence: A small number of probes. + [first two instructions above] + clr [%g1] + add %g1, -, %g1 + clr [%g1] + [repeat the two instructions above any (small) number of times] + clr [%g1 - some immediate] */ + + /* clr [%g1] */ + else if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 0) + { + while (1) + { + /* add %g1, -, %g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 1)) + break; + + /* clr [%g1] */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 0 && X_RS1 (insn) == 1)) + return start_pc; + } + + /* clr [%g1 - some immediate] */ + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 0)) + return start_pc; + + /* We found a valid stack-check sequence, return the new PC. */ + return pc; + } + + /* Third sequence: A probing loop. + [first two instructions above] + sethi , %g4 + sub %g1, %g4, %g4 + cmp %g1, %g4 + be + add %g1, -, %g1 + ba + clr [%g1] + clr [%g4 - some immediate] */ + + /* sethi , %g4 */ + else if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4) + { + /* sub %g1, %g4, %g4 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4)) + return start_pc; + + /* cmp %g1, %g4 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x14 && !X_I(insn) + && X_RD (insn) == 0 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4)) + return start_pc; + + /* be */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 0 && X_COND (insn) == 0x1)) + return start_pc; + + /* add %g1, -, %g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 1)) + return start_pc; + + /* ba */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8)) + return start_pc; + + /* clr [%g1] */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 0 && X_RS1 (insn) == 1)) + return start_pc; + + /* clr [%g4 - some immediate] */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn) + && X_RS1 (insn) == 4 && X_RD (insn) == 0)) + return start_pc; + + /* We found a valid stack-check sequence, return the new PC. */ + return pc; + } + + /* No stack check code in our prologue, return the start_pc. */ + return start_pc; +} + CORE_ADDR sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, struct sparc_frame_cache *cache) @@ -580,6 +731,8 @@ sparc_analyze_prologue (CORE_ADDR pc, CO int offset = 0; int dest = -1; + pc = sparc_skip_stack_check (pc); + if (current_pc <= pc) return current_pc; --yNb1oOkm5a9FJOVX--