aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/alpha-tdep.c111
-rw-r--r--gdb/config/alpha/tm-alpha.h3
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 */