From de9f48f0c431c9dcbee390a7ba8aad1a4f45128c Mon Sep 17 00:00:00 2001 From: Jerome Guitton Date: Mon, 8 Sep 2008 16:18:24 +0000 Subject: [PATCH] * rs6000-tdep.c (rs6000_fetch_instruction) (rs6000_skip_stack_check): New functions. (skip_prologue): Skip stack check sequence. --- gdb/ChangeLog | 6 ++ gdb/rs6000-tdep.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 18d73f42fbe..1ec1b871c65 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2008-09-08 Jerome Guitton + + * rs6000-tdep.c (rs6000_fetch_instruction) + (rs6000_skip_stack_check): New functions. + (skip_prologue): Skip stack check sequence. + 2008-09-08 David Daney * dummy-frame.h (frame.h): Include it. diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index d85af53133d..c8bc7ac082a 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -1274,6 +1274,187 @@ bl_to_blrl_insn_p (CORE_ADDR pc, int insn) #define BL_INSTRUCTION 0x48000001 #define BL_DISPLACEMENT_MASK 0x03fffffc +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. @@ -1333,6 +1514,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, 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 -- 2.30.2