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:
marcel 2004-07-10 23:47:20 +00:00
parent a7df680fac
commit d54b27a1b4
29 changed files with 1683 additions and 2337 deletions

View File

@ -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);
}

View File

@ -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;
/*

View File

@ -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

View File

@ -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

View File

@ -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)&regs->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

View File

@ -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)

View File

@ -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)
/*

View File

@ -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

View File

@ -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();
}
}

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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();

View File

@ -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());
}

View File

@ -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
}

View File

@ -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
View 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);
}
}

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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)&regs->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

View File

@ -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)

View File

@ -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)
/*

View File

@ -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 ((&regs->tf_scratch.gr2)[regno - 2]);
if (regno >= 8 && regno <= 11)
return ((&regs->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 ((&regs->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;
}
}

View File

@ -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

View File

@ -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_ */

View File

@ -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)

View File

@ -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

View File

@ -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));
}