aboutsummaryrefslogtreecommitdiff
path: root/gdb/rs6000-tdep.c
diff options
context:
space:
mode:
authorJerome Guitton <guitton@adacore.com>2008-09-08 16:18:24 +0000
committerJerome Guitton <guitton@adacore.com>2008-09-08 16:18:24 +0000
commitde9f48f0c431c9dcbee390a7ba8aad1a4f45128c (patch)
treed82f08c0d5974bfd9648ede233f6dbbd9969ee04 /gdb/rs6000-tdep.c
parent25d650345cf4e8ba795eef7b944373967aeb95c8 (diff)
downloadgdb-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.c185
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