Code for software-assisted DDB single-stepping from Chuck Silvers.

This commit is contained in:
pk 1997-12-10 23:12:13 +00:00
parent 1581707b5d
commit 9e087acb89
3 changed files with 297 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_machdep.h,v 1.10 1997/08/31 21:23:40 pk Exp $ */
/* $NetBSD: db_machdep.h,v 1.11 1997/12/10 23:12:15 pk Exp $ */
/*
* Mach Operating System
@ -70,18 +70,40 @@ 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 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.db_tf.tf_npc)
#define DB_MACHINE_COMMANDS

View File

@ -1,4 +1,4 @@
/* $NetBSD: instr.h,v 1.3 1997/03/14 23:54:07 christos Exp $ */
/* $NetBSD: instr.h,v 1.4 1997/12/10 23:12:13 pk 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,32 @@ 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: db_interface.c,v 1.18 1997/09/01 00:16:31 pk Exp $ */
/* $NetBSD: db_interface.c,v 1.19 1997/12/10 23:12:17 pk Exp $ */
/*
* Mach Operating System
@ -50,6 +50,7 @@
#include <ddb/db_variables.h>
#include <ddb/db_extern.h>
#include <ddb/db_output.h>
#include <machine/instr.h>
#endif
#include <machine/bsd_openprom.h>
@ -233,4 +234,239 @@ 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.db_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;
}
}
#endif /* DDB */