#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kgdb_machdep.c,v 1.6 2022/08/22 13:57:24 hannken Exp $");
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/kgdb.h>
#include <sys/systm.h>
#include <machine/pmap_private.h>
#include <machine/pte.h>
#include <machine/trap.h>
int
kgdb_acc(vaddr_t va, size_t len)
{
vaddr_t last_va;
pt_entry_t *pte;
last_va = va + len;
va &= ~PGOFSET;
last_va &= ~PGOFSET;
do {
if (va < VM_MIN_KERNEL_ADDRESS)
pte = vtopte(va);
else
pte = kvtopte(va);
if ((*pte & PTE_P) == 0)
return 0;
if (*pte & PTE_PS)
va = (va & PTE_LGFRAME) + NBPD_L2;
else
va += PAGE_SIZE;
} while (va < last_va);
return 1;
}
void
kgdb_entry_notice(int type, db_regs_t *regs)
{
if (type == T_NMI)
printf("NMI ... going to debugger\n");
}
int
kgdb_signal(int type)
{
switch (type) {
case T_NMI:
return SIGINT;
case T_ALIGNFLT:
return SIGILL;
case T_BPTFLT:
case T_TRCTRAP:
return SIGTRAP;
case T_ASTFLT:
case T_DOUBLEFLT:
return SIGEMT;
case T_ARITHTRAP:
case T_DIVIDE:
case T_OFLOW:
case T_DNA:
case T_FPOPFLT:
return SIGFPE;
case T_PRIVINFLT:
case T_PROTFLT:
case T_PAGEFLT:
case T_TSSFLT:
case T_SEGNPFLT:
case T_STKFLT:
return SIGSEGV;
case T_BOUND:
return SIGURG;
default:
return SIGEMT;
}
}
void
kgdb_getregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
{
#ifdef __x86_64__
gdb_regs[ 0] = regs->tf_rax;
gdb_regs[ 1] = regs->tf_rbx;
gdb_regs[ 2] = regs->tf_rcx;
gdb_regs[ 3] = regs->tf_rdx;
gdb_regs[ 4] = regs->tf_rsi;
gdb_regs[ 5] = regs->tf_rdi;
gdb_regs[ 6] = regs->tf_rbp;
gdb_regs[ 7] = regs->tf_rsp;
gdb_regs[ 8] = regs->tf_r8;
gdb_regs[ 9] = regs->tf_r9;
gdb_regs[10] = regs->tf_r10;
gdb_regs[11] = regs->tf_r11;
gdb_regs[12] = regs->tf_r12;
gdb_regs[13] = regs->tf_r13;
gdb_regs[14] = regs->tf_r14;
gdb_regs[15] = regs->tf_r15;
gdb_regs[16] = regs->tf_rip;
gdb_regs[17] = regs->tf_rflags;
gdb_regs[18] = regs->tf_cs;
gdb_regs[19] = regs->tf_ss;
#else
gdb_regs[ 0] = regs->tf_eax;
gdb_regs[ 1] = regs->tf_ecx;
gdb_regs[ 2] = regs->tf_edx;
gdb_regs[ 3] = regs->tf_ebx;
gdb_regs[ 5] = regs->tf_ebp;
gdb_regs[ 6] = regs->tf_esi;
gdb_regs[ 7] = regs->tf_edi;
gdb_regs[ 8] = regs->tf_eip;
gdb_regs[ 9] = regs->tf_eflags;
gdb_regs[10] = regs->tf_cs;
gdb_regs[12] = regs->tf_ds;
gdb_regs[13] = regs->tf_es;
gdb_regs[14] = regs->tf_fs;
gdb_regs[15] = regs->tf_gs;
if (KERNELMODE(regs->tf_cs)) {
gdb_regs[ 4] = (kgdb_reg_t)®s->tf_esp;
gdb_regs[11] = x86_getss();
}
#endif
}
void
kgdb_setregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
{
#ifdef __x86_64__
regs->tf_rax = gdb_regs[ 0];
regs->tf_rbx = gdb_regs[ 1];
regs->tf_rcx = gdb_regs[ 2];
regs->tf_rdx = gdb_regs[ 3];
regs->tf_rsi = gdb_regs[ 4];
regs->tf_rdi = gdb_regs[ 5];
regs->tf_rbp = gdb_regs[ 6];
regs->tf_rsp = gdb_regs[ 7];
regs->tf_r8 = gdb_regs[ 8];
regs->tf_r9 = gdb_regs[ 9];
regs->tf_r10 = gdb_regs[10];
regs->tf_r11 = gdb_regs[11];
regs->tf_r12 = gdb_regs[12];
regs->tf_r13 = gdb_regs[13];
regs->tf_r14 = gdb_regs[14];
regs->tf_r15 = gdb_regs[15];
regs->tf_rip = gdb_regs[16];
regs->tf_rflags = gdb_regs[17];
regs->tf_cs = gdb_regs[18];
regs->tf_ss = gdb_regs[19];
#else
regs->tf_eax = gdb_regs[ 0];
regs->tf_ecx = gdb_regs[ 1];
regs->tf_edx = gdb_regs[ 2];
regs->tf_ebx = gdb_regs[ 3];
regs->tf_ebp = gdb_regs[ 5];
regs->tf_esi = gdb_regs[ 6];
regs->tf_edi = gdb_regs[ 7];
regs->tf_eip = gdb_regs[ 8];
regs->tf_eflags = gdb_regs[ 9];
regs->tf_cs = gdb_regs[10];
regs->tf_ds = gdb_regs[12];
regs->tf_es = gdb_regs[13];
if (KERNELMODE(regs->tf_cs) == 0) {
regs->tf_esp = gdb_regs[ 4];
regs->tf_ss = gdb_regs[11];
}
#endif
}
void
kgdb_connect(int verbose)
{
if (kgdb_dev == NODEV)
return;
if (verbose)
printf("kgdb waiting...");
breakpoint();
if (verbose)
printf("connected.\n");
kgdb_debug_panic = 1;
}
void
kgdb_panic(void)
{
if (kgdb_dev != NODEV && kgdb_debug_panic) {
printf("entering kgdb\n");
kgdb_connect(kgdb_active == 0);
}
}