diff options
author | Jerome Guitton <guitton@adacore.com> | 2008-09-08 16:18:24 +0000 |
---|---|---|
committer | Jerome Guitton <guitton@adacore.com> | 2008-09-08 16:18:24 +0000 |
commit | de9f48f0c431c9dcbee390a7ba8aad1a4f45128c (patch) | |
tree | d82f08c0d5974bfd9648ede233f6dbbd9969ee04 /gdb/rs6000-tdep.c | |
parent | 25d650345cf4e8ba795eef7b944373967aeb95c8 (diff) | |
download | gdb-de9f48f0c431c9dcbee390a7ba8aad1a4f45128c.zip gdb-de9f48f0c431c9dcbee390a7ba8aad1a4f45128c.tar.gz gdb-de9f48f0c431c9dcbee390a7ba8aad1a4f45128c.tar.bz2 |
* rs6000-tdep.c (rs6000_fetch_instruction)
(rs6000_skip_stack_check): New functions.
(skip_prologue): Skip stack check sequence.
Diffstat (limited to 'gdb/rs6000-tdep.c')
-rw-r--r-- | gdb/rs6000-tdep.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index d85af53..c8bc7ac 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, -<some immediate>(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,-<some immediate> + lis 0,-<some immediate> + [possibly ori 0,0,<some immediate>] + add 0,12,0 + cmpw 0,12,0 + beq 0,<disp> + addi 12,12,-<some immediate> + stw 0,0(12) + b <disp> + [possibly one last probe: stw 0,<some immediate>(12)] + */ + + while (1) + { + /* addi 12,1,-<some immediate> */ + if ((op & 0xffff0000) != 0x39810000) + break; + + /* lis 0,-<some immediate> */ + 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,<some immediate>] */ + 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,<disp> */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xff9f0001) != 0x41820000) + break; + + /* addi 12,12,-<some immediate> */ + 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 <disp> */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xfc000001) != 0x48000000) + break; + + /* [possibly one last probe: stw 0,<some immediate>(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,-<some immediate> + 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,<some immediate> + addic 0,0,-<some immediate> + lis 12,__gnat_stack_limit@ha + lwz 12,__gnat_stack_limit@l(12) + twllt 0,12 + */ + while (1) + { + /* addi 0,1,-<some immediate> */ + if ((op & 0xffff0000) != 0x38010000) + { + /* small stack frame variant not recognized; try the + big stack frame variant: */ + + /* addis 0,1,<some immediate> */ + if ((op & 0xffff0000) != 0x3c010000) + break; + + /* addic 0,0,-<some immediate> */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x30000000) + break; + } + + /* lis 12,<some immediate> */ + pc = pc + 4; + op = rs6000_fetch_instruction (pc); + if ((op & 0xffff0000) != 0x3d800000) + break; + + /* lwz 12,<some immediate>(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 |