X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Falpha-tdep.c;h=b470470d7d8b58003afd7c207e1a870581c05bba;hb=91158a569dc571a9916dfad98c6c95ce789ad18d;hp=1a188cf3094c23740ceaa8ab515823f915e3a255;hpb=e17a4113357102b55cfa5b80557d590a46a43300;p=binutils-gdb.git diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index 1a188cf3094..b470470d7d8 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -1,7 +1,7 @@ /* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger. Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + 2003, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GDB. @@ -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. @@ -265,7 +295,7 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, struct value *function, int accumulate_size = struct_return ? 8 : 0; struct alpha_arg { - gdb_byte *contents; + const gdb_byte *contents; int len; int offset; }; @@ -363,7 +393,7 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, struct value *function, m_arg->len = TYPE_LENGTH (arg_type); m_arg->offset = accumulate_size; accumulate_size = (accumulate_size + m_arg->len + 7) & ~7; - m_arg->contents = value_contents_writeable (arg); + m_arg->contents = value_contents (arg); } /* Determine required argument register loads, loading an argument register @@ -385,7 +415,7 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* `Push' arguments on the stack. */ for (i = nargs; m_arg--, --i >= 0;) { - gdb_byte *contents = m_arg->contents; + const gdb_byte *contents = m_arg->contents; int offset = m_arg->offset; int len = m_arg->len; @@ -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,(sp) + + LOOP_START: + stq zero,(REG_PROBE) + subq REG_INDEX,0x1,REG_INDEX + lda REG_PROBE,(REG_PROBE) + bne REG_INDEX, LOOP_START + + lda sp,(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,(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,(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,(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,(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 @@ -1390,8 +1524,8 @@ alpha_next_pc (struct frame_info *frame, CORE_ADDR pc) { /* Branch format: target PC is: (new PC) + (4 * sext(displacement)) */ - if (op == 0x30 || /* BR */ - op == 0x34) /* BSR */ + if (op == 0x30 /* BR */ + || op == 0x34) /* BSR */ { branch_taken: offset = (insn & 0x001fffff); @@ -1489,12 +1623,13 @@ int alpha_software_single_step (struct frame_info *frame) { struct gdbarch *gdbarch = get_frame_arch (frame); + struct address_space *aspace = get_frame_address_space (frame); CORE_ADDR pc, next_pc; pc = get_frame_pc (frame); next_pc = alpha_next_pc (frame, pc); - insert_single_step_breakpoint (gdbarch, next_pc); + insert_single_step_breakpoint (gdbarch, aspace, next_pc); return 1; }