#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.10 2022/12/24 14:47:47 uwe Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#ifndef _KERNEL
#include <stdbool.h>
#endif
#include <machine/frame.h>
#include <machine/trap.h>
#include <machine/intrdefs.h>
#include <machine/cpu.h>
#include <uvm/uvm_prot.h>
#include <uvm/uvm_pmap.h>
#include <machine/pmap.h>
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_access.h>
#include <ddb/db_variables.h>
#include <ddb/db_output.h>
#include <ddb/db_interface.h>
#include <ddb/db_user.h>
#include <ddb/db_proc.h>
#include <ddb/db_command.h>
#include <ddb/db_cpu.h>
#include <x86/db_machdep.h>
#define dbreg(xx) (long *)offsetof(db_regs_t, tf_ ## xx)
const struct db_variable db_regs[] = {
{ "ds", dbreg(ds), db_x86_regop, NULL },
{ "es", dbreg(es), db_x86_regop, NULL },
{ "fs", dbreg(fs), db_x86_regop, NULL },
{ "gs", dbreg(gs), db_x86_regop, NULL },
{ "edi", dbreg(edi), db_x86_regop, NULL },
{ "esi", dbreg(esi), db_x86_regop, NULL },
{ "ebp", dbreg(ebp), db_x86_regop, NULL },
{ "ebx", dbreg(ebx), db_x86_regop, NULL },
{ "edx", dbreg(edx), db_x86_regop, NULL },
{ "ecx", dbreg(ecx), db_x86_regop, NULL },
{ "eax", dbreg(eax), db_x86_regop, NULL },
{ "eip", dbreg(eip), db_x86_regop, NULL },
{ "cs", dbreg(cs), db_x86_regop, NULL },
{ "eflags", dbreg(eflags), db_x86_regop, NULL },
{ "esp", dbreg(esp), db_x86_regop, NULL },
{ "ss", dbreg(ss), db_x86_regop, NULL },
};
const struct db_variable * const db_eregs =
db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
int
db_numargs(long *retaddrp)
{
int *argp;
int inst;
int args;
extern char etext[];
argp = (int *)db_get_value((int)retaddrp, 4, false);
if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext) {
args = 10;
} else {
inst = db_get_value((int)argp, 4, false);
if ((inst & 0xff) == 0x59)
args = 1;
else if ((inst & 0xffff) == 0xc483)
args = ((inst >> 16) & 0xff) / 4;
else
args = 10;
}
return (args);
}
int
db_nextframe(long **nextframe, long **retaddr, long **arg0, db_addr_t *ip,
long *argp, int is_trap, void (*pr)(const char *, ...))
{
static struct trapframe tf;
static struct i386tss tss;
struct i386_frame *fp;
uintptr_t ptr;
switch (is_trap) {
case NONE:
*ip = (db_addr_t)
db_get_value((int)*retaddr, 4, false);
fp = (struct i386_frame *)
db_get_value((int)*nextframe, 4, false);
if (fp == NULL)
return 0;
*nextframe = (long *)&fp->f_frame;
*retaddr = (long *)&fp->f_retaddr;
*arg0 = (long *)&fp->f_arg0;
break;
case TRAP_TSS:
case INTERRUPT_TSS:
ptr = db_get_value((int)argp, 4, false);
db_read_bytes((db_addr_t)ptr, sizeof(tss), (char *)&tss);
*ip = tss.__tss_eip;
fp = (struct i386_frame *)tss.tss_ebp;
if (fp == NULL)
return 0;
*nextframe = (long *)&fp->f_frame;
*retaddr = (long *)&fp->f_retaddr;
*arg0 = (long *)&fp->f_arg0;
if (is_trap == INTERRUPT_TSS)
(*pr)("--- interrupt via task gate ---\n");
else
(*pr)("--- trap via task gate ---\n");
break;
case TRAP:
case SYSCALL:
case INTERRUPT:
case SOFTINTR:
default:
switch (is_trap) {
case TRAP:
ptr = db_get_value((int)argp, 4, false);
db_read_bytes((db_addr_t)ptr, sizeof(tf), (char *)&tf);
(*pr)("--- trap (number %d) ---\n", tf.tf_trapno);
break;
case SYSCALL:
ptr = db_get_value((int)argp, 4, false);
db_read_bytes((db_addr_t)ptr, sizeof(tf), (char *)&tf);
(*pr)("--- syscall (number %d) ---\n", tf.tf_eax);
break;
case INTERRUPT:
(*pr)("--- interrupt ---\n");
db_read_bytes((db_addr_t)argp, sizeof(tf), (char *)&tf);
break;
case SOFTINTR:
(*pr)("--- softint ---\n");
tf.tf_eip = 0;
tf.tf_ebp = 0;
break;
}
*ip = (db_addr_t)tf.tf_eip;
fp = (struct i386_frame *)tf.tf_ebp;
if (fp == NULL)
return 0;
*nextframe = (long *)&fp->f_frame;
*retaddr = (long *)&fp->f_retaddr;
*arg0 = (long *)&fp->f_arg0;
break;
}
int traptype = NONE;
db_sym_t sym = db_frame_info(*nextframe, (db_addr_t)*ip,
NULL, NULL, &traptype, NULL);
if (sym != DB_SYM_NULL && traptype == INTERRUPT) {
struct intrframe *ifp;
int trapno;
int err;
ifp = (struct intrframe *)
db_get_value((db_addr_t)(argp + 1), sizeof(ifp), false);
err = db_get_value((db_addr_t)&ifp->__if_err,
sizeof(ifp->__if_err), false);
trapno = db_get_value((db_addr_t)&ifp->__if_trapno,
sizeof(ifp->__if_trapno), false);
if ((err == 0 || err == IREENT_MAGIC) && trapno == T_ASTFLT) {
*nextframe = (long *)ifp - 1;
} else {
(*pr)("DDB lost frame for ");
db_printsym(*ip, DB_STGY_ANY, pr);
(*pr)(", trying %p\n",argp);
*nextframe = argp;
}
}
return 1;
}
db_sym_t
db_frame_info(long *frame, db_addr_t callpc, const char **namep,
db_expr_t *offp, int *is_trap, int *nargp)
{
db_expr_t offset;
db_sym_t sym;
int narg;
const char *name;
sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
if (sym != DB_SYM_NULL && offset == 0) {
sym = db_search_symbol(callpc - 1, DB_STGY_ANY, &offset);
offset++;
}
db_symbol_values(sym, &name, NULL);
if (sym == DB_SYM_NULL)
return DB_SYM_NULL;
*is_trap = NONE;
narg = MAXNARG;
if (INKERNEL((int)frame) && name) {
if (!strcmp(name, "trap_tss")) {
*is_trap = TRAP_TSS;
narg = 0;
} else if (!strcmp(name, "trap")) {
*is_trap = TRAP;
narg = 0;
} else if (!strcmp(name, "syscall")) {
*is_trap = SYSCALL;
narg = 0;
} else if (name[0] == 'X') {
if (!strncmp(name, "Xintr", 5) ||
!strncmp(name, "Xresume", 7) ||
!strncmp(name, "Xstray", 6) ||
!strncmp(name, "Xhold", 5) ||
!strncmp(name, "Xrecurse", 8) ||
!strcmp(name, "Xdoreti")) {
*is_trap = INTERRUPT;
narg = 0;
} else if (!strcmp(name, "Xsoftintr")) {
*is_trap = SOFTINTR;
narg = 0;
} else if (!strncmp(name, "Xtss_", 5)) {
*is_trap = INTERRUPT_TSS;
narg = 0;
}
}
}
if (offp != NULL)
*offp = offset;
if (nargp != NULL)
*nargp = narg;
if (namep != NULL)
*namep = name;
return sym;
}
bool
db_intrstack_p(const void *vp)
{
struct cpu_info *ci;
const char *cp;
for (ci = db_cpu_first(); ci != NULL; ci = db_cpu_next(ci)) {
db_read_bytes((db_addr_t)&ci->ci_intrstack, sizeof(cp),
(char *)&cp);
if (cp == NULL) {
continue;
}
if ((cp - INTRSTACKSIZE + 4) <= (const char *)vp &&
(const char *)vp <= cp) {
return true;
}
}
return false;
}