Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src supports single step!
details: https://anonhg.NetBSD.org/src/rev/ff8ee7b1368b
branches: trunk
changeset: 485999:ff8ee7b1368b
user: msaitoh <msaitoh%NetBSD.org@localhost>
date: Wed May 10 20:28:33 2000 +0000
description:
supports single step!
diffstat:
gnu/dist/gdb/config/sh/tm-nbsd.h | 5 +
gnu/dist/gdb/sh-tdep.c | 177 +++++++++++++++++++++++++++++++++++++++
sys/arch/sh3/include/ptrace.h | 6 +-
3 files changed, 187 insertions(+), 1 deletions(-)
diffs (218 lines):
diff -r 2ee3528f09b3 -r ff8ee7b1368b gnu/dist/gdb/config/sh/tm-nbsd.h
--- a/gnu/dist/gdb/config/sh/tm-nbsd.h Wed May 10 20:20:21 2000 +0000
+++ b/gnu/dist/gdb/config/sh/tm-nbsd.h Wed May 10 20:28:33 2000 +0000
@@ -23,4 +23,9 @@
#include "sh/tm-sh.h"
#include "tm-nbsd.h"
+#define NO_SINGLE_STEP
+
+#undef DECR_PC_AFTER_BREAK
+#define DECR_PC_AFTER_BREAK 2
+
#endif /* TM_NBSD_H */
diff -r 2ee3528f09b3 -r ff8ee7b1368b gnu/dist/gdb/sh-tdep.c
--- a/gnu/dist/gdb/sh-tdep.c Wed May 10 20:20:21 2000 +0000
+++ b/gnu/dist/gdb/sh-tdep.c Wed May 10 20:28:33 2000 +0000
@@ -689,3 +689,180 @@
add_com ("regs", class_vars, sh_show_regs, "Print all registers");
}
+
+#ifdef NO_SINGLE_STEP
+/* Non-zero if we just simulated a single-step ptrace call. This is
+ needed because we cannot remove the breakpoints in the inferior
+ process until after the `wait' in `wait_for_inferior'. Used for
+ 4.4bsd for mips, where the kernel does not emulate single-step. */
+
+int one_stepped;
+CORE_ADDR target_addr; /* Branch target offset, if we have a
+ breakpoint there... */
+CORE_ADDR step_addr; /* Offset of instruction after instruction
+ to be stepped, if we have a breakpoint
+ there. */
+long step_cache [3]; /* Cache for instructions wiped out by
+ step breakpoint(s)... */
+
+/* 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 (as on NetBSD). We find all the possible targets of the
+ coming instruction and breakpoint them.
+
+ single_step is also called just after the inferior stops. If we had
+ set up a simulated single-step, we undo our damage. */
+
+/* thoughts:
+
+ For the current instruction, check to see if we're in a delay slot.
+ If we are, the next instruction executed will either be the target of
+ the branch or jump instruction preceding the current instruction, or
+ it will be the instruction following the current instruction. If
+ we are not, then the next instruction executed will either be the
+ instruction following the current instruction, or the instruction
+ following that (if the current instruction is a branch likely instruction
+ and the branch is not taken).
+
+ So, if we are in a delay slot then we set a breakpoint for the target
+ of the preceding instruction. Unless the preceding instruction was
+ a jump instruction (only jumps are unconditional), we also set a break-
+ point at the instruction following the current one and the instruction
+ following that. Setting two breakpoints after the current instruction
+ is cheaper and easier than figuring out whether the current instruction
+ is a branch likely instruction. */
+
+#define IS_JMP(x) (((x) & 0xf0ff) == 0x402b)
+#define IS_JSR(x) (((x) & 0xf0ff) == 0x400b)
+
+#define IS_RTS(x) ((x) == 0x000b)
+
+#define IS_BRAF(x) (((x) & 0xf0ff) == 0x0023)
+#define IS_BSRF(x) (((x) & 0xf0ff) == 0x0003)
+
+#define IS_BSR(x) (((x) & 0xf000) == 0xb000)
+#define IS_BRA(x) (((x) & 0xf000) == 0xa000)
+#define IS_BTS(x) (((x) & 0xff00) == 0x8d00)
+#define IS_BFS(x) (((x) & 0xff00) == 0x8f00)
+
+#define IS_BT(x) (((x) & 0xff00) == 0x8900)
+#define IS_BF(x) (((x) & 0xff00) == 0x8b00)
+
+
+#define IS_PCLOADFROMREG(x) ((IS_JMP(x)) || (IS_JSR(x)))
+#define IS_ADDPCBYREG(x) ((IS_BRAF(x)) || (IS_BSRF(x)))
+#define IS_ADDPCBYIMM(x) ((IS_BSR(x)) || (IS_BRA(x)) || (IS_BFS(x)) \
+ || (IS_BTS(x)))
+#define IS_ADDPCBYIMM_ND(x) ((IS_BF(x)) || (IS_BT(x)))
+
+#define IS_DELAYEDBRANCH(x) (IS_PCLOADFROMREG(x) || IS_RTS(x) \
+ || IS_ADDPCBYREG(x) || IS_ADDPCBYIMM(x))
+
+#define IS_BRANCH(x) (IS_DELAYEDBRANCH(x) || IS_ADDPCBYIMM_ND(x))
+
+
+#define M2REG(x) (((x) & 0x0f00) >> 8)
+#define GETIMM8(x) ((x) & 0x00ff)
+#define IMM8SIGN(x) ((x) & 0x0080)
+#define GETIMM12(x) ((x) & 0x0fff)
+#define IMM12SIGN(x) ((x) & 0x0800)
+
+void
+single_step (ignore)
+ enum target_signal ignore; /* not used */
+{
+ CORE_ADDR pc;
+ CORE_ADDR epc;
+ CORE_ADDR next;
+ unsigned short delay_instruction;
+ CORE_ADDR offset;
+ unsigned short insn;
+
+ if (!one_stepped)
+ {
+ pc = epc = read_register (PC_REGNUM);
+ insn = read_memory_integer(pc, sizeof(insn));
+
+ if (IS_DELAYEDBRANCH(insn))
+ pc += 2;
+ next = pc + 2;
+ target_addr = 0;
+ step_addr = next;
+
+ if (IS_BRANCH(insn))
+ {
+ if (IS_PCLOADFROMREG(insn)) {
+ target_addr = read_register(M2REG (insn));
+ step_addr = 0;
+ } else if (IS_RTS(insn)) {
+ target_addr = read_register(PR_REGNUM);
+ step_addr = 0;
+ } else if (IS_ADDPCBYREG(insn)) {
+ target_addr = next + read_register(M2REG (insn));
+ step_addr = 0;
+ } else if (IS_BT(insn) || IS_BF(insn) || IS_BTS(insn)
+ || IS_BFS(insn)) {
+ target_addr = GETIMM8(insn);
+ if (IMM8SIGN(insn))
+ target_addr |= ~(CORE_ADDR)0x00ff;
+ target_addr = epc + 4 + (target_addr << 1);
+ } else if (IS_BSR(insn) || IS_BRA(insn)) {
+ target_addr = GETIMM12(insn);
+ if (IMM12SIGN(insn))
+ target_addr |= ~(CORE_ADDR)0x0fff;
+ target_addr = next + (target_addr << 1);
+ step_addr = 0;
+ }
+ }
+
+ /* Don't try to put down two breakpoints in the same spot... */
+ if (step_addr == target_addr)
+ target_addr = 0;
+
+ if (step_addr)
+ {
+ target_insert_breakpoint (step_addr, (char *)&step_cache [0]);
+ if (step_addr + 2 != target_addr)
+ target_insert_breakpoint (step_addr + 2, (char *)&step_cache [1]);
+ }
+ if (target_addr)
+ {
+ target_insert_breakpoint (target_addr, (char *)&step_cache [2]);
+ }
+
+ /* If the breakpoint occurred in a branch instruction,
+ re-run the branch (the breakpoint instruction should
+ be gone by now)... */
+ if (epc != pc)
+ {
+ write_register (PC_REGNUM, epc);
+ }
+ one_stepped = 1;
+ return;
+ }
+ else
+ {
+ pc = epc = read_register(PC_REGNUM);
+
+ write_pc(pc -= 2);
+
+ insn = read_memory_integer(pc, sizeof(insn));
+
+ /* Remove step breakpoints */
+ if (step_addr)
+ {
+ target_remove_breakpoint (step_addr, (char *)&step_cache [0]);
+ if (step_addr + 2 != target_addr)
+ target_remove_breakpoint (step_addr + 2, (char *)&step_cache [1]);
+ }
+
+ if (target_addr)
+ {
+ target_remove_breakpoint (target_addr, (char *)&step_cache [2]);
+ target_addr = 0;
+ }
+
+ one_stepped = 0;
+ }
+}
+#endif /* NO_SINGLE_STEP */
diff -r 2ee3528f09b3 -r ff8ee7b1368b sys/arch/sh3/include/ptrace.h
--- a/sys/arch/sh3/include/ptrace.h Wed May 10 20:20:21 2000 +0000
+++ b/sys/arch/sh3/include/ptrace.h Wed May 10 20:28:33 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.1 1999/09/13 10:31:21 itojun Exp $ */
+/* $NetBSD: ptrace.h,v 1.2 2000/05/10 20:28:33 msaitoh Exp $ */
/*
* Copyright (c) 1993 Christopher G. Demetriou
@@ -33,7 +33,11 @@
/*
* sh3-dependent ptrace definitions
*/
+
+#if 0
#define PT_STEP (PT_FIRSTMACH + 0)
+#endif
+
#define PT_GETREGS (PT_FIRSTMACH + 1)
#define PT_SETREGS (PT_FIRSTMACH + 2)
Home |
Main Index |
Thread Index |
Old Index