Mega update for the KDB framework: turn DDB into a KDB backend.
Most of the changes are a direct result of adding thread awareness. Typically, DDB_REGS is gone. All registers are taken from the trapframe and backtraces use the PCB based contexts. DDB_REGS was defined to be a trapframe on all platforms anyway. Thread awareness introduces the following new commands: thread X switch to thread X (where X is the TID), show threads list all threads. The backtrace code has been made more flexible so that one can create backtraces for any thread by giving the thread ID as an argument to trace. With this change, ia64 has support for breakpoints.
This commit is contained in:
parent
a7df680fac
commit
d54b27a1b4
@ -813,26 +813,9 @@ register_name (ireg)
|
||||
* (optional) alternate format. Return address of start of
|
||||
* next instruction.
|
||||
*/
|
||||
int alpha_print_instruction(db_addr_t, alpha_instruction, boolean_t);
|
||||
|
||||
db_addr_t
|
||||
db_disasm(loc, altfmt)
|
||||
db_addr_t loc;
|
||||
boolean_t altfmt;
|
||||
{
|
||||
alpha_instruction inst;
|
||||
|
||||
inst.bits = db_get_value(loc, 4, 0);
|
||||
|
||||
loc += alpha_print_instruction(loc, inst, altfmt);
|
||||
return (loc);
|
||||
}
|
||||
|
||||
int
|
||||
alpha_print_instruction(iadr, i, showregs)
|
||||
db_addr_t iadr;
|
||||
alpha_instruction i;
|
||||
boolean_t showregs;
|
||||
static int
|
||||
alpha_print_instr(db_addr_t iadr, alpha_instruction i, boolean_t showregs)
|
||||
{
|
||||
const char *opcode;
|
||||
int ireg;
|
||||
@ -1038,7 +1021,7 @@ alpha_print_instruction(iadr, i, showregs)
|
||||
if (i.mem_format.opcode == op_ldah)
|
||||
signed_immediate <<= 16;
|
||||
db_printf(" <0x%lx>", signed_immediate +
|
||||
db_register_value(DDB_REGS, i.mem_format.rs));
|
||||
db_register_value(i.mem_format.rs));
|
||||
}
|
||||
break;
|
||||
case op_br:
|
||||
@ -1084,10 +1067,23 @@ alpha_print_instruction(iadr, i, showregs)
|
||||
db_printf(",");
|
||||
db_printf("%s=0x%lx",
|
||||
name_of_register[regnum[ireg]],
|
||||
db_register_value(DDB_REGS, regnum[ireg]));
|
||||
db_register_value(regnum[ireg]));
|
||||
}
|
||||
db_printf(">");
|
||||
}
|
||||
db_printf("\n");
|
||||
return (sizeof(alpha_instruction));
|
||||
}
|
||||
|
||||
db_addr_t
|
||||
db_disasm(loc, altfmt)
|
||||
db_addr_t loc;
|
||||
boolean_t altfmt;
|
||||
{
|
||||
alpha_instruction inst;
|
||||
|
||||
inst.bits = db_get_value(loc, 4, 0);
|
||||
|
||||
loc += alpha_print_instr(loc, inst, altfmt);
|
||||
return (loc);
|
||||
}
|
||||
|
@ -50,14 +50,12 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
@ -73,209 +71,104 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ddb/db_access.h>
|
||||
#include <ddb/db_sym.h>
|
||||
#include <ddb/db_variables.h>
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
static jmp_buf *db_nofault = 0;
|
||||
extern jmp_buf db_jmpbuf;
|
||||
|
||||
extern void gdb_handle_exception(db_regs_t *, int, int);
|
||||
|
||||
#if 0
|
||||
extern char *trap_type[];
|
||||
extern int trap_types;
|
||||
#endif
|
||||
|
||||
int db_active;
|
||||
|
||||
void ddbprinttrap(unsigned long, unsigned long, unsigned long,
|
||||
unsigned long);
|
||||
static db_varfcn_t db_frame;
|
||||
|
||||
struct db_variable db_regs[] = {
|
||||
{ "v0", &ddb_regs.tf_regs[FRAME_V0], FCN_NULL },
|
||||
{ "t0", &ddb_regs.tf_regs[FRAME_T0], FCN_NULL },
|
||||
{ "t1", &ddb_regs.tf_regs[FRAME_T1], FCN_NULL },
|
||||
{ "t2", &ddb_regs.tf_regs[FRAME_T2], FCN_NULL },
|
||||
{ "t3", &ddb_regs.tf_regs[FRAME_T3], FCN_NULL },
|
||||
{ "t4", &ddb_regs.tf_regs[FRAME_T4], FCN_NULL },
|
||||
{ "t5", &ddb_regs.tf_regs[FRAME_T5], FCN_NULL },
|
||||
{ "t6", &ddb_regs.tf_regs[FRAME_T6], FCN_NULL },
|
||||
{ "t7", &ddb_regs.tf_regs[FRAME_T7], FCN_NULL },
|
||||
{ "s0", &ddb_regs.tf_regs[FRAME_S0], FCN_NULL },
|
||||
{ "s1", &ddb_regs.tf_regs[FRAME_S1], FCN_NULL },
|
||||
{ "s2", &ddb_regs.tf_regs[FRAME_S2], FCN_NULL },
|
||||
{ "s3", &ddb_regs.tf_regs[FRAME_S3], FCN_NULL },
|
||||
{ "s4", &ddb_regs.tf_regs[FRAME_S4], FCN_NULL },
|
||||
{ "s5", &ddb_regs.tf_regs[FRAME_S5], FCN_NULL },
|
||||
{ "s6", &ddb_regs.tf_regs[FRAME_S6], FCN_NULL },
|
||||
{ "a0", &ddb_regs.tf_regs[FRAME_A0], FCN_NULL },
|
||||
{ "a1", &ddb_regs.tf_regs[FRAME_A1], FCN_NULL },
|
||||
{ "a2", &ddb_regs.tf_regs[FRAME_A2], FCN_NULL },
|
||||
{ "a3", &ddb_regs.tf_regs[FRAME_A3], FCN_NULL },
|
||||
{ "a4", &ddb_regs.tf_regs[FRAME_A4], FCN_NULL },
|
||||
{ "a5", &ddb_regs.tf_regs[FRAME_A5], FCN_NULL },
|
||||
{ "t8", &ddb_regs.tf_regs[FRAME_T8], FCN_NULL },
|
||||
{ "t9", &ddb_regs.tf_regs[FRAME_T9], FCN_NULL },
|
||||
{ "t10", &ddb_regs.tf_regs[FRAME_T10], FCN_NULL },
|
||||
{ "t11", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL },
|
||||
{ "ra", &ddb_regs.tf_regs[FRAME_RA], FCN_NULL },
|
||||
{ "t12", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL },
|
||||
{ "at", &ddb_regs.tf_regs[FRAME_AT], FCN_NULL },
|
||||
{ "gp", &ddb_regs.tf_regs[FRAME_GP], FCN_NULL },
|
||||
{ "sp", &ddb_regs.tf_regs[FRAME_SP], FCN_NULL },
|
||||
{ "pc", &ddb_regs.tf_regs[FRAME_PC], FCN_NULL },
|
||||
{ "ps", &ddb_regs.tf_regs[FRAME_PS], FCN_NULL },
|
||||
{ "ai", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL },
|
||||
{ "pv", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL },
|
||||
{ "v0", (db_expr_t *)FRAME_V0, db_frame },
|
||||
{ "t0", (db_expr_t *)FRAME_T0, db_frame },
|
||||
{ "t1", (db_expr_t *)FRAME_T1, db_frame },
|
||||
{ "t2", (db_expr_t *)FRAME_T2, db_frame },
|
||||
{ "t3", (db_expr_t *)FRAME_T3, db_frame },
|
||||
{ "t4", (db_expr_t *)FRAME_T4, db_frame },
|
||||
{ "t5", (db_expr_t *)FRAME_T5, db_frame },
|
||||
{ "t6", (db_expr_t *)FRAME_T6, db_frame },
|
||||
{ "t7", (db_expr_t *)FRAME_T7, db_frame },
|
||||
{ "s0", (db_expr_t *)FRAME_S0, db_frame },
|
||||
{ "s1", (db_expr_t *)FRAME_S1, db_frame },
|
||||
{ "s2", (db_expr_t *)FRAME_S2, db_frame },
|
||||
{ "s3", (db_expr_t *)FRAME_S3, db_frame },
|
||||
{ "s4", (db_expr_t *)FRAME_S4, db_frame },
|
||||
{ "s5", (db_expr_t *)FRAME_S5, db_frame },
|
||||
{ "s6", (db_expr_t *)FRAME_S6, db_frame },
|
||||
{ "a0", (db_expr_t *)FRAME_A0, db_frame },
|
||||
{ "a1", (db_expr_t *)FRAME_A1, db_frame },
|
||||
{ "a2", (db_expr_t *)FRAME_A2, db_frame },
|
||||
{ "a3", (db_expr_t *)FRAME_A3, db_frame },
|
||||
{ "a4", (db_expr_t *)FRAME_A4, db_frame },
|
||||
{ "a5", (db_expr_t *)FRAME_A5, db_frame },
|
||||
{ "t8", (db_expr_t *)FRAME_T8, db_frame },
|
||||
{ "t9", (db_expr_t *)FRAME_T9, db_frame },
|
||||
{ "t10", (db_expr_t *)FRAME_T10, db_frame },
|
||||
{ "t11", (db_expr_t *)FRAME_T11, db_frame },
|
||||
{ "ra", (db_expr_t *)FRAME_RA, db_frame },
|
||||
{ "t12", (db_expr_t *)FRAME_T12, db_frame },
|
||||
{ "at", (db_expr_t *)FRAME_AT, db_frame },
|
||||
{ "gp", (db_expr_t *)FRAME_GP, db_frame },
|
||||
{ "sp", (db_expr_t *)FRAME_SP, db_frame },
|
||||
{ "pc", (db_expr_t *)FRAME_PC, db_frame },
|
||||
{ "ps", (db_expr_t *)FRAME_PS, db_frame },
|
||||
{ "ai", (db_expr_t *)FRAME_T11, db_frame },
|
||||
{ "pv", (db_expr_t *)FRAME_T12, db_frame },
|
||||
};
|
||||
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
|
||||
|
||||
/*
|
||||
* Print trap reason.
|
||||
*/
|
||||
void
|
||||
ddbprinttrap(a0, a1, a2, entry)
|
||||
unsigned long a0, a1, a2, entry;
|
||||
static int
|
||||
db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
|
||||
/* XXX Implement. */
|
||||
|
||||
printf("ddbprinttrap(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", a0, a1, a2,
|
||||
entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* ddb_trap - field a kernel trap
|
||||
*/
|
||||
int
|
||||
kdb_trap(a0, a1, a2, entry, regs)
|
||||
unsigned long a0, a1, a2, entry;
|
||||
db_regs_t *regs;
|
||||
{
|
||||
int ddb_mode = !(boothowto & RB_GDB);
|
||||
register_t s;
|
||||
|
||||
/*
|
||||
* Don't bother checking for usermode, since a benign entry
|
||||
* by the kernel (call to Debugger() or a breakpoint) has
|
||||
* already checked for usermode. If neither of those
|
||||
* conditions exist, something Bad has happened.
|
||||
*/
|
||||
|
||||
if (entry != ALPHA_KENTRY_IF ||
|
||||
(a0 != ALPHA_IF_CODE_BUGCHK && a0 != ALPHA_IF_CODE_BPT
|
||||
&& a0 != ALPHA_IF_CODE_GENTRAP)) {
|
||||
#if 0
|
||||
if (ddb_mode) {
|
||||
db_printf("ddbprinttrap from 0x%lx\n", /* XXX */
|
||||
regs->tf_regs[FRAME_PC]);
|
||||
ddbprinttrap(a0, a1, a2, entry);
|
||||
/*
|
||||
* Tell caller "We did NOT handle the trap."
|
||||
* Caller should panic, or whatever.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (db_nofault) {
|
||||
jmp_buf *no_fault = db_nofault;
|
||||
db_nofault = 0;
|
||||
longjmp(*no_fault, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Should switch to DDB's own stack, here.
|
||||
*/
|
||||
|
||||
ddb_regs = *regs;
|
||||
|
||||
s = intr_disable();
|
||||
|
||||
#ifdef SMP
|
||||
#ifdef DIAGNOSTIC
|
||||
db_printf("stopping %x\n", PCPU_GET(other_cpus));
|
||||
#endif
|
||||
stop_cpus(PCPU_GET(other_cpus));
|
||||
#ifdef DIAGNOSTIC
|
||||
db_printf("stopped_cpus=%x\n", stopped_cpus);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
db_active++;
|
||||
|
||||
if (ddb_mode) {
|
||||
cndbctl(TRUE); /* DDB active, unblank video */
|
||||
db_trap(entry, a0); /* Where the work happens */
|
||||
cndbctl(FALSE); /* DDB inactive */
|
||||
} else
|
||||
gdb_handle_exception(&ddb_regs, entry, a0);
|
||||
|
||||
db_active--;
|
||||
|
||||
#ifdef SMP
|
||||
restart_cpus(stopped_cpus);
|
||||
#endif
|
||||
|
||||
intr_restore(s);
|
||||
|
||||
*regs = ddb_regs;
|
||||
|
||||
/*
|
||||
* Tell caller "We HAVE handled the trap."
|
||||
*/
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = kdb_frame->tf_regs[(uintptr_t)vp->valuep];
|
||||
else
|
||||
kdb_frame->tf_regs[(uintptr_t)vp->valuep] = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read bytes from kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
db_read_bytes(addr, size, data)
|
||||
vm_offset_t addr;
|
||||
register size_t size;
|
||||
register char *data;
|
||||
int
|
||||
db_read_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
register char *src;
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *src;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
|
||||
db_nofault = 0;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write bytes to kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
db_write_bytes(addr, size, data)
|
||||
vm_offset_t addr;
|
||||
register size_t size;
|
||||
register char *data;
|
||||
int
|
||||
db_write_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
register char *dst;
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *dst;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
|
||||
dst = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
alpha_pal_imb();
|
||||
|
||||
db_nofault = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Debugger(const char* msg)
|
||||
{
|
||||
u_int saveintr;
|
||||
|
||||
printf("%s\n", msg);
|
||||
saveintr = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
|
||||
__asm("call_pal 0x81"); /* XXX bugchk */
|
||||
alpha_pal_swpipl(saveintr);
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
dst = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
alpha_pal_imb();
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -338,9 +231,7 @@ static int reg_to_frame[32] = {
|
||||
};
|
||||
|
||||
u_long
|
||||
db_register_value(regs, regno)
|
||||
db_regs_t *regs;
|
||||
int regno;
|
||||
db_register_value(int regno)
|
||||
{
|
||||
|
||||
if (regno > 31 || regno < 0) {
|
||||
@ -351,7 +242,7 @@ db_register_value(regs, regno)
|
||||
if (regno == 31)
|
||||
return (0);
|
||||
|
||||
return (regs->tf_regs[reg_to_frame[regno]]);
|
||||
return (kdb_frame->tf_regs[reg_to_frame[regno]]);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -446,19 +337,6 @@ db_inst_unconditional_flow_transfer(ins)
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
boolean_t
|
||||
db_inst_spill(ins, regn)
|
||||
int ins, regn;
|
||||
{
|
||||
alpha_instruction insn;
|
||||
|
||||
insn.bits = ins;
|
||||
return ((insn.mem_format.opcode == op_stq) &&
|
||||
(insn.mem_format.rd == regn));
|
||||
}
|
||||
#endif
|
||||
|
||||
boolean_t
|
||||
db_inst_load(ins)
|
||||
int ins;
|
||||
@ -520,10 +398,7 @@ db_inst_store(ins)
|
||||
}
|
||||
|
||||
db_addr_t
|
||||
db_branch_taken(ins, pc, regs)
|
||||
int ins;
|
||||
db_addr_t pc;
|
||||
db_regs_t *regs;
|
||||
db_branch_taken(int ins, db_addr_t pc)
|
||||
{
|
||||
alpha_instruction insn;
|
||||
db_addr_t newpc;
|
||||
@ -534,7 +409,7 @@ db_branch_taken(ins, pc, regs)
|
||||
* Jump format: target PC is (contents of instruction's "RB") & ~3.
|
||||
*/
|
||||
case op_j:
|
||||
newpc = db_register_value(regs, insn.jump_format.rs) & ~3;
|
||||
newpc = db_register_value(insn.jump_format.rs) & ~3;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/sysent.h>
|
||||
@ -60,11 +61,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ddb/db_output.h>
|
||||
#include <alpha/alpha/db_instruction.h>
|
||||
|
||||
struct trace_request {
|
||||
register_t ksp;
|
||||
register_t pc;
|
||||
};
|
||||
|
||||
/*
|
||||
* Information about the `standard' Alpha function prologue.
|
||||
*/
|
||||
@ -186,13 +182,15 @@ sym_is_trapsymbol(uintptr_t v)
|
||||
}
|
||||
|
||||
static void
|
||||
decode_syscall(int number, struct proc *p)
|
||||
decode_syscall(int number, struct thread *td)
|
||||
{
|
||||
struct proc *p;
|
||||
c_db_sym_t sym;
|
||||
db_expr_t diff;
|
||||
sy_call_t *f;
|
||||
const char *symname;
|
||||
|
||||
p = (td != NULL) ? td->td_proc : NULL;
|
||||
db_printf(" (%d", number);
|
||||
if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
|
||||
f = p->p_sysent->sv_table[number].sy_call;
|
||||
@ -205,99 +203,34 @@ decode_syscall(int number, struct proc *p)
|
||||
db_printf(")");
|
||||
}
|
||||
|
||||
void
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif)
|
||||
static int
|
||||
db_backtrace(struct thread *td, db_addr_t frame, db_addr_t pc, int count)
|
||||
{
|
||||
db_addr_t callpc = 0, frame = 0, symval;
|
||||
struct prologue_info pi;
|
||||
db_expr_t diff;
|
||||
c_db_sym_t sym;
|
||||
int i;
|
||||
u_long tfps;
|
||||
struct trapframe *tf;
|
||||
const char *symname;
|
||||
struct pcb *pcbp;
|
||||
struct trapframe *tf = NULL;
|
||||
boolean_t ra_from_tf = FALSE;
|
||||
boolean_t ra_from_pcb;
|
||||
u_long last_ipl = ~0L;
|
||||
struct proc *p = NULL;
|
||||
struct thread *td = NULL;
|
||||
boolean_t have_trapframe = FALSE;
|
||||
pid_t pid;
|
||||
c_db_sym_t sym;
|
||||
db_expr_t diff;
|
||||
db_addr_t symval;
|
||||
u_long last_ipl, tfps;
|
||||
int i;
|
||||
|
||||
if (count == -1)
|
||||
count = 65535;
|
||||
|
||||
if (!have_addr) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8;
|
||||
tf = (struct trapframe *)addr;
|
||||
have_trapframe = 1;
|
||||
} else if (addr < KERNBASE) {
|
||||
pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
|
||||
((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
|
||||
((addr >> 16) % 16) * 10000;
|
||||
/*
|
||||
* The pcb for curproc is not valid at this point,
|
||||
* so fall back to the default case.
|
||||
*/
|
||||
if (pid == curthread->td_proc->p_pid) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8;
|
||||
tf = (struct trapframe *)addr;
|
||||
have_trapframe = 1;
|
||||
} else {
|
||||
/* sx_slock(&allproc_lock); */
|
||||
LIST_FOREACH(p, &allproc, p_list) {
|
||||
if (p->p_pid == pid)
|
||||
break;
|
||||
}
|
||||
/* sx_sunlock(&allproc_lock); */
|
||||
if (p == NULL) {
|
||||
db_printf("pid %d not found\n", pid);
|
||||
return;
|
||||
}
|
||||
if ((p->p_sflag & PS_INMEM) == 0) {
|
||||
db_printf("pid %d swapped out\n", pid);
|
||||
return;
|
||||
}
|
||||
pcbp = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */
|
||||
addr = (db_expr_t)pcbp->pcb_hw.apcb_ksp;
|
||||
callpc = pcbp->pcb_context[7];
|
||||
frame = addr;
|
||||
}
|
||||
} else {
|
||||
struct trace_request *tr;
|
||||
|
||||
tr = (struct trace_request *)addr;
|
||||
if (tr->ksp < KERNBASE || tr->pc < KERNBASE) {
|
||||
db_printf("alpha trace requires known PC =eject=\n");
|
||||
return;
|
||||
}
|
||||
callpc = tr->pc;
|
||||
addr = tr->ksp;
|
||||
frame = addr;
|
||||
}
|
||||
count = 1024;
|
||||
|
||||
last_ipl = ~0L;
|
||||
tf = NULL;
|
||||
while (count--) {
|
||||
if (have_trapframe) {
|
||||
frame = (db_addr_t)tf + FRAME_SIZE * 8;
|
||||
callpc = tf->tf_regs[FRAME_PC];
|
||||
ra_from_tf = TRUE;
|
||||
have_trapframe = 0;
|
||||
}
|
||||
sym = db_search_symbol(callpc, DB_STGY_ANY, &diff);
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &diff);
|
||||
if (sym == DB_SYM_NULL)
|
||||
break;
|
||||
return (ENOENT);
|
||||
|
||||
db_symbol_values(sym, &symname, (db_expr_t *)&symval);
|
||||
|
||||
if (callpc < symval) {
|
||||
db_printf("symbol botch: callpc 0x%lx < "
|
||||
"func 0x%lx (%s)\n", callpc, symval, symname);
|
||||
return;
|
||||
if (pc < symval) {
|
||||
db_printf("symbol botch: pc 0x%lx < "
|
||||
"func 0x%lx (%s)\n", pc, symval, symname);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -328,7 +261,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
|
||||
* debugger (for serious debugging).
|
||||
*/
|
||||
db_printf("%s() at ", symname);
|
||||
db_printsym(callpc, DB_STGY_PROC);
|
||||
db_printsym(pc, DB_STGY_PROC);
|
||||
db_printf("\n");
|
||||
|
||||
/*
|
||||
@ -337,7 +270,6 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
|
||||
*/
|
||||
if (sym_is_trapsymbol(symval)) {
|
||||
tf = (struct trapframe *)frame;
|
||||
|
||||
for (i = 0; special_symbols[i].ss_val != 0; ++i)
|
||||
if (symval == special_symbols[i].ss_val)
|
||||
db_printf("--- %s",
|
||||
@ -345,7 +277,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
|
||||
|
||||
tfps = tf->tf_regs[FRAME_PS];
|
||||
if (symval == (uintptr_t)&XentSys)
|
||||
decode_syscall(tf->tf_regs[FRAME_V0], p);
|
||||
decode_syscall(tf->tf_regs[FRAME_V0], td);
|
||||
if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) {
|
||||
last_ipl = tfps & ALPHA_PSL_IPL_MASK;
|
||||
if (symval != (uintptr_t)&XentSys)
|
||||
@ -356,7 +288,8 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
|
||||
db_printf("--- user mode ---\n");
|
||||
break; /* Terminate search. */
|
||||
}
|
||||
have_trapframe = 1;
|
||||
frame = (db_addr_t)(tf + 1);
|
||||
pc = tf->tf_regs[FRAME_PC];
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -366,8 +299,8 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
|
||||
*
|
||||
* XXX How does this interact w/ alloca()?!
|
||||
*/
|
||||
if (decode_prologue(callpc, symval, &pi))
|
||||
return;
|
||||
if (decode_prologue(pc, symval, &pi))
|
||||
return (0);
|
||||
if ((pi.pi_regmask & (1 << 26)) == 0) {
|
||||
/*
|
||||
* No saved RA found. We might have RA from
|
||||
@ -375,37 +308,56 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *m
|
||||
* in a leaf call). If not, we've found the
|
||||
* root of the call graph.
|
||||
*/
|
||||
if (ra_from_tf)
|
||||
callpc = tf->tf_regs[FRAME_RA];
|
||||
if (tf)
|
||||
pc = tf->tf_regs[FRAME_RA];
|
||||
else {
|
||||
db_printf("--- root of call graph ---\n");
|
||||
break;
|
||||
}
|
||||
} else
|
||||
callpc = *(u_long *)(frame + pi.pi_reg_offset[26]);
|
||||
ra_from_tf = ra_from_pcb = FALSE;
|
||||
#if 0
|
||||
/*
|
||||
* The call was actually made at RA - 4; the PC is
|
||||
* updated before being stored in RA.
|
||||
*/
|
||||
callpc -= 4;
|
||||
#endif
|
||||
pc = *(u_long *)(frame + pi.pi_reg_offset[26]);
|
||||
frame += pi.pi_frame_size;
|
||||
tf = NULL;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
db_print_backtrace(void)
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
{
|
||||
struct trace_request tr;
|
||||
struct thread *td;
|
||||
|
||||
td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread;
|
||||
if (td == NULL) {
|
||||
db_printf("Thread %d not found\n", (int)addr);
|
||||
return;
|
||||
}
|
||||
db_trace_thread(td, count);
|
||||
}
|
||||
|
||||
void
|
||||
db_trace_self(void)
|
||||
{
|
||||
register_t pc, sp;
|
||||
|
||||
__asm __volatile(
|
||||
" mov $30,%0 \n"
|
||||
" lda %1,1f \n"
|
||||
"1:\n"
|
||||
: "=r" (tr.ksp), "=r" (tr.pc));
|
||||
db_stack_trace_cmd((db_addr_t)&tr, 1, -1, NULL);
|
||||
: "=r" (sp), "=r" (pc));
|
||||
db_backtrace(curthread, sp, pc, -1);
|
||||
}
|
||||
|
||||
int
|
||||
db_trace_thread(struct thread *thr, int count)
|
||||
{
|
||||
struct pcb *ctx;
|
||||
|
||||
ctx = kdb_thr_ctx(thr);
|
||||
return (db_backtrace(thr, ctx->pcb_hw.apcb_ksp, ctx->pcb_context[7],
|
||||
count));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -31,54 +31,40 @@
|
||||
#ifndef _ALPHA_DB_MACHDEP_H_
|
||||
#define _ALPHA_DB_MACHDEP_H_
|
||||
|
||||
/*
|
||||
* Machine-dependent defines for new kernel debugger.
|
||||
*/
|
||||
#ifndef KLD_MODULE
|
||||
#include "opt_ddb.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <vm/vm.h>
|
||||
#include <machine/frame.h>
|
||||
|
||||
#define DB_NO_AOUT
|
||||
#define DB_NO_AOUT
|
||||
|
||||
typedef vm_offset_t db_addr_t; /* address - unsigned */
|
||||
typedef long db_expr_t; /* expression - signed */
|
||||
|
||||
typedef struct trapframe db_regs_t;
|
||||
#ifdef DDB
|
||||
extern db_regs_t ddb_regs; /* register state */
|
||||
#endif
|
||||
#define DDB_REGS (&ddb_regs)
|
||||
|
||||
#define PC_REGS(regs) ((db_addr_t)(regs)->tf_regs[FRAME_PC])
|
||||
#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_context[7])
|
||||
|
||||
#define BKPT_INST 0x00000080 /* breakpoint instruction */
|
||||
#define BKPT_SIZE (4) /* size of breakpoint inst */
|
||||
#define BKPT_SET(inst) (BKPT_INST)
|
||||
|
||||
#define FIXUP_PC_AFTER_BREAK \
|
||||
(ddb_regs.tf_regs[FRAME_PC] -= BKPT_SIZE);
|
||||
#define FIXUP_PC_AFTER_BREAK (kdb_frame->tf_regs[FRAME_PC] -= BKPT_SIZE);
|
||||
|
||||
#define SOFTWARE_SSTEP 1 /* no hardware support */
|
||||
#define IS_BREAKPOINT_TRAP(type, code) ((type) == ALPHA_KENTRY_IF && \
|
||||
(code) == ALPHA_IF_CODE_BPT)
|
||||
|
||||
#define IS_BREAKPOINT_TRAP(type, code) \
|
||||
((type) == ALPHA_KENTRY_IF && (code) == ALPHA_IF_CODE_BPT)
|
||||
#define IS_WATCHPOINT_TRAP(type, code) 0
|
||||
|
||||
/*
|
||||
* Functions needed for software single-stepping.
|
||||
*/
|
||||
|
||||
boolean_t db_inst_trap_return(int inst);
|
||||
boolean_t db_inst_return(int inst);
|
||||
boolean_t db_inst_call(int inst);
|
||||
boolean_t db_inst_branch(int inst);
|
||||
boolean_t db_inst_load(int inst);
|
||||
boolean_t db_inst_store(int inst);
|
||||
boolean_t db_inst_unconditional_flow_transfer(int inst);
|
||||
db_addr_t db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs);
|
||||
boolean_t db_inst_trap_return(int inst);
|
||||
boolean_t db_inst_return(int inst);
|
||||
boolean_t db_inst_call(int inst);
|
||||
boolean_t db_inst_branch(int inst);
|
||||
boolean_t db_inst_load(int inst);
|
||||
boolean_t db_inst_store(int inst);
|
||||
boolean_t db_inst_unconditional_flow_transfer(int inst);
|
||||
db_addr_t db_branch_taken(int inst, db_addr_t pc);
|
||||
|
||||
#define inst_trap_return(ins) db_inst_trap_return(ins)
|
||||
#define inst_return(ins) db_inst_return(ins)
|
||||
@ -88,15 +74,12 @@ db_addr_t db_branch_taken(int inst, db_addr_t pc, db_regs_t *regs);
|
||||
#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))
|
||||
#define branch_taken(ins, pc) db_branch_taken(ins, pc)
|
||||
|
||||
/* No delay slots on Alpha. */
|
||||
#define next_instr_address(v, b) ((db_addr_t) ((b) ? (v) : ((v) + 4)))
|
||||
|
||||
u_long db_register_value(db_regs_t *, int);
|
||||
int kdb_trap(unsigned long, unsigned long, unsigned long,
|
||||
unsigned long, struct trapframe *);
|
||||
u_long db_register_value(int);
|
||||
|
||||
/*
|
||||
* Pretty arbitrary
|
||||
|
@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/pcpu.h>
|
||||
@ -45,284 +46,95 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
static jmp_buf *db_nofault = 0;
|
||||
extern jmp_buf db_jmpbuf;
|
||||
|
||||
extern void gdb_handle_exception(db_regs_t *, int, int);
|
||||
|
||||
int db_active;
|
||||
db_regs_t ddb_regs;
|
||||
|
||||
static jmp_buf db_global_jmpbuf;
|
||||
|
||||
/*
|
||||
* kdb_trap - field a TRACE or BPT trap
|
||||
*/
|
||||
int
|
||||
kdb_trap(int type, int code, struct amd64_saved_state *regs)
|
||||
{
|
||||
u_long ef;
|
||||
volatile int ddb_mode = !(boothowto & RB_GDB);
|
||||
|
||||
/*
|
||||
* XXX try to do nothing if the console is in graphics mode.
|
||||
* Handle trace traps (and hardware breakpoints...) by ignoring
|
||||
* them except for forgetting about them. Return 0 for other
|
||||
* traps to say that we haven't done anything. The trap handler
|
||||
* will usually panic. We should handle breakpoint traps for
|
||||
* our breakpoints by disarming our breakpoints and fixing up
|
||||
* %eip.
|
||||
*/
|
||||
if (cnunavailable() != 0 && ddb_mode) {
|
||||
if (type == T_TRCTRAP) {
|
||||
regs->tf_rflags &= ~PSL_T;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
ef = read_rflags();
|
||||
disable_intr();
|
||||
|
||||
#ifdef SMP
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf("\nCPU%d stopping CPUs: 0x%08x...", PCPU_GET(cpuid),
|
||||
PCPU_GET(other_cpus));
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
/* We stop all CPUs except ourselves (obviously) */
|
||||
stop_cpus(PCPU_GET(other_cpus));
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf(" stopped.\n");
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
#endif /* SMP */
|
||||
|
||||
switch (type) {
|
||||
case T_BPTFLT: /* breakpoint */
|
||||
case T_TRCTRAP: /* debug exception */
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* XXX this is almost useless now. In most cases,
|
||||
* trap_fatal() has already printed a much more verbose
|
||||
* message. However, it is dangerous to print things in
|
||||
* trap_fatal() - printf() might be reentered and trap.
|
||||
* The debugger should be given control first.
|
||||
*/
|
||||
if (ddb_mode)
|
||||
db_printf("kernel: type %d trap, code=%x\n", type, code);
|
||||
|
||||
if (db_nofault) {
|
||||
jmp_buf *no_fault = db_nofault;
|
||||
db_nofault = 0;
|
||||
longjmp(*no_fault, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This handles unexpected traps in ddb commands, including calls to
|
||||
* non-ddb functions. db_nofault only applies to memory accesses by
|
||||
* internal ddb commands.
|
||||
*/
|
||||
if (db_active)
|
||||
longjmp(db_global_jmpbuf, 1);
|
||||
|
||||
/*
|
||||
* XXX We really should switch to a local stack here.
|
||||
*/
|
||||
ddb_regs = *regs;
|
||||
|
||||
/*
|
||||
* If in kernel mode, esp and ss are not saved, so dummy them up.
|
||||
*/
|
||||
if (ISPL(regs->tf_cs) == 0) {
|
||||
ddb_regs.tf_rsp = (long)®s->tf_rsp;
|
||||
ddb_regs.tf_ss = rss();
|
||||
}
|
||||
|
||||
(void) setjmp(db_global_jmpbuf);
|
||||
if (ddb_mode) {
|
||||
if (!db_active)
|
||||
cndbctl(TRUE);
|
||||
db_active = 1;
|
||||
db_trap(type, code);
|
||||
cndbctl(FALSE);
|
||||
} else {
|
||||
db_active = 1;
|
||||
gdb_handle_exception(&ddb_regs, type, code);
|
||||
}
|
||||
db_active = 0;
|
||||
|
||||
regs->tf_rip = ddb_regs.tf_rip;
|
||||
regs->tf_rflags = ddb_regs.tf_rflags;
|
||||
regs->tf_rax = ddb_regs.tf_rax;
|
||||
regs->tf_rcx = ddb_regs.tf_rcx;
|
||||
regs->tf_rdx = ddb_regs.tf_rdx;
|
||||
regs->tf_rbx = ddb_regs.tf_rbx;
|
||||
|
||||
/*
|
||||
* If in user mode, the saved ESP and SS were valid, restore them.
|
||||
*/
|
||||
if (ISPL(regs->tf_cs)) {
|
||||
regs->tf_rsp = ddb_regs.tf_rsp;
|
||||
regs->tf_ss = ddb_regs.tf_ss & 0xffff;
|
||||
}
|
||||
|
||||
regs->tf_rbp = ddb_regs.tf_rbp;
|
||||
regs->tf_rsi = ddb_regs.tf_rsi;
|
||||
regs->tf_rdi = ddb_regs.tf_rdi;
|
||||
|
||||
regs->tf_r8 = ddb_regs.tf_r8;
|
||||
regs->tf_r9 = ddb_regs.tf_r9;
|
||||
regs->tf_r10 = ddb_regs.tf_r10;
|
||||
regs->tf_r11 = ddb_regs.tf_r11;
|
||||
regs->tf_r12 = ddb_regs.tf_r12;
|
||||
regs->tf_r13 = ddb_regs.tf_r13;
|
||||
regs->tf_r14 = ddb_regs.tf_r14;
|
||||
regs->tf_r15 = ddb_regs.tf_r15;
|
||||
|
||||
#if 0
|
||||
regs->tf_es = ddb_regs.tf_es & 0xffff;
|
||||
regs->tf_fs = ddb_regs.tf_fs & 0xffff;
|
||||
#endif
|
||||
regs->tf_cs = ddb_regs.tf_cs & 0xffff;
|
||||
#if 0
|
||||
regs->tf_ds = ddb_regs.tf_ds & 0xffff;
|
||||
#endif
|
||||
|
||||
#ifdef SMP
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf("\nCPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid),
|
||||
stopped_cpus);
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
/* Restart all the CPUs we previously stopped */
|
||||
if (stopped_cpus != PCPU_GET(other_cpus) && smp_started != 0) {
|
||||
db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
|
||||
PCPU_GET(other_cpus), stopped_cpus);
|
||||
panic("stop_cpus() failed");
|
||||
}
|
||||
restart_cpus(stopped_cpus);
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf(" restarted.\n");
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
#endif /* SMP */
|
||||
|
||||
write_rflags(ef);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read bytes from kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
int
|
||||
db_read_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
char *src;
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *src;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
|
||||
db_nofault = 0;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write bytes to kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
int
|
||||
db_write_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
char *dst;
|
||||
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *dst;
|
||||
pt_entry_t *ptep0 = NULL;
|
||||
pt_entry_t oldmap0 = 0;
|
||||
vm_offset_t addr1;
|
||||
pt_entry_t *ptep1 = NULL;
|
||||
pt_entry_t oldmap1 = 0;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
if (addr > trunc_page((vm_offset_t)btext) - size &&
|
||||
addr < round_page((vm_offset_t)etext)) {
|
||||
|
||||
if (addr > trunc_page((vm_offset_t)btext) - size &&
|
||||
addr < round_page((vm_offset_t)etext)) {
|
||||
ptep0 = vtopte(addr);
|
||||
oldmap0 = *ptep0;
|
||||
*ptep0 |= PG_RW;
|
||||
|
||||
ptep0 = vtopte(addr);
|
||||
oldmap0 = *ptep0;
|
||||
*ptep0 |= PG_RW;
|
||||
/*
|
||||
* Map another page if the data crosses a page
|
||||
* boundary.
|
||||
*/
|
||||
if ((*ptep0 & PG_PS) == 0) {
|
||||
addr1 = trunc_page(addr + size - 1);
|
||||
if (trunc_page(addr) != addr1) {
|
||||
ptep1 = vtopte(addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
}
|
||||
} else {
|
||||
addr1 = trunc_2mpage(addr + size - 1);
|
||||
if (trunc_2mpage(addr) != addr1) {
|
||||
ptep1 = vtopte(addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map another page if the data crosses a page boundary. */
|
||||
if ((*ptep0 & PG_PS) == 0) {
|
||||
addr1 = trunc_page(addr + size - 1);
|
||||
if (trunc_page(addr) != addr1) {
|
||||
ptep1 = vtopte(addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
}
|
||||
} else {
|
||||
addr1 = trunc_2mpage(addr + size - 1);
|
||||
if (trunc_2mpage(addr) != addr1) {
|
||||
ptep1 = vtopte(addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
invltlb();
|
||||
}
|
||||
}
|
||||
|
||||
invltlb();
|
||||
dst = (char *)addr;
|
||||
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
}
|
||||
|
||||
dst = (char *)addr;
|
||||
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
|
||||
db_nofault = 0;
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
|
||||
if (ptep0) {
|
||||
*ptep0 = oldmap0;
|
||||
*ptep0 = oldmap0;
|
||||
|
||||
if (ptep1)
|
||||
*ptep1 = oldmap1;
|
||||
if (ptep1)
|
||||
*ptep1 = oldmap1;
|
||||
|
||||
invltlb();
|
||||
invltlb();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Move this to machdep.c and allow it to be called if any debugger is
|
||||
* installed.
|
||||
*/
|
||||
void
|
||||
Debugger(const char *msg)
|
||||
{
|
||||
static volatile u_int in_Debugger;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Do nothing if the console is in graphics mode. This is
|
||||
* OK if the call is for the debugger hotkey but not if the call
|
||||
* is a weak form of panicing.
|
||||
*/
|
||||
if (cnunavailable() != 0 && !(boothowto & RB_GDB))
|
||||
return;
|
||||
|
||||
if (atomic_cmpset_acq_int(&in_Debugger, 0, 1)) {
|
||||
db_printf("Debugger(\"%s\")\n", msg);
|
||||
breakpoint();
|
||||
atomic_store_rel_int(&in_Debugger, 0);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sysent.h>
|
||||
|
||||
@ -46,56 +47,134 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ddb/db_sym.h>
|
||||
#include <ddb/db_variables.h>
|
||||
|
||||
db_varfcn_t db_dr0;
|
||||
db_varfcn_t db_dr1;
|
||||
db_varfcn_t db_dr2;
|
||||
db_varfcn_t db_dr3;
|
||||
db_varfcn_t db_dr4;
|
||||
db_varfcn_t db_dr5;
|
||||
db_varfcn_t db_dr6;
|
||||
db_varfcn_t db_dr7;
|
||||
static db_varfcn_t db_dr0;
|
||||
static db_varfcn_t db_dr1;
|
||||
static db_varfcn_t db_dr2;
|
||||
static db_varfcn_t db_dr3;
|
||||
static db_varfcn_t db_dr4;
|
||||
static db_varfcn_t db_dr5;
|
||||
static db_varfcn_t db_dr6;
|
||||
static db_varfcn_t db_dr7;
|
||||
static db_varfcn_t db_frame;
|
||||
static db_varfcn_t db_rsp;
|
||||
static db_varfcn_t db_ss;
|
||||
|
||||
/*
|
||||
* Machine register set.
|
||||
*/
|
||||
#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x)
|
||||
struct db_variable db_regs[] = {
|
||||
{ "cs", &ddb_regs.tf_cs, FCN_NULL },
|
||||
{ "cs", DB_OFFSET(tf_cs), db_frame },
|
||||
#if 0
|
||||
{ "ds", &ddb_regs.tf_ds, FCN_NULL },
|
||||
{ "es", &ddb_regs.tf_es, FCN_NULL },
|
||||
{ "fs", &ddb_regs.tf_fs, FCN_NULL },
|
||||
{ "gs", &ddb_regs.tf_gs, FCN_NULL },
|
||||
{ "ds", DB_OFFSET(tf_ds), db_frame },
|
||||
{ "es", DB_OFFSET(tf_es), db_frame },
|
||||
{ "fs", DB_OFFSET(tf_fs), db_frame },
|
||||
{ "gs", DB_OFFSET(tf_gs), db_frame },
|
||||
#endif
|
||||
{ "ss", &ddb_regs.tf_ss, FCN_NULL },
|
||||
{ "rax", &ddb_regs.tf_rax, FCN_NULL },
|
||||
{ "rcx", &ddb_regs.tf_rcx, FCN_NULL },
|
||||
{ "rdx", &ddb_regs.tf_rdx, FCN_NULL },
|
||||
{ "rbx", &ddb_regs.tf_rbx, FCN_NULL },
|
||||
{ "rsp", &ddb_regs.tf_rsp, FCN_NULL },
|
||||
{ "rbp", &ddb_regs.tf_rbp, FCN_NULL },
|
||||
{ "rsi", &ddb_regs.tf_rsi, FCN_NULL },
|
||||
{ "rdi", &ddb_regs.tf_rdi, FCN_NULL },
|
||||
{ "r8", &ddb_regs.tf_r8, FCN_NULL },
|
||||
{ "r9", &ddb_regs.tf_r9, FCN_NULL },
|
||||
{ "r10", &ddb_regs.tf_r10, FCN_NULL },
|
||||
{ "r11", &ddb_regs.tf_r11, FCN_NULL },
|
||||
{ "r12", &ddb_regs.tf_r12, FCN_NULL },
|
||||
{ "r13", &ddb_regs.tf_r13, FCN_NULL },
|
||||
{ "r14", &ddb_regs.tf_r14, FCN_NULL },
|
||||
{ "r15", &ddb_regs.tf_r15, FCN_NULL },
|
||||
{ "rip", &ddb_regs.tf_rip, FCN_NULL },
|
||||
{ "rflags", &ddb_regs.tf_rflags, FCN_NULL },
|
||||
{ "dr0", NULL, db_dr0 },
|
||||
{ "dr1", NULL, db_dr1 },
|
||||
{ "dr2", NULL, db_dr2 },
|
||||
{ "dr3", NULL, db_dr3 },
|
||||
{ "dr4", NULL, db_dr4 },
|
||||
{ "dr5", NULL, db_dr5 },
|
||||
{ "dr6", NULL, db_dr6 },
|
||||
{ "dr7", NULL, db_dr7 },
|
||||
{ "ss", NULL, db_ss },
|
||||
{ "rax", DB_OFFSET(tf_rax), db_frame },
|
||||
{ "rcx", DB_OFFSET(tf_rcx), db_frame },
|
||||
{ "rdx", DB_OFFSET(tf_rdx), db_frame },
|
||||
{ "rbx", DB_OFFSET(tf_rbx), db_frame },
|
||||
{ "rsp", NULL, db_rsp },
|
||||
{ "rbp", DB_OFFSET(tf_rbp), db_frame },
|
||||
{ "rsi", DB_OFFSET(tf_rsi), db_frame },
|
||||
{ "rdi", DB_OFFSET(tf_rdi), db_frame },
|
||||
{ "r8", DB_OFFSET(tf_r8), db_frame },
|
||||
{ "r9", DB_OFFSET(tf_r9), db_frame },
|
||||
{ "r10", DB_OFFSET(tf_r10), db_frame },
|
||||
{ "r11", DB_OFFSET(tf_r11), db_frame },
|
||||
{ "r12", DB_OFFSET(tf_r12), db_frame },
|
||||
{ "r13", DB_OFFSET(tf_r13), db_frame },
|
||||
{ "r14", DB_OFFSET(tf_r14), db_frame },
|
||||
{ "r15", DB_OFFSET(tf_r15), db_frame },
|
||||
{ "rip", DB_OFFSET(tf_rip), db_frame },
|
||||
{ "rflags", DB_OFFSET(tf_rflags), db_frame },
|
||||
{ "dr0", NULL, db_dr0 },
|
||||
{ "dr1", NULL, db_dr1 },
|
||||
{ "dr2", NULL, db_dr2 },
|
||||
{ "dr3", NULL, db_dr3 },
|
||||
{ "dr4", NULL, db_dr4 },
|
||||
{ "dr5", NULL, db_dr5 },
|
||||
{ "dr6", NULL, db_dr6 },
|
||||
{ "dr7", NULL, db_dr7 },
|
||||
};
|
||||
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
|
||||
|
||||
#define DB_DRX_FUNC(reg) \
|
||||
static int \
|
||||
db_ ## reg (vp, valuep, op) \
|
||||
struct db_variable *vp; \
|
||||
db_expr_t * valuep; \
|
||||
int op; \
|
||||
{ \
|
||||
if (op == DB_VAR_GET) \
|
||||
*valuep = r ## reg (); \
|
||||
else \
|
||||
load_ ## reg (*valuep); \
|
||||
return (1); \
|
||||
}
|
||||
|
||||
DB_DRX_FUNC(dr0)
|
||||
DB_DRX_FUNC(dr1)
|
||||
DB_DRX_FUNC(dr2)
|
||||
DB_DRX_FUNC(dr3)
|
||||
DB_DRX_FUNC(dr4)
|
||||
DB_DRX_FUNC(dr5)
|
||||
DB_DRX_FUNC(dr6)
|
||||
DB_DRX_FUNC(dr7)
|
||||
|
||||
static __inline long
|
||||
get_rsp(struct trapframe *tf)
|
||||
{
|
||||
return ((ISPL(tf->tf_cs)) ? tf->tf_rsp :
|
||||
(db_expr_t)tf + offsetof(struct trapframe, tf_rsp));
|
||||
}
|
||||
|
||||
static int
|
||||
db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
long *reg;
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
reg = (long *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = *reg;
|
||||
else
|
||||
*reg = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_rsp(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = get_rsp(kdb_frame);
|
||||
else if (ISPL(kdb_frame->tf_cs))
|
||||
kdb_frame->tf_rsp = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_ss(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = (ISPL(kdb_frame->tf_cs)) ? kdb_frame->tf_ss : rss();
|
||||
else if (ISPL(kdb_frame->tf_cs))
|
||||
kdb_frame->tf_ss = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack trace.
|
||||
*/
|
||||
@ -112,13 +191,10 @@ struct amd64_frame {
|
||||
#define INTERRUPT 2
|
||||
#define SYSCALL 3
|
||||
|
||||
static void db_nextframe(struct amd64_frame **, db_addr_t *, struct proc *);
|
||||
static void db_nextframe(struct amd64_frame **, db_addr_t *, struct thread *);
|
||||
static int db_numargs(struct amd64_frame *);
|
||||
static void db_print_stack_entry(const char *, int, char **, long *, db_addr_t);
|
||||
static void decode_syscall(int, struct proc *);
|
||||
static void db_trace_one_stack(int count, boolean_t have_addr,
|
||||
struct proc *p, struct amd64_frame *frame, db_addr_t callpc);
|
||||
|
||||
static void decode_syscall(int, struct thread *);
|
||||
|
||||
static char * watchtype_str(int type);
|
||||
int amd64_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
|
||||
@ -128,7 +204,6 @@ int db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
|
||||
int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
|
||||
void db_md_list_watchpoints(void);
|
||||
|
||||
|
||||
/*
|
||||
* Figure out how many arguments were passed into the frame at "fp".
|
||||
*/
|
||||
@ -189,16 +264,16 @@ db_print_stack_entry(name, narg, argnp, argp, callpc)
|
||||
}
|
||||
|
||||
static void
|
||||
decode_syscall(number, p)
|
||||
int number;
|
||||
struct proc *p;
|
||||
decode_syscall(int number, struct thread *td)
|
||||
{
|
||||
struct proc *p;
|
||||
c_db_sym_t sym;
|
||||
db_expr_t diff;
|
||||
sy_call_t *f;
|
||||
const char *symname;
|
||||
|
||||
db_printf(" (%d", number);
|
||||
p = (td != NULL) ? td->td_proc : NULL;
|
||||
if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
|
||||
f = p->p_sysent->sv_table[number].sy_call;
|
||||
sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
|
||||
@ -214,10 +289,7 @@ decode_syscall(number, p)
|
||||
* Figure out the next frame up in the call stack.
|
||||
*/
|
||||
static void
|
||||
db_nextframe(fp, ip, p)
|
||||
struct amd64_frame **fp; /* in/out */
|
||||
db_addr_t *ip; /* out */
|
||||
struct proc *p; /* in */
|
||||
db_nextframe(struct amd64_frame **fp, db_addr_t *ip, struct thread *td)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
int frame_type;
|
||||
@ -265,8 +337,7 @@ db_nextframe(fp, ip, p)
|
||||
tf = (struct trapframe *)((long)*fp + 16);
|
||||
|
||||
if (INKERNEL((long) tf)) {
|
||||
rsp = (ISPL(tf->tf_cs) == SEL_UPL) ?
|
||||
tf->tf_rsp : (long)&tf->tf_rsp;
|
||||
rsp = get_rsp(tf);
|
||||
rip = tf->tf_rip;
|
||||
rbp = tf->tf_rbp;
|
||||
switch (frame_type) {
|
||||
@ -275,7 +346,7 @@ db_nextframe(fp, ip, p)
|
||||
break;
|
||||
case SYSCALL:
|
||||
db_printf("--- syscall");
|
||||
decode_syscall(tf->tf_rax, p);
|
||||
decode_syscall(tf->tf_rax, td);
|
||||
break;
|
||||
case INTERRUPT:
|
||||
db_printf("--- interrupt");
|
||||
@ -291,135 +362,26 @@ db_nextframe(fp, ip, p)
|
||||
*fp = (struct amd64_frame *) rbp;
|
||||
}
|
||||
|
||||
void
|
||||
db_stack_trace_cmd(addr, have_addr, count, modif)
|
||||
db_expr_t addr;
|
||||
boolean_t have_addr;
|
||||
db_expr_t count;
|
||||
char *modif;
|
||||
static int
|
||||
db_backtrace(struct thread *td, struct trapframe *tf,
|
||||
struct amd64_frame *frame, db_addr_t pc, int count)
|
||||
{
|
||||
struct amd64_frame *frame;
|
||||
struct proc *p;
|
||||
struct pcb *pcb;
|
||||
struct thread *td;
|
||||
db_addr_t callpc;
|
||||
pid_t pid;
|
||||
struct amd64_frame *actframe;
|
||||
#define MAXNARG 16
|
||||
char *argnames[MAXNARG], **argnp = NULL;
|
||||
const char *name;
|
||||
long *argp;
|
||||
db_expr_t offset;
|
||||
c_db_sym_t sym;
|
||||
int narg;
|
||||
boolean_t first;
|
||||
|
||||
if (count == -1)
|
||||
count = 1024;
|
||||
|
||||
if (!have_addr) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
frame = (struct amd64_frame *)ddb_regs.tf_rbp;
|
||||
if (frame == NULL)
|
||||
frame = (struct amd64_frame *)(ddb_regs.tf_rsp - 8);
|
||||
callpc = (db_addr_t)ddb_regs.tf_rip;
|
||||
} else if (!INKERNEL(addr)) {
|
||||
pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
|
||||
((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
|
||||
((addr >> 16) % 16) * 10000;
|
||||
/*
|
||||
* The pcb for curproc is not valid at this point,
|
||||
* so fall back to the default case.
|
||||
*/
|
||||
if (pid == curthread->td_proc->p_pid) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
frame = (struct amd64_frame *)ddb_regs.tf_rbp;
|
||||
if (frame == NULL)
|
||||
frame = (struct amd64_frame *)
|
||||
(ddb_regs.tf_rsp - 8);
|
||||
callpc = (db_addr_t)ddb_regs.tf_rip;
|
||||
} else {
|
||||
|
||||
/* sx_slock(&allproc_lock); */
|
||||
LIST_FOREACH(p, &allproc, p_list) {
|
||||
if (p->p_pid == pid)
|
||||
break;
|
||||
}
|
||||
/* sx_sunlock(&allproc_lock); */
|
||||
if (p == NULL) {
|
||||
db_printf("pid %d not found\n", pid);
|
||||
return;
|
||||
}
|
||||
if ((p->p_sflag & PS_INMEM) == 0) {
|
||||
db_printf("pid %d swapped out\n", pid);
|
||||
return;
|
||||
}
|
||||
pcb = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */
|
||||
frame = (struct amd64_frame *)pcb->pcb_rbp;
|
||||
if (frame == NULL)
|
||||
frame = (struct amd64_frame *)
|
||||
(pcb->pcb_rsp - 8);
|
||||
callpc = (db_addr_t)pcb->pcb_rip;
|
||||
}
|
||||
} else {
|
||||
p = NULL;
|
||||
frame = (struct amd64_frame *)addr;
|
||||
callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
|
||||
frame = frame->f_frame;
|
||||
}
|
||||
db_trace_one_stack(count, have_addr, p, frame, callpc);
|
||||
}
|
||||
|
||||
void
|
||||
db_stack_thread(db_expr_t addr, boolean_t have_addr,
|
||||
db_expr_t count, char *modif)
|
||||
{
|
||||
struct amd64_frame *frame;
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
struct pcb *pcb;
|
||||
db_addr_t callpc;
|
||||
|
||||
if (!have_addr)
|
||||
return;
|
||||
if (!INKERNEL(addr)) {
|
||||
printf("bad thread address");
|
||||
return;
|
||||
}
|
||||
td = (struct thread *)addr;
|
||||
/* quick sanity check */
|
||||
if ((p = td->td_proc) != td->td_ksegrp->kg_proc)
|
||||
return;
|
||||
if (TD_IS_SWAPPED(td)) {
|
||||
db_printf("thread at %p swapped out\n", td);
|
||||
return;
|
||||
}
|
||||
if (td == curthread) {
|
||||
frame = (struct amd64_frame *)ddb_regs.tf_rbp;
|
||||
if (frame == NULL)
|
||||
frame = (struct amd64_frame *)(ddb_regs.tf_rsp - 8);
|
||||
callpc = (db_addr_t)ddb_regs.tf_rip;
|
||||
} else {
|
||||
pcb = td->td_pcb;
|
||||
frame = (struct amd64_frame *)pcb->pcb_rbp;
|
||||
if (frame == NULL)
|
||||
frame = (struct amd64_frame *) (pcb->pcb_rsp - 8);
|
||||
callpc = (db_addr_t)pcb->pcb_rip;
|
||||
}
|
||||
db_trace_one_stack(count, have_addr, p, frame, callpc);
|
||||
}
|
||||
|
||||
static void
|
||||
db_trace_one_stack(int count, boolean_t have_addr,
|
||||
struct proc *p, struct amd64_frame *frame, db_addr_t callpc)
|
||||
{
|
||||
long *argp;
|
||||
boolean_t first;
|
||||
|
||||
first = TRUE;
|
||||
while (count--) {
|
||||
struct amd64_frame *actframe;
|
||||
int narg;
|
||||
const char * name;
|
||||
db_expr_t offset;
|
||||
c_db_sym_t sym;
|
||||
#define MAXNARG 16
|
||||
char *argnames[MAXNARG], **argnp = NULL;
|
||||
|
||||
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
||||
db_symbol_values(sym, &name, NULL);
|
||||
|
||||
/*
|
||||
@ -435,37 +397,33 @@ db_trace_one_stack(int count, boolean_t have_addr,
|
||||
*/
|
||||
actframe = frame;
|
||||
if (first) {
|
||||
if (!have_addr) {
|
||||
if (tf != NULL) {
|
||||
int instr;
|
||||
|
||||
instr = db_get_value(callpc, 4, FALSE);
|
||||
instr = db_get_value(pc, 4, FALSE);
|
||||
if ((instr & 0xffffffff) == 0xe5894855) {
|
||||
/* pushq %rbp; movq %rsp, %rbp */
|
||||
actframe = (struct amd64_frame *)
|
||||
(ddb_regs.tf_rsp - 8);
|
||||
} else if ((instr & 0x00ffffff) == 0x00e58948) {
|
||||
actframe = (void *)(get_rsp(tf) - 8);
|
||||
} else if ((instr & 0xffffff) == 0xe58948) {
|
||||
/* movq %rsp, %rbp */
|
||||
actframe = (struct amd64_frame *)
|
||||
ddb_regs.tf_rsp;
|
||||
if (ddb_regs.tf_rbp == 0) {
|
||||
/* Fake caller's frame better. */
|
||||
actframe = (void *)get_rsp(tf);
|
||||
if (tf->tf_rbp == 0) {
|
||||
/* Fake frame better. */
|
||||
frame = actframe;
|
||||
}
|
||||
} else if ((instr & 0x000000ff) == 0x000000c3) {
|
||||
} else if ((instr & 0xff) == 0xc3) {
|
||||
/* ret */
|
||||
actframe = (struct amd64_frame *)
|
||||
(ddb_regs.tf_rsp - 8);
|
||||
actframe = (void *)(get_rsp(tf) - 8);
|
||||
} else if (offset == 0) {
|
||||
/* Probably a symbol in assembler code. */
|
||||
actframe = (struct amd64_frame *)
|
||||
(ddb_regs.tf_rsp - 8);
|
||||
/* Probably an assembler symbol. */
|
||||
actframe = (void *)(get_rsp(tf) - 8);
|
||||
}
|
||||
} else if (strcmp(name, "fork_trampoline") == 0) {
|
||||
/*
|
||||
* Don't try to walk back on a stack for a
|
||||
* process that hasn't actually been run yet.
|
||||
*/
|
||||
db_print_stack_entry(name, 0, 0, 0, callpc);
|
||||
db_print_stack_entry(name, 0, 0, 0, pc);
|
||||
break;
|
||||
}
|
||||
first = FALSE;
|
||||
@ -479,60 +437,68 @@ db_trace_one_stack(int count, boolean_t have_addr,
|
||||
narg = db_numargs(frame);
|
||||
}
|
||||
|
||||
db_print_stack_entry(name, narg, argnp, argp, callpc);
|
||||
db_print_stack_entry(name, narg, argnp, argp, pc);
|
||||
|
||||
if (actframe != frame) {
|
||||
/* `frame' belongs to caller. */
|
||||
callpc = (db_addr_t)
|
||||
pc = (db_addr_t)
|
||||
db_get_value((long)&actframe->f_retaddr, 8, FALSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
db_nextframe(&frame, &callpc, p);
|
||||
db_nextframe(&frame, &pc, td);
|
||||
|
||||
if (INKERNEL((long) callpc) && !INKERNEL((long) frame)) {
|
||||
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
|
||||
if (INKERNEL((long)pc) && !INKERNEL((long)frame)) {
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
||||
db_symbol_values(sym, &name, NULL);
|
||||
db_print_stack_entry(name, 0, 0, 0, callpc);
|
||||
db_print_stack_entry(name, 0, 0, 0, pc);
|
||||
break;
|
||||
}
|
||||
if (!INKERNEL((long) frame)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
db_print_backtrace(void)
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
{
|
||||
register_t ebp;
|
||||
struct thread *td;
|
||||
|
||||
__asm __volatile("movq %%rbp,%0" : "=r" (ebp));
|
||||
db_stack_trace_cmd(ebp, 1, -1, NULL);
|
||||
td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread;
|
||||
if (td == NULL) {
|
||||
db_printf("Thread %ld not found\n", addr);
|
||||
return;
|
||||
}
|
||||
db_trace_thread(td, count);
|
||||
}
|
||||
|
||||
#define DB_DRX_FUNC(reg) \
|
||||
int \
|
||||
db_ ## reg (vp, valuep, op) \
|
||||
struct db_variable *vp; \
|
||||
db_expr_t * valuep; \
|
||||
int op; \
|
||||
{ \
|
||||
if (op == DB_VAR_GET) \
|
||||
*valuep = r ## reg (); \
|
||||
else \
|
||||
load_ ## reg (*valuep); \
|
||||
return (0); \
|
||||
}
|
||||
void
|
||||
db_trace_self(void)
|
||||
{
|
||||
struct amd64_frame *frame;
|
||||
db_addr_t callpc;
|
||||
register_t rbp;
|
||||
|
||||
DB_DRX_FUNC(dr0)
|
||||
DB_DRX_FUNC(dr1)
|
||||
DB_DRX_FUNC(dr2)
|
||||
DB_DRX_FUNC(dr3)
|
||||
DB_DRX_FUNC(dr4)
|
||||
DB_DRX_FUNC(dr5)
|
||||
DB_DRX_FUNC(dr6)
|
||||
DB_DRX_FUNC(dr7)
|
||||
__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
|
||||
frame = (struct amd64_frame *)rbp;
|
||||
callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
|
||||
frame = frame->f_frame;
|
||||
db_backtrace(curthread, NULL, frame, callpc, -1);
|
||||
}
|
||||
|
||||
int
|
||||
db_trace_thread(struct thread *thr, int count)
|
||||
{
|
||||
struct pcb *ctx;
|
||||
|
||||
ctx = kdb_thr_ctx(thr);
|
||||
return (db_backtrace(thr, NULL, (struct amd64_frame *)ctx->pcb_rbp,
|
||||
ctx->pcb_rip, count));
|
||||
}
|
||||
|
||||
int
|
||||
amd64_set_watch(watchnum, watchaddr, size, access, d)
|
||||
|
@ -30,30 +30,23 @@
|
||||
#define _MACHINE_DB_MACHDEP_H_
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
#define amd64_saved_state trapframe
|
||||
|
||||
typedef vm_offset_t db_addr_t; /* address - unsigned */
|
||||
typedef long db_expr_t; /* expression - signed */
|
||||
|
||||
typedef struct amd64_saved_state db_regs_t;
|
||||
extern db_regs_t ddb_regs; /* register state */
|
||||
#define DDB_REGS (&ddb_regs)
|
||||
|
||||
#define PC_REGS(regs) ((db_addr_t)(regs)->tf_rip)
|
||||
#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_rip)
|
||||
|
||||
#define BKPT_INST 0xcc /* breakpoint instruction */
|
||||
#define BKPT_SIZE (1) /* size of breakpoint inst */
|
||||
#define BKPT_SET(inst) (BKPT_INST)
|
||||
|
||||
#define BKPT_SKIP ddb_regs.tf_rip += 1
|
||||
#define BKPT_SKIP kdb_frame->tf_rip += 1
|
||||
|
||||
#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_rip -= 1;
|
||||
#define FIXUP_PC_AFTER_BREAK kdb_frame->tf_rip -= 1;
|
||||
|
||||
#define db_clear_single_step(regs) ((regs)->tf_rflags &= ~PSL_T)
|
||||
#define db_set_single_step(regs) ((regs)->tf_rflags |= PSL_T)
|
||||
#define db_clear_single_step kdb_cpu_clear_singlestep
|
||||
#define db_set_single_step kdb_cpu_set_singlestep
|
||||
|
||||
#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT)
|
||||
/*
|
||||
|
@ -249,25 +249,23 @@ crypto/rijndael/rijndael-api.c optional ipsec
|
||||
opencrypto/rmd160.c optional ipsec
|
||||
crypto/sha1.c optional ipsec
|
||||
crypto/sha2/sha2.c optional ipsec
|
||||
ddb/db_access.c optional ddb
|
||||
ddb/db_break.c optional ddb
|
||||
ddb/db_command.c optional ddb
|
||||
ddb/db_elf.c optional ddb
|
||||
ddb/db_examine.c optional ddb
|
||||
ddb/db_expr.c optional ddb
|
||||
ddb/db_input.c optional ddb
|
||||
ddb/db_kld.c optional ddb
|
||||
ddb/db_lex.c optional ddb
|
||||
ddb/db_output.c optional ddb
|
||||
ddb/db_print.c optional ddb
|
||||
ddb/db_ps.c optional ddb
|
||||
ddb/db_run.c optional ddb
|
||||
ddb/db_sym.c optional ddb
|
||||
ddb/db_sysctl.c optional ddb
|
||||
ddb/db_trap.c optional ddb
|
||||
ddb/db_variables.c optional ddb
|
||||
ddb/db_watch.c optional ddb
|
||||
ddb/db_write_cmd.c optional ddb
|
||||
ddb/db_access.c optional ddb
|
||||
ddb/db_break.c optional ddb
|
||||
ddb/db_command.c optional ddb
|
||||
ddb/db_examine.c optional ddb
|
||||
ddb/db_expr.c optional ddb
|
||||
ddb/db_input.c optional ddb
|
||||
ddb/db_lex.c optional ddb
|
||||
ddb/db_main.c optional ddb
|
||||
ddb/db_output.c optional ddb
|
||||
ddb/db_print.c optional ddb
|
||||
ddb/db_ps.c optional ddb
|
||||
ddb/db_run.c optional ddb
|
||||
ddb/db_sym.c optional ddb
|
||||
ddb/db_thread.c optional ddb
|
||||
ddb/db_variables.c optional ddb
|
||||
ddb/db_watch.c optional ddb
|
||||
ddb/db_write_cmd.c optional ddb
|
||||
dev/aac/aac.c optional aac
|
||||
dev/aac/aac_debug.c optional aac
|
||||
dev/aac/aac_disk.c optional aac
|
||||
|
@ -32,6 +32,7 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_access.h>
|
||||
@ -58,7 +59,11 @@ db_get_value(addr, size, is_signed)
|
||||
register db_expr_t value;
|
||||
register int i;
|
||||
|
||||
db_read_bytes(addr, size, data);
|
||||
if (db_read_bytes(addr, size, data) != 0) {
|
||||
db_printf("*** error reading from address %llx ***\n",
|
||||
(long long)addr);
|
||||
kdb_reenter();
|
||||
}
|
||||
|
||||
value = 0;
|
||||
#if BYTE_MSF
|
||||
@ -96,6 +101,9 @@ db_put_value(addr, size, value)
|
||||
value >>= 8;
|
||||
}
|
||||
|
||||
db_write_bytes(addr, size, data);
|
||||
if (db_write_bytes(addr, size, data) != 0) {
|
||||
db_printf("*** error writing to address %llx ***\n",
|
||||
(long long)addr);
|
||||
kdb_reenter();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,46 +367,3 @@ db_map_addr(addr)
|
||||
#endif
|
||||
return kernel_map;
|
||||
}
|
||||
|
||||
#ifdef ALT_BREAK_TO_DEBUGGER
|
||||
/*
|
||||
* Solaris implements a new BREAK which is initiated by a character sequence
|
||||
* CR ~ ^b which is similar to a familiar pattern used on Sun servers by the
|
||||
* Remote Console.
|
||||
*
|
||||
* Note that this function may be called from almost anywhere, with interrupts
|
||||
* disabled and with unknown locks held, so it must not access data other than
|
||||
* its arguments. Its up to the caller to ensure that the state variable is
|
||||
* consistent.
|
||||
*/
|
||||
|
||||
#define KEY_CR 13 /* CR '\r' */
|
||||
#define KEY_TILDE 126 /* ~ */
|
||||
#define KEY_CRTLB 2 /* ^B */
|
||||
|
||||
int
|
||||
db_alt_break(int data, int *state)
|
||||
{
|
||||
int brk = 0;
|
||||
|
||||
switch (data) {
|
||||
case KEY_CR:
|
||||
*state = KEY_TILDE;
|
||||
break;
|
||||
case KEY_TILDE:
|
||||
if (*state == KEY_TILDE)
|
||||
*state = KEY_CRTLB;
|
||||
else
|
||||
*state = 0;
|
||||
break;
|
||||
case KEY_CRTLB:
|
||||
if (*state == KEY_CRTLB)
|
||||
brk = 1;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
*state = 0;
|
||||
break;
|
||||
}
|
||||
return (brk);
|
||||
}
|
||||
#endif
|
||||
|
@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker_set.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/reboot.h>
|
||||
@ -58,7 +59,6 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
boolean_t db_cmd_loop_done;
|
||||
db_addr_t db_dot;
|
||||
jmp_buf db_jmpbuf;
|
||||
db_addr_t db_last_addr;
|
||||
db_addr_t db_prev;
|
||||
db_addr_t db_next;
|
||||
@ -67,7 +67,6 @@ SET_DECLARE(db_cmd_set, struct command);
|
||||
SET_DECLARE(db_show_cmd_set, struct command);
|
||||
|
||||
static db_cmdfcn_t db_fncall;
|
||||
static db_cmdfcn_t db_gdb;
|
||||
static db_cmdfcn_t db_kill;
|
||||
static db_cmdfcn_t db_reset;
|
||||
static db_cmdfcn_t db_watchdog;
|
||||
@ -375,9 +374,6 @@ db_command(last_cmdp, cmd_table, aux_cmd_tablep, aux_cmd_tablep_end)
|
||||
*/
|
||||
|
||||
static struct command db_show_all_cmds[] = {
|
||||
#if 0
|
||||
{ "threads", db_show_all_threads, 0, 0 },
|
||||
#endif
|
||||
{ "procs", db_ps, 0, 0 },
|
||||
{ (char *)0 }
|
||||
};
|
||||
@ -386,10 +382,7 @@ static struct command db_show_cmds[] = {
|
||||
{ "all", 0, 0, db_show_all_cmds },
|
||||
{ "registers", db_show_regs, 0, 0 },
|
||||
{ "breaks", db_listbreak_cmd, 0, 0 },
|
||||
{ "thread", db_show_one_thread, 0, 0 },
|
||||
#if 0
|
||||
{ "port", ipc_port_print, 0, 0 },
|
||||
#endif
|
||||
{ "threads", db_show_threads, 0, 0 },
|
||||
{ (char *)0, }
|
||||
};
|
||||
|
||||
@ -421,29 +414,15 @@ static struct command db_command_table[] = {
|
||||
{ "call", db_fncall, CS_OWN, 0 },
|
||||
{ "show", 0, 0, db_show_cmds },
|
||||
{ "ps", db_ps, 0, 0 },
|
||||
{ "gdb", db_gdb, 0, 0 },
|
||||
{ "reset", db_reset, 0, 0 },
|
||||
{ "kill", db_kill, CS_OWN, 0 },
|
||||
{ "watchdog", db_watchdog, 0, 0 },
|
||||
{ "thread", db_set_thread, CS_OWN, 0 },
|
||||
{ (char *)0, }
|
||||
};
|
||||
|
||||
static struct command *db_last_command = 0;
|
||||
|
||||
#if 0
|
||||
void
|
||||
db_help_cmd()
|
||||
{
|
||||
struct command *cmd = db_command_table;
|
||||
|
||||
while (cmd->name != 0) {
|
||||
db_printf("%-12s", cmd->name);
|
||||
db_end_line();
|
||||
cmd++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* At least one non-optional command must be implemented using
|
||||
* DB_COMMAND() so that db_cmd_set gets created. Here is one.
|
||||
@ -464,8 +443,6 @@ db_command_loop()
|
||||
|
||||
db_cmd_loop_done = 0;
|
||||
while (!db_cmd_loop_done) {
|
||||
|
||||
(void) setjmp(db_jmpbuf);
|
||||
if (db_print_position() != 0)
|
||||
db_printf("\n");
|
||||
|
||||
@ -484,7 +461,7 @@ db_error(s)
|
||||
if (s)
|
||||
db_printf("%s", s);
|
||||
db_flush_lex();
|
||||
longjmp(db_jmpbuf, 1);
|
||||
kdb_reenter();
|
||||
}
|
||||
|
||||
|
||||
@ -553,32 +530,6 @@ db_fncall(dummy1, dummy2, dummy3, dummy4)
|
||||
db_printf("%#lr\n", (long)retval);
|
||||
}
|
||||
|
||||
/* Enter GDB remote protocol debugger on the next trap. */
|
||||
|
||||
void *gdb_arg = NULL;
|
||||
cn_getc_t *gdb_getc;
|
||||
cn_putc_t *gdb_putc;
|
||||
|
||||
static void
|
||||
db_gdb (dummy1, dummy2, dummy3, dummy4)
|
||||
db_expr_t dummy1;
|
||||
boolean_t dummy2;
|
||||
db_expr_t dummy3;
|
||||
char * dummy4;
|
||||
{
|
||||
|
||||
if (gdb_arg == NULL) {
|
||||
db_printf("No gdb port enabled. Set flag 0x80 on desired port\n");
|
||||
db_printf("in your configuration file (currently sio only).\n");
|
||||
return;
|
||||
}
|
||||
boothowto ^= RB_GDB;
|
||||
|
||||
db_printf("Next trap will enter %s\n",
|
||||
boothowto & RB_GDB ? "GDB remote protocol mode"
|
||||
: "DDB debugger");
|
||||
}
|
||||
|
||||
static void
|
||||
db_kill(dummy1, dummy2, dummy3, dummy4)
|
||||
db_expr_t dummy1;
|
||||
|
226
sys/ddb/db_main.c
Normal file
226
sys/ddb/db_main.c
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Mach Operating System
|
||||
* Copyright (c) 1991,1990 Carnegie Mellon University
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
|
||||
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
|
||||
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*
|
||||
* Carnegie Mellon requests users of this software to return to
|
||||
*
|
||||
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
||||
* School of Computer Science
|
||||
* Carnegie Mellon University
|
||||
* Pittsburgh PA 15213-3890
|
||||
*
|
||||
* any improvements or extensions that they make and grant Carnegie the
|
||||
* rights to redistribute these changes.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/reboot.h>
|
||||
|
||||
#include <machine/kdb.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_command.h>
|
||||
#include <ddb/db_sym.h>
|
||||
|
||||
static dbbe_init_f db_init;
|
||||
static dbbe_trap_f db_trap;
|
||||
|
||||
KDB_BACKEND(ddb, db_init, db_trace_self, db_trap);
|
||||
|
||||
vm_offset_t ksym_start, ksym_end;
|
||||
|
||||
boolean_t
|
||||
X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
|
||||
db_expr_t off)
|
||||
{
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
c_db_sym_t
|
||||
X_db_lookup(db_symtab_t *symtab, const char *symbol)
|
||||
{
|
||||
c_linker_sym_t lsym;
|
||||
Elf_Sym *sym;
|
||||
|
||||
if (symtab->private == NULL) {
|
||||
return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym))
|
||||
? lsym : NULL));
|
||||
} else {
|
||||
sym = (Elf_Sym *)symtab->start;
|
||||
while ((char *)sym < symtab->end) {
|
||||
if (sym->st_name != 0 &&
|
||||
!strcmp(symtab->private + sym->st_name, symbol))
|
||||
return ((c_db_sym_t)sym);
|
||||
sym++;
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
c_db_sym_t
|
||||
X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat,
|
||||
db_expr_t *diffp)
|
||||
{
|
||||
c_linker_sym_t lsym;
|
||||
Elf_Sym *sym, *match;
|
||||
unsigned long diff;
|
||||
|
||||
if (symtab->private == NULL) {
|
||||
if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) {
|
||||
*diffp = (db_expr_t)diff;
|
||||
return ((c_db_sym_t)lsym);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
diff = ~0UL;
|
||||
match = NULL;
|
||||
for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) {
|
||||
if (sym->st_name == 0)
|
||||
continue;
|
||||
if (off < sym->st_value)
|
||||
continue;
|
||||
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
|
||||
ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
|
||||
ELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
|
||||
continue;
|
||||
if ((off - sym->st_value) > diff)
|
||||
continue;
|
||||
if ((off - sym->st_value) < diff) {
|
||||
diff = off - sym->st_value;
|
||||
match = sym;
|
||||
} else {
|
||||
if (match == NULL)
|
||||
match = sym;
|
||||
else if (ELF_ST_BIND(match->st_info) == STB_LOCAL &&
|
||||
ELF_ST_BIND(sym->st_info) != STB_LOCAL)
|
||||
match = sym;
|
||||
}
|
||||
if (diff == 0) {
|
||||
if (strat == DB_STGY_PROC &&
|
||||
ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
|
||||
ELF_ST_BIND(sym->st_info) != STB_LOCAL)
|
||||
break;
|
||||
if (strat == DB_STGY_ANY &&
|
||||
ELF_ST_BIND(sym->st_info) != STB_LOCAL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*diffp = (match == NULL) ? off : diff;
|
||||
return ((c_db_sym_t)match);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp,
|
||||
char **argp)
|
||||
{
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep,
|
||||
db_expr_t *valp)
|
||||
{
|
||||
linker_symval_t lval;
|
||||
|
||||
if (symtab->private == NULL) {
|
||||
linker_ddb_symbol_values((c_linker_sym_t)sym, &lval);
|
||||
if (namep != NULL)
|
||||
*namep = (const char*)lval.name;
|
||||
if (valp != NULL)
|
||||
*valp = (db_expr_t)lval.value;
|
||||
} else {
|
||||
if (namep != NULL)
|
||||
*namep = (const char *)symtab->private +
|
||||
((const Elf_Sym *)sym)->st_name;
|
||||
if (valp != NULL)
|
||||
*valp = (db_expr_t)((const Elf_Sym *)sym)->st_value;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
db_init(void)
|
||||
{
|
||||
uintptr_t symtab, strtab;
|
||||
Elf_Size tabsz, strsz;
|
||||
|
||||
if (ksym_end > ksym_start && ksym_start != 0) {
|
||||
symtab = ksym_start;
|
||||
tabsz = *((Elf_Size*)symtab)++;
|
||||
strtab = symtab + tabsz;
|
||||
strsz = *((Elf_Size*)strtab)++;
|
||||
if (strtab + strsz <= ksym_end) {
|
||||
db_add_symbol_table((char *)symtab,
|
||||
(char *)(symtab + tabsz), "elf", (char *)strtab);
|
||||
}
|
||||
}
|
||||
db_add_symbol_table(NULL, NULL, "kld", NULL);
|
||||
return (1); /* We're the default debugger. */
|
||||
}
|
||||
|
||||
static int
|
||||
db_trap(int type, int code)
|
||||
{
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
boolean_t bkpt, watchpt;
|
||||
|
||||
/*
|
||||
* Don't handle the trap if the console is unavailable (i.e. it
|
||||
* is in graphics mode).
|
||||
*/
|
||||
if (cnunavailable())
|
||||
return (0);
|
||||
|
||||
bkpt = IS_BREAKPOINT_TRAP(type, code);
|
||||
watchpt = IS_WATCHPOINT_TRAP(type, code);
|
||||
|
||||
if (db_stop_at_pc(&bkpt)) {
|
||||
if (db_inst_count) {
|
||||
db_printf("After %d instructions (%d loads, %d stores),\n",
|
||||
db_inst_count, db_load_count, db_store_count);
|
||||
}
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
if (setjmp(jb) == 0) {
|
||||
db_dot = PC_REGS();
|
||||
db_print_thread();
|
||||
if (bkpt)
|
||||
db_printf("Breakpoint at\t");
|
||||
else if (watchpt)
|
||||
db_printf("Watchpoint at\t");
|
||||
else
|
||||
db_printf("Stopped at\t");
|
||||
db_print_loc_and_inst(db_dot);
|
||||
}
|
||||
db_command_loop();
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
}
|
||||
|
||||
db_restart_at_pc(watchpt);
|
||||
|
||||
return (1);
|
||||
}
|
@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
@ -112,9 +113,9 @@ db_putchar(c, arg)
|
||||
* If not in the debugger or the user requests it, output data to
|
||||
* both the console and the message buffer.
|
||||
*/
|
||||
if (!db_active || ddb_use_printf) {
|
||||
if (!kdb_active || ddb_use_printf) {
|
||||
printf("%c", c);
|
||||
if (!db_active)
|
||||
if (!kdb_active)
|
||||
return;
|
||||
if (c == '\r' || c == '\n')
|
||||
db_check_interrupt();
|
||||
|
@ -37,33 +37,33 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_variables.h>
|
||||
#include <ddb/db_sym.h>
|
||||
|
||||
void
|
||||
db_show_regs(dummy1, dummy2, dummy3, dummy4)
|
||||
db_expr_t dummy1;
|
||||
boolean_t dummy2;
|
||||
db_expr_t dummy3;
|
||||
char * dummy4;
|
||||
db_show_regs(db_expr_t _1, boolean_t _2, db_expr_t _3, char *_4)
|
||||
{
|
||||
register struct db_variable *regp;
|
||||
db_expr_t value, offset;
|
||||
const char * name;
|
||||
struct db_variable *regp;
|
||||
db_expr_t value, offset;
|
||||
const char *name;
|
||||
|
||||
for (regp = db_regs; regp < db_eregs; regp++) {
|
||||
db_read_variable(regp, &value);
|
||||
db_printf("%-12s%#10lr", regp->name, (unsigned long)value);
|
||||
db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
|
||||
if (name != NULL && offset <= (unsigned long)db_maxoff &&
|
||||
offset != value) {
|
||||
db_printf("\t%s", name);
|
||||
if (offset != 0)
|
||||
db_printf("+%+#lr", (long)offset);
|
||||
}
|
||||
db_printf("\n");
|
||||
if (!db_read_variable(regp, &value))
|
||||
continue;
|
||||
db_printf("%-12s%#10lr", regp->name, (unsigned long)value);
|
||||
db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
|
||||
if (name != NULL && offset <= (unsigned long)db_maxoff &&
|
||||
offset != value) {
|
||||
db_printf("\t%s", name);
|
||||
if (offset != 0)
|
||||
db_printf("+%+#lr", (long)offset);
|
||||
}
|
||||
db_printf("\n");
|
||||
}
|
||||
db_print_loc_and_inst(PC_REGS(DDB_REGS));
|
||||
db_print_loc_and_inst(PC_REGS());
|
||||
}
|
||||
|
@ -166,29 +166,3 @@ dumpthread(volatile struct proc *p, volatile struct thread *td)
|
||||
} else
|
||||
db_printf(" %s\n", p->p_comm);
|
||||
}
|
||||
|
||||
|
||||
#define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK)
|
||||
void
|
||||
db_show_one_thread(db_expr_t addr, boolean_t have_addr,
|
||||
db_expr_t count, char *modif)
|
||||
{
|
||||
struct proc *p;
|
||||
struct thread *td;
|
||||
|
||||
if (!have_addr)
|
||||
td = curthread;
|
||||
else if (!INKERNEL(addr)) {
|
||||
printf("bad thread address");
|
||||
return;
|
||||
} else
|
||||
td = (struct thread *)addr;
|
||||
/* quick sanity check */
|
||||
if ((p = td->td_proc) != td->td_ksegrp->kg_proc)
|
||||
return;
|
||||
printf("Proc %p ",p);
|
||||
dumpthread(p, td);
|
||||
#ifdef __i386__
|
||||
db_stack_thread((db_expr_t)td, 1, count, modif);
|
||||
#endif
|
||||
}
|
||||
|
@ -36,6 +36,10 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
|
||||
#include <machine/kdb.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
@ -61,14 +65,10 @@ int db_load_count;
|
||||
int db_store_count;
|
||||
|
||||
#ifndef db_set_single_step
|
||||
extern void db_set_single_step(db_regs_t *regs);
|
||||
void db_set_single_step(void);
|
||||
#endif
|
||||
#ifndef db_clear_single_step
|
||||
extern void db_clear_single_step(db_regs_t *regs);
|
||||
#endif
|
||||
|
||||
#ifdef notused
|
||||
static void db_single_step(db_regs_t *regs);
|
||||
void db_clear_single_step(void);
|
||||
#endif
|
||||
|
||||
boolean_t
|
||||
@ -78,10 +78,10 @@ db_stop_at_pc(is_breakpoint)
|
||||
register db_addr_t pc;
|
||||
register db_breakpoint_t bkpt;
|
||||
|
||||
db_clear_single_step(DDB_REGS);
|
||||
db_clear_single_step();
|
||||
db_clear_breakpoints();
|
||||
db_clear_watchpoints();
|
||||
pc = PC_REGS(DDB_REGS);
|
||||
pc = PC_REGS();
|
||||
|
||||
#ifdef FIXUP_PC_AFTER_BREAK
|
||||
if (*is_breakpoint) {
|
||||
@ -90,7 +90,7 @@ db_stop_at_pc(is_breakpoint)
|
||||
* machine requires it.
|
||||
*/
|
||||
FIXUP_PC_AFTER_BREAK
|
||||
pc = PC_REGS(DDB_REGS);
|
||||
pc = PC_REGS();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -171,7 +171,7 @@ void
|
||||
db_restart_at_pc(watchpt)
|
||||
boolean_t watchpt;
|
||||
{
|
||||
register db_addr_t pc = PC_REGS(DDB_REGS);
|
||||
register db_addr_t pc = PC_REGS();
|
||||
|
||||
if ((db_run_mode == STEP_COUNT) ||
|
||||
(db_run_mode == STEP_RETURN) ||
|
||||
@ -205,28 +205,16 @@ db_restart_at_pc(watchpt)
|
||||
* Step over breakpoint/watchpoint.
|
||||
*/
|
||||
db_run_mode = STEP_INVISIBLE;
|
||||
db_set_single_step(DDB_REGS);
|
||||
db_set_single_step();
|
||||
} else {
|
||||
db_set_breakpoints();
|
||||
db_set_watchpoints();
|
||||
}
|
||||
} else {
|
||||
db_set_single_step(DDB_REGS);
|
||||
db_set_single_step();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef notused
|
||||
static void
|
||||
db_single_step(regs)
|
||||
db_regs_t *regs;
|
||||
{
|
||||
if (db_run_mode == STEP_CONTINUE) {
|
||||
db_run_mode = STEP_INVISIBLE;
|
||||
db_set_single_step(regs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SOFTWARE_SSTEP
|
||||
/*
|
||||
* Software implementation of single-stepping.
|
||||
@ -261,11 +249,10 @@ db_breakpoint_t db_not_taken_bkpt = 0;
|
||||
db_breakpoint_t db_taken_bkpt = 0;
|
||||
|
||||
void
|
||||
db_set_single_step(regs)
|
||||
register db_regs_t *regs;
|
||||
db_set_single_step(void)
|
||||
{
|
||||
db_addr_t pc = PC_REGS(regs), brpc;
|
||||
unsigned inst;
|
||||
db_addr_t pc = PC_REGS(), brpc;
|
||||
unsigned inst;
|
||||
|
||||
/*
|
||||
* User was stopped at pc, e.g. the instruction
|
||||
@ -273,28 +260,27 @@ db_set_single_step(regs)
|
||||
*/
|
||||
inst = db_get_value(pc, sizeof(int), FALSE);
|
||||
if (inst_branch(inst) || inst_call(inst)) {
|
||||
brpc = branch_taken(inst, pc, regs);
|
||||
if (brpc != pc) { /* self-branches are hopeless */
|
||||
db_taken_bkpt = db_set_temp_breakpoint(brpc);
|
||||
}
|
||||
pc = next_instr_address(pc,1);
|
||||
brpc = branch_taken(inst, pc);
|
||||
if (brpc != pc) { /* self-branches are hopeless */
|
||||
db_taken_bkpt = db_set_temp_breakpoint(brpc);
|
||||
}
|
||||
pc = next_instr_address(pc, 1);
|
||||
}
|
||||
pc = next_instr_address(pc,0);
|
||||
pc = next_instr_address(pc, 0);
|
||||
db_not_taken_bkpt = db_set_temp_breakpoint(pc);
|
||||
}
|
||||
|
||||
void
|
||||
db_clear_single_step(regs)
|
||||
db_regs_t *regs;
|
||||
db_clear_single_step(void)
|
||||
{
|
||||
|
||||
if (db_not_taken_bkpt != 0) {
|
||||
db_delete_temp_breakpoint(db_not_taken_bkpt);
|
||||
db_not_taken_bkpt = 0;
|
||||
db_delete_temp_breakpoint(db_not_taken_bkpt);
|
||||
db_not_taken_bkpt = 0;
|
||||
}
|
||||
if (db_taken_bkpt != 0) {
|
||||
db_delete_temp_breakpoint(db_taken_bkpt);
|
||||
db_taken_bkpt = 0;
|
||||
db_delete_temp_breakpoint(db_taken_bkpt);
|
||||
db_taken_bkpt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
105
sys/ddb/db_thread.c
Normal file
105
sys/ddb/db_thread.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2004 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_command.h>
|
||||
#include <ddb/db_sym.h>
|
||||
|
||||
void
|
||||
db_print_thread(void)
|
||||
{
|
||||
db_printf("[thread %ld]\n", (long)kdb_thread->td_tid);
|
||||
}
|
||||
|
||||
void
|
||||
db_set_thread(db_expr_t tid, boolean_t hastid, db_expr_t cnt, char *mod)
|
||||
{
|
||||
struct thread *thr;
|
||||
db_expr_t radix;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* We parse our own arguments. We don't like the default radix.
|
||||
*/
|
||||
radix = db_radix;
|
||||
db_radix = 10;
|
||||
hastid = db_expression(&tid);
|
||||
db_radix = radix;
|
||||
db_skip_to_eol();
|
||||
|
||||
if (hastid) {
|
||||
thr = kdb_thr_lookup(tid);
|
||||
if (thr != NULL) {
|
||||
err = kdb_thr_select(thr);
|
||||
if (err != 0) {
|
||||
db_printf("unable to switch to thread %ld\n",
|
||||
(long)thr->td_tid);
|
||||
return;
|
||||
}
|
||||
db_dot = PC_REGS();
|
||||
} else {
|
||||
db_printf("%d: invalid thread\n", (int)tid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
db_print_thread();
|
||||
db_print_loc_and_inst(PC_REGS());
|
||||
}
|
||||
|
||||
void
|
||||
db_show_threads(db_expr_t addr, boolean_t hasaddr, db_expr_t cnt, char *mod)
|
||||
{
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
struct thread *thr;
|
||||
int pager_quit;
|
||||
|
||||
db_setup_paging(db_simple_pager, &pager_quit, DB_LINES_PER_PAGE);
|
||||
|
||||
pager_quit = 0;
|
||||
thr = kdb_thr_first();
|
||||
while (!pager_quit && thr != NULL) {
|
||||
db_printf(" %6ld (%p) ", (long)thr->td_tid, thr);
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
if (setjmp(jb) == 0) {
|
||||
if (db_trace_thread(thr, 1) != 0)
|
||||
db_printf("***\n");
|
||||
}
|
||||
kdb_jmpbuf(prev_jb);
|
||||
thr = kdb_thr_next(thr);
|
||||
}
|
||||
}
|
@ -39,11 +39,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ddb/db_variables.h>
|
||||
|
||||
static int db_find_variable(struct db_variable **varp);
|
||||
static void db_write_variable(struct db_variable *, db_expr_t *);
|
||||
|
||||
#ifdef notused
|
||||
static int db_set_variable(db_expr_t value);
|
||||
#endif
|
||||
|
||||
static struct db_variable db_vars[] = {
|
||||
{ "radix", &db_radix, FCN_NULL },
|
||||
@ -51,123 +46,107 @@ static struct db_variable db_vars[] = {
|
||||
{ "maxwidth", &db_max_width, FCN_NULL },
|
||||
{ "tabstops", &db_tab_stop_width, FCN_NULL },
|
||||
};
|
||||
static struct db_variable *db_evars =
|
||||
db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
|
||||
static struct db_variable *db_evars =
|
||||
db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
|
||||
|
||||
static int
|
||||
db_find_variable(varp)
|
||||
struct db_variable **varp;
|
||||
db_find_variable(struct db_variable **varp)
|
||||
{
|
||||
int t;
|
||||
struct db_variable *vp;
|
||||
int t;
|
||||
|
||||
t = db_read_token();
|
||||
if (t == tIDENT) {
|
||||
for (vp = db_vars; vp < db_evars; vp++) {
|
||||
if (!strcmp(db_tok_string, vp->name)) {
|
||||
*varp = vp;
|
||||
return (1);
|
||||
for (vp = db_vars; vp < db_evars; vp++) {
|
||||
if (!strcmp(db_tok_string, vp->name)) {
|
||||
*varp = vp;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (vp = db_regs; vp < db_eregs; vp++) {
|
||||
if (!strcmp(db_tok_string, vp->name)) {
|
||||
*varp = vp;
|
||||
return (1);
|
||||
for (vp = db_regs; vp < db_eregs; vp++) {
|
||||
if (!strcmp(db_tok_string, vp->name)) {
|
||||
*varp = vp;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
db_error("Unknown variable\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
db_get_variable(valuep)
|
||||
db_expr_t *valuep;
|
||||
db_get_variable(db_expr_t *valuep)
|
||||
{
|
||||
struct db_variable *vp;
|
||||
|
||||
if (!db_find_variable(&vp))
|
||||
return (0);
|
||||
return (0);
|
||||
|
||||
db_read_variable(vp, valuep);
|
||||
|
||||
return (1);
|
||||
return (db_read_variable(vp, valuep));
|
||||
}
|
||||
|
||||
#ifdef notused
|
||||
static int
|
||||
db_set_variable(value)
|
||||
db_expr_t value;
|
||||
int
|
||||
db_set_variable(db_expr_t value)
|
||||
{
|
||||
struct db_variable *vp;
|
||||
|
||||
if (!db_find_variable(&vp))
|
||||
return (0);
|
||||
return (0);
|
||||
|
||||
db_write_variable(vp, &value);
|
||||
|
||||
return (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
db_read_variable(vp, valuep)
|
||||
struct db_variable *vp;
|
||||
db_expr_t *valuep;
|
||||
{
|
||||
db_varfcn_t *func = vp->fcn;
|
||||
|
||||
if (func == FCN_NULL)
|
||||
*valuep = *(vp->valuep);
|
||||
else
|
||||
(*func)(vp, valuep, DB_VAR_GET);
|
||||
return (db_write_variable(vp, value));
|
||||
}
|
||||
|
||||
static void
|
||||
db_write_variable(vp, valuep)
|
||||
struct db_variable *vp;
|
||||
db_expr_t *valuep;
|
||||
int
|
||||
db_read_variable(struct db_variable *vp, db_expr_t *valuep)
|
||||
{
|
||||
db_varfcn_t *func = vp->fcn;
|
||||
db_varfcn_t *func = vp->fcn;
|
||||
|
||||
if (func == FCN_NULL)
|
||||
*(vp->valuep) = *valuep;
|
||||
else
|
||||
(*func)(vp, valuep, DB_VAR_SET);
|
||||
if (func == FCN_NULL) {
|
||||
*valuep = *(vp->valuep);
|
||||
return (1);
|
||||
}
|
||||
return ((*func)(vp, valuep, DB_VAR_GET));
|
||||
}
|
||||
|
||||
int
|
||||
db_write_variable(struct db_variable *vp, db_expr_t value)
|
||||
{
|
||||
db_varfcn_t *func = vp->fcn;
|
||||
|
||||
if (func == FCN_NULL) {
|
||||
*(vp->valuep) = value;
|
||||
return (1);
|
||||
}
|
||||
return ((*func)(vp, &value, DB_VAR_SET));
|
||||
}
|
||||
|
||||
void
|
||||
db_set_cmd(dummy1, dummy2, dummy3, dummy4)
|
||||
db_expr_t dummy1;
|
||||
boolean_t dummy2;
|
||||
db_expr_t dummy3;
|
||||
char * dummy4;
|
||||
db_set_cmd(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4)
|
||||
{
|
||||
db_expr_t value;
|
||||
struct db_variable *vp;
|
||||
int t;
|
||||
db_expr_t value;
|
||||
int t;
|
||||
|
||||
t = db_read_token();
|
||||
if (t != tDOLLAR) {
|
||||
db_error("Unknown variable\n");
|
||||
return;
|
||||
db_error("Unknown variable\n");
|
||||
return;
|
||||
}
|
||||
if (!db_find_variable(&vp)) {
|
||||
db_error("Unknown variable\n");
|
||||
return;
|
||||
db_error("Unknown variable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
t = db_read_token();
|
||||
if (t != tEQ)
|
||||
db_unread_token(t);
|
||||
db_unread_token(t);
|
||||
|
||||
if (!db_expression(&value)) {
|
||||
db_error("No value\n");
|
||||
return;
|
||||
}
|
||||
if (db_read_token() != tEOL) {
|
||||
db_error("?\n");
|
||||
db_error("No value\n");
|
||||
return;
|
||||
}
|
||||
if (db_read_token() != tEOL)
|
||||
db_error("?\n");
|
||||
|
||||
db_write_variable(vp, &value);
|
||||
db_write_variable(vp, value);
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ struct db_variable {
|
||||
extern struct db_variable db_regs[]; /* machine registers */
|
||||
extern struct db_variable *db_eregs;
|
||||
|
||||
void db_read_variable(struct db_variable *, db_expr_t *);
|
||||
int db_read_variable(struct db_variable *, db_expr_t *);
|
||||
int db_write_variable(struct db_variable *, db_expr_t);
|
||||
|
||||
#endif /* _!DDB_DB_VARIABLES_H_ */
|
||||
|
@ -69,9 +69,7 @@ func_name(addr, have_addr, count, modif) \
|
||||
db_expr_t count; \
|
||||
char *modif;
|
||||
|
||||
extern char *esym;
|
||||
extern db_expr_t db_maxoff;
|
||||
extern int db_active;
|
||||
extern int db_indent;
|
||||
extern int db_inst_count;
|
||||
extern int db_load_count;
|
||||
@ -81,11 +79,9 @@ extern db_expr_t db_radix;
|
||||
extern db_expr_t db_max_width;
|
||||
extern db_expr_t db_tab_stop_width;
|
||||
|
||||
struct thread;
|
||||
struct vm_map;
|
||||
|
||||
#ifdef ALT_BREAK_TO_DEBUGGER
|
||||
int db_alt_break(int, int *);
|
||||
#endif
|
||||
void db_check_interrupt(void);
|
||||
void db_clear_watchpoints(void);
|
||||
db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt);
|
||||
@ -98,24 +94,23 @@ struct vm_map *db_map_addr(vm_offset_t);
|
||||
boolean_t db_map_current(struct vm_map *);
|
||||
boolean_t db_map_equal(struct vm_map *, struct vm_map *);
|
||||
void db_print_loc_and_inst(db_addr_t loc);
|
||||
void db_print_thread(void);
|
||||
void db_printf(const char *fmt, ...) __printflike(1, 2);
|
||||
void db_read_bytes(vm_offset_t addr, size_t size, char *data);
|
||||
int db_read_bytes(vm_offset_t addr, size_t size, char *data);
|
||||
/* machine-dependent */
|
||||
int db_readline(char *lstart, int lsize);
|
||||
void db_restart_at_pc(boolean_t watchpt);
|
||||
int db_set_variable(db_expr_t value);
|
||||
void db_set_watchpoints(void);
|
||||
void db_setup_paging(db_page_calloutfcn_t *callout, void *arg,
|
||||
int maxlines);
|
||||
void db_skip_to_eol(void);
|
||||
boolean_t db_stop_at_pc(boolean_t *is_breakpoint);
|
||||
#define db_strcpy strcpy
|
||||
void db_trap(int type, int code);
|
||||
void db_trace_self(void);
|
||||
int db_trace_thread(struct thread *, int);
|
||||
int db_value_of_name(const char *name, db_expr_t *valuep);
|
||||
void db_write_bytes(vm_offset_t addr, size_t size, char *data);
|
||||
/* machine-dependent */
|
||||
void db_stack_thread(db_expr_t addr, boolean_t have_addr,
|
||||
db_expr_t count, char *modif);
|
||||
void kdb_init(void);
|
||||
int db_write_bytes(vm_offset_t addr, size_t size, char *data);
|
||||
|
||||
db_cmdfcn_t db_breakpoint_cmd;
|
||||
db_cmdfcn_t db_continue_cmd;
|
||||
@ -129,27 +124,18 @@ db_cmdfcn_t db_print_cmd;
|
||||
db_cmdfcn_t db_ps;
|
||||
db_cmdfcn_t db_search_cmd;
|
||||
db_cmdfcn_t db_set_cmd;
|
||||
db_cmdfcn_t db_set_thread;
|
||||
db_cmdfcn_t db_show_regs;
|
||||
db_cmdfcn_t db_show_threads;
|
||||
db_cmdfcn_t db_single_step_cmd;
|
||||
db_cmdfcn_t db_stack_trace_cmd;
|
||||
db_cmdfcn_t db_trace_until_call_cmd;
|
||||
db_cmdfcn_t db_trace_until_matching_cmd;
|
||||
db_cmdfcn_t db_watchpoint_cmd;
|
||||
db_cmdfcn_t db_write_cmd;
|
||||
db_cmdfcn_t db_show_one_thread;
|
||||
|
||||
#if 0
|
||||
db_cmdfcn_t db_help_cmd;
|
||||
db_cmdfcn_t db_show_all_threads;
|
||||
db_cmdfcn_t ipc_port_print;
|
||||
db_cmdfcn_t vm_page_print;
|
||||
#endif
|
||||
|
||||
db_page_calloutfcn_t db_simple_pager;
|
||||
|
||||
/* Scare the user with backtrace of curthread to console. */
|
||||
void db_print_backtrace(void);
|
||||
|
||||
/*
|
||||
* Command table.
|
||||
*/
|
||||
@ -164,14 +150,4 @@ struct command {
|
||||
struct command *more; /* another level of command */
|
||||
};
|
||||
|
||||
/* XXX: UGLY hack */
|
||||
#ifdef CN_DEAD
|
||||
/*
|
||||
* Routines to support GDB on an sio port.
|
||||
*/
|
||||
extern void *gdb_arg;
|
||||
extern cn_getc_t *gdb_getc;
|
||||
extern cn_putc_t *gdb_putc;
|
||||
#endif
|
||||
|
||||
#endif /* !_DDB_DDB_H_ */
|
||||
|
@ -32,290 +32,107 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#ifdef SMP
|
||||
#include <machine/smptests.h> /** CPUSTOP_ON_DDBBREAK */
|
||||
#endif
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
static jmp_buf *db_nofault = 0;
|
||||
extern jmp_buf db_jmpbuf;
|
||||
|
||||
extern void gdb_handle_exception(db_regs_t *, int, int);
|
||||
|
||||
int db_active;
|
||||
db_regs_t ddb_regs;
|
||||
|
||||
static jmp_buf db_global_jmpbuf;
|
||||
|
||||
/*
|
||||
* kdb_trap - field a TRACE or BPT trap
|
||||
*/
|
||||
int
|
||||
kdb_trap(int type, int code, struct i386_saved_state *regs)
|
||||
{
|
||||
u_int ef;
|
||||
volatile int ddb_mode = !(boothowto & RB_GDB);
|
||||
|
||||
/*
|
||||
* XXX try to do nothing if the console is in graphics mode.
|
||||
* Handle trace traps (and hardware breakpoints...) by ignoring
|
||||
* them except for forgetting about them. Return 0 for other
|
||||
* traps to say that we haven't done anything. The trap handler
|
||||
* will usually panic. We should handle breakpoint traps for
|
||||
* our breakpoints by disarming our breakpoints and fixing up
|
||||
* %eip.
|
||||
*/
|
||||
if (cnunavailable() != 0 && ddb_mode) {
|
||||
if (type == T_TRCTRAP) {
|
||||
regs->tf_eflags &= ~PSL_T;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
ef = read_eflags();
|
||||
disable_intr();
|
||||
|
||||
#ifdef SMP
|
||||
#ifdef CPUSTOP_ON_DDBBREAK
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf("\nCPU%d stopping CPUs: 0x%08x...", PCPU_GET(cpuid),
|
||||
PCPU_GET(other_cpus));
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
/* We stop all CPUs except ourselves (obviously) */
|
||||
stop_cpus(PCPU_GET(other_cpus));
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf(" stopped.\n");
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
#endif /* CPUSTOP_ON_DDBBREAK */
|
||||
#endif /* SMP */
|
||||
|
||||
switch (type) {
|
||||
case T_BPTFLT: /* breakpoint */
|
||||
case T_TRCTRAP: /* debug exception */
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* XXX this is almost useless now. In most cases,
|
||||
* trap_fatal() has already printed a much more verbose
|
||||
* message. However, it is dangerous to print things in
|
||||
* trap_fatal() - printf() might be reentered and trap.
|
||||
* The debugger should be given control first.
|
||||
*/
|
||||
if (ddb_mode)
|
||||
db_printf("kernel: type %d trap, code=%x\n", type, code);
|
||||
|
||||
if (db_nofault) {
|
||||
jmp_buf *no_fault = db_nofault;
|
||||
db_nofault = 0;
|
||||
longjmp(*no_fault, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This handles unexpected traps in ddb commands, including calls to
|
||||
* non-ddb functions. db_nofault only applies to memory accesses by
|
||||
* internal ddb commands.
|
||||
*/
|
||||
if (db_active)
|
||||
longjmp(db_global_jmpbuf, 1);
|
||||
|
||||
/*
|
||||
* XXX We really should switch to a local stack here.
|
||||
*/
|
||||
ddb_regs = *regs;
|
||||
|
||||
/*
|
||||
* If in kernel mode, esp and ss are not saved, so dummy them up.
|
||||
*/
|
||||
if (ISPL(regs->tf_cs) == 0) {
|
||||
ddb_regs.tf_esp = (int)®s->tf_esp;
|
||||
ddb_regs.tf_ss = rss();
|
||||
}
|
||||
|
||||
(void) setjmp(db_global_jmpbuf);
|
||||
if (ddb_mode) {
|
||||
if (!db_active)
|
||||
cndbctl(TRUE);
|
||||
db_active = 1;
|
||||
db_trap(type, code);
|
||||
cndbctl(FALSE);
|
||||
} else {
|
||||
db_active = 1;
|
||||
gdb_handle_exception(&ddb_regs, type, code);
|
||||
}
|
||||
db_active = 0;
|
||||
|
||||
regs->tf_eip = ddb_regs.tf_eip;
|
||||
regs->tf_eflags = ddb_regs.tf_eflags;
|
||||
regs->tf_eax = ddb_regs.tf_eax;
|
||||
regs->tf_ecx = ddb_regs.tf_ecx;
|
||||
regs->tf_edx = ddb_regs.tf_edx;
|
||||
regs->tf_ebx = ddb_regs.tf_ebx;
|
||||
|
||||
/*
|
||||
* If in user mode, the saved ESP and SS were valid, restore them.
|
||||
*/
|
||||
if (ISPL(regs->tf_cs)) {
|
||||
regs->tf_esp = ddb_regs.tf_esp;
|
||||
regs->tf_ss = ddb_regs.tf_ss & 0xffff;
|
||||
}
|
||||
|
||||
regs->tf_ebp = ddb_regs.tf_ebp;
|
||||
regs->tf_esi = ddb_regs.tf_esi;
|
||||
regs->tf_edi = ddb_regs.tf_edi;
|
||||
regs->tf_es = ddb_regs.tf_es & 0xffff;
|
||||
regs->tf_fs = ddb_regs.tf_fs & 0xffff;
|
||||
regs->tf_cs = ddb_regs.tf_cs & 0xffff;
|
||||
regs->tf_ds = ddb_regs.tf_ds & 0xffff;
|
||||
|
||||
#ifdef SMP
|
||||
#ifdef CPUSTOP_ON_DDBBREAK
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf("\nCPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid),
|
||||
stopped_cpus);
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
/* Restart all the CPUs we previously stopped */
|
||||
if (stopped_cpus != PCPU_GET(other_cpus) && smp_started != 0) {
|
||||
db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
|
||||
PCPU_GET(other_cpus), stopped_cpus);
|
||||
panic("stop_cpus() failed");
|
||||
}
|
||||
restart_cpus(stopped_cpus);
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf(" restarted.\n");
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
#endif /* CPUSTOP_ON_DDBBREAK */
|
||||
#endif /* SMP */
|
||||
|
||||
write_eflags(ef);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read bytes from kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
int
|
||||
db_read_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
char *src;
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *src;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
|
||||
db_nofault = 0;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write bytes to kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
int
|
||||
db_write_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
char *dst;
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *dst;
|
||||
pt_entry_t *ptep0 = NULL;
|
||||
pt_entry_t oldmap0 = 0;
|
||||
vm_offset_t addr1;
|
||||
pt_entry_t *ptep1 = NULL;
|
||||
pt_entry_t oldmap1 = 0;
|
||||
int ret;
|
||||
|
||||
pt_entry_t *ptep0 = NULL;
|
||||
pt_entry_t oldmap0 = 0;
|
||||
vm_offset_t addr1;
|
||||
pt_entry_t *ptep1 = NULL;
|
||||
pt_entry_t oldmap1 = 0;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
if (addr > trunc_page((vm_offset_t)btext) - size &&
|
||||
addr < round_page((vm_offset_t)etext)) {
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
ptep0 = pmap_pte(kernel_pmap, addr);
|
||||
oldmap0 = *ptep0;
|
||||
*ptep0 |= PG_RW;
|
||||
|
||||
if (addr > trunc_page((vm_offset_t)btext) - size &&
|
||||
addr < round_page((vm_offset_t)etext)) {
|
||||
/*
|
||||
* Map another page if the data crosses a page
|
||||
* boundary.
|
||||
*/
|
||||
if ((*ptep0 & PG_PS) == 0) {
|
||||
addr1 = trunc_page(addr + size - 1);
|
||||
if (trunc_page(addr) != addr1) {
|
||||
ptep1 = pmap_pte(kernel_pmap, addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
}
|
||||
} else {
|
||||
addr1 = trunc_4mpage(addr + size - 1);
|
||||
if (trunc_4mpage(addr) != addr1) {
|
||||
ptep1 = pmap_pte(kernel_pmap, addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
}
|
||||
}
|
||||
|
||||
ptep0 = pmap_pte(kernel_pmap, addr);
|
||||
oldmap0 = *ptep0;
|
||||
*ptep0 |= PG_RW;
|
||||
|
||||
/* Map another page if the data crosses a page boundary. */
|
||||
if ((*ptep0 & PG_PS) == 0) {
|
||||
addr1 = trunc_page(addr + size - 1);
|
||||
if (trunc_page(addr) != addr1) {
|
||||
ptep1 = pmap_pte(kernel_pmap, addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
}
|
||||
} else {
|
||||
addr1 = trunc_4mpage(addr + size - 1);
|
||||
if (trunc_4mpage(addr) != addr1) {
|
||||
ptep1 = pmap_pte(kernel_pmap, addr1);
|
||||
oldmap1 = *ptep1;
|
||||
*ptep1 |= PG_RW;
|
||||
invltlb();
|
||||
}
|
||||
}
|
||||
|
||||
invltlb();
|
||||
dst = (char *)addr;
|
||||
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
}
|
||||
|
||||
dst = (char *)addr;
|
||||
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
|
||||
db_nofault = 0;
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
|
||||
if (ptep0) {
|
||||
*ptep0 = oldmap0;
|
||||
*ptep0 = oldmap0;
|
||||
|
||||
if (ptep1)
|
||||
*ptep1 = oldmap1;
|
||||
if (ptep1)
|
||||
*ptep1 = oldmap1;
|
||||
|
||||
invltlb();
|
||||
invltlb();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Move this to machdep.c and allow it to be called if any debugger is
|
||||
* installed.
|
||||
*/
|
||||
void
|
||||
Debugger(const char *msg)
|
||||
{
|
||||
static volatile u_int in_Debugger;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Do nothing if the console is in graphics mode. This is
|
||||
* OK if the call is for the debugger hotkey but not if the call
|
||||
* is a weak form of panicing.
|
||||
*/
|
||||
if (cnunavailable() != 0 && !(boothowto & RB_GDB))
|
||||
return;
|
||||
|
||||
if (atomic_cmpset_acq_int(&in_Debugger, 0, 1)) {
|
||||
db_printf("Debugger(\"%s\")\n", msg);
|
||||
breakpoint();
|
||||
atomic_store_rel_int(&in_Debugger, 0);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sysent.h>
|
||||
|
||||
@ -46,48 +47,123 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ddb/db_sym.h>
|
||||
#include <ddb/db_variables.h>
|
||||
|
||||
db_varfcn_t db_dr0;
|
||||
db_varfcn_t db_dr1;
|
||||
db_varfcn_t db_dr2;
|
||||
db_varfcn_t db_dr3;
|
||||
db_varfcn_t db_dr4;
|
||||
db_varfcn_t db_dr5;
|
||||
db_varfcn_t db_dr6;
|
||||
db_varfcn_t db_dr7;
|
||||
static db_varfcn_t db_dr0;
|
||||
static db_varfcn_t db_dr1;
|
||||
static db_varfcn_t db_dr2;
|
||||
static db_varfcn_t db_dr3;
|
||||
static db_varfcn_t db_dr4;
|
||||
static db_varfcn_t db_dr5;
|
||||
static db_varfcn_t db_dr6;
|
||||
static db_varfcn_t db_dr7;
|
||||
static db_varfcn_t db_esp;
|
||||
static db_varfcn_t db_frame;
|
||||
static db_varfcn_t db_ss;
|
||||
|
||||
/*
|
||||
* Machine register set.
|
||||
*/
|
||||
#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x)
|
||||
struct db_variable db_regs[] = {
|
||||
{ "cs", &ddb_regs.tf_cs, FCN_NULL },
|
||||
{ "ds", &ddb_regs.tf_ds, FCN_NULL },
|
||||
{ "es", &ddb_regs.tf_es, FCN_NULL },
|
||||
{ "fs", &ddb_regs.tf_fs, FCN_NULL },
|
||||
#if 0
|
||||
{ "gs", &ddb_regs.tf_gs, FCN_NULL },
|
||||
#endif
|
||||
{ "ss", &ddb_regs.tf_ss, FCN_NULL },
|
||||
{ "eax", &ddb_regs.tf_eax, FCN_NULL },
|
||||
{ "ecx", &ddb_regs.tf_ecx, FCN_NULL },
|
||||
{ "edx", &ddb_regs.tf_edx, FCN_NULL },
|
||||
{ "ebx", &ddb_regs.tf_ebx, FCN_NULL },
|
||||
{ "esp", &ddb_regs.tf_esp, FCN_NULL },
|
||||
{ "ebp", &ddb_regs.tf_ebp, FCN_NULL },
|
||||
{ "esi", &ddb_regs.tf_esi, FCN_NULL },
|
||||
{ "edi", &ddb_regs.tf_edi, FCN_NULL },
|
||||
{ "eip", &ddb_regs.tf_eip, FCN_NULL },
|
||||
{ "efl", &ddb_regs.tf_eflags, FCN_NULL },
|
||||
{ "dr0", NULL, db_dr0 },
|
||||
{ "dr1", NULL, db_dr1 },
|
||||
{ "dr2", NULL, db_dr2 },
|
||||
{ "dr3", NULL, db_dr3 },
|
||||
{ "dr4", NULL, db_dr4 },
|
||||
{ "dr5", NULL, db_dr5 },
|
||||
{ "dr6", NULL, db_dr6 },
|
||||
{ "dr7", NULL, db_dr7 },
|
||||
{ "cs", DB_OFFSET(tf_cs), db_frame },
|
||||
{ "ds", DB_OFFSET(tf_ds), db_frame },
|
||||
{ "es", DB_OFFSET(tf_es), db_frame },
|
||||
{ "fs", DB_OFFSET(tf_fs), db_frame },
|
||||
{ "ss", NULL, db_ss },
|
||||
{ "eax", DB_OFFSET(tf_eax), db_frame },
|
||||
{ "ecx", DB_OFFSET(tf_ecx), db_frame },
|
||||
{ "edx", DB_OFFSET(tf_edx), db_frame },
|
||||
{ "ebx", DB_OFFSET(tf_ebx), db_frame },
|
||||
{ "esp", NULL, db_esp },
|
||||
{ "ebp", DB_OFFSET(tf_ebp), db_frame },
|
||||
{ "esi", DB_OFFSET(tf_esi), db_frame },
|
||||
{ "edi", DB_OFFSET(tf_edi), db_frame },
|
||||
{ "eip", DB_OFFSET(tf_eip), db_frame },
|
||||
{ "efl", DB_OFFSET(tf_eflags), db_frame },
|
||||
{ "dr0", NULL, db_dr0 },
|
||||
{ "dr1", NULL, db_dr1 },
|
||||
{ "dr2", NULL, db_dr2 },
|
||||
{ "dr3", NULL, db_dr3 },
|
||||
{ "dr4", NULL, db_dr4 },
|
||||
{ "dr5", NULL, db_dr5 },
|
||||
{ "dr6", NULL, db_dr6 },
|
||||
{ "dr7", NULL, db_dr7 },
|
||||
};
|
||||
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
|
||||
|
||||
#define DB_DRX_FUNC(reg) \
|
||||
static int \
|
||||
db_ ## reg (vp, valuep, op) \
|
||||
struct db_variable *vp; \
|
||||
db_expr_t * valuep; \
|
||||
int op; \
|
||||
{ \
|
||||
if (op == DB_VAR_GET) \
|
||||
*valuep = r ## reg (); \
|
||||
else \
|
||||
load_ ## reg (*valuep); \
|
||||
return (1); \
|
||||
}
|
||||
|
||||
DB_DRX_FUNC(dr0)
|
||||
DB_DRX_FUNC(dr1)
|
||||
DB_DRX_FUNC(dr2)
|
||||
DB_DRX_FUNC(dr3)
|
||||
DB_DRX_FUNC(dr4)
|
||||
DB_DRX_FUNC(dr5)
|
||||
DB_DRX_FUNC(dr6)
|
||||
DB_DRX_FUNC(dr7)
|
||||
|
||||
static __inline int
|
||||
get_esp(struct trapframe *tf)
|
||||
{
|
||||
return ((ISPL(tf->tf_cs)) ? tf->tf_esp :
|
||||
(db_expr_t)tf + (uintptr_t)DB_OFFSET(tf_esp));
|
||||
}
|
||||
|
||||
static int
|
||||
db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
int *reg;
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = *reg;
|
||||
else
|
||||
*reg = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_esp(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = get_esp(kdb_frame);
|
||||
else if (ISPL(kdb_frame->tf_cs))
|
||||
kdb_frame->tf_esp = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_ss(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = (ISPL(kdb_frame->tf_cs)) ? kdb_frame->tf_ss : rss();
|
||||
else if (ISPL(kdb_frame->tf_cs))
|
||||
kdb_frame->tf_ss = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack trace.
|
||||
*/
|
||||
@ -104,13 +180,10 @@ struct i386_frame {
|
||||
#define INTERRUPT 2
|
||||
#define SYSCALL 3
|
||||
|
||||
static void db_nextframe(struct i386_frame **, db_addr_t *, struct proc *);
|
||||
static void db_nextframe(struct i386_frame **, db_addr_t *, struct thread *);
|
||||
static int db_numargs(struct i386_frame *);
|
||||
static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t);
|
||||
static void decode_syscall(int, struct proc *);
|
||||
static void db_trace_one_stack(int count, boolean_t have_addr,
|
||||
struct proc *p, struct i386_frame *frame, db_addr_t callpc);
|
||||
|
||||
static void decode_syscall(int, struct thread *);
|
||||
|
||||
static char * watchtype_str(int type);
|
||||
int i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
|
||||
@ -120,7 +193,6 @@ int db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
|
||||
int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
|
||||
void db_md_list_watchpoints(void);
|
||||
|
||||
|
||||
/*
|
||||
* Figure out how many arguments were passed into the frame at "fp".
|
||||
*/
|
||||
@ -175,16 +247,16 @@ db_print_stack_entry(name, narg, argnp, argp, callpc)
|
||||
}
|
||||
|
||||
static void
|
||||
decode_syscall(number, p)
|
||||
int number;
|
||||
struct proc *p;
|
||||
decode_syscall(int number, struct thread *td)
|
||||
{
|
||||
struct proc *p;
|
||||
c_db_sym_t sym;
|
||||
db_expr_t diff;
|
||||
sy_call_t *f;
|
||||
const char *symname;
|
||||
|
||||
db_printf(" (%d", number);
|
||||
p = (td != NULL) ? td->td_proc : NULL;
|
||||
if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
|
||||
f = p->p_sysent->sv_table[number].sy_call;
|
||||
sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
|
||||
@ -200,10 +272,7 @@ decode_syscall(number, p)
|
||||
* Figure out the next frame up in the call stack.
|
||||
*/
|
||||
static void
|
||||
db_nextframe(fp, ip, p)
|
||||
struct i386_frame **fp; /* in/out */
|
||||
db_addr_t *ip; /* out */
|
||||
struct proc *p; /* in */
|
||||
db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
int frame_type;
|
||||
@ -254,8 +323,7 @@ db_nextframe(fp, ip, p)
|
||||
tf = (struct trapframe *)((int)*fp + 8);
|
||||
|
||||
if (INKERNEL((int) tf)) {
|
||||
esp = (ISPL(tf->tf_cs) == SEL_UPL) ?
|
||||
tf->tf_esp : (int)&tf->tf_esp;
|
||||
esp = get_esp(tf);
|
||||
eip = tf->tf_eip;
|
||||
ebp = tf->tf_ebp;
|
||||
switch (frame_type) {
|
||||
@ -264,7 +332,7 @@ db_nextframe(fp, ip, p)
|
||||
break;
|
||||
case SYSCALL:
|
||||
db_printf("--- syscall");
|
||||
decode_syscall(tf->tf_eax, p);
|
||||
decode_syscall(tf->tf_eax, td);
|
||||
break;
|
||||
case INTERRUPT:
|
||||
db_printf("--- interrupt");
|
||||
@ -280,135 +348,26 @@ db_nextframe(fp, ip, p)
|
||||
*fp = (struct i386_frame *) ebp;
|
||||
}
|
||||
|
||||
void
|
||||
db_stack_trace_cmd(addr, have_addr, count, modif)
|
||||
db_expr_t addr;
|
||||
boolean_t have_addr;
|
||||
db_expr_t count;
|
||||
char *modif;
|
||||
static int
|
||||
db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame,
|
||||
db_addr_t pc, int count)
|
||||
{
|
||||
struct i386_frame *frame;
|
||||
struct proc *p;
|
||||
struct pcb *pcb;
|
||||
struct thread *td;
|
||||
db_addr_t callpc;
|
||||
pid_t pid;
|
||||
struct i386_frame *actframe;
|
||||
#define MAXNARG 16
|
||||
char *argnames[MAXNARG], **argnp = NULL;
|
||||
const char *name;
|
||||
int *argp;
|
||||
db_expr_t offset;
|
||||
c_db_sym_t sym;
|
||||
int narg;
|
||||
boolean_t first;
|
||||
|
||||
if (count == -1)
|
||||
count = 1024;
|
||||
|
||||
if (!have_addr) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
frame = (struct i386_frame *)ddb_regs.tf_ebp;
|
||||
if (frame == NULL)
|
||||
frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
|
||||
callpc = (db_addr_t)ddb_regs.tf_eip;
|
||||
} else if (!INKERNEL(addr)) {
|
||||
pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
|
||||
((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
|
||||
((addr >> 16) % 16) * 10000;
|
||||
/*
|
||||
* The pcb for curproc is not valid at this point,
|
||||
* so fall back to the default case.
|
||||
*/
|
||||
if (pid == curthread->td_proc->p_pid) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
frame = (struct i386_frame *)ddb_regs.tf_ebp;
|
||||
if (frame == NULL)
|
||||
frame = (struct i386_frame *)
|
||||
(ddb_regs.tf_esp - 4);
|
||||
callpc = (db_addr_t)ddb_regs.tf_eip;
|
||||
} else {
|
||||
|
||||
/* sx_slock(&allproc_lock); */
|
||||
LIST_FOREACH(p, &allproc, p_list) {
|
||||
if (p->p_pid == pid)
|
||||
break;
|
||||
}
|
||||
/* sx_sunlock(&allproc_lock); */
|
||||
if (p == NULL) {
|
||||
db_printf("pid %d not found\n", pid);
|
||||
return;
|
||||
}
|
||||
if ((p->p_sflag & PS_INMEM) == 0) {
|
||||
db_printf("pid %d swapped out\n", pid);
|
||||
return;
|
||||
}
|
||||
pcb = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */
|
||||
frame = (struct i386_frame *)pcb->pcb_ebp;
|
||||
if (frame == NULL)
|
||||
frame = (struct i386_frame *)
|
||||
(pcb->pcb_esp - 4);
|
||||
callpc = (db_addr_t)pcb->pcb_eip;
|
||||
}
|
||||
} else {
|
||||
p = NULL;
|
||||
frame = (struct i386_frame *)addr;
|
||||
callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
|
||||
frame = frame->f_frame;
|
||||
}
|
||||
db_trace_one_stack(count, have_addr, p, frame, callpc);
|
||||
}
|
||||
|
||||
void
|
||||
db_stack_thread(db_expr_t addr, boolean_t have_addr,
|
||||
db_expr_t count, char *modif)
|
||||
{
|
||||
struct i386_frame *frame;
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
struct pcb *pcb;
|
||||
db_addr_t callpc;
|
||||
|
||||
if (!have_addr)
|
||||
return;
|
||||
if (!INKERNEL(addr)) {
|
||||
printf("bad thread address");
|
||||
return;
|
||||
}
|
||||
td = (struct thread *)addr;
|
||||
/* quick sanity check */
|
||||
if ((p = td->td_proc) != td->td_ksegrp->kg_proc)
|
||||
return;
|
||||
if (TD_IS_SWAPPED(td)) {
|
||||
db_printf("thread at %p swapped out\n", td);
|
||||
return;
|
||||
}
|
||||
if (td == curthread) {
|
||||
frame = (struct i386_frame *)ddb_regs.tf_ebp;
|
||||
if (frame == NULL)
|
||||
frame = (struct i386_frame *)(ddb_regs.tf_esp - 4);
|
||||
callpc = (db_addr_t)ddb_regs.tf_eip;
|
||||
} else {
|
||||
pcb = td->td_pcb;
|
||||
frame = (struct i386_frame *)pcb->pcb_ebp;
|
||||
if (frame == NULL)
|
||||
frame = (struct i386_frame *) (pcb->pcb_esp - 4);
|
||||
callpc = (db_addr_t)pcb->pcb_eip;
|
||||
}
|
||||
db_trace_one_stack(count, have_addr, p, frame, callpc);
|
||||
}
|
||||
|
||||
static void
|
||||
db_trace_one_stack(int count, boolean_t have_addr,
|
||||
struct proc *p, struct i386_frame *frame, db_addr_t callpc)
|
||||
{
|
||||
int *argp;
|
||||
boolean_t first;
|
||||
|
||||
first = TRUE;
|
||||
while (count--) {
|
||||
struct i386_frame *actframe;
|
||||
int narg;
|
||||
const char * name;
|
||||
db_expr_t offset;
|
||||
c_db_sym_t sym;
|
||||
#define MAXNARG 16
|
||||
char *argnames[MAXNARG], **argnp = NULL;
|
||||
|
||||
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
||||
db_symbol_values(sym, &name, NULL);
|
||||
|
||||
/*
|
||||
@ -424,37 +383,33 @@ db_trace_one_stack(int count, boolean_t have_addr,
|
||||
*/
|
||||
actframe = frame;
|
||||
if (first) {
|
||||
if (!have_addr) {
|
||||
if (tf != NULL) {
|
||||
int instr;
|
||||
|
||||
instr = db_get_value(callpc, 4, FALSE);
|
||||
if ((instr & 0x00ffffff) == 0x00e58955) {
|
||||
instr = db_get_value(pc, 4, FALSE);
|
||||
if ((instr & 0xffffff) == 0x00e58955) {
|
||||
/* pushl %ebp; movl %esp, %ebp */
|
||||
actframe = (struct i386_frame *)
|
||||
(ddb_regs.tf_esp - 4);
|
||||
} else if ((instr & 0x0000ffff) == 0x0000e589) {
|
||||
actframe = (void *)(get_esp(tf) - 4);
|
||||
} else if ((instr & 0xffff) == 0x0000e589) {
|
||||
/* movl %esp, %ebp */
|
||||
actframe = (struct i386_frame *)
|
||||
ddb_regs.tf_esp;
|
||||
if (ddb_regs.tf_ebp == 0) {
|
||||
/* Fake caller's frame better. */
|
||||
actframe = (void *)get_esp(tf);
|
||||
if (tf->tf_ebp == 0) {
|
||||
/* Fake frame better. */
|
||||
frame = actframe;
|
||||
}
|
||||
} else if ((instr & 0x000000ff) == 0x000000c3) {
|
||||
} else if ((instr & 0xff) == 0x000000c3) {
|
||||
/* ret */
|
||||
actframe = (struct i386_frame *)
|
||||
(ddb_regs.tf_esp - 4);
|
||||
actframe = (void *)(get_esp(tf) - 4);
|
||||
} else if (offset == 0) {
|
||||
/* Probably a symbol in assembler code. */
|
||||
actframe = (struct i386_frame *)
|
||||
(ddb_regs.tf_esp - 4);
|
||||
/* Probably an assembler symbol. */
|
||||
actframe = (void *)(get_esp(tf) - 4);
|
||||
}
|
||||
} else if (strcmp(name, "fork_trampoline") == 0) {
|
||||
/*
|
||||
* Don't try to walk back on a stack for a
|
||||
* process that hasn't actually been run yet.
|
||||
*/
|
||||
db_print_stack_entry(name, 0, 0, 0, callpc);
|
||||
db_print_stack_entry(name, 0, 0, 0, pc);
|
||||
break;
|
||||
}
|
||||
first = FALSE;
|
||||
@ -468,60 +423,68 @@ db_trace_one_stack(int count, boolean_t have_addr,
|
||||
narg = db_numargs(frame);
|
||||
}
|
||||
|
||||
db_print_stack_entry(name, narg, argnp, argp, callpc);
|
||||
db_print_stack_entry(name, narg, argnp, argp, pc);
|
||||
|
||||
if (actframe != frame) {
|
||||
/* `frame' belongs to caller. */
|
||||
callpc = (db_addr_t)
|
||||
pc = (db_addr_t)
|
||||
db_get_value((int)&actframe->f_retaddr, 4, FALSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
db_nextframe(&frame, &callpc, p);
|
||||
db_nextframe(&frame, &pc, td);
|
||||
|
||||
if (INKERNEL((int) callpc) && !INKERNEL((int) frame)) {
|
||||
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
|
||||
if (INKERNEL((int)pc) && !INKERNEL((int) frame)) {
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
||||
db_symbol_values(sym, &name, NULL);
|
||||
db_print_stack_entry(name, 0, 0, 0, callpc);
|
||||
db_print_stack_entry(name, 0, 0, 0, pc);
|
||||
break;
|
||||
}
|
||||
if (!INKERNEL((int) frame)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
db_print_backtrace(void)
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread;
|
||||
if (td == NULL) {
|
||||
db_printf("Thread %d not found\n", addr);
|
||||
return;
|
||||
}
|
||||
db_trace_thread(td, count);
|
||||
}
|
||||
|
||||
void
|
||||
db_trace_self(void)
|
||||
{
|
||||
struct i386_frame *frame;
|
||||
db_addr_t callpc;
|
||||
register_t ebp;
|
||||
|
||||
__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
|
||||
db_stack_trace_cmd(ebp, 1, -1, NULL);
|
||||
frame = (struct i386_frame *)ebp;
|
||||
callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
|
||||
frame = frame->f_frame;
|
||||
db_backtrace(curthread, NULL, frame, callpc, -1);
|
||||
}
|
||||
|
||||
#define DB_DRX_FUNC(reg) \
|
||||
int \
|
||||
db_ ## reg (vp, valuep, op) \
|
||||
struct db_variable *vp; \
|
||||
db_expr_t * valuep; \
|
||||
int op; \
|
||||
{ \
|
||||
if (op == DB_VAR_GET) \
|
||||
*valuep = r ## reg (); \
|
||||
else \
|
||||
load_ ## reg (*valuep); \
|
||||
return (0); \
|
||||
}
|
||||
int
|
||||
db_trace_thread(struct thread *thr, int count)
|
||||
{
|
||||
struct pcb *ctx;
|
||||
|
||||
DB_DRX_FUNC(dr0)
|
||||
DB_DRX_FUNC(dr1)
|
||||
DB_DRX_FUNC(dr2)
|
||||
DB_DRX_FUNC(dr3)
|
||||
DB_DRX_FUNC(dr4)
|
||||
DB_DRX_FUNC(dr5)
|
||||
DB_DRX_FUNC(dr6)
|
||||
DB_DRX_FUNC(dr7)
|
||||
ctx = kdb_thr_ctx(thr);
|
||||
return (db_backtrace(thr, NULL, (struct i386_frame *)ctx->pcb_ebp,
|
||||
ctx->pcb_eip, count));
|
||||
}
|
||||
|
||||
int
|
||||
i386_set_watch(watchnum, watchaddr, size, access, d)
|
||||
|
@ -30,30 +30,23 @@
|
||||
#define _MACHINE_DB_MACHDEP_H_
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
#define i386_saved_state trapframe
|
||||
|
||||
typedef vm_offset_t db_addr_t; /* address - unsigned */
|
||||
typedef int db_expr_t; /* expression - signed */
|
||||
|
||||
typedef struct i386_saved_state db_regs_t;
|
||||
extern db_regs_t ddb_regs; /* register state */
|
||||
#define DDB_REGS (&ddb_regs)
|
||||
|
||||
#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip)
|
||||
#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_eip)
|
||||
|
||||
#define BKPT_INST 0xcc /* breakpoint instruction */
|
||||
#define BKPT_SIZE (1) /* size of breakpoint inst */
|
||||
#define BKPT_SET(inst) (BKPT_INST)
|
||||
|
||||
#define BKPT_SKIP ddb_regs.tf_eip += 1
|
||||
#define BKPT_SKIP kdb_frame->tf_eip += 1
|
||||
|
||||
#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1;
|
||||
#define FIXUP_PC_AFTER_BREAK kdb_frame->tf_eip -= 1;
|
||||
|
||||
#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~PSL_T)
|
||||
#define db_set_single_step(regs) ((regs)->tf_eflags |= PSL_T)
|
||||
#define db_clear_single_step kdb_cpu_clear_singlestep
|
||||
#define db_set_single_step kdb_cpu_set_singlestep
|
||||
|
||||
#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT)
|
||||
/*
|
||||
|
@ -1,5 +1,3 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*
|
||||
* Mach Operating System
|
||||
* Copyright (c) 1992,1991,1990 Carnegie Mellon University
|
||||
@ -28,29 +26,26 @@
|
||||
* db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parts of this file are derived from Mach 3:
|
||||
*
|
||||
* File: alpha_instruction.c
|
||||
* Author: Alessandro Forin, Carnegie Mellon University
|
||||
* Date: 6/92
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Interface to DDB.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/smp.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/ktr.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
#include <machine/db_machdep.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/mutex.h>
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
@ -61,433 +56,319 @@
|
||||
|
||||
#include <ia64/disasm/disasm.h>
|
||||
|
||||
static jmp_buf *db_nofault = 0;
|
||||
extern jmp_buf db_jmpbuf;
|
||||
#define TMPL_BITS 5
|
||||
#define TMPL_MASK ((1 << TMPL_BITS) - 1)
|
||||
#define SLOT_BITS 41
|
||||
#define SLOT_COUNT 3
|
||||
#define SLOT_MASK ((1ULL << SLOT_BITS) - 1ULL)
|
||||
#define SLOT_SHIFT(i) (TMPL_BITS+((i)<<3)+(i))
|
||||
|
||||
extern void gdb_handle_exception(db_regs_t *, int);
|
||||
|
||||
int db_active;
|
||||
db_regs_t ddb_regs;
|
||||
|
||||
static int db_get_rse_reg(struct db_variable *vp, db_expr_t *valuep, int op);
|
||||
static int db_get_ip_reg(struct db_variable *vp, db_expr_t *valuep, int op);
|
||||
static db_varfcn_t db_frame;
|
||||
static db_varfcn_t db_getrse;
|
||||
static db_varfcn_t db_getip;
|
||||
|
||||
#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x)
|
||||
struct db_variable db_regs[] = {
|
||||
/* Misc control/app registers */
|
||||
#define DB_MISC_REGS 13 /* make sure this is correct */
|
||||
|
||||
{"ip", NULL, db_get_ip_reg},
|
||||
{"psr", (db_expr_t*) &ddb_regs.tf_special.psr, FCN_NULL},
|
||||
{"cr.isr", (db_expr_t*) &ddb_regs.tf_special.isr, FCN_NULL},
|
||||
{"cr.ifa", (db_expr_t*) &ddb_regs.tf_special.ifa, FCN_NULL},
|
||||
{"pr", (db_expr_t*) &ddb_regs.tf_special.pr, FCN_NULL},
|
||||
{"ar.rsc", (db_expr_t*) &ddb_regs.tf_special.rsc, FCN_NULL},
|
||||
{"ar.pfs", (db_expr_t*) &ddb_regs.tf_special.pfs, FCN_NULL},
|
||||
{"cr.ifs", (db_expr_t*) &ddb_regs.tf_special.cfm, FCN_NULL},
|
||||
{"ar.bspstore", (db_expr_t*) &ddb_regs.tf_special.bspstore, FCN_NULL},
|
||||
{"ndirty", (db_expr_t*) &ddb_regs.tf_special.ndirty, FCN_NULL},
|
||||
{"ar.rnat", (db_expr_t*) &ddb_regs.tf_special.rnat, FCN_NULL},
|
||||
{"ar.unat", (db_expr_t*) &ddb_regs.tf_special.unat, FCN_NULL},
|
||||
{"ar.fpsr", (db_expr_t*) &ddb_regs.tf_special.fpsr, FCN_NULL},
|
||||
|
||||
/* Branch registers */
|
||||
{"rp", (db_expr_t*) &ddb_regs.tf_special.rp, FCN_NULL},
|
||||
/* b1, b2, b3, b4, b5 are preserved */
|
||||
{"b6", (db_expr_t*) &ddb_regs.tf_scratch.br6, FCN_NULL},
|
||||
{"b7", (db_expr_t*) &ddb_regs.tf_scratch.br7, FCN_NULL},
|
||||
|
||||
/* Static registers */
|
||||
{"gp", (db_expr_t*) &ddb_regs.tf_special.gp, FCN_NULL},
|
||||
{"r2", (db_expr_t*) &ddb_regs.tf_scratch.gr2, FCN_NULL},
|
||||
{"r3", (db_expr_t*) &ddb_regs.tf_scratch.gr3, FCN_NULL},
|
||||
{"r8", (db_expr_t*) &ddb_regs.tf_scratch.gr8, FCN_NULL},
|
||||
{"r9", (db_expr_t*) &ddb_regs.tf_scratch.gr9, FCN_NULL},
|
||||
{"r10", (db_expr_t*) &ddb_regs.tf_scratch.gr10, FCN_NULL},
|
||||
{"r11", (db_expr_t*) &ddb_regs.tf_scratch.gr11, FCN_NULL},
|
||||
{"sp", (db_expr_t*) &ddb_regs.tf_special.sp, FCN_NULL},
|
||||
{"tp", (db_expr_t*) &ddb_regs.tf_special.tp, FCN_NULL},
|
||||
{"r14", (db_expr_t*) &ddb_regs.tf_scratch.gr14, FCN_NULL},
|
||||
{"r15", (db_expr_t*) &ddb_regs.tf_scratch.gr15, FCN_NULL},
|
||||
{"r16", (db_expr_t*) &ddb_regs.tf_scratch.gr16, FCN_NULL},
|
||||
{"r17", (db_expr_t*) &ddb_regs.tf_scratch.gr17, FCN_NULL},
|
||||
{"r18", (db_expr_t*) &ddb_regs.tf_scratch.gr18, FCN_NULL},
|
||||
{"r19", (db_expr_t*) &ddb_regs.tf_scratch.gr19, FCN_NULL},
|
||||
{"r20", (db_expr_t*) &ddb_regs.tf_scratch.gr20, FCN_NULL},
|
||||
{"r21", (db_expr_t*) &ddb_regs.tf_scratch.gr21, FCN_NULL},
|
||||
{"r22", (db_expr_t*) &ddb_regs.tf_scratch.gr22, FCN_NULL},
|
||||
{"r23", (db_expr_t*) &ddb_regs.tf_scratch.gr23, FCN_NULL},
|
||||
{"r24", (db_expr_t*) &ddb_regs.tf_scratch.gr24, FCN_NULL},
|
||||
{"r25", (db_expr_t*) &ddb_regs.tf_scratch.gr25, FCN_NULL},
|
||||
{"r26", (db_expr_t*) &ddb_regs.tf_scratch.gr26, FCN_NULL},
|
||||
{"r27", (db_expr_t*) &ddb_regs.tf_scratch.gr27, FCN_NULL},
|
||||
{"r28", (db_expr_t*) &ddb_regs.tf_scratch.gr28, FCN_NULL},
|
||||
{"r29", (db_expr_t*) &ddb_regs.tf_scratch.gr29, FCN_NULL},
|
||||
{"r30", (db_expr_t*) &ddb_regs.tf_scratch.gr30, FCN_NULL},
|
||||
{"r31", (db_expr_t*) &ddb_regs.tf_scratch.gr31, FCN_NULL},
|
||||
|
||||
/* Stacked registers */
|
||||
{"r32", (db_expr_t*) 32, db_get_rse_reg},
|
||||
{"r33", (db_expr_t*) 33, db_get_rse_reg},
|
||||
{"r34", (db_expr_t*) 34, db_get_rse_reg},
|
||||
{"r35", (db_expr_t*) 35, db_get_rse_reg},
|
||||
{"r36", (db_expr_t*) 36, db_get_rse_reg},
|
||||
{"r37", (db_expr_t*) 37, db_get_rse_reg},
|
||||
{"r38", (db_expr_t*) 38, db_get_rse_reg},
|
||||
{"r39", (db_expr_t*) 39, db_get_rse_reg},
|
||||
{"r40", (db_expr_t*) 40, db_get_rse_reg},
|
||||
{"r41", (db_expr_t*) 41, db_get_rse_reg},
|
||||
{"r42", (db_expr_t*) 42, db_get_rse_reg},
|
||||
{"r43", (db_expr_t*) 43, db_get_rse_reg},
|
||||
{"r44", (db_expr_t*) 44, db_get_rse_reg},
|
||||
{"r45", (db_expr_t*) 45, db_get_rse_reg},
|
||||
{"r46", (db_expr_t*) 46, db_get_rse_reg},
|
||||
{"r47", (db_expr_t*) 47, db_get_rse_reg},
|
||||
{"r48", (db_expr_t*) 48, db_get_rse_reg},
|
||||
{"r49", (db_expr_t*) 49, db_get_rse_reg},
|
||||
{"r50", (db_expr_t*) 50, db_get_rse_reg},
|
||||
{"r51", (db_expr_t*) 51, db_get_rse_reg},
|
||||
{"r52", (db_expr_t*) 52, db_get_rse_reg},
|
||||
{"r53", (db_expr_t*) 53, db_get_rse_reg},
|
||||
{"r54", (db_expr_t*) 54, db_get_rse_reg},
|
||||
{"r55", (db_expr_t*) 55, db_get_rse_reg},
|
||||
{"r56", (db_expr_t*) 56, db_get_rse_reg},
|
||||
{"r57", (db_expr_t*) 57, db_get_rse_reg},
|
||||
{"r58", (db_expr_t*) 58, db_get_rse_reg},
|
||||
{"r59", (db_expr_t*) 59, db_get_rse_reg},
|
||||
{"r60", (db_expr_t*) 60, db_get_rse_reg},
|
||||
{"r61", (db_expr_t*) 61, db_get_rse_reg},
|
||||
{"r62", (db_expr_t*) 62, db_get_rse_reg},
|
||||
{"r63", (db_expr_t*) 63, db_get_rse_reg},
|
||||
{"r64", (db_expr_t*) 64, db_get_rse_reg},
|
||||
{"r65", (db_expr_t*) 65, db_get_rse_reg},
|
||||
{"r66", (db_expr_t*) 66, db_get_rse_reg},
|
||||
{"r67", (db_expr_t*) 67, db_get_rse_reg},
|
||||
{"r68", (db_expr_t*) 68, db_get_rse_reg},
|
||||
{"r69", (db_expr_t*) 69, db_get_rse_reg},
|
||||
{"r70", (db_expr_t*) 70, db_get_rse_reg},
|
||||
{"r71", (db_expr_t*) 71, db_get_rse_reg},
|
||||
{"r72", (db_expr_t*) 72, db_get_rse_reg},
|
||||
{"r73", (db_expr_t*) 73, db_get_rse_reg},
|
||||
{"r74", (db_expr_t*) 74, db_get_rse_reg},
|
||||
{"r75", (db_expr_t*) 75, db_get_rse_reg},
|
||||
{"r76", (db_expr_t*) 76, db_get_rse_reg},
|
||||
{"r77", (db_expr_t*) 77, db_get_rse_reg},
|
||||
{"r78", (db_expr_t*) 78, db_get_rse_reg},
|
||||
{"r79", (db_expr_t*) 79, db_get_rse_reg},
|
||||
{"r80", (db_expr_t*) 80, db_get_rse_reg},
|
||||
{"r81", (db_expr_t*) 81, db_get_rse_reg},
|
||||
{"r82", (db_expr_t*) 82, db_get_rse_reg},
|
||||
{"r83", (db_expr_t*) 83, db_get_rse_reg},
|
||||
{"r84", (db_expr_t*) 84, db_get_rse_reg},
|
||||
{"r85", (db_expr_t*) 85, db_get_rse_reg},
|
||||
{"r86", (db_expr_t*) 86, db_get_rse_reg},
|
||||
{"r87", (db_expr_t*) 87, db_get_rse_reg},
|
||||
{"r88", (db_expr_t*) 88, db_get_rse_reg},
|
||||
{"r89", (db_expr_t*) 89, db_get_rse_reg},
|
||||
{"r90", (db_expr_t*) 90, db_get_rse_reg},
|
||||
{"r91", (db_expr_t*) 91, db_get_rse_reg},
|
||||
{"r92", (db_expr_t*) 92, db_get_rse_reg},
|
||||
{"r93", (db_expr_t*) 93, db_get_rse_reg},
|
||||
{"r94", (db_expr_t*) 94, db_get_rse_reg},
|
||||
{"r95", (db_expr_t*) 95, db_get_rse_reg},
|
||||
{"r96", (db_expr_t*) 96, db_get_rse_reg},
|
||||
{"r97", (db_expr_t*) 97, db_get_rse_reg},
|
||||
{"r98", (db_expr_t*) 98, db_get_rse_reg},
|
||||
{"r99", (db_expr_t*) 99, db_get_rse_reg},
|
||||
{"r100", (db_expr_t*) 100, db_get_rse_reg},
|
||||
{"r101", (db_expr_t*) 101, db_get_rse_reg},
|
||||
{"r102", (db_expr_t*) 102, db_get_rse_reg},
|
||||
{"r103", (db_expr_t*) 103, db_get_rse_reg},
|
||||
{"r104", (db_expr_t*) 104, db_get_rse_reg},
|
||||
{"r105", (db_expr_t*) 105, db_get_rse_reg},
|
||||
{"r106", (db_expr_t*) 106, db_get_rse_reg},
|
||||
{"r107", (db_expr_t*) 107, db_get_rse_reg},
|
||||
{"r108", (db_expr_t*) 108, db_get_rse_reg},
|
||||
{"r109", (db_expr_t*) 109, db_get_rse_reg},
|
||||
{"r110", (db_expr_t*) 110, db_get_rse_reg},
|
||||
{"r111", (db_expr_t*) 111, db_get_rse_reg},
|
||||
{"r112", (db_expr_t*) 112, db_get_rse_reg},
|
||||
{"r113", (db_expr_t*) 113, db_get_rse_reg},
|
||||
{"r114", (db_expr_t*) 114, db_get_rse_reg},
|
||||
{"r115", (db_expr_t*) 115, db_get_rse_reg},
|
||||
{"r116", (db_expr_t*) 116, db_get_rse_reg},
|
||||
{"r117", (db_expr_t*) 117, db_get_rse_reg},
|
||||
{"r118", (db_expr_t*) 118, db_get_rse_reg},
|
||||
{"r119", (db_expr_t*) 119, db_get_rse_reg},
|
||||
{"r120", (db_expr_t*) 120, db_get_rse_reg},
|
||||
{"r121", (db_expr_t*) 121, db_get_rse_reg},
|
||||
{"r122", (db_expr_t*) 122, db_get_rse_reg},
|
||||
{"r123", (db_expr_t*) 123, db_get_rse_reg},
|
||||
{"r124", (db_expr_t*) 124, db_get_rse_reg},
|
||||
{"r125", (db_expr_t*) 125, db_get_rse_reg},
|
||||
{"r126", (db_expr_t*) 126, db_get_rse_reg},
|
||||
{"r127", (db_expr_t*) 127, db_get_rse_reg},
|
||||
{"ip", NULL, db_getip},
|
||||
{"cr.ifs", DB_OFFSET(tf_special.cfm), db_frame},
|
||||
{"cr.ifa", DB_OFFSET(tf_special.ifa), db_frame},
|
||||
{"ar.bspstore", DB_OFFSET(tf_special.bspstore), db_frame},
|
||||
{"ndirty", DB_OFFSET(tf_special.ndirty), db_frame},
|
||||
{"rp", DB_OFFSET(tf_special.rp), db_frame},
|
||||
{"ar.pfs", DB_OFFSET(tf_special.pfs), db_frame},
|
||||
{"psr", DB_OFFSET(tf_special.psr), db_frame},
|
||||
{"cr.isr", DB_OFFSET(tf_special.isr), db_frame},
|
||||
{"pr", DB_OFFSET(tf_special.pr), db_frame},
|
||||
{"ar.rsc", DB_OFFSET(tf_special.rsc), db_frame},
|
||||
{"ar.rnat", DB_OFFSET(tf_special.rnat), db_frame},
|
||||
{"ar.unat", DB_OFFSET(tf_special.unat), db_frame},
|
||||
{"ar.fpsr", DB_OFFSET(tf_special.fpsr), db_frame},
|
||||
{"gp", DB_OFFSET(tf_special.gp), db_frame},
|
||||
{"sp", DB_OFFSET(tf_special.sp), db_frame},
|
||||
{"tp", DB_OFFSET(tf_special.tp), db_frame},
|
||||
{"b6", DB_OFFSET(tf_scratch.br6), db_frame},
|
||||
{"b7", DB_OFFSET(tf_scratch.br7), db_frame},
|
||||
{"r2", DB_OFFSET(tf_scratch.gr2), db_frame},
|
||||
{"r3", DB_OFFSET(tf_scratch.gr3), db_frame},
|
||||
{"r8", DB_OFFSET(tf_scratch.gr8), db_frame},
|
||||
{"r9", DB_OFFSET(tf_scratch.gr9), db_frame},
|
||||
{"r10", DB_OFFSET(tf_scratch.gr10), db_frame},
|
||||
{"r11", DB_OFFSET(tf_scratch.gr11), db_frame},
|
||||
{"r14", DB_OFFSET(tf_scratch.gr14), db_frame},
|
||||
{"r15", DB_OFFSET(tf_scratch.gr15), db_frame},
|
||||
{"r16", DB_OFFSET(tf_scratch.gr16), db_frame},
|
||||
{"r17", DB_OFFSET(tf_scratch.gr17), db_frame},
|
||||
{"r18", DB_OFFSET(tf_scratch.gr18), db_frame},
|
||||
{"r19", DB_OFFSET(tf_scratch.gr19), db_frame},
|
||||
{"r20", DB_OFFSET(tf_scratch.gr20), db_frame},
|
||||
{"r21", DB_OFFSET(tf_scratch.gr21), db_frame},
|
||||
{"r22", DB_OFFSET(tf_scratch.gr22), db_frame},
|
||||
{"r23", DB_OFFSET(tf_scratch.gr23), db_frame},
|
||||
{"r24", DB_OFFSET(tf_scratch.gr24), db_frame},
|
||||
{"r25", DB_OFFSET(tf_scratch.gr25), db_frame},
|
||||
{"r26", DB_OFFSET(tf_scratch.gr26), db_frame},
|
||||
{"r27", DB_OFFSET(tf_scratch.gr27), db_frame},
|
||||
{"r28", DB_OFFSET(tf_scratch.gr28), db_frame},
|
||||
{"r29", DB_OFFSET(tf_scratch.gr29), db_frame},
|
||||
{"r30", DB_OFFSET(tf_scratch.gr30), db_frame},
|
||||
{"r31", DB_OFFSET(tf_scratch.gr31), db_frame},
|
||||
{"r32", (db_expr_t*)0, db_getrse},
|
||||
{"r33", (db_expr_t*)1, db_getrse},
|
||||
{"r34", (db_expr_t*)2, db_getrse},
|
||||
{"r35", (db_expr_t*)3, db_getrse},
|
||||
{"r36", (db_expr_t*)4, db_getrse},
|
||||
{"r37", (db_expr_t*)5, db_getrse},
|
||||
{"r38", (db_expr_t*)6, db_getrse},
|
||||
{"r39", (db_expr_t*)7, db_getrse},
|
||||
{"r40", (db_expr_t*)8, db_getrse},
|
||||
{"r41", (db_expr_t*)9, db_getrse},
|
||||
{"r42", (db_expr_t*)10, db_getrse},
|
||||
{"r43", (db_expr_t*)11, db_getrse},
|
||||
{"r44", (db_expr_t*)12, db_getrse},
|
||||
{"r45", (db_expr_t*)13, db_getrse},
|
||||
{"r46", (db_expr_t*)14, db_getrse},
|
||||
{"r47", (db_expr_t*)15, db_getrse},
|
||||
{"r48", (db_expr_t*)16, db_getrse},
|
||||
{"r49", (db_expr_t*)17, db_getrse},
|
||||
{"r50", (db_expr_t*)18, db_getrse},
|
||||
{"r51", (db_expr_t*)19, db_getrse},
|
||||
{"r52", (db_expr_t*)20, db_getrse},
|
||||
{"r53", (db_expr_t*)21, db_getrse},
|
||||
{"r54", (db_expr_t*)22, db_getrse},
|
||||
{"r55", (db_expr_t*)23, db_getrse},
|
||||
{"r56", (db_expr_t*)24, db_getrse},
|
||||
{"r57", (db_expr_t*)25, db_getrse},
|
||||
{"r58", (db_expr_t*)26, db_getrse},
|
||||
{"r59", (db_expr_t*)27, db_getrse},
|
||||
{"r60", (db_expr_t*)28, db_getrse},
|
||||
{"r61", (db_expr_t*)29, db_getrse},
|
||||
{"r62", (db_expr_t*)30, db_getrse},
|
||||
{"r63", (db_expr_t*)31, db_getrse},
|
||||
{"r64", (db_expr_t*)32, db_getrse},
|
||||
{"r65", (db_expr_t*)33, db_getrse},
|
||||
{"r66", (db_expr_t*)34, db_getrse},
|
||||
{"r67", (db_expr_t*)35, db_getrse},
|
||||
{"r68", (db_expr_t*)36, db_getrse},
|
||||
{"r69", (db_expr_t*)37, db_getrse},
|
||||
{"r70", (db_expr_t*)38, db_getrse},
|
||||
{"r71", (db_expr_t*)39, db_getrse},
|
||||
{"r72", (db_expr_t*)40, db_getrse},
|
||||
{"r73", (db_expr_t*)41, db_getrse},
|
||||
{"r74", (db_expr_t*)42, db_getrse},
|
||||
{"r75", (db_expr_t*)43, db_getrse},
|
||||
{"r76", (db_expr_t*)44, db_getrse},
|
||||
{"r77", (db_expr_t*)45, db_getrse},
|
||||
{"r78", (db_expr_t*)46, db_getrse},
|
||||
{"r79", (db_expr_t*)47, db_getrse},
|
||||
{"r80", (db_expr_t*)48, db_getrse},
|
||||
{"r81", (db_expr_t*)49, db_getrse},
|
||||
{"r82", (db_expr_t*)50, db_getrse},
|
||||
{"r83", (db_expr_t*)51, db_getrse},
|
||||
{"r84", (db_expr_t*)52, db_getrse},
|
||||
{"r85", (db_expr_t*)53, db_getrse},
|
||||
{"r86", (db_expr_t*)54, db_getrse},
|
||||
{"r87", (db_expr_t*)55, db_getrse},
|
||||
{"r88", (db_expr_t*)56, db_getrse},
|
||||
{"r89", (db_expr_t*)57, db_getrse},
|
||||
{"r90", (db_expr_t*)58, db_getrse},
|
||||
{"r91", (db_expr_t*)59, db_getrse},
|
||||
{"r92", (db_expr_t*)60, db_getrse},
|
||||
{"r93", (db_expr_t*)61, db_getrse},
|
||||
{"r94", (db_expr_t*)62, db_getrse},
|
||||
{"r95", (db_expr_t*)63, db_getrse},
|
||||
{"r96", (db_expr_t*)64, db_getrse},
|
||||
{"r97", (db_expr_t*)65, db_getrse},
|
||||
{"r98", (db_expr_t*)66, db_getrse},
|
||||
{"r99", (db_expr_t*)67, db_getrse},
|
||||
{"r100", (db_expr_t*)68, db_getrse},
|
||||
{"r101", (db_expr_t*)69, db_getrse},
|
||||
{"r102", (db_expr_t*)70, db_getrse},
|
||||
{"r103", (db_expr_t*)71, db_getrse},
|
||||
{"r104", (db_expr_t*)72, db_getrse},
|
||||
{"r105", (db_expr_t*)73, db_getrse},
|
||||
{"r106", (db_expr_t*)74, db_getrse},
|
||||
{"r107", (db_expr_t*)75, db_getrse},
|
||||
{"r108", (db_expr_t*)76, db_getrse},
|
||||
{"r109", (db_expr_t*)77, db_getrse},
|
||||
{"r110", (db_expr_t*)78, db_getrse},
|
||||
{"r111", (db_expr_t*)79, db_getrse},
|
||||
{"r112", (db_expr_t*)80, db_getrse},
|
||||
{"r113", (db_expr_t*)81, db_getrse},
|
||||
{"r114", (db_expr_t*)82, db_getrse},
|
||||
{"r115", (db_expr_t*)83, db_getrse},
|
||||
{"r116", (db_expr_t*)84, db_getrse},
|
||||
{"r117", (db_expr_t*)85, db_getrse},
|
||||
{"r118", (db_expr_t*)86, db_getrse},
|
||||
{"r119", (db_expr_t*)87, db_getrse},
|
||||
{"r120", (db_expr_t*)88, db_getrse},
|
||||
{"r121", (db_expr_t*)89, db_getrse},
|
||||
{"r122", (db_expr_t*)90, db_getrse},
|
||||
{"r123", (db_expr_t*)91, db_getrse},
|
||||
{"r124", (db_expr_t*)92, db_getrse},
|
||||
{"r125", (db_expr_t*)93, db_getrse},
|
||||
{"r126", (db_expr_t*)94, db_getrse},
|
||||
{"r127", (db_expr_t*)95, db_getrse},
|
||||
};
|
||||
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
|
||||
|
||||
static int
|
||||
db_get_rse_reg(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
uint64_t *reg;
|
||||
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = *reg;
|
||||
else
|
||||
*reg = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_getrse(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
u_int64_t *reg;
|
||||
uint64_t bsp;
|
||||
int nats, regno, sof;
|
||||
|
||||
bsp = ddb_regs.tf_special.bspstore + ddb_regs.tf_special.ndirty;
|
||||
regno = (db_expr_t)vp->valuep - 32;
|
||||
sof = (int)(ddb_regs.tf_special.cfm & 0x7f);
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
regno = (int)(intptr_t)valuep;
|
||||
bsp = kdb_frame->tf_special.bspstore + kdb_frame->tf_special.ndirty;
|
||||
sof = (int)(kdb_frame->tf_special.cfm & 0x7f);
|
||||
|
||||
if (regno >= sof)
|
||||
return (0);
|
||||
|
||||
nats = (sof - regno + 63 - ((int)(bsp >> 3) & 0x3f)) / 63;
|
||||
|
||||
reg = (void*)(bsp - ((sof - regno + nats) << 3));
|
||||
|
||||
if (regno < sof) {
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = *reg;
|
||||
else
|
||||
*reg = *valuep;
|
||||
} else {
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = 0xdeadbeefdeadbeef;
|
||||
}
|
||||
|
||||
return (0);
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = *reg;
|
||||
else
|
||||
*reg = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_get_ip_reg(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
db_getip(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
/* Read only */
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = PC_REGS(DDB_REGS);
|
||||
return 0;
|
||||
}
|
||||
u_long iip, slot;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Print trap reason.
|
||||
*/
|
||||
static void
|
||||
ddbprinttrap(int vector)
|
||||
{
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
|
||||
/* XXX Implement. */
|
||||
|
||||
printf("ddbprinttrap(%d)\n", vector);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CPUSTOP_ON_DDBBREAK
|
||||
#define VERBOSE_CPUSTOP_ON_DDBBREAK
|
||||
|
||||
/*
|
||||
* ddb_trap - field a kernel trap
|
||||
*/
|
||||
int
|
||||
kdb_trap(int vector, struct trapframe *regs)
|
||||
{
|
||||
int ddb_mode = !(boothowto & RB_GDB);
|
||||
register_t s;
|
||||
|
||||
/*
|
||||
* Don't bother checking for usermode, since a benign entry
|
||||
* by the kernel (call to Debugger() or a breakpoint) has
|
||||
* already checked for usermode. If neither of those
|
||||
* conditions exist, something Bad has happened.
|
||||
*/
|
||||
|
||||
if (vector != IA64_VEC_BREAK
|
||||
&& vector != IA64_VEC_SINGLE_STEP_TRAP) {
|
||||
#if 0
|
||||
if (ddb_mode) {
|
||||
db_printf("ddbprinttrap from 0x%lx\n", /* XXX */
|
||||
regs->tf_regs[FRAME_PC]);
|
||||
ddbprinttrap(a0, a1, a2, entry);
|
||||
/*
|
||||
* Tell caller "We did NOT handle the trap."
|
||||
* Caller should panic, or whatever.
|
||||
*/
|
||||
if (op == DB_VAR_GET) {
|
||||
iip = kdb_frame->tf_special.iip;
|
||||
slot = (kdb_frame->tf_special.psr >> 41) & 3;
|
||||
*valuep = iip + slot;
|
||||
} else {
|
||||
iip = *valuep & ~0xf;
|
||||
slot = *valuep & 0xf;
|
||||
if (slot > 2)
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
if (db_nofault) {
|
||||
jmp_buf *no_fault = db_nofault;
|
||||
db_nofault = 0;
|
||||
longjmp(*no_fault, 1);
|
||||
}
|
||||
kdb_frame->tf_special.iip = iip;
|
||||
kdb_frame->tf_special.psr &= ~IA64_PSR_RI;
|
||||
kdb_frame->tf_special.psr |= slot << 41;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Should switch to DDB's own stack, here.
|
||||
*/
|
||||
|
||||
s = intr_disable();
|
||||
|
||||
#ifdef SMP
|
||||
#ifdef CPUSTOP_ON_DDBBREAK
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf("CPU%d stopping CPUs: 0x%08x...", PCPU_GET(cpuid),
|
||||
PCPU_GET(other_cpus));
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
/* We stop all CPUs except ourselves (obviously) */
|
||||
stop_cpus(PCPU_GET(other_cpus));
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf(" stopped.\n");
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
#endif /* CPUSTOP_ON_DDBBREAK */
|
||||
#endif /* SMP */
|
||||
|
||||
ddb_regs = *regs;
|
||||
|
||||
/*
|
||||
* XXX pretend that registers outside the current frame don't exist.
|
||||
*/
|
||||
db_eregs = db_regs + DB_MISC_REGS + 3 + 27 +
|
||||
(ddb_regs.tf_special.cfm & 0x7f);
|
||||
|
||||
__asm __volatile("flushrs"); /* so we can look at them */
|
||||
|
||||
db_active++;
|
||||
|
||||
if (ddb_mode) {
|
||||
cndbctl(TRUE); /* DDB active, unblank video */
|
||||
db_trap(vector, 0); /* Where the work happens */
|
||||
cndbctl(FALSE); /* DDB inactive */
|
||||
} else
|
||||
gdb_handle_exception(&ddb_regs, vector);
|
||||
|
||||
db_active--;
|
||||
|
||||
#ifdef SMP
|
||||
#ifdef CPUSTOP_ON_DDBBREAK
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf("CPU%d restarting CPUs: 0x%08x...", PCPU_GET(cpuid),
|
||||
stopped_cpus);
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
/* Restart all the CPUs we previously stopped */
|
||||
if (stopped_cpus != PCPU_GET(other_cpus) && smp_started != 0) {
|
||||
db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
|
||||
PCPU_GET(other_cpus), stopped_cpus);
|
||||
panic("stop_cpus() failed");
|
||||
}
|
||||
restart_cpus(stopped_cpus);
|
||||
|
||||
#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
|
||||
db_printf(" restarted.\n");
|
||||
#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
|
||||
|
||||
#endif /* CPUSTOP_ON_DDBBREAK */
|
||||
#endif /* SMP */
|
||||
|
||||
*regs = ddb_regs;
|
||||
|
||||
intr_restore(s);
|
||||
|
||||
|
||||
/*
|
||||
* Tell caller "We HAVE handled the trap."
|
||||
*/
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read bytes from kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
int
|
||||
db_read_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *src;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
|
||||
if (addr < VM_MAX_ADDRESS)
|
||||
copyin((char *)addr, data, size);
|
||||
else
|
||||
bcopy((char *)addr, data, size);
|
||||
|
||||
db_nofault = 0;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write bytes to kernel address space for debugger.
|
||||
*/
|
||||
void
|
||||
int
|
||||
db_write_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *dst;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
|
||||
if (addr < VM_MAX_ADDRESS)
|
||||
copyout(data, (char *)addr, size);
|
||||
else
|
||||
bcopy(data, (char *)addr, size);
|
||||
|
||||
db_nofault = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Debugger(const char* msg)
|
||||
{
|
||||
printf("%s\n", msg);
|
||||
__asm("break 0x80100");
|
||||
}
|
||||
|
||||
u_long
|
||||
db_register_value(db_regs_t *regs, int regno)
|
||||
{
|
||||
uint64_t *rsp;
|
||||
uint64_t bsp;
|
||||
int nats, sof;
|
||||
|
||||
if (regno == 0)
|
||||
return (0);
|
||||
if (regno == 1)
|
||||
return (regs->tf_special.gp);
|
||||
if (regno >= 2 && regno <= 3)
|
||||
return ((®s->tf_scratch.gr2)[regno - 2]);
|
||||
if (regno >= 8 && regno <= 11)
|
||||
return ((®s->tf_scratch.gr8)[regno - 8]);
|
||||
if (regno == 12)
|
||||
return (regs->tf_special.sp);
|
||||
if (regno == 13)
|
||||
return (regs->tf_special.tp);
|
||||
if (regno >= 14 && regno <= 31)
|
||||
return ((®s->tf_scratch.gr14)[regno - 14]);
|
||||
|
||||
sof = (int)(regs->tf_special.cfm & 0x7f);
|
||||
if (regno >= 32 && regno < sof + 32) {
|
||||
bsp = regs->tf_special.bspstore + regs->tf_special.ndirty;
|
||||
regno -= 32;
|
||||
nats = (sof - regno + 63 - ((int)(bsp >> 3) & 0x3f)) / 63;
|
||||
rsp = (void*)(bsp - ((sof - regno + nats) << 3));
|
||||
return (*rsp);
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
dst = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
}
|
||||
|
||||
db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno);
|
||||
return (0);
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
db_write_breakpoint(vm_offset_t addr, u_int64_t *storage)
|
||||
db_bkpt_write(db_addr_t addr, BKPT_INST_TYPE *storage)
|
||||
{
|
||||
BKPT_INST_TYPE tmp;
|
||||
db_addr_t loc;
|
||||
int slot;
|
||||
|
||||
slot = addr & 0xfUL;
|
||||
if (slot >= SLOT_COUNT)
|
||||
return;
|
||||
loc = (addr & ~0xfUL) + (slot << 2);
|
||||
|
||||
db_read_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp);
|
||||
*storage = (tmp >> SLOT_SHIFT(slot)) & SLOT_MASK;
|
||||
|
||||
tmp &= ~(SLOT_MASK << SLOT_SHIFT(slot));
|
||||
tmp |= (0x84000 << 6) << SLOT_SHIFT(slot);
|
||||
db_write_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp);
|
||||
}
|
||||
|
||||
void
|
||||
db_clear_breakpoint(vm_offset_t addr, u_int64_t *storage)
|
||||
db_bkpt_clear(db_addr_t addr, BKPT_INST_TYPE *storage)
|
||||
{
|
||||
BKPT_INST_TYPE tmp;
|
||||
db_addr_t loc;
|
||||
int slot;
|
||||
|
||||
slot = addr & 0xfUL;
|
||||
if (slot >= SLOT_COUNT)
|
||||
return;
|
||||
loc = (addr & ~0xfUL) + (slot << 2);
|
||||
|
||||
db_read_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp);
|
||||
tmp &= ~(SLOT_MASK << SLOT_SHIFT(slot));
|
||||
tmp |= *storage << SLOT_SHIFT(slot);
|
||||
db_write_bytes(loc, sizeof(BKPT_INST_TYPE), (char *)&tmp);
|
||||
}
|
||||
|
||||
void
|
||||
db_skip_breakpoint()
|
||||
db_bkpt_skip(void)
|
||||
{
|
||||
|
||||
ddb_regs.tf_special.psr += IA64_PSR_RI_1;
|
||||
if ((ddb_regs.tf_special.psr & IA64_PSR_RI) > IA64_PSR_RI_2) {
|
||||
ddb_regs.tf_special.psr &= ~IA64_PSR_RI;
|
||||
ddb_regs.tf_special.iip += 16;
|
||||
if (kdb_frame == NULL)
|
||||
return;
|
||||
|
||||
kdb_frame->tf_special.psr += IA64_PSR_RI_1;
|
||||
if ((kdb_frame->tf_special.psr & IA64_PSR_RI) > IA64_PSR_RI_2) {
|
||||
kdb_frame->tf_special.psr &= ~IA64_PSR_RI;
|
||||
kdb_frame->tf_special.iip += 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2003, 2004 Marcel Moolenaar
|
||||
* Copyright (c) 2000-2001 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -27,8 +28,13 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <machine/db_machdep.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/unwind.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
@ -38,14 +44,12 @@
|
||||
#include <ddb/db_variables.h>
|
||||
#include <ddb/db_output.h>
|
||||
|
||||
|
||||
int db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
|
||||
int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
|
||||
void db_md_list_watchpoints(void);
|
||||
|
||||
void
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
static int
|
||||
db_backtrace(struct thread *td, struct pcb *pcb, int count)
|
||||
{
|
||||
struct unw_regstate rs;
|
||||
struct trapframe *tf;
|
||||
@ -55,8 +59,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
c_db_sym_t sym;
|
||||
int args, error, i;
|
||||
|
||||
tf = &ddb_regs;
|
||||
error = unw_create(&rs, tf);
|
||||
error = unw_create_from_pcb(&rs, pcb);
|
||||
while (!error && count--) {
|
||||
error = unw_get_cfm(&rs, &cfm);
|
||||
if (!error)
|
||||
@ -68,15 +71,14 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
if (error)
|
||||
break;
|
||||
|
||||
args = (cfm >> 7) & 0x7f;
|
||||
args = IA64_CFM_SOL(cfm);
|
||||
if (args > 8)
|
||||
args = 8;
|
||||
|
||||
error = unw_step(&rs);
|
||||
if (!error) {
|
||||
error = unw_get_cfm(&rs, &pfs);
|
||||
if (!error) {
|
||||
i = (pfs & 0x7f) - ((pfs >> 7) & 0x7f);
|
||||
if (!unw_get_cfm(&rs, &pfs)) {
|
||||
i = IA64_CFM_SOF(pfs) - IA64_CFM_SOL(pfs);
|
||||
if (args > i)
|
||||
args = i;
|
||||
}
|
||||
@ -115,15 +117,43 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
/* XXX ask if we should unwind across the trapframe. */
|
||||
db_printf("--- trapframe at %p\n", tf);
|
||||
unw_delete(&rs);
|
||||
error = unw_create(&rs, tf);
|
||||
error = unw_create_from_frame(&rs, tf);
|
||||
}
|
||||
|
||||
unw_delete(&rs);
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
db_print_backtrace(void)
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread;
|
||||
if (td == NULL) {
|
||||
db_printf("Thread %d not found\n", (int)addr);
|
||||
return;
|
||||
}
|
||||
db_trace_thread(td, count);
|
||||
}
|
||||
|
||||
void
|
||||
db_trace_self(void)
|
||||
{
|
||||
struct pcb pcb;
|
||||
|
||||
savectx(&pcb);
|
||||
db_backtrace(curthread, &pcb, -1);
|
||||
}
|
||||
|
||||
int
|
||||
db_trace_thread(struct thread *td, int count)
|
||||
{
|
||||
struct pcb *ctx;
|
||||
|
||||
ctx = kdb_thr_ctx(td);
|
||||
return (db_backtrace(td, ctx, count));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1,66 +1,64 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $NetBSD: db_machdep.h,v 1.6 1997/09/06 02:02:25 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995 Carnegie-Mellon University.
|
||||
* Copyright (c) 2004 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Chris G. Demetriou
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and
|
||||
* its documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
||||
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
|
||||
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Carnegie Mellon requests users of this software to return to
|
||||
*
|
||||
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
||||
* School of Computer Science
|
||||
* Carnegie Mellon University
|
||||
* Pittsburgh PA 15213-3890
|
||||
*
|
||||
* any improvements or extensions that they make and grant Carnegie the
|
||||
* rights to redistribute these changes.
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MACHINE_DB_MACHDEP_H_
|
||||
#define _MACHINE_DB_MACHDEP_H_
|
||||
|
||||
/*
|
||||
* Machine-dependent defines for new kernel debugger.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <vm/vm.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/ia64_cpu.h>
|
||||
|
||||
#define DB_NO_AOUT
|
||||
/* We define some of our own commands. */
|
||||
#define DB_MACHINE_COMMANDS
|
||||
|
||||
struct ia64_bundle;
|
||||
/* We use Elf64 symbols in DDB. */
|
||||
#define DB_ELFSIZE 64
|
||||
|
||||
/* Pretty arbitrary. */
|
||||
#define DB_SMALL_VALUE_MAX 0x7fffffff
|
||||
#define DB_SMALL_VALUE_MIN (-0x400001)
|
||||
|
||||
typedef vm_offset_t db_addr_t; /* address - unsigned */
|
||||
typedef long db_expr_t; /* expression - signed */
|
||||
typedef struct trapframe db_regs_t;
|
||||
extern db_regs_t ddb_regs; /* register state */
|
||||
#define DDB_REGS (&ddb_regs)
|
||||
|
||||
#define PC_REGS(regs) ((db_addr_t)(regs)->tf_special.iip + \
|
||||
(((regs)->tf_special.psr >> 41) & 3))
|
||||
#define PC_REGS() ((kdb_thrctx->pcb_special.__spare == 0) ? \
|
||||
kdb_thrctx->pcb_special.rp : \
|
||||
kdb_thrctx->pcb_special.iip + ((kdb_thrctx->pcb_special.psr>>41) & 3))
|
||||
|
||||
#define BKPT_WRITE(addr, storage) db_write_breakpoint(addr, storage)
|
||||
#define BKPT_CLEAR(addr, storage) db_clear_breakpoint(addr, storage)
|
||||
#define BKPT_INST_TYPE u_int64_t
|
||||
#define BKPT_WRITE(addr, storage) db_bkpt_write(addr, storage)
|
||||
#define BKPT_CLEAR(addr, storage) db_bkpt_clear(addr, storage)
|
||||
#define BKPT_SKIP db_bkpt_skip()
|
||||
#define BKPT_INST_TYPE uint64_t
|
||||
|
||||
#define BKPT_SKIP db_skip_breakpoint()
|
||||
void db_bkpt_write(db_addr_t, BKPT_INST_TYPE *storage);
|
||||
void db_bkpt_clear(db_addr_t, uint64_t *storage);
|
||||
void db_bkpt_skip(void);
|
||||
|
||||
#define db_clear_single_step(regs) ddb_regs.tf_special.psr &= ~IA64_PSR_SS
|
||||
#define db_set_single_step(regs) ddb_regs.tf_special.psr |= IA64_PSR_SS
|
||||
#define db_clear_single_step kdb_cpu_clear_singlestep
|
||||
#define db_set_single_step kdb_cpu_set_singlestep
|
||||
|
||||
#define IS_BREAKPOINT_TRAP(type, code) (type == IA64_VEC_BREAK)
|
||||
#define IS_WATCHPOINT_TRAP(type, code) 0
|
||||
@ -72,43 +70,7 @@ extern db_regs_t ddb_regs; /* register state */
|
||||
#define inst_load(ins) (ins & 0)
|
||||
#define inst_store(ins) (ins & 0)
|
||||
#define inst_unconditional_flow_transfer(ins) (ins & 0)
|
||||
|
||||
|
||||
#define branch_taken(ins, pc, regs) pc
|
||||
|
||||
/*
|
||||
* Functions needed for software single-stepping.
|
||||
*/
|
||||
|
||||
/* No delay slots on Alpha. */
|
||||
#define next_instr_address(v, b) ((db_addr_t) ((b) ? (v) : ((v) + 4)))
|
||||
|
||||
u_long db_register_value(db_regs_t *, int);
|
||||
int kdb_trap(int vector, struct trapframe *regs);
|
||||
|
||||
u_int64_t *db_rse_current_frame(void);
|
||||
u_int64_t *db_rse_previous_frame(u_int64_t *bsp, int sof);
|
||||
u_int64_t *db_rse_register_address(u_int64_t *bsp, int regno);
|
||||
|
||||
void db_read_bundle(db_addr_t addr, struct ia64_bundle *bp);
|
||||
void db_write_bundle(db_addr_t addr, struct ia64_bundle *bp);
|
||||
void db_write_breakpoint(db_addr_t addr, u_int64_t *storage);
|
||||
void db_clear_breakpoint(db_addr_t addr, u_int64_t *storage);
|
||||
void db_skip_breakpoint(void);
|
||||
|
||||
/*
|
||||
* Pretty arbitrary
|
||||
*/
|
||||
#define DB_SMALL_VALUE_MAX 0x7fffffff
|
||||
#define DB_SMALL_VALUE_MIN (-0x400001)
|
||||
|
||||
/*
|
||||
* We define some of our own commands.
|
||||
*/
|
||||
#define DB_MACHINE_COMMANDS
|
||||
|
||||
/*
|
||||
* We use Elf64 symbols in DDB.
|
||||
*/
|
||||
#define DB_ELFSIZE 64
|
||||
|
||||
#endif /* _MACHINE_DB_MACHDEP_H_ */
|
||||
|
@ -38,23 +38,19 @@
|
||||
typedef vm_offset_t db_addr_t;
|
||||
typedef long db_expr_t;
|
||||
|
||||
typedef struct trapframe db_regs_t;
|
||||
extern db_regs_t ddb_regs;
|
||||
#define DDB_REGS (&ddb_regs)
|
||||
|
||||
#define PC_REGS(regs) ((db_addr_t)(regs)->tf_tpc)
|
||||
#define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_pc)
|
||||
|
||||
#define BKPT_INST (0x91d03001)
|
||||
#define BKPT_SIZE (4)
|
||||
#define BKPT_SET(inst) (BKPT_INST)
|
||||
|
||||
#define BKPT_SKIP do { \
|
||||
ddb_regs.tf_tpc = ddb_regs.tf_tnpc + 4; \
|
||||
ddb_regs.tf_tnpc += 8; \
|
||||
kdb_frame->tf_tpc = kdb_frame->tf_tnpc + 4; \
|
||||
kdb_frame->tf_tnpc += 8; \
|
||||
} while (0)
|
||||
|
||||
#define db_clear_single_step(regs)
|
||||
#define db_set_single_step(regs)
|
||||
#define db_clear_single_step kdb_cpu_clear_singlestep
|
||||
#define db_set_single_step kdb_cpu_set_singlestep
|
||||
|
||||
#define IS_BREAKPOINT_TRAP(type, code) (type == T_BREAKPOINT)
|
||||
#define IS_WATCHPOINT_TRAP(type, code) (0)
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <sys/systm.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/cons.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/linker_set.h>
|
||||
#include <sys/lock.h>
|
||||
@ -51,66 +52,42 @@
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/setjmp.h>
|
||||
|
||||
static jmp_buf *db_nofault = 0;
|
||||
extern jmp_buf db_jmpbuf;
|
||||
|
||||
int db_active;
|
||||
db_regs_t ddb_regs;
|
||||
|
||||
static jmp_buf db_global_jmpbuf;
|
||||
static int db_global_jmpbuf_valid;
|
||||
|
||||
int
|
||||
kdb_trap(struct trapframe *tf)
|
||||
{
|
||||
|
||||
if (db_global_jmpbuf_valid)
|
||||
longjmp(db_global_jmpbuf, 1);
|
||||
flushw();
|
||||
ddb_regs = *tf;
|
||||
critical_enter();
|
||||
setjmp(db_global_jmpbuf);
|
||||
db_global_jmpbuf_valid = TRUE;
|
||||
atomic_add_acq_int(&db_active, 1);
|
||||
#ifdef SMP
|
||||
stop_cpus(PCPU_GET(other_cpus));
|
||||
#endif
|
||||
cndbctl(TRUE);
|
||||
db_trap(tf->tf_type, 0);
|
||||
cndbctl(FALSE);
|
||||
db_active--;
|
||||
#ifdef SMP
|
||||
restart_cpus(stopped_cpus);
|
||||
#endif
|
||||
db_global_jmpbuf_valid = FALSE;
|
||||
critical_exit();
|
||||
*tf = ddb_regs;
|
||||
TF_DONE(tf);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
db_read_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *src;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
db_nofault = NULL;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
src = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*data++ = *src++;
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
db_write_bytes(vm_offset_t addr, size_t size, char *data)
|
||||
{
|
||||
jmp_buf jb;
|
||||
void *prev_jb;
|
||||
char *dst;
|
||||
int ret;
|
||||
|
||||
db_nofault = &db_jmpbuf;
|
||||
dst = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
db_nofault = NULL;
|
||||
prev_jb = kdb_jmpbuf(jb);
|
||||
ret = setjmp(jb);
|
||||
if (ret == 0) {
|
||||
dst = (char *)addr;
|
||||
while (size-- > 0)
|
||||
*dst++ = *data++;
|
||||
}
|
||||
(void)kdb_jmpbuf(prev_jb);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/linker_set.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sysent.h>
|
||||
@ -47,138 +48,89 @@
|
||||
#include <ddb/db_variables.h>
|
||||
#include <ddb/db_watch.h>
|
||||
|
||||
static int db_print_trap(struct thread *td, struct trapframe *);
|
||||
static void db_utrace(struct thread *td, struct trapframe *tf);
|
||||
|
||||
#define INKERNEL(va) \
|
||||
((va) >= VM_MIN_KERNEL_ADDRESS && (va) <= VM_MAX_KERNEL_ADDRESS)
|
||||
|
||||
static db_varfcn_t db_frame;
|
||||
|
||||
#define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x)
|
||||
struct db_variable db_regs[] = {
|
||||
{ "g0", &ddb_regs.tf_global[0], FCN_NULL },
|
||||
{ "g1", &ddb_regs.tf_global[1], FCN_NULL },
|
||||
{ "g2", &ddb_regs.tf_global[2], FCN_NULL },
|
||||
{ "g3", &ddb_regs.tf_global[3], FCN_NULL },
|
||||
{ "g4", &ddb_regs.tf_global[4], FCN_NULL },
|
||||
{ "g5", &ddb_regs.tf_global[5], FCN_NULL },
|
||||
{ "g6", &ddb_regs.tf_global[6], FCN_NULL },
|
||||
{ "g7", &ddb_regs.tf_global[7], FCN_NULL },
|
||||
{ "i0", &ddb_regs.tf_out[0], FCN_NULL },
|
||||
{ "i1", &ddb_regs.tf_out[1], FCN_NULL },
|
||||
{ "i2", &ddb_regs.tf_out[2], FCN_NULL },
|
||||
{ "i3", &ddb_regs.tf_out[3], FCN_NULL },
|
||||
{ "i4", &ddb_regs.tf_out[4], FCN_NULL },
|
||||
{ "i5", &ddb_regs.tf_out[5], FCN_NULL },
|
||||
{ "i6", &ddb_regs.tf_out[6], FCN_NULL },
|
||||
{ "i7", &ddb_regs.tf_out[7], FCN_NULL },
|
||||
{ "tnpc", &ddb_regs.tf_tnpc, FCN_NULL },
|
||||
{ "tpc", &ddb_regs.tf_tpc, FCN_NULL },
|
||||
{ "tstate", &ddb_regs.tf_tstate, FCN_NULL },
|
||||
{ "g0", DB_OFFSET(tf_global[0]), db_frame },
|
||||
{ "g1", DB_OFFSET(tf_global[1]), db_frame },
|
||||
{ "g2", DB_OFFSET(tf_global[2]), db_frame },
|
||||
{ "g3", DB_OFFSET(tf_global[3]), db_frame },
|
||||
{ "g4", DB_OFFSET(tf_global[4]), db_frame },
|
||||
{ "g5", DB_OFFSET(tf_global[5]), db_frame },
|
||||
{ "g6", DB_OFFSET(tf_global[6]), db_frame },
|
||||
{ "g7", DB_OFFSET(tf_global[7]), db_frame },
|
||||
{ "i0", DB_OFFSET(tf_out[0]), db_frame },
|
||||
{ "i1", DB_OFFSET(tf_out[1]), db_frame },
|
||||
{ "i2", DB_OFFSET(tf_out[2]), db_frame },
|
||||
{ "i3", DB_OFFSET(tf_out[3]), db_frame },
|
||||
{ "i4", DB_OFFSET(tf_out[4]), db_frame },
|
||||
{ "i5", DB_OFFSET(tf_out[5]), db_frame },
|
||||
{ "i6", DB_OFFSET(tf_out[6]), db_frame },
|
||||
{ "i7", DB_OFFSET(tf_out[7]), db_frame },
|
||||
{ "tnpc", DB_OFFSET(tf_tnpc), db_frame },
|
||||
{ "tpc", DB_OFFSET(tf_tpc), db_frame },
|
||||
{ "tstate", DB_OFFSET(tf_tstate), db_frame },
|
||||
};
|
||||
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
|
||||
|
||||
void
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
static int
|
||||
db_frame(struct db_variable *vp, db_expr_t *valuep, int op)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
struct frame *fp;
|
||||
struct proc *p;
|
||||
struct thread *td;
|
||||
const char *name;
|
||||
c_db_sym_t sym;
|
||||
db_expr_t offset;
|
||||
db_expr_t value;
|
||||
db_addr_t npc;
|
||||
db_addr_t pc;
|
||||
int trap;
|
||||
int user;
|
||||
pid_t pid;
|
||||
uint64_t *reg;
|
||||
|
||||
trap = 0;
|
||||
user = 0;
|
||||
npc = 0;
|
||||
if (count == -1)
|
||||
count = 1024;
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
/*
|
||||
* Provide an /a modifier to pass the stack address instead of a PID
|
||||
* as argument.
|
||||
* Note that, if this address is not on the stack of curthread, the
|
||||
* printed data may be wrong (at the moment, this applies only to the
|
||||
* sysent list).
|
||||
*/
|
||||
if (!have_addr)
|
||||
addr = DDB_REGS->tf_out[6];
|
||||
else if (strcmp(modif, "a") != 0) {
|
||||
/*
|
||||
* addr was parsed as hex, convert so it is interpreted as
|
||||
* decimal (ugh).
|
||||
*/
|
||||
pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
|
||||
((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
|
||||
((addr >> 16) % 16) * 10000;
|
||||
/*
|
||||
* The pcb for curproc is not valid at this point,
|
||||
* so fall back to the default case.
|
||||
*/
|
||||
if (pid == curthread->td_proc->p_pid) {
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
addr = DDB_REGS->tf_out[6];
|
||||
} else {
|
||||
/* sx_slock(&allproc_lock); */
|
||||
LIST_FOREACH(p, &allproc, p_list) {
|
||||
if (p->p_pid == pid)
|
||||
break;
|
||||
if (kdb_frame == NULL)
|
||||
return (0);
|
||||
reg = (uint64_t*)((uintptr_t)kdb_frame + (uintptr_t)vp->valuep);
|
||||
if (op == DB_VAR_GET)
|
||||
*valuep = *reg;
|
||||
else
|
||||
*reg = *valuep;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* User stack trace (debugging aid).
|
||||
*/
|
||||
static void
|
||||
db_utrace(struct thread *td, struct trapframe *tf)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
db_addr_t sp, rsp, o7, pc;
|
||||
int i, found;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
|
||||
o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
|
||||
FALSE);
|
||||
pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
|
||||
db_printf("user trace: trap %%o7=%#lx\n", o7);
|
||||
while (sp != 0) {
|
||||
db_printf("pc %#lx, sp %#lx\n", pc, sp);
|
||||
/* First, check whether the frame is in the pcb. */
|
||||
found = 0;
|
||||
for (i = 0; i < pcb->pcb_nsaved; i++) {
|
||||
if (pcb->pcb_rwsp[i] == sp) {
|
||||
found = 1;
|
||||
sp = pcb->pcb_rw[i].rw_in[6];
|
||||
pc = pcb->pcb_rw[i].rw_in[7];
|
||||
break;
|
||||
}
|
||||
/* sx_sunlock(&allproc_lock); */
|
||||
if (p == NULL) {
|
||||
db_printf("pid %d not found\n", pid);
|
||||
return;
|
||||
}
|
||||
if ((p->p_sflag & PS_INMEM) == 0) {
|
||||
db_printf("pid %d swapped out\n", pid);
|
||||
return;
|
||||
}
|
||||
td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */
|
||||
addr = td->td_pcb->pcb_sp;
|
||||
}
|
||||
}
|
||||
fp = (struct frame *)(addr + SPOFF);
|
||||
|
||||
while (count-- && !user) {
|
||||
pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
|
||||
sizeof(fp->fr_pc), FALSE);
|
||||
if (trap) {
|
||||
pc = npc;
|
||||
trap = 0;
|
||||
}
|
||||
if (!INKERNEL((vm_offset_t)pc))
|
||||
break;
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
||||
if (sym == C_DB_SYM_NULL) {
|
||||
value = 0;
|
||||
name = NULL;
|
||||
} else
|
||||
db_symbol_values(sym, &name, &value);
|
||||
if (name == NULL)
|
||||
name = "(null)";
|
||||
fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
|
||||
sizeof(fp->fr_fp), FALSE) + SPOFF);
|
||||
if (bcmp(name, "tl0_", 4) == 0 ||
|
||||
bcmp(name, "tl1_", 4) == 0) {
|
||||
tf = (struct trapframe *)(fp + 1);
|
||||
npc = db_get_value((db_addr_t)&tf->tf_tpc,
|
||||
sizeof(tf->tf_tpc), FALSE);
|
||||
user = db_print_trap(td, tf);
|
||||
trap = 1;
|
||||
} else {
|
||||
db_printf("%s() at ", name);
|
||||
db_printsym(pc, DB_STGY_PROC);
|
||||
db_printf("\n");
|
||||
}
|
||||
if (!found) {
|
||||
rsp = sp + SPOFF;
|
||||
sp = 0;
|
||||
if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
|
||||
&sp, sizeof(sp)) != 0 ||
|
||||
copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
|
||||
&pc, sizeof(pc)) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
db_printf("done\n");
|
||||
}
|
||||
|
||||
static int
|
||||
@ -265,52 +217,88 @@ db_print_trap(struct thread *td, struct trapframe *tf)
|
||||
return (user);
|
||||
}
|
||||
|
||||
/*
|
||||
* User stack trace (debugging aid).
|
||||
*/
|
||||
static void
|
||||
db_utrace(struct thread *td, struct trapframe *tf)
|
||||
static int
|
||||
db_backtrace(struct thread *td, struct frame *fp, int count)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
db_addr_t sp, rsp, o7, pc;
|
||||
int i, found;
|
||||
struct trapframe *tf;
|
||||
const char *name;
|
||||
c_db_sym_t sym;
|
||||
db_expr_t offset;
|
||||
db_expr_t value;
|
||||
db_addr_t npc;
|
||||
db_addr_t pc;
|
||||
int trap;
|
||||
int user;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
sp = db_get_value((db_addr_t)&tf->tf_sp, sizeof(tf->tf_sp), FALSE);
|
||||
o7 = db_get_value((db_addr_t)&tf->tf_out[7], sizeof(tf->tf_out[7]),
|
||||
FALSE);
|
||||
pc = db_get_value((db_addr_t)&tf->tf_tpc, sizeof(tf->tf_tpc), FALSE);
|
||||
db_printf("user trace: trap %%o7=%#lx\n", o7);
|
||||
while (sp != 0) {
|
||||
db_printf("pc %#lx, sp %#lx\n", pc, sp);
|
||||
/* First, check whether the frame is in the pcb. */
|
||||
found = 0;
|
||||
for (i = 0; i < pcb->pcb_nsaved; i++) {
|
||||
if (pcb->pcb_rwsp[i] == sp) {
|
||||
found = 1;
|
||||
sp = pcb->pcb_rw[i].rw_in[6];
|
||||
pc = pcb->pcb_rw[i].rw_in[7];
|
||||
break;
|
||||
}
|
||||
if (count == -1)
|
||||
count = 1024;
|
||||
|
||||
trap = 0;
|
||||
user = 0;
|
||||
npc = 0;
|
||||
while (count-- && !user) {
|
||||
pc = (db_addr_t)db_get_value((db_addr_t)&fp->fr_pc,
|
||||
sizeof(fp->fr_pc), FALSE);
|
||||
if (trap) {
|
||||
pc = npc;
|
||||
trap = 0;
|
||||
}
|
||||
if (!found) {
|
||||
rsp = sp + SPOFF;
|
||||
sp = 0;
|
||||
if (copyin((void *)(rsp + offsetof(struct frame, fr_fp)),
|
||||
&sp, sizeof(sp)) != 0 ||
|
||||
copyin((void *)(rsp + offsetof(struct frame, fr_pc)),
|
||||
&pc, sizeof(pc)) != 0)
|
||||
break;
|
||||
if (!INKERNEL((vm_offset_t)pc))
|
||||
break;
|
||||
sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
|
||||
if (sym == C_DB_SYM_NULL) {
|
||||
value = 0;
|
||||
name = NULL;
|
||||
} else
|
||||
db_symbol_values(sym, &name, &value);
|
||||
if (name == NULL)
|
||||
name = "(null)";
|
||||
fp = (struct frame *)(db_get_value((db_addr_t)&fp->fr_fp,
|
||||
sizeof(fp->fr_fp), FALSE) + SPOFF);
|
||||
if (bcmp(name, "tl0_", 4) == 0 ||
|
||||
bcmp(name, "tl1_", 4) == 0) {
|
||||
tf = (struct trapframe *)(fp + 1);
|
||||
npc = db_get_value((db_addr_t)&tf->tf_tpc,
|
||||
sizeof(tf->tf_tpc), FALSE);
|
||||
user = db_print_trap(td, tf);
|
||||
trap = 1;
|
||||
} else {
|
||||
db_printf("%s() at ", name);
|
||||
db_printsym(pc, DB_STGY_PROC);
|
||||
db_printf("\n");
|
||||
}
|
||||
}
|
||||
db_printf("done\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
db_print_backtrace(void)
|
||||
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
|
||||
char *modif)
|
||||
{
|
||||
u_long *sp;
|
||||
struct thread *td;
|
||||
|
||||
sp = __builtin_frame_address(1);
|
||||
db_stack_trace_cmd((db_expr_t)sp, TRUE, -1, "a");
|
||||
td = (have_addr) ? kdb_thr_lookup(addr) : kdb_thread;
|
||||
if (td == NULL) {
|
||||
db_printf("Thread %d not found\n", (int)addr);
|
||||
return;
|
||||
}
|
||||
db_trace_thread(td, count);
|
||||
}
|
||||
|
||||
void
|
||||
db_trace_self(void)
|
||||
{
|
||||
db_expr_t addr;
|
||||
|
||||
addr = (db_expr_t)__builtin_frame_address(1);
|
||||
db_backtrace(curthread, (struct frame *)(addr + SPOFF), -1);
|
||||
}
|
||||
|
||||
int
|
||||
db_trace_thread(struct thread *td, int count)
|
||||
{
|
||||
struct pcb *ctx;
|
||||
|
||||
ctx = kdb_thr_ctx(td);
|
||||
return (db_backtrace(td, (struct frame*)(ctx->pcb_sp + SPOFF), count));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user