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