diff options
author | Mark Salter <msalter@redhat.com> | 1997-09-16 14:59:54 +0000 |
---|---|---|
committer | Mark Salter <msalter@redhat.com> | 1997-09-16 14:59:54 +0000 |
commit | 13646a91cb1a42943a091bfc680e18b4071fd825 (patch) | |
tree | 646d9656c2d492a8f2b33f89af268a8b7d9a9362 /arch/mips/kernel/gdb-stub.c | |
parent | 393457c0ddc6ce88f11fdf1b6012ee6642909786 (diff) |
Added set_async_breakpoint(). This can be called from serial
drivers to support asynchronous interruption of kernel during
kgdb sessions.
Diffstat (limited to 'arch/mips/kernel/gdb-stub.c')
-rw-r--r-- | arch/mips/kernel/gdb-stub.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 8a2929e6a..fe999bb31 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -12,7 +12,7 @@ * * Copyright (C) 1995 Andreas Busse * - * $Id: gdb-stub.c,v 1.3 1997/07/29 03:10:57 ralf Exp $ + * $Id: gdb-stub.c,v 1.4 1997/09/01 21:00:01 marks Exp $ */ /* @@ -77,6 +77,7 @@ #include <asm/pgtable.h> #include <asm/system.h> #include <asm/gdb-stub.h> +#include <asm/inst.h> /* * external low-level support routines @@ -456,11 +457,13 @@ void show_gdbregs(struct gdb_regs * regs) * * This is where we save the original instructions. */ -static struct { +static struct gdb_bp_save { unsigned int addr; unsigned int val; } step_bp[2]; +#define BP 0x0000000d /* break opcode */ + /* * Set breakpoint instructions for single stepping. */ @@ -470,8 +473,6 @@ static void single_step(struct gdb_regs *regs) unsigned int targ; int is_branch, is_cond, i; -#define BP 0x0000000d - targ = regs->cp0_epc; insn.word = *(unsigned int *)targ; is_branch = is_cond = 0; @@ -550,6 +551,22 @@ static void single_step(struct gdb_regs *regs) } /* + * If asynchronously interrupted by gdb, then we need to set a breakpoint + * at the interrupted instruction so that we wind up stopped with a + * reasonable stack frame. + */ +static struct gdb_bp_save async_bp; + +void set_async_breakpoint(unsigned int epc) +{ + async_bp.addr = epc; + async_bp.val = *(unsigned *)epc; + *(unsigned *)epc = BP; + flush_cache_all(); +} + + +/* * This function does all command processing for interfacing to gdb. It * returns 1 if you should skip the instruction at the trap address, 0 * otherwise. @@ -604,6 +621,16 @@ void handle_exception (struct gdb_regs *regs) } } + /* + * If we were interrupted asynchronously by gdb, then a + * breakpoint was set at the EPC of the interrupt so + * that we'd wind up here with an interesting stack frame. + */ + if (async_bp.addr) { + *(unsigned *)async_bp.addr = async_bp.val; + async_bp.addr = 0; + } + stack = (long *)regs->reg29; /* stack ptr */ sigval = computeSignal(trap); |