summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/alpha/alpha/db_instruction.h7
-rw-r--r--sys/alpha/alpha/db_trace.c93
-rw-r--r--sys/alpha/alpha/swtch.s6
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)
OpenPOWER on IntegriCloud