diff options
author | Jerome Guitton <guitton@adacore.com> | 2010-04-23 15:14:22 +0000 |
---|---|---|
committer | Jerome Guitton <guitton@adacore.com> | 2010-04-23 15:14:22 +0000 |
commit | 3a48e6ff66b76a9bd077a7a3671f13b537e418cd (patch) | |
tree | b76abf9e78350c0df5fb1677e0740cee5c5ddffa /gdb/alpha-tdep.c | |
parent | e4166a49ea402e8ec97329268d80cf75144c4628 (diff) | |
download | gdb-3a48e6ff66b76a9bd077a7a3671f13b537e418cd.zip gdb-3a48e6ff66b76a9bd077a7a3671f13b537e418cd.tar.gz gdb-3a48e6ff66b76a9bd077a7a3671f13b537e418cd.tar.bz2 |
* alpha-tdep.c (INSN_OPCODE, MEM_RA, MEM_RB, MEM_DISP, BR_RA)
(OPR_FUNCTION, OPR_HAS_IMMEDIATE, OPR_RA, OPR_RC, OPR_LIT): New macros.
(lda_opcode, stq_opcode, bne_opcode, subq_opcode, subq_function):
New constants.
(alpha_heuristic_analyze_probing_loop): New function.
(alpha_heuristic_frame_unwind_cache): In the prologue analysis, detect
and handle cases when a stack probe loop is generated.
* alpha-mdebug-tdep.c (alpha_mdebug_frameless): New function.
(alpha_mdebug_max_frame_size_exceeded): New function.
(alpha_mdebug_after_prologue): Use alpha_mdebug_frameless.
(alpha_mdebug_frame_sniffer, alpha_mdebug_frame_base_sniffer):
Return 0 when the maximum debuggable frame size has been exceeded.
Diffstat (limited to 'gdb/alpha-tdep.c')
-rw-r--r-- | gdb/alpha-tdep.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index 2f583e9..8c93777 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -46,6 +46,36 @@ #include "alpha-tdep.h" +/* Instruction decoding. The notations for registers, immediates and + opcodes are the same as the one used in Compaq's Alpha architecture + handbook. */ + +#define INSN_OPCODE(insn) ((insn & 0xfc000000) >> 26) + +/* Memory instruction format */ +#define MEM_RA(insn) ((insn & 0x03e00000) >> 21) +#define MEM_RB(insn) ((insn & 0x001f0000) >> 16) +#define MEM_DISP(insn) \ + (((insn & 0x8000) == 0) ? (insn & 0xffff) : -((-insn) & 0xffff)) + +static const int lda_opcode = 0x08; +static const int stq_opcode = 0x2d; + +/* Branch instruction format */ +#define BR_RA(insn) MEM_RA(insn) + +static const int bne_opcode = 0x3d; + +/* Operate instruction format */ +#define OPR_FUNCTION(insn) ((insn & 0xfe0) >> 5) +#define OPR_HAS_IMMEDIATE(insn) ((insn & 0x1000) == 0x1000) +#define OPR_RA(insn) MEM_RA(insn) +#define OPR_RC(insn) ((insn & 0x1f)) +#define OPR_LIT(insn) ((insn & 0x1fe000) >> 13) + +static const int subq_opcode = 0x10; +static const int subq_function = 0x29; + /* Return the name of the REGNO register. @@ -1000,6 +1030,108 @@ struct alpha_heuristic_unwind_cache int return_reg; }; +/* If a probing loop sequence starts at PC, simulate it and compute + FRAME_SIZE and PC after its execution. Otherwise, return with PC and + FRAME_SIZE unchanged. */ + +static void +alpha_heuristic_analyze_probing_loop (struct gdbarch *gdbarch, CORE_ADDR *pc, + int *frame_size) +{ + CORE_ADDR cur_pc = *pc; + int cur_frame_size = *frame_size; + int nb_of_iterations, reg_index, reg_probe; + unsigned int insn; + + /* The following pattern is recognized as a probing loop: + + lda REG_INDEX,NB_OF_ITERATIONS + lda REG_PROBE,<immediate>(sp) + + LOOP_START: + stq zero,<immediate>(REG_PROBE) + subq REG_INDEX,0x1,REG_INDEX + lda REG_PROBE,<immediate>(REG_PROBE) + bne REG_INDEX, LOOP_START + + lda sp,<immediate>(REG_PROBE) + + If anything different is found, the function returns without + changing PC and FRAME_SIZE. Otherwise, PC will point immediately + after this sequence, and FRAME_SIZE will be updated. + */ + + /* lda REG_INDEX,NB_OF_ITERATIONS */ + + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode) + return; + reg_index = MEM_RA (insn); + nb_of_iterations = MEM_DISP (insn); + + /* lda REG_PROBE,<immediate>(sp) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode + || MEM_RB (insn) != ALPHA_SP_REGNUM) + return; + reg_probe = MEM_RA (insn); + cur_frame_size -= MEM_DISP (insn); + + /* stq zero,<immediate>(REG_PROBE) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != stq_opcode + || MEM_RA (insn) != 0x1f + || MEM_RB (insn) != reg_probe) + return; + + /* subq REG_INDEX,0x1,REG_INDEX */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != subq_opcode + || !OPR_HAS_IMMEDIATE (insn) + || OPR_FUNCTION (insn) != subq_function + || OPR_LIT(insn) != 1 + || OPR_RA (insn) != reg_index + || OPR_RC (insn) != reg_index) + return; + + /* lda REG_PROBE,<immediate>(REG_PROBE) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode + || MEM_RA (insn) != reg_probe + || MEM_RB (insn) != reg_probe) + return; + cur_frame_size -= MEM_DISP (insn) * nb_of_iterations; + + /* bne REG_INDEX, LOOP_START */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != bne_opcode + || MEM_RA (insn) != reg_index) + return; + + /* lda sp,<immediate>(REG_PROBE) */ + + cur_pc += ALPHA_INSN_SIZE; + insn = alpha_read_insn (gdbarch, cur_pc); + if (INSN_OPCODE (insn) != lda_opcode + || MEM_RA (insn) != ALPHA_SP_REGNUM + || MEM_RB (insn) != reg_probe) + return; + cur_frame_size -= MEM_DISP (insn); + + *pc = cur_pc; + *frame_size = cur_frame_size; +} + static struct alpha_heuristic_unwind_cache * alpha_heuristic_frame_unwind_cache (struct frame_info *this_frame, void **this_prologue_cache, @@ -1116,6 +1248,8 @@ alpha_heuristic_frame_unwind_cache (struct frame_info *this_frame, frame_reg = ALPHA_GCC_FP_REGNUM; else if (word == 0x47fe040f) /* bis zero,sp,fp */ frame_reg = ALPHA_GCC_FP_REGNUM; + + alpha_heuristic_analyze_probing_loop (gdbarch, &cur_pc, &frame_size); } /* If we haven't found a valid return address register yet, keep |