From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5557 invoked by alias); 1 Sep 2008 16:47:20 -0000 Received: (qmail 5549 invoked by uid 22791); 1 Sep 2008 16:47:19 -0000 X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (212.99.106.210) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 01 Sep 2008 16:46:45 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id E9783290002; Mon, 1 Sep 2008 18:46:41 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 20waOEMrbhp5; Mon, 1 Sep 2008 18:46:41 +0200 (CEST) Received: from province.act-europe.fr (province.act-europe.fr [10.10.0.214]) by mel.act-europe.fr (Postfix) with ESMTP id 30DEE290001 for ; Mon, 1 Sep 2008 18:46:41 +0200 (CEST) Received: by province.act-europe.fr (Postfix, from userid 560) id 10E9A1672BA; Mon, 1 Sep 2008 18:46:41 +0200 (CEST) Date: Mon, 01 Sep 2008 16:47:00 -0000 From: Jerome Guitton To: gdb-patches@sourceware.org Subject: [RFA/powerpc] Add handling for stack-check sequences in prologue Message-ID: <20080901164641.GA226@adacore.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Dxnq1zWXvFF0Q93v" Content-Disposition: inline User-Agent: Mutt/1.5.17 (2007-11-01) 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-09/txt/msg00005.txt.bz2 --Dxnq1zWXvFF0Q93v Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1228 Hello, On PPC targets, the debugger fails to unwind past some stack-check sequences. The attached patch should fix that. I have double-checked with Eric Botcazou to make sure that all possible cases are caught... Roughly: 1) A small number of probes: stw 0, -(1) repeated any (small) number of times... 2) A probing loop: addi 12,1,- lis 0,- [possibly ori 0,0,] add 0,12,0 cmpw 0,12,0 beq 0, addi 12,12,- stw 0,0(12) b [possibly one last probe: stw 0,(12)] 3) No probe; instead, a comparizon between the stack size limit (saved in a run-time global variable) and the current stack pointer: addi 0,1,- lis 12,__gnat_stack_limit@ha lwz 12,__gnat_stack_limit@l(12) twllt 0,12 2008-09-01 Jerome Guitton * rs6000-tdep.c (rs6000_fetch_instruction) (rs6000_skip_stack_check): New functions. (skip_prologue): Skip stack check sequence. Tested on AIX, no regression. I'll post my testcases in a minute. OK to apply? Thanks, - Jerome --Dxnq1zWXvFF0Q93v Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="stack-check.diff" Content-length: 5682 Index: rs6000-tdep.c =================================================================== --- rs6000-tdep.c (revision 134839) +++ rs6000-tdep.c (working copy) @@ -1374,6 +1374,191 @@ bl_to_blrl_insn_p (CORE_ADDR pc, int ins return 0; } +static unsigned long +rs6000_fetch_instruction (const CORE_ADDR pc) +{ + gdb_byte buf[4]; + unsigned long op; + + /* Fetch the instruction and convert it to an integer. */ + if (target_read_memory (pc, buf, 4)) + return 0; + op = extract_unsigned_integer (buf, 4); + + return op; +} + +/* 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 +rs6000_skip_stack_check (const CORE_ADDR start_pc) +{ + CORE_ADDR pc = start_pc; + unsigned long op = rs6000_fetch_instruction (pc); + + /* First possible sequence: A small number of probes. + stw 0, -(1) + [repeat this instruction any (small) number of times] + */ + + if ((op & 0xffff0000) == 0x90010000) + { + while ((op & 0xffff0000) == 0x90010000) + { + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + } + return pc; + } + + /* Second sequence: A probing loop. + addi 12,1,- + lis 0,- + [possibly ori 0,0,] + add 0,12,0 + cmpw 0,12,0 + beq 0, + addi 12,12,- + stw 0,0(12) + b + [possibly one last probe: stw 0,(12)] + */ + + while (1) + { + /* addi 12,1,- */ + if ((op & 0xffff0000) != 0x39810000) + break; + + /* lis 0,- */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x3c000000) + break; + + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + /* [possibly ori 0,0,] */ + if ((op & 0xffff0000) == 0x60000000) + { + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + } + /* add 0,12,0 */ + if (op != 0x7c0c0214) + break; + + /* cmpw 0,12,0 */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if (op != 0x7c0c0000) + break; + + /* beq 0, */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xff9f0001) != 0x41820000) + break; + + /* addi 12,12,- */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x398c0000) + break; + + /* stw 0,0(12) */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if (op != 0x900c0000) + break; + + /* b */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xfc000001) != 0x48000000) + break; + + + /* [possibly one last probe: stw 0,(12)] */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) == 0x900c0000) + { + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + } + + /* We found a valid stack-check sequence, return the new PC. */ + return pc; + } + + /* Third sequence: No probe; instead, a comparizon between the stack size + limit (saved in a run-time global variable) and the current stack + pointer: + + addi 0,1,- + lis 12,__gnat_stack_limit@ha + lwz 12,__gnat_stack_limit@l(12) + twllt 0,12 + + or, with a small variant in the case of a bigger stack frame: + addis 0,1, + addic 0,0,- + lis 12,__gnat_stack_limit@ha + lwz 12,__gnat_stack_limit@l(12) + twllt 0,12 + */ + while (1) + { + /* addi 0,1,- */ + if ((op & 0xffff0000) != 0x38010000) + { + /* small stack frame variant not recognized; try the + big stack frame variant: */ + + /* addis 0,1, */ + if ((op & 0xffff0000) != 0x3c010000) + break; + + /* addic 0,0,- */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x30000000) + break; + } + + + /* lis 12, */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x3d800000) + break; + + /* lwz 12,(12) */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x818c0000) + break; + + /* twllt 0,12 */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xfffffffe) != 0x7c406008) + break; + + /* 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; +} + + /* return pc value after skipping a function prologue and also return information about a function frame. @@ -1433,6 +1618,10 @@ skip_prologue (struct gdbarch *gdbarch, fdata->nosavedpc = 1; fdata->lr_register = -1; + pc = rs6000_skip_stack_check (pc); + if (pc >= lim_pc) + pc = lim_pc; + for (;; pc += 4) { /* Sometimes it isn't clear if an instruction is a prologue --Dxnq1zWXvFF0Q93v--