diff options
-rw-r--r-- | sys/alpha/alpha/db_instruction.h | 7 | ||||
-rw-r--r-- | sys/alpha/alpha/db_trace.c | 93 | ||||
-rw-r--r-- | sys/alpha/alpha/swtch.s | 6 |
3 files changed, 99 insertions, 7 deletions
diff --git a/sys/alpha/alpha/db_instruction.h b/sys/alpha/alpha/db_instruction.h index 54d9d11..00c2d23 100644 --- a/sys/alpha/alpha/db_instruction.h +++ b/sys/alpha/alpha/db_instruction.h @@ -97,6 +97,13 @@ typedef union { } jump_format; + struct { + signed int offset : 16; + unsigned rb : 5; + unsigned ra : 5; + unsigned opcode : 6; + } memory_format; + /* * Operate instructions are of two types, with * a second source register or with a literal diff --git a/sys/alpha/alpha/db_trace.c b/sys/alpha/alpha/db_trace.c index 944e171..fd59343 100644 --- a/sys/alpha/alpha/db_trace.c +++ b/sys/alpha/alpha/db_trace.c @@ -13,13 +13,94 @@ #include <ddb/db_access.h> #include <ddb/db_variables.h> #include <ddb/db_output.h> +#include <alpha/alpha/db_instruction.h> + +struct alpha_proc { + int pcreg; /* index of return pc register */ + int frame_size; /* size of stack frame */ + u_int32_t reg_mask; + int regs[32]; /* offsets from sp to saved regs */ +}; + +static void +parse_proc(db_expr_t addr, struct alpha_proc* frame) +{ + db_sym_t sym; + db_expr_t func; + db_expr_t junk, pc, limit; + int frame_size; + int reg_mask; + int got_frame; + + frame->pcreg = -1; + frame->reg_mask = 0; + frame->frame_size = 0; + + sym = db_search_symbol(addr, DB_STGY_PROC, &junk); + if (!sym) + return; + db_symbol_values(sym, 0, &func); + + pc = func; + limit = addr; + if (limit - pc > 200) + limit = pc + 200; + for (; pc < limit; pc += 4) { + alpha_instruction ins; + ins.bits = *(u_int32_t*) pc; + if (ins.memory_format.opcode == op_lda + && ins.memory_format.ra == 30) { + frame->frame_size += -ins.memory_format.offset; + } else if (ins.memory_format.opcode == op_stq + && ins.memory_format.rb == 30 + && ins.memory_format.ra != 31) { + int reg = ins.memory_format.ra; + frame->reg_mask |= 1 << reg; + frame->regs[reg] = ins.memory_format.offset; + if (frame->pcreg == -1 && reg == 26) + frame->pcreg = reg; + } + } +} void -db_stack_trace_cmd(addr, have_addr, count, modif) - db_expr_t addr; - boolean_t have_addr; - db_expr_t count; - char *modif; +db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif) { - /* nothing, yet. */ + struct alpha_proc proc; + db_addr_t callpc; + db_addr_t frame; + + if (count == -1) + count = 65535; + + if (!have_addr) { + frame = (db_addr_t) ddb_regs.tf_regs[FRAME_SP]; + callpc = (db_addr_t)ddb_regs.tf_regs[FRAME_PC]; + } else { + frame = (db_addr_t)addr; + callpc = (db_addr_t)db_get_value(frame, 8, FALSE); + } + + while (count--) { + u_int64_t *actframe; + char * name; + db_expr_t offset; + db_sym_t sym; + struct alpha_proc proc; + + sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); + db_symbol_values(sym, &name, NULL); + + db_printf("%s() at ", name); + db_printsym(callpc, DB_STGY_PROC); + db_printf("\n"); + + parse_proc(callpc, &proc); + + if (proc.pcreg == -1) + break; + + callpc = db_get_value(frame + proc.regs[proc.pcreg], 8, FALSE); + frame = frame + proc.frame_size; + } } diff --git a/sys/alpha/alpha/swtch.s b/sys/alpha/alpha/swtch.s index 018e429..712b921 100644 --- a/sys/alpha/alpha/swtch.s +++ b/sys/alpha/alpha/swtch.s @@ -1,4 +1,4 @@ -/* $Id: swtch.s,v 1.1 1998/06/10 10:53:23 dfr Exp $ */ +/* $Id: swtch.s,v 1.2 1998/06/11 11:51:26 dfr Exp $ */ /* $NetBSD: locore.s,v 1.47 1998/03/22 07:26:32 thorpej Exp $ */ /* @@ -356,6 +356,10 @@ LEAF(exception_save_regs, 0) stq t10,(FRAME_T10*8)(sp) stq t11,(FRAME_T11*8)(sp) stq t12,(FRAME_T12*8)(sp) + .set noat + lda at_reg,(FRAME_SIZE*8)(sp) + stq at_reg,(FRAME_SP*8)(sp) + .set at RET END(exception_save_regs) |