diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/alpha-tdep.c | 111 | ||||
-rw-r--r-- | gdb/config/alpha/tm-alpha.h | 3 |
3 files changed, 121 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6bf80c4..e08d55a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,13 @@ 2002-01-18 Jason Thorpe <thorpej@wasabisystems.com> + * 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. + +2002-01-18 Jason Thorpe <thorpej@wasabisystems.com> + * alphabsd-nat.c: Update copyright years. (fill_gregset): Use regcache_collect. (fill_fpregset): Likewise. 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) { diff --git a/gdb/config/alpha/tm-alpha.h b/gdb/config/alpha/tm-alpha.h index f5f3497..2e069eb 100644 --- a/gdb/config/alpha/tm-alpha.h +++ b/gdb/config/alpha/tm-alpha.h @@ -474,4 +474,7 @@ extern struct frame_info *setup_arbitrary_frame (int, CORE_ADDR *); extern CORE_ADDR alpha_osf_skip_sigtramp_frame (struct frame_info *, CORE_ADDR); +/* Single step based on where the current instruction will take us. */ +extern void alpha_software_single_step (enum target_signal, int); + #endif /* TM_ALPHA_H */ |