Code for software-assisted DDB single-stepping from Chuck Silvers.
This commit is contained in:
parent
1581707b5d
commit
9e087acb89
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue