diff options
author | Jason Thorpe <thorpej@netbsd.org> | 2002-01-18 18:00:44 +0000 |
---|---|---|
committer | Jason Thorpe <thorpej@netbsd.org> | 2002-01-18 18:00:44 +0000 |
commit | ec32e4bec5c4f66fd211c56f7677f243b7ec1a4b (patch) | |
tree | 6e5d6c72f7430527b7778f562ea40736ce630000 /gdb/alpha-tdep.c | |
parent | e771a8713483f7e8ce3fb5057dfe0ad7656dbb6a (diff) | |
download | gdb-ec32e4bec5c4f66fd211c56f7677f243b7ec1a4b.zip gdb-ec32e4bec5c4f66fd211c56f7677f243b7ec1a4b.tar.gz gdb-ec32e4bec5c4f66fd211c56f7677f243b7ec1a4b.tar.bz2 |
* alpha-tdep.c: Update copyright years.
(alpha_next_pc): New function.
(alpha_software_single_step): Ditto.
* config/alpha/tm-alpha.h: Add prototype for
alpha_software_single_step.
Diffstat (limited to 'gdb/alpha-tdep.c')
-rw-r--r-- | gdb/alpha-tdep.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index c420cb5..be53a84 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -1,5 +1,5 @@ /* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger. - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GDB. @@ -1386,6 +1386,115 @@ alpha_call_dummy_address (void) return SYMBOL_VALUE_ADDRESS (sym) + 4; } +/* alpha_software_single_step() is called just before we want to resume + the inferior, if we want to single-step it but there is no hardware + or kernel single-step support (NetBSD on Alpha, for example). We find + the target of the coming instruction and breakpoint it. + + single_step is also called just after the inferior stops. If we had + set up a simulated single-step, we undo our damage. */ + +static CORE_ADDR +alpha_next_pc (CORE_ADDR pc) +{ + unsigned int insn; + unsigned int op; + int offset; + LONGEST rav; + + insn = read_memory_unsigned_integer (pc, sizeof (insn)); + + /* Opcode is top 6 bits. */ + op = (insn >> 26) & 0x3f; + + if (op == 0x1a) + { + /* Jump format: target PC is: + RB & ~3 */ + return (read_register ((insn >> 16) & 0x1f) & ~3); + } + + if ((op & 0x30) == 0x30) + { + /* Branch format: target PC is: + (new PC) + (4 * sext(displacement)) */ + if (op == 0x30 || /* BR */ + op == 0x34) /* BSR */ + { + branch_taken: + offset = (insn & 0x001fffff); + if (offset & 0x00100000) + offset |= 0xffe00000; + offset *= 4; + return (pc + 4 + offset); + } + + /* Need to determine if branch is taken; read RA. */ + rav = (LONGEST) read_register ((insn >> 21) & 0x1f); + switch (op) + { + case 0x38: /* BLBC */ + if ((rav & 1) == 0) + goto branch_taken; + break; + case 0x3c: /* BLBS */ + if (rav & 1) + goto branch_taken; + break; + case 0x39: /* BEQ */ + if (rav == 0) + goto branch_taken; + break; + case 0x3d: /* BNE */ + if (rav != 0) + goto branch_taken; + break; + case 0x3a: /* BLT */ + if (rav < 0) + goto branch_taken; + break; + case 0x3b: /* BLE */ + if (rav <= 0) + goto branch_taken; + break; + case 0x3f: /* BGT */ + if (rav > 0) + goto branch_taken; + break; + case 0x3e: /* BGE */ + if (rav >= 0) + goto branch_taken; + break; + } + } + + /* Not a branch or branch not taken; target PC is: + pc + 4 */ + return (pc + 4); +} + +void +alpha_software_single_step (enum target_signal sig, int insert_breakpoints_p) +{ + static CORE_ADDR next_pc; + typedef char binsn_quantum[BREAKPOINT_MAX]; + static binsn_quantum break_mem; + CORE_ADDR pc; + + if (insert_breakpoints_p) + { + pc = read_pc (); + next_pc = alpha_next_pc (pc); + + target_insert_breakpoint (next_pc, break_mem); + } + else + { + target_remove_breakpoint (next_pc, break_mem); + write_pc (next_pc); + } +} + void _initialize_alpha_tdep (void) { |