aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/alpha/alpha/db_trace.c378
-rw-r--r--sys/alpha/alpha/exception.s12
-rw-r--r--sys/alpha/include/asm.h4
3 files changed, 325 insertions, 69 deletions
diff --git a/sys/alpha/alpha/db_trace.c b/sys/alpha/alpha/db_trace.c
index 2df25c15678cb..a459b5c1ebf18 100644
--- a/sys/alpha/alpha/db_trace.c
+++ b/sys/alpha/alpha/db_trace.c
@@ -1,14 +1,58 @@
/* $FreeBSD$ */
-/* $NetBSD: db_trace.c,v 1.1 1997/09/06 02:00:50 thorpej Exp $ */
+/* $NetBSD: db_trace.c,v 1.9 2000/12/13 03:16:36 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ross Harvey.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
-/* __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.1 1997/09/06 02:00:50 thorpej Exp $"); */
+/*__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.9 2000/12/13 03:16:36 mycroft Exp $");*/
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/sysent.h>
#include <machine/db_machdep.h>
+
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
#include <ddb/db_access.h>
@@ -16,93 +60,305 @@
#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 */
+/*
+ * Information about the `standard' Alpha function prologue.
+ */
+struct prologue_info {
+ int pi_reg_offset[32]; /* offset of registers in stack frame */
+ u_int32_t pi_regmask; /* which registers are in frame */
+ int pi_frame_size; /* frame size */
+};
+
+/*
+ * We use several symbols to take special action:
+ *
+ * Trap vectors, which use a different (fixed-size) stack frame:
+ *
+ * XentArith
+ * XentIF
+ * XentInt
+ * XentMM
+ * XentSys
+ * XentUna
+ */
+
+static struct special_symbol {
+ uintptr_t ss_val;
+ const char *ss_note;
+} special_symbols[] = {
+ { (uintptr_t)&XentArith, "arithmetic trap" },
+ { (uintptr_t)&XentIF, "instruction fault" },
+ { (uintptr_t)&XentInt, "interrupt" },
+ { (uintptr_t)&XentMM, "memory management fault" },
+ { (uintptr_t)&XentSys, "syscall" },
+ { (uintptr_t)&XentUna, "unaligned access fault" },
+ { (uintptr_t)&XentRestart, "console restart" },
+ { NULL }
};
+/*
+ * Decode the function prologue for the function we're in, and note
+ * which registers are stored where, and how large the stack frame is.
+ */
static void
-parse_proc(db_expr_t addr, struct alpha_proc* frame)
+decode_prologue(db_addr_t callpc, db_addr_t func,
+ struct prologue_info *pi)
{
- c_db_sym_t sym;
- db_expr_t func;
- db_expr_t junk, pc, limit;
+ long signed_immediate;
+ alpha_instruction ins;
+ db_expr_t pc;
- frame->pcreg = -1;
- frame->reg_mask = 0;
- frame->frame_size = 0;
+ pi->pi_regmask = 0;
+ pi->pi_frame_size = 0;
- sym = db_search_symbol(addr, DB_STGY_PROC, &junk);
- if (!sym)
- return;
- db_symbol_values(sym, 0, &func);
+#define CHECK_FRAMESIZE \
+do { \
+ if (pi->pi_frame_size != 0) { \
+ printf("frame size botch: adjust register offsets?\n"); \
+ } \
+} while (0)
- 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) {
- /* gcc 2.7 */
- frame->frame_size += -ins.memory_format.offset;
- } else if (ins.operate_lit_format.opcode == op_arit
- && ins.operate_lit_format.function == op_subq
- && ins.operate_lit_format.rs == 30) {
- /* egcs */
- frame->frame_size += ins.operate_lit_format.literal;
- } 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;
+ for (pc = func; pc < callpc; pc += sizeof(alpha_instruction)) {
+ ins.bits = *(unsigned int *)pc;
+
+ if (ins.memory_format.opcode == op_lda &&
+ ins.memory_format.ra == 30 &&
+ ins.memory_format.rb == 30) {
+ /*
+ * GCC 2.7-style stack adjust:
+ *
+ * lda sp, -64(sp)
+ */
+ signed_immediate = (long)ins.mem_format.displacement;
+#if 1
+ if (signed_immediate > 0)
+ printf("prologue botch: displacement %ld\n",
+ signed_immediate);
+#endif
+ CHECK_FRAMESIZE;
+ pi->pi_frame_size += -signed_immediate;
+ } else if (ins.operate_lit_format.opcode == op_arit &&
+ ins.operate_lit_format.function == op_subq &&
+ ins.operate_lit_format.rs == 30 &&
+ ins.operate_lit_format.rd == 30) {
+ /*
+ * EGCS-style stack adjust:
+ *
+ * subq sp, 64, sp
+ */
+ CHECK_FRAMESIZE;
+ pi->pi_frame_size += ins.operate_lit_format.literal;
+ } else if (ins.mem_format.opcode == op_stq &&
+ ins.mem_format.rs == 30 &&
+ ins.mem_format.rd != 31) {
+ /* Store of (non-zero) register onto the stack. */
+ signed_immediate = (long)ins.mem_format.displacement;
+ pi->pi_regmask |= 1 << ins.mem_format.rd;
+ pi->pi_reg_offset[ins.mem_format.rd] = signed_immediate;
}
}
}
+static int
+sym_is_trapsymbol(uintptr_t v)
+{
+ int i;
+
+ for (i = 0; special_symbols[i].ss_val != NULL; ++i)
+ if (v == special_symbols[i].ss_val)
+ return 1;
+ return 0;
+}
+
+static void
+decode_syscall(int number, struct proc *p)
+{
+ c_db_sym_t sym;
+ db_expr_t diff;
+ sy_call_t *f;
+ const char *symname;
+
+ printf(" (%d", number);
+ if (!p)
+ goto out;
+
+ if (0 <= number && number < p->p_sysent->sv_size) {
+
+ f = p->p_sysent->sv_table[number].sy_call;
+ sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
+ if (sym == DB_SYM_NULL || diff != 0)
+ goto out;
+ db_symbol_values(sym, &symname, NULL);
+ printf(", %s, %s", p->p_sysent->sv_name, symname);
+ }
+ out:
+ printf(")");
+
+}
+
void
db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif)
{
- db_addr_t callpc;
- db_addr_t frame;
+ db_addr_t callpc = 0, frame = 0, symval;
+ struct prologue_info pi;
+ db_expr_t diff;
+ c_db_sym_t sym;
+ int i;
+ u_long tfps;
+ const char *symname;
+ struct pcb *pcbp;
+ char c, *cp = modif;
+ struct trapframe *tf = NULL;
+ boolean_t ra_from_tf = FALSE;
+ boolean_t ra_from_pcb;
+ u_long last_ipl = ~0L;
+ struct proc *p = NULL;
+ boolean_t trace_thread = FALSE;
+ boolean_t have_trapframe = FALSE;
+
+ while ((c = *cp++) != 0)
+ trace_thread |= c == 't';
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];
+ p = curproc;
+ addr = DDB_REGS->tf_regs[FRAME_SP] - FRAME_SIZE * 8;
+ tf = (struct trapframe *)addr;
+ have_trapframe = 1;
} else {
- frame = (db_addr_t)addr;
- callpc = (db_addr_t)db_get_value(frame, 8, FALSE);
+ if (trace_thread) {
+ printf("trace: pid %d ", (int)addr);
+ p = pfind(addr);
+ if (p == NULL) {
+ printf("not found\n");
+ return;
+ }
+ if ((p->p_sflag & PS_INMEM) == 0) {
+ printf("swapped out\n");
+ return;
+ }
+ pcbp = &p->p_addr->u_pcb;
+ addr = (db_expr_t)pcbp->pcb_hw.apcb_ksp;
+ callpc = pcbp->pcb_context[7];
+ printf("at 0x%lx\n", addr);
+ } else {
+ printf("alpha trace requires known PC =eject=\n");
+ return;
+ }
+ frame = addr;
}
while (count--) {
- const char * name;
- db_expr_t offset;
- c_db_sym_t sym;
- struct alpha_proc proc;
+ if (have_trapframe) {
+ frame = (db_addr_t)tf + FRAME_SIZE * 8;
+ callpc = tf->tf_regs[FRAME_PC];
+ ra_from_tf = TRUE;
+ have_trapframe = 0;
+ }
+ sym = db_search_symbol(callpc, DB_STGY_ANY, &diff);
+ if (sym == DB_SYM_NULL)
+ break;
- sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
- db_symbol_values(sym, &name, NULL);
+ db_symbol_values(sym, &symname, (db_expr_t *)&symval);
+
+ if (callpc < symval) {
+ printf("symbol botch: callpc 0x%lx < "
+ "func 0x%lx (%s)\n", callpc, symval, symname);
+ return;
+ }
- db_printf("%s() at ", name);
+ /*
+ * XXX Printing out arguments is Hard. We'd have to
+ * keep lots of state as we traverse the frame, figuring
+ * out where the arguments to the function are stored
+ * on the stack.
+ *
+ * Even worse, they may be stored to the stack _after_
+ * being modified in place; arguments are passed in
+ * registers.
+ *
+ * So, in order for this to work reliably, we pretty much
+ * have to have a kernel built with `cc -g':
+ *
+ * - The debugging symbols would tell us where the
+ * arguments are, how many there are, if there were
+ * any passed on the stack, etc.
+ *
+ * - Presumably, the compiler would be careful to
+ * store the argument registers on the stack before
+ * modifying the registers, so that a debugger could
+ * know what those values were upon procedure entry.
+ *
+ * Because of this, we don't bother. We've got most of the
+ * benefit of back tracking without the arguments, and we
+ * could get the arguments if we use a remote source-level
+ * debugger (for serious debugging).
+ */
+ printf("%s() at ", symname);
db_printsym(callpc, DB_STGY_PROC);
- db_printf("\n");
+ printf("\n");
- parse_proc(callpc, &proc);
+ /*
+ * If we are in a trap vector, frame points to a
+ * trapframe.
+ */
+ if (sym_is_trapsymbol(symval)) {
+ tf = (struct trapframe *)frame;
- if (proc.pcreg == -1)
- break;
+ for (i = 0; special_symbols[i].ss_val != NULL; ++i)
+ if (symval == special_symbols[i].ss_val)
+ printf("--- %s",
+ special_symbols[i].ss_note);
+
+ tfps = tf->tf_regs[FRAME_PS];
+ if (symval == (uintptr_t)&XentSys)
+ decode_syscall(tf->tf_regs[FRAME_V0], p);
+ if ((tfps & ALPHA_PSL_IPL_MASK) != last_ipl) {
+ last_ipl = tfps & ALPHA_PSL_IPL_MASK;
+ if (symval != (uintptr_t)&XentSys)
+ printf(" (from ipl %ld)", last_ipl);
+ }
+ printf(" ---\n");
+ if (tfps & ALPHA_PSL_USERMODE) {
+ printf("--- user mode ---\n");
+ break; /* Terminate search. */
+ }
+ have_trapframe = 1;
+ continue;
+ }
- callpc = db_get_value(frame + proc.regs[proc.pcreg], 8, FALSE);
- frame = frame + proc.frame_size;
+ /*
+ * This is a bit trickier; we must decode the function
+ * prologue to find the saved RA.
+ *
+ * XXX How does this interact w/ alloca()?!
+ */
+ decode_prologue(callpc, symval, &pi);
+ if ((pi.pi_regmask & (1 << 26)) == 0) {
+ /*
+ * No saved RA found. We might have RA from
+ * the trap frame, however (e.g trap occurred
+ * in a leaf call). If not, we've found the
+ * root of the call graph.
+ */
+ if (ra_from_tf)
+ callpc = tf->tf_regs[FRAME_RA];
+ else {
+ printf("--- root of call graph ---\n");
+ break;
+ }
+ } else
+ callpc = *(u_long *)(frame + pi.pi_reg_offset[26]);
+ ra_from_tf = ra_from_pcb = FALSE;
+#if 0
+ /*
+ * The call was actually made at RA - 4; the PC is
+ * updated before being stored in RA.
+ */
+ callpc -= 4;
+#endif
+ frame += pi.pi_frame_size;
}
}
diff --git a/sys/alpha/alpha/exception.s b/sys/alpha/alpha/exception.s
index 31665c898e553..c7119b0d49f6b 100644
--- a/sys/alpha/alpha/exception.s
+++ b/sys/alpha/alpha/exception.s
@@ -125,8 +125,8 @@
/* syscall number, passed in v0, is first arg, frame pointer second */
mov v0,a0
mov sp,a1 ; .loc 1 __LINE__
- br pv,XentSys1
-XentSys1: LDGP(pv)
+ br pv,1f
+1: LDGP(pv)
CALL(syscall)
/* Handle any AST's. */
@@ -192,8 +192,8 @@ LEAF(XentUna, 3) /* XXX should be NESTED */
/* a0, a1, & a2 already set up */
ldiq a3, ALPHA_KENTRY_UNA
mov sp, a4 ; .loc 1 __LINE__
- br pv, XentUna1
-XentUna1: LDGP(pv)
+ br pv, 1f
+1: LDGP(pv)
CALL(trap)
jmp zero, exception_return
@@ -236,8 +236,8 @@ LEAF(XentRestart, 1) /* XXX should be NESTED */
stq t12,(FRAME_T12*8)(sp)
stq ra,(FRAME_RA*8)(sp)
- br pv,LXconsole_restart1
-LXconsole_restart1: LDGP(pv)
+ br pv,1f
+1: LDGP(pv)
ldq a0,(FRAME_RA*8)(sp) /* a0 = ra */
ldq a1,(FRAME_T11*8)(sp) /* a1 = ai */
diff --git a/sys/alpha/include/asm.h b/sys/alpha/include/asm.h
index b6cc41ef83820..4a9963c5a40b9 100644
--- a/sys/alpha/include/asm.h
+++ b/sys/alpha/include/asm.h
@@ -256,8 +256,8 @@
#define PALVECT(_name_) \
ESETUP(_name_); \
ERSAVE(); \
- br pv, _name_##lgp; \
-_name_##lgp:; \
+ br pv, 1001f; \
+1001:; \
LDGP(pv)
#define ESETUP(_name_) \