Add debugger single-stepping and fix interrupt dispatch bugs.

This commit is contained in:
eeh 2000-01-10 03:53:20 +00:00
parent ede7778a1c
commit 082d2d0074
8 changed files with 355 additions and 61 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_machdep.h,v 1.8 1999/11/06 20:13:50 eeh Exp $ */
/* $NetBSD: db_machdep.h,v 1.9 2000/01/10 03:53:20 eeh Exp $ */
/*
* Mach Operating System
@ -96,18 +96,39 @@ db_regs_t ddb_regs; /* register state */
#define BKPT_SIZE (4) /* size of breakpoint inst */
#define BKPT_SET(inst) (BKPT_INST)
#define db_clear_single_step(regs) (void) (0)
#define db_set_single_step(regs) (void) (0)
#define IS_BREAKPOINT_TRAP(type, code) \
((type) == T_BREAKPOINT || (type) == T_KGDB_EXEC)
#define IS_WATCHPOINT_TRAP(type, code) (0)
#define IS_WATCHPOINT_TRAP(type, code) \
((type) ==T_PA_WATCHPT || (type) == T_VA_WATCHPT)
#define inst_trap_return(ins) ((ins)&0)
#define inst_return(ins) ((ins)&0)
#define inst_call(ins) ((ins)&0)
#define inst_load(ins) 0
#define inst_store(ins) 0
/*
* Sparc cpus have no hardware single-step.
*/
#define SOFTWARE_SSTEP
boolean_t db_inst_trap_return __P((int inst));
boolean_t db_inst_return __P((int inst));
boolean_t db_inst_call __P((int inst));
boolean_t db_inst_branch __P((int inst));
int db_inst_load __P((int inst));
int db_inst_store __P((int inst));
boolean_t db_inst_unconditional_flow_transfer __P((int inst));
db_addr_t db_branch_taken __P((int inst, db_addr_t pc, db_regs_t *regs));
#define inst_trap_return(ins) db_inst_trap_return(ins)
#define inst_return(ins) db_inst_return(ins)
#define inst_call(ins) db_inst_call(ins)
#define inst_branch(ins) db_inst_branch(ins)
#define inst_load(ins) db_inst_load(ins)
#define inst_store(ins) db_inst_store(ins)
#define inst_unconditional_flow_transfer(ins) \
db_inst_unconditional_flow_transfer(ins)
#define branch_taken(ins, pc, regs) \
db_branch_taken((ins), (pc), (regs))
/* see note in db_interface.c about reversed breakpoint addrs */
#define next_instr_address(pc, bd) \
((bd) ? (pc) : ddb_regs.ddb_tf.tf_npc)
#define DB_MACHINE_COMMANDS

View File

@ -1,4 +1,4 @@
/* $NetBSD: instr.h,v 1.2 1998/09/22 02:48:43 eeh Exp $ */
/* $NetBSD: instr.h,v 1.3 2000/01/10 03:53:20 eeh Exp $ */
/*
* Copyright (c) 1992, 1993
@ -46,8 +46,8 @@
/* see also Appendix F of the SPARC version 8 document */
enum IOP { IOP_OP2, IOP_CALL, IOP_reg, IOP_mem };
enum IOP2 { IOP2_UNIMP, IOP2_err1, IOP2_Bicc, IOP2_err3,
IOP2_SETHI, IOP2_err5, IOP2_FBfcc, IOP2_CBccc };
enum IOP2 { IOP2_UNIMP, IOP2_BPcc, IOP2_Bicc, IOP2_BPr,
IOP2_SETHI, IOP2_FBPfcc, IOP2_FBfcc, IOP2_CBccc };
enum IOP3_reg {
IOP3_ADD, IOP3_AND, IOP3_OR, IOP3_XOR,
IOP3_SUB, IOP3_ANDN, IOP3_ORN, IOP3_XNOR,
@ -193,6 +193,31 @@ union instr {
int i_disp:22; /* branch displacement */
} i_branch;
/* more branches: BPcc, FBPfcc */
struct {
u_int :2; /* 00 */
u_int i_annul:1; /* annul bit */
u_int i_cond:4; /* condition codes */
u_int i_op2:3; /* opcode: {BP,FBPf}cc */
u_int i_cc:2; /* condition code selector */
u_int i_pred:1; /* branch prediction bit */
int i_disp:19; /* branch displacement */
} i_branch_p;
/* one last branch: BPr */
struct {
u_int :2; /* 00 */
u_int i_annul:1; /* annul bit */
u_int :1; /* 0 */
u_int i_rcond:4; /* register condition */
u_int :3; /* 011 */
int i_disphi:2; /* branch displacement, hi bits */
u_int i_pred:1; /* branch prediction bit */
u_int i_rs1:1; /* source register 1 */
u_int i_displo:16; /* branch displacement, lo bits */
} i_branch_pr;
/*
* Format 3 instructions (memory reference; arithmetic, logical,
* shift, and other miscellaneous operations). The second-level

View File

@ -1,4 +1,4 @@
/* $NetBSD: reg.h,v 1.5 1999/12/30 16:20:43 eeh Exp $ */
/* $NetBSD: reg.h,v 1.6 2000/01/10 03:53:20 eeh Exp $ */
/*
* Copyright (c) 1992, 1993
@ -142,6 +142,8 @@ struct reg64 {
* ``I'd suggest allowing 16 ... allowing an indeterminate variable
* size would be even better''. Of course, we cannot do that; we
* need to malloc these.
*
* XXXX UltraSPARC processors don't implement a floating point queue.
*/
#define FP_QSIZE 16
#define ALIGNFPSTATE(f) ((struct fpstate64 *)(((long)(f))&(~BLOCK_ALIGN)))
@ -170,14 +172,14 @@ struct fpstate32 {
};
/*
* Clone fpstate into an fpreg structure to satisfy <kern/sys_process.c>
* The actual FP registers are made accessable (c.f. ptrace(2)) through
* a `struct fpreg'; <arch/sparc64/sparc64/process_machdep.c> relies on the
* fact that `fpreg' is a prefix of `fpstate'.
*/
struct fpreg64 {
u_int fr_regs[64]; /* our view is 64 32-bit registers */
int64_t fr_fsr; /* %fsr */
int fr_gsr; /* graphics state reg */
int fr_qsize; /* actual queue depth */
struct fp_qentry fr_queue[FP_QSIZE]; /* queue contents */
};
/*
@ -186,8 +188,6 @@ struct fpreg64 {
struct fpreg32 {
u_int fr_regs[32]; /* our view is 32 32-bit registers */
int fr_fsr; /* %fsr */
int fr_qsize; /* actual queue depth */
struct fp_qentry fr_queue[FP_QSIZE]; /* queue contents */
};
#if defined(__arch64__)

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_interface.c,v 1.25 1999/12/30 16:34:02 eeh Exp $ */
/* $NetBSD: db_interface.c,v 1.26 2000/01/10 03:53:22 eeh Exp $ */
/*
* Mach Operating System
@ -52,6 +52,7 @@
#include <ddb/db_output.h>
#include <ddb/db_interface.h>
#include <machine/instr.h>
#include <machine/cpu.h>
#include <machine/openfirm.h>
#include <machine/ctlreg.h>
@ -179,13 +180,6 @@ kdb_trap(type, tf)
default:
printf("kernel trap %x: %s\n", type, trap_type[type & 0x1ff]);
if (db_recover != 0) {
#if 0
#ifdef __arch64__
/* For now, don't get into infinite DDB trap loop */
printf("Faulted in DDB; going to OBP...\n");
OF_enter();
#endif
#endif
db_error("Faulted in DDB; continuing...\n");
OF_enter();
/*NOTREACHED*/
@ -224,10 +218,10 @@ kdb_trap(type, tf)
}
#endif
s = splhigh();
db_active++;
cnpollc(TRUE);
/* Need to do spl stuff till cnpollc works */
s = splhigh();
tl = savetstate(ts);
for (i=0; i<tl; i++) {
printf("%d tt=%lx tstate=%lx tpc=%p tnpc=%p\n",
@ -236,15 +230,15 @@ kdb_trap(type, tf)
}
db_trap(type, 0/*code*/);
restoretstate(tl,ts);
splx(s);
cnpollc(FALSE);
db_active--;
splx(s);
#if 0
/* We will not alter the machine's running state until we get everything else working */
*(struct frame *)tf->tf_out[6] = ddb_regs.ddb_fr;
*tf = ddb_regs.ddb_tf;
#endif
*tf = ddb_regs.ddb_tf;
trap_trace_dis = traptrace_enabled;
return (1);
@ -865,3 +859,235 @@ db_machine_init()
{
db_machine_commands_install(sparc_db_command_table);
}
/*
* support for SOFTWARE_SSTEP:
* return the next pc if the given branch is taken.
*
* note: in the case of conditional branches with annul,
* this actually returns the next pc in the "not taken" path,
* but in that case next_instr_address() will return the
* next pc in the "taken" path. so even tho the breakpoints
* are backwards, everything will still work, and the logic is
* much simpler this way.
*/
db_addr_t
db_branch_taken(inst, pc, regs)
int inst;
db_addr_t pc;
db_regs_t *regs;
{
union instr insn;
db_addr_t npc = ddb_regs.ddb_tf.tf_npc;
insn.i_int = inst;
/*
* if this is not an annulled conditional branch, the next pc is "npc".
*/
if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1)
return npc;
switch (insn.i_op2.i_op2) {
case IOP2_Bicc:
case IOP2_FBfcc:
case IOP2_BPcc:
case IOP2_FBPfcc:
case IOP2_CBccc:
/* branch on some condition-code */
switch (insn.i_branch.i_cond)
{
case Icc_A: /* always */
return pc + ((inst << 10) >> 8);
default: /* all other conditions */
return npc + 4;
}
case IOP2_BPr:
/* branch on register, always conditional */
return npc + 4;
default:
/* not a branch */
panic("branch_taken() on non-branch");
}
}
boolean_t
db_inst_branch(inst)
int inst;
{
union instr insn;
insn.i_int = inst;
if (insn.i_any.i_op != IOP_OP2)
return FALSE;
switch (insn.i_op2.i_op2) {
case IOP2_BPcc:
case IOP2_Bicc:
case IOP2_BPr:
case IOP2_FBPfcc:
case IOP2_FBfcc:
case IOP2_CBccc:
return TRUE;
default:
return FALSE;
}
}
boolean_t
db_inst_call(inst)
int inst;
{
union instr insn;
insn.i_int = inst;
switch (insn.i_any.i_op) {
case IOP_CALL:
return TRUE;
case IOP_reg:
return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst);
default:
return FALSE;
}
}
boolean_t
db_inst_unconditional_flow_transfer(inst)
int inst;
{
union instr insn;
insn.i_int = inst;
if (db_inst_call(inst))
return TRUE;
if (insn.i_any.i_op != IOP_OP2)
return FALSE;
switch (insn.i_op2.i_op2)
{
case IOP2_BPcc:
case IOP2_Bicc:
case IOP2_FBPfcc:
case IOP2_FBfcc:
case IOP2_CBccc:
return insn.i_branch.i_cond == Icc_A;
default:
return FALSE;
}
}
boolean_t
db_inst_return(inst)
int inst;
{
return (inst == I_JMPLri(I_G0, I_O7, 8) || /* ret */
inst == I_JMPLri(I_G0, I_I7, 8)); /* retl */
}
boolean_t
db_inst_trap_return(inst)
int inst;
{
union instr insn;
insn.i_int = inst;
return (insn.i_any.i_op == IOP_reg &&
insn.i_op3.i_op3 == IOP3_RETT);
}
int
db_inst_load(inst)
int inst;
{
union instr insn;
insn.i_int = inst;
if (insn.i_any.i_op != IOP_mem)
return 0;
switch (insn.i_op3.i_op3) {
case IOP3_LD:
case IOP3_LDUB:
case IOP3_LDUH:
case IOP3_LDD:
case IOP3_LDSB:
case IOP3_LDSH:
case IOP3_LDSTUB:
case IOP3_SWAP:
case IOP3_LDA:
case IOP3_LDUBA:
case IOP3_LDUHA:
case IOP3_LDDA:
case IOP3_LDSBA:
case IOP3_LDSHA:
case IOP3_LDSTUBA:
case IOP3_SWAPA:
case IOP3_LDF:
case IOP3_LDFSR:
case IOP3_LDDF:
case IOP3_LFC:
case IOP3_LDCSR:
case IOP3_LDDC:
return 1;
default:
return 0;
}
}
int
db_inst_store(inst)
int inst;
{
union instr insn;
insn.i_int = inst;
if (insn.i_any.i_op != IOP_mem)
return 0;
switch (insn.i_op3.i_op3) {
case IOP3_ST:
case IOP3_STB:
case IOP3_STH:
case IOP3_STD:
case IOP3_LDSTUB:
case IOP3_SWAP:
case IOP3_STA:
case IOP3_STBA:
case IOP3_STHA:
case IOP3_STDA:
case IOP3_LDSTUBA:
case IOP3_SWAPA:
case IOP3_STF:
case IOP3_STFSR:
case IOP3_STDFQ:
case IOP3_STDF:
case IOP3_STC:
case IOP3_STCSR:
case IOP3_STDCQ:
case IOP3_STDC:
return 1;
default:
return 0;
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.c,v 1.17 1999/11/06 20:18:50 eeh Exp $ */
/* $NetBSD: intr.c,v 1.18 2000/01/10 03:53:21 eeh Exp $ */
/*
* Copyright (c) 1992, 1993
@ -105,16 +105,20 @@
*/
struct intrhand *intrlev[MAXINTNUM];
void strayintr __P((const struct trapframe64 *));
void strayintr __P((const struct trapframe64 *, int));
int soft01intr __P((void *));
/*
* Stray interrupt handler. Clear it if possible.
* If not, and if we get 10 interrupts in 10 seconds, panic.
*/
int ignore_stray = 1;
int straycnt[16];
void
strayintr(fp)
strayintr(fp, vectored)
const struct trapframe64 *fp;
int vectored;
{
static int straytime, nstray;
int timesince;
@ -122,14 +126,18 @@ strayintr(fp)
extern int swallow_zsintrs;
#endif
return;
if (fp->tf_pil < 16)
straycnt[(int)fp->tf_pil]++;
if (ignore_stray)
return;
/* If we're in polled mode ignore spurious interrupts */
if ((fp->tf_pil == PIL_SER) /* && swallow_zsintrs */) return;
printf("stray interrupt ipl %u pc=%lx npc=%lx pstate=%lb\n",
printf("stray interrupt ipl %u pc=%lx npc=%lx pstate=%lb vecttored=%d\n",
fp->tf_pil, fp->tf_pc, fp->tf_npc,
(unsigned long)(fp->tf_tstate>>TSTATE_PSTATE_SHIFT), PSTATE_BITS);
(unsigned long)(fp->tf_tstate>>TSTATE_PSTATE_SHIFT), PSTATE_BITS, vectored);
timesince = time.tv_sec - straytime;
if (timesince <= 10) {
if (++nstray > 500)

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.s,v 1.48 1999/12/30 16:39:53 eeh Exp $ */
/* $NetBSD: locore.s,v 1.49 2000/01/10 03:53:21 eeh Exp $ */
/*
* Copyright (c) 1996-1999 Eduardo Horvath
* Copyright (c) 1996 Paul Kranenburg
@ -130,6 +130,7 @@
#define LDPTRA ldxa
#define STPTR stx
#define STPTRA stxa
#define CASPTR casxa
/* Now something to calculate the stack bias */
#define STKB BIAS
#else
@ -141,6 +142,7 @@
#define LDPTRA lduwa
#define STPTR stw
#define STPTRA stwa
#define CASPTR casa
#define STKB 0
#endif
@ -3768,11 +3770,18 @@ setup_sparcintr:
mov 8, %g7 ! Number of slots to search
sll %g6, PTRSHFT+3, %g2 ! Find start of table for this IPL
add %g1, %g2, %g1
LDPTR [%g1], %g2 ! Get slot
dec %g7
brz,a,pt %g2, 4f ! Available?
STPTR %g5, [%g1] ! Put intrhand in slot
brgz,pt %g7, 1b
2:
#if 1
mov %g5, %g2
CASPTR [%g1] ASI_N, %g0, %g2 ! Try a slot -- MPU safe
brz,pt %g2, 4f ! Available?
#else
LDPTR [%g1], %g2 ! Try a slog
brz,a %g2, 4f ! Available?
STPTR %g5, [%g1] ! Grab it
#endif
dec %g7
brgz,pt %g7, 2b
inc PTRSZ, %g1 ! Next slot
!! If we get here we have a problem.
@ -3995,10 +4004,17 @@ _C_LABEL(sparc_interrupt):
movrz %o0, %o2, %o0 ! arg = (arg == 0) ? arg : tf
brz,pt %o0, intrcmplt ! Done?
nop
call _C_LABEL(strayintr) ! strayintr(&intrframe)
mov 1, %o1
call _C_LABEL(strayintr) ! strayintr(&intrframe, 1)
add %sp, CC64FSZ + STKB, %o0
ba,a,pt %icc, intrcmplt ! done
2:
#endif
#ifdef TRAPSTATS
set _C_LABEL(intrpoll), %l4
ld [%l4], %o0
inc %o0 ! Increment non-vectored interrupts.
st %o0, [%l4]
#endif
set _C_LABEL(intrhand), %l4 ! %l4 = intrhand[intlev];
LDPTR [%l4 + %l3], %l4
@ -4073,21 +4089,23 @@ _C_LABEL(sparc_interrupt):
clr %l3 ! Make sure we don't have a valid pointer
brnz,pn %l5, intrcmplt ! if (handled) break
nop
! call _C_LABEL(strayintr) ! strayintr(&intrframe)
clr %o1
! call _C_LABEL(strayintr) ! strayintr(&intrframe, 0)
add %sp, CC64FSZ + STKB, %o0
/* all done: restore registers and go return */
#else
brz,a,pn %o0, 2f
add %sp, CC64FSZ + STKB, %o0
2: jmpl %o1, %o7 ! handled = (*ih->ih_fun)(...)
LDPTR [%l4 + IH_CLR], %l3
add %sp, CC64FSZ + STKB, %o2
jmpl %o1, %o7 ! handled = (*ih->ih_fun)(...)
movrz %o0, %o2, %o0
LDPTR [%l4 + IH_CLR], %l3
brnz,a,pt %l3, 5f ! Clear intr?
stx %g0, [%l3] ! Yes
5: brnz,pn %o0, intrcmplt ! if (handled) break
LDPTR [%l4 + IH_NEXT], %l4 ! and ih = ih->ih_next
3: brnz,pt %l4, 1b ! while (ih)
clr %l3 ! Make sure we don't have a valid pointer
call _C_LABEL(strayintr) ! strayintr(&intrframe)
clr %o1
call _C_LABEL(strayintr) ! strayintr(&intrframe, 0)
add %sp, CC64FSZ + STKB, %o0
/* all done: restore registers and go return */
#endif
@ -9202,7 +9220,7 @@ Lbzero_block:
#ifdef DEBUG
LDPTR [%l1 + %lo(_C_LABEL(fpproc))], %l7
cmp %l7, %l5
tnz 1 ! fpproc has changed!
! tnz 1 ! fpproc has changed!
LDPTR [%l5 + P_FPSTATE], %l7
cmp %l7, %l0
tnz 1 ! fpstate has changed!

View File

@ -1,4 +1,4 @@
/* $NetBSD: process_machdep.c,v 1.8 1999/12/30 16:42:10 eeh Exp $ */
/* $NetBSD: process_machdep.c,v 1.9 2000/01/10 03:53:22 eeh Exp $ */
/*
* Copyright (c) 1993 The Regents of the University of California.
@ -192,10 +192,6 @@ struct fpreg *regs;
statep = p->p_md.md_fpstate;
for (i=0; i<32; i++)
regp->fr_regs[i] = statep->fs_regs[i];
regp->fr_fsr = statep->fs_fsr;
regp->fr_qsize = statep->fs_qsize;
for (i=0; i<statep->fs_qsize; i++)
regp->fr_queue[i] = statep->fs_queue[i];
return 0;
}
@ -226,9 +222,6 @@ struct fpreg *regs;
for (i=0; i<32; i++)
statep->fs_regs[i] = regp->fr_regs[i];
statep->fs_fsr = regp->fr_fsr;
statep->fs_qsize = regp->fr_qsize;
for (i=0; i<regp->fr_qsize; i++)
statep->fs_queue[i] = regp->fr_queue[i];
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.34 1999/12/30 16:57:27 eeh Exp $ */
/* $NetBSD: trap.c,v 1.35 2000/01/10 03:53:22 eeh Exp $ */
/*
* Copyright (c) 1996
@ -124,6 +124,7 @@ int uintrcnt = 0;
int kiveccnt = 0;
int kintrcnt = 0;
int intristk = 0; /* interrupts when already on intrstack */
int intrpoll = 0; /* interrupts not using vector lists */
int wfill = 0;
int kwfill = 0;
int wspill = 0;
@ -502,6 +503,7 @@ trap(type, tstate, pc, tf)
printf("trap: tpc %p == tnpc %p\n", tf->tf_pc, tf->tf_npc);
Debugger();
}
#if 0
{
/* Check to make sure we're on the normal stack */
int* sp;
@ -515,6 +517,7 @@ trap(type, tstate, pc, tf)
}
}
#endif
#endif
#ifdef DEBUG
@ -558,7 +561,7 @@ trap(type, tstate, pc, tf)
if (type == T_BREAKPOINT) {
write_all_windows();
if (kdb_trap(type, tf)) {
ADVANCE;
/* ADVANCE; */
return;
}
}
@ -1981,7 +1984,7 @@ syscall(code, tf, pc)
for (j=0; j<i; j++)
temp[j] = args.i[j];
ktrsyscall(p->p_tracep, code,
callp->sy_argsize, (register_t *)temp);
i * sizeof(register_t), (register_t *)temp);
#else
ktrsyscall(p->p_tracep, code,
callp->sy_argsize, (register_t *)args.i);