diff options
author | Joel Brobecker <brobecker@gnat.com> | 2007-04-11 07:10:08 +0000 |
---|---|---|
committer | Joel Brobecker <brobecker@gnat.com> | 2007-04-11 07:10:08 +0000 |
commit | b0b925864597e040ca3f793f382cea6a9593e647 (patch) | |
tree | cedc053421e6383fa01863ed1dfdd8ffd998d6ec /gdb/sparc-tdep.c | |
parent | 14ee09e13ccc6fb7e06f15f3354eecf914d75f0a (diff) | |
download | gdb-b0b925864597e040ca3f793f382cea6a9593e647.zip gdb-b0b925864597e040ca3f793f382cea6a9593e647.tar.gz gdb-b0b925864597e040ca3f793f382cea6a9593e647.tar.bz2 |
* sparc-tdep.c (X_RS2): New macro.
(sparc_skip_stack_check): New function.
(sparc_analyze_prologue): Adjust PC past stack probing
sequence if necessary.
Diffstat (limited to 'gdb/sparc-tdep.c')
-rw-r--r-- | gdb/sparc-tdep.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index bbcdb08..9f934b3 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -82,6 +82,7 @@ struct regset; #define X_IMM22(i) ((i) & 0x3fffff) #define X_OP3(i) (((i) >> 19) & 0x3f) #define X_RS1(i) (((i) >> 14) & 0x1f) +#define X_RS2(i) ((i) & 0x1f) #define X_I(i) (((i) >> 13) & 1) /* Sign extension macros. */ #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000) @@ -571,6 +572,156 @@ sparc_alloc_frame_cache (void) return cache; } +/* 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 +sparc_skip_stack_check (const CORE_ADDR start_pc) +{ + CORE_ADDR pc = start_pc; + unsigned long insn; + int offset_stack_checking_sequence = 0; + + /* With GCC, all stack checking sequences begin with the same two + instructions. */ + + /* sethi <some immediate>,%g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1)) + return start_pc; + + /* sub %sp, %g1, %g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1)) + return start_pc; + + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + + /* First possible sequence: + [first two instructions above] + clr [%g1 - some immediate] */ + + /* clr [%g1 - some immediate] */ + if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 0) + { + /* Valid stack-check sequence, return the new PC. */ + return pc; + } + + /* Second possible sequence: A small number of probes. + [first two instructions above] + clr [%g1] + add %g1, -<some immediate>, %g1 + clr [%g1] + [repeat the two instructions above any (small) number of times] + clr [%g1 - some immediate] */ + + /* clr [%g1] */ + else if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 0) + { + while (1) + { + /* add %g1, -<some immediate>, %g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 1)) + break; + + /* clr [%g1] */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 0 && X_RS1 (insn) == 1)) + return start_pc; + } + + /* clr [%g1 - some immediate] */ + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 0)) + return start_pc; + + /* We found a valid stack-check sequence, return the new PC. */ + return pc; + } + + /* Third sequence: A probing loop. + [first two instructions above] + sethi <some immediate>, %g4 + sub %g1, %g4, %g4 + cmp %g1, %g4 + be <disp> + add %g1, -<some immediate>, %g1 + ba <disp> + clr [%g1] + clr [%g4 - some immediate] */ + + /* sethi <some immediate>, %g4 */ + else if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4) + { + /* sub %g1, %g4, %g4 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4)) + return start_pc; + + /* cmp %g1, %g4 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x14 && !X_I(insn) + && X_RD (insn) == 0 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4)) + return start_pc; + + /* be <disp> */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 0 && X_COND (insn) == 0x1)) + return start_pc; + + /* add %g1, -<some immediate>, %g1 */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 2 && X_OP3(insn) == 0 && X_I(insn) + && X_RS1 (insn) == 1 && X_RD (insn) == 1)) + return start_pc; + + /* ba <disp> */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8)) + return start_pc; + + /* clr [%g1] */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn) + && X_RD (insn) == 0 && X_RS1 (insn) == 1)) + return start_pc; + + /* clr [%g4 - some immediate] */ + insn = sparc_fetch_instruction (pc); + pc = pc + 4; + if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn) + && X_RS1 (insn) == 4 && X_RD (insn) == 0)) + return start_pc; + + /* 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; +} + CORE_ADDR sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, struct sparc_frame_cache *cache) @@ -580,6 +731,8 @@ sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, int offset = 0; int dest = -1; + pc = sparc_skip_stack_check (pc); + if (current_pc <= pc) return current_pc; |