Fix pieces of aarch64 ddb support: kernel vs user mode detection implement (optimize) 8 byte reads cast address pointers to vaddr_t, not uint32_t (do not truncate) remove db_fetch_reg(), not used by OpenBSD implement ddb backtrace
note that "ddb> trace <address>" expects a stack address, not a frame pointer address. These two addresses are offset by 16 bytes (frame = *(sp+16)) diff --git a/sys/arch/arm64/arm64/db_interface.c b/sys/arch/arm64/arm64/db_interface.c index 440a29729fb..82cf76de4fc 100644 --- a/sys/arch/arm64/arm64/db_interface.c +++ b/sys/arch/arm64/arm64/db_interface.c @@ -60,7 +60,7 @@ int db_access_abt_sp (struct db_variable *, db_expr_t *, int); int db_access_irq_sp (struct db_variable *, db_expr_t *, int); u_int db_fetch_reg (int, db_regs_t *); -int db_trapper (u_int, u_int, trapframe_t *, int); +int db_trapper (vaddr_t, u_int, trapframe_t *, int); struct db_variable db_regs[] = { { "x0", (long *)&DDB_REGS->tf_x[0], FCN_NULL, }, @@ -146,6 +146,8 @@ kdb_trap(int type, db_regs_t *regs) #endif +#define INKERNEL(va) (((vaddr_t)(va)) & (1ULL << 63)) + static int db_validate_address(vaddr_t addr); static int @@ -155,12 +157,7 @@ db_validate_address(vaddr_t addr) struct pmap *pmap; if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || -#ifndef ARM32_NEW_VM_LAYOUT - addr >= VM_MAXUSER_ADDRESS -#else - addr >= VM_MIN_KERNEL_ADDRESS -#endif - ) + INKERNEL(addr)) pmap = pmap_kernel(); else pmap = p->p_vmspace->vm_map.pmap; @@ -179,23 +176,28 @@ db_read_bytes(addr, size, data) { char *src = (char *)addr; - if (db_validate_address((u_int)src)) { + if (db_validate_address((vaddr_t)src)) { db_printf("address %p is invalid\n", src); return; } - if (size == 4 && (addr & 3) == 0 && ((u_int32_t)data & 3) == 0) { + if (size == 8 && (addr & 7) == 0 && ((vaddr_t)data & 7) == 0) { + *((uint64_t*)data) = *((uint64_t*)src); + return; + } + + if (size == 4 && (addr & 3) == 0 && ((vaddr_t)data & 3) == 0) { *((int*)data) = *((int*)src); return; } - if (size == 2 && (addr & 1) == 0 && ((u_int32_t)data & 1) == 0) { + if (size == 2 && (addr & 1) == 0 && ((vaddr_t)data & 1) == 0) { *((short*)data) = *((short*)src); return; } while (size-- > 0) { - if (db_validate_address((u_int)src)) { + if (db_validate_address((vaddr_t)src)) { db_printf("address %p is invalid\n", src); return; } @@ -233,7 +235,7 @@ db_write_bytes(vaddr_t addr, size_t size, char *data) dst = (char *)addr; loop = size; while (loop-- > 0) { - if (db_validate_address((u_int)dst)) { + if (db_validate_address((vaddr_t)dst)) { db_printf("address %p is invalid\n", dst); return; } @@ -259,7 +261,7 @@ struct db_command db_machine_command_table[] = { }; int -db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code) +db_trapper(vaddr_t addr, u_int inst, trapframe_t *frame, int fault_code) { if (fault_code == EXCP_BRK) { @@ -270,8 +272,8 @@ db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code) return (0); } -extern u_int esym; -extern u_int end; +extern vaddr_t esym; +extern vaddr_t end; void db_machine_init(void) @@ -286,84 +288,6 @@ db_machine_init(void) db_machine_commands_install(db_machine_command_table); } -u_int -db_fetch_reg(int reg, db_regs_t *db_regs) -{ - - switch (reg) { - case 0: - return (db_regs->tf_x[0]); - case 1: - return (db_regs->tf_x[1]); - case 2: - return (db_regs->tf_x[2]); - case 3: - return (db_regs->tf_x[3]); - case 4: - return (db_regs->tf_x[4]); - case 5: - return (db_regs->tf_x[5]); - case 6: - return (db_regs->tf_x[6]); - case 7: - return (db_regs->tf_x[7]); - case 8: - return (db_regs->tf_x[8]); - case 9: - return (db_regs->tf_x[9]); - case 10: - return (db_regs->tf_x[10]); - case 11: - return (db_regs->tf_x[11]); - case 12: - return (db_regs->tf_x[12]); - case 13: - return (db_regs->tf_x[13]); - case 14: - return (db_regs->tf_x[14]); - case 15: - return (db_regs->tf_x[15]); - case 16: - return (db_regs->tf_x[16]); - case 17: - return (db_regs->tf_x[17]); - case 18: - return (db_regs->tf_x[18]); - case 19: - return (db_regs->tf_x[19]); - case 20: - return (db_regs->tf_x[20]); - case 21: - return (db_regs->tf_x[21]); - case 22: - return (db_regs->tf_x[22]); - case 23: - return (db_regs->tf_x[23]); - case 24: - return (db_regs->tf_x[24]); - case 25: - return (db_regs->tf_x[25]); - case 26: - return (db_regs->tf_x[26]); - case 27: - return (db_regs->tf_x[27]); - case 28: - return (db_regs->tf_x[28]); - case 29: - return (db_regs->tf_x[29]); - case 30: - return (db_regs->tf_lr); - case 31: - return (db_regs->tf_sp); - case 32: - return (db_regs->tf_elr); - case 33: - return (db_regs->tf_spsr); - default: - panic("db_fetch_reg: botch"); - } -} - db_addr_t db_branch_taken(u_int insn, db_addr_t pc, db_regs_t *db_regs) { diff --git a/sys/arch/arm64/arm64/db_trace.c b/sys/arch/arm64/arm64/db_trace.c index 3c22bf81af7..8c61d893b5c 100644 --- a/sys/arch/arm64/arm64/db_trace.c +++ b/sys/arch/arm64/arm64/db_trace.c @@ -39,12 +39,13 @@ #include <ddb/db_access.h> #include <ddb/db_interface.h> +#include <ddb/db_variables.h> #include <ddb/db_sym.h> #include <ddb/db_output.h> db_regs_t ddb_regs; -#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) +#define INKERNEL(va) (((vaddr_t)(va)) & (1ULL << 63)) #ifndef __clang__ /* @@ -55,19 +56,21 @@ db_regs_t ddb_regs; * */ #define FR_RFP (0x0) -#define FR_RLV (+0x4) +#define FR_RLV (0x4) #endif /* !__clang__ */ void db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, char *modif, int (*pr)(const char *, ...)) { - u_int32_t frame, lastframe; + u_int64_t frame, lastframe, lr, lastlr, sp; char c, *cp = modif; + db_expr_t offset; + db_sym_t sym; + char *name; boolean_t kernel_only = TRUE; boolean_t trace_thread = FALSE; //db_addr_t scp = 0; - int scp_offset; while ((c = *cp++) != 0) { if (c == 'u') @@ -77,18 +80,71 @@ db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, } if (!have_addr) { - // Implement - frame = 0; + sp = ddb_regs.tf_sp; + lr = ddb_regs.tf_lr; + lastlr = ddb_regs.tf_elr; + frame = ddb_regs.tf_x[29]; } else { - // Implement - frame = 0; + if (trace_thread) { + struct proc *p = tfind((pid_t)addr); + if (p == NULL) { + (*pr) ("not found\n"); + return; + } + frame = p->p_addr->u_pcb.pcb_tf->tf_x[29]; + sp = p->p_addr->u_pcb.pcb_tf->tf_sp; + lr = p->p_addr->u_pcb.pcb_tf->tf_lr; + lastlr = p->p_addr->u_pcb.pcb_tf->tf_elr; + } else { + sp = addr; + db_read_bytes(sp+16, sizeof(db_addr_t), + (char *)&frame); + db_read_bytes(sp + 8, sizeof(db_addr_t), + (char *)&lr); + lastlr = 0; + } } - lastframe = 0; - //scp_offset = -get_pc_str_offset(); - scp_offset = -4; while (count-- && frame != 0) { - break; - // Implement + lastframe = frame; + + sym = db_search_symbol(lastlr, DB_STGY_ANY, &offset); + db_symbol_values(sym, &name, NULL); + + if (name == NULL || strcmp(name, "end") == 0) { + (*pr)("%llx at 0x%lx", lastlr, lr - 4); + } else { + (*pr)("%s() at ", name); + db_printsym(lr - 4, DB_STGY_PROC, pr); + } + (*pr)("\n"); + + // can we detect traps ? + db_read_bytes(frame, sizeof(db_addr_t), (char *)&frame); + if (frame == 0) + break; + lastlr = lr; + db_read_bytes(frame + 8, sizeof(db_addr_t), (char *)&lr); + + if (name != NULL) { + if ((strcmp (name, "handle_el0_irq") == 0) || + (strcmp (name, "handle_el1_irq") == 0)) { + (*pr)("--- interrupt ---\n"); + } else if ( + (strcmp (name, "handle_el0_sync") == 0) || + (strcmp (name, "handle_el1_sync") == 0)) { + (*pr)("--- trap ---\n"); + } + } + if (INKERNEL(frame)) { + if (frame <= lastframe) { + (*pr)("Bad frame pointer: 0x%lx\n", frame); + break; + } + } else { + if (kernel_only) + break; + } + --count; } } Dale Rahn dr...@dalerahn.com