Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/debug_monitor.c
Show All 38 Lines | |||||
#include <machine/armreg.h> | #include <machine/armreg.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/debug_monitor.h> | #include <machine/debug_monitor.h> | ||||
#include <machine/kdb.h> | #include <machine/kdb.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
#ifdef DDB | #ifdef DDB | ||||
#include <vm/vm.h> | |||||
#include <ddb/ddb.h> | #include <ddb/ddb.h> | ||||
#include <ddb/db_break.h> | |||||
#include <ddb/db_sym.h> | #include <ddb/db_sym.h> | ||||
#endif | #endif | ||||
enum dbg_t { | enum dbg_t { | ||||
DBG_TYPE_BREAKPOINT = 0, | DBG_TYPE_BREAKPOINT = 0, | ||||
DBG_TYPE_WATCHPOINT = 1, | DBG_TYPE_WATCHPOINT = 1, | ||||
}; | }; | ||||
static int dbg_watchpoint_num; | static int dbg_watchpoint_num; | ||||
static int dbg_breakpoint_num; | static int dbg_breakpoint_num; | ||||
static struct debug_monitor_state kernel_monitor = { | static struct debug_monitor_state kernel_monitor = { | ||||
.dbg_flags = DBGMON_KERNEL | .dbg_flags = DBGMON_KERNEL | ||||
}; | }; | ||||
static int dbg_setup_breakpoint(struct debug_monitor_state *monitor, | |||||
vm_offset_t addr); | |||||
static int dbg_remove_breakpoint(struct debug_monitor_state *monitor, | |||||
vm_offset_t addr); | |||||
static int dbg_setup_watchpoint(struct debug_monitor_state *, vm_offset_t, | static int dbg_setup_watchpoint(struct debug_monitor_state *, vm_offset_t, | ||||
vm_size_t, enum dbg_access_t); | vm_size_t, enum dbg_access_t); | ||||
static int dbg_remove_watchpoint(struct debug_monitor_state *, vm_offset_t, | static int dbg_remove_watchpoint(struct debug_monitor_state *, vm_offset_t, | ||||
vm_size_t); | vm_size_t); | ||||
/* Called from the exception handlers */ | /* Called from the exception handlers */ | ||||
void dbg_monitor_enter(struct thread *); | void dbg_monitor_enter(struct thread *); | ||||
void dbg_monitor_exit(struct thread *, struct trapframe *); | void dbg_monitor_exit(struct thread *, struct trapframe *); | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | dbg_wb_write_reg(int reg, int n, uint64_t val) | ||||
default: | default: | ||||
printf("trying to write to wrong debug register %d\n", n); | printf("trying to write to wrong debug register %d\n", n); | ||||
return; | return; | ||||
} | } | ||||
isb(); | isb(); | ||||
} | } | ||||
#if defined(DDB) || defined(GDB) | #if defined(DDB) || defined(GDB) | ||||
int | |||||
kdb_cpu_set_breakpoint(vm_offset_t addr) | |||||
{ | |||||
return (dbg_setup_breakpoint(NULL, addr)); | |||||
} | |||||
int | |||||
kdb_cpu_clr_breakpoint(vm_offset_t addr) | |||||
{ | |||||
return (dbg_remove_breakpoint(NULL, addr)); | |||||
} | |||||
void | void | ||||
kdb_cpu_set_singlestep(void) | kdb_cpu_set_singlestep(void) | ||||
{ | { | ||||
KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D, | KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D, | ||||
("%s: debug exceptions are not masked", __func__)); | ("%s: debug exceptions are not masked", __func__)); | ||||
kdb_frame->tf_spsr |= PSR_SS; | kdb_frame->tf_spsr |= PSR_SS; | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size) | kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size) | ||||
{ | { | ||||
return (dbg_remove_watchpoint(NULL, addr, size)); | return (dbg_remove_watchpoint(NULL, addr, size)); | ||||
} | } | ||||
#endif /* DDB || GDB */ | #endif /* DDB || GDB */ | ||||
#ifdef DDB | #ifdef DDB | ||||
void | |||||
dbg_show_breakpoint(void) | |||||
{ | |||||
db_breakpoint_t bkpt; | |||||
uint32_t bcr; | |||||
uint64_t addr; | |||||
int i; | |||||
db_printf("\nhardware breakpoints:\n"); | |||||
db_printf(" break status count address symbol\n"); | |||||
db_printf(" ----- -------- ----- ------------------ ------------------\n"); | |||||
for (i = 0; i < dbg_breakpoint_num; i++) { | |||||
bcr = dbg_wb_read_reg(DBG_REG_BASE_BCR, i); | |||||
if ((bcr & DBG_WB_CTRL_E) != 0) { | |||||
addr = dbg_wb_read_reg(DBG_REG_BASE_BVR, i); | |||||
bkpt = db_find_breakpoint_here(addr); | |||||
db_printf(" %-5d %-8s %-5d 0x%16lx ", | |||||
i, "enabled", bkpt == NULL ? -1 : bkpt->count, | |||||
addr); | |||||
db_printsym((db_addr_t)addr, DB_STGY_ANY); | |||||
db_printf("\n"); | |||||
} else { | |||||
db_printf(" %-5d disabled\n", i); | |||||
} | |||||
} | |||||
} | |||||
static const char * | static const char * | ||||
dbg_watchtype_str(uint32_t type) | dbg_watchtype_str(uint32_t type) | ||||
{ | { | ||||
switch (type) { | switch (type) { | ||||
case DBG_WATCH_CTRL_EXEC: | case DBG_WATCH_CTRL_EXEC: | ||||
return ("execute"); | return ("execute"); | ||||
case DBG_WATCH_CTRL_STORE: | case DBG_WATCH_CTRL_STORE: | ||||
return ("write"); | return ("write"); | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type, | ||||
for (i = 0; i < max; i++) { | for (i = 0; i < max; i++) { | ||||
if (reg_addr[i] == addr && | if (reg_addr[i] == addr && | ||||
(reg_ctrl[i] & DBG_WB_CTRL_E) != 0) | (reg_ctrl[i] & DBG_WB_CTRL_E) != 0) | ||||
return (i); | return (i); | ||||
} | } | ||||
return (-1); | return (-1); | ||||
} | |||||
static int | |||||
dbg_setup_breakpoint(struct debug_monitor_state *monitor, vm_offset_t addr) | |||||
{ | |||||
uint64_t bcr_priv; | |||||
u_int i; | |||||
if (monitor == NULL) | |||||
monitor = &kernel_monitor; | |||||
i = dbg_find_free_slot(monitor, DBG_TYPE_BREAKPOINT); | |||||
if (i == -1) { | |||||
printf("Can not find slot for breakpoint, max %d" | |||||
" breakpoints supported\n", dbg_breakpoint_num); | |||||
return (EBUSY); | |||||
} | |||||
if ((monitor->dbg_flags & DBGMON_KERNEL) == 0) | |||||
bcr_priv = DBG_WB_CTRL_EL0; | |||||
else | |||||
bcr_priv = DBG_WB_CTRL_EL1; | |||||
monitor->dbg_bvr[i] = addr; | |||||
monitor->dbg_bcr[i] = (0xf << 5) | bcr_priv | DBG_WB_CTRL_E; | |||||
monitor->dbg_enable_count++; | |||||
monitor->dbg_flags |= DBGMON_ENABLED; | |||||
dbg_register_sync(monitor); | |||||
return (0); | |||||
} | |||||
static int | |||||
dbg_remove_breakpoint(struct debug_monitor_state *monitor, vm_offset_t addr) | |||||
{ | |||||
u_int i; | |||||
if (monitor == NULL) | |||||
monitor = &kernel_monitor; | |||||
i = dbg_find_slot(monitor, DBG_TYPE_BREAKPOINT, addr); | |||||
if (i == -1) { | |||||
printf("Can not find breakpoint for address 0%lx\n", addr); | |||||
return (i); | |||||
} | |||||
monitor->dbg_bvr[i] = 0; | |||||
monitor->dbg_bcr[i] = 0; | |||||
monitor->dbg_enable_count--; | |||||
if (monitor->dbg_enable_count == 0) | |||||
monitor->dbg_flags &= ~DBGMON_ENABLED; | |||||
dbg_register_sync(monitor); | |||||
return (0); | |||||
} | } | ||||
static int | static int | ||||
dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr, | dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr, | ||||
vm_size_t size, enum dbg_access_t access) | vm_size_t size, enum dbg_access_t access) | ||||
{ | { | ||||
uint64_t wcr_size, wcr_priv, wcr_access; | uint64_t wcr_size, wcr_priv, wcr_access; | ||||
u_int i; | u_int i; | ||||
▲ Show 20 Lines • Show All 216 Lines • Show Last 20 Lines |