summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgallatin <gallatin@FreeBSD.org>2001-06-08 13:38:02 +0000
committergallatin <gallatin@FreeBSD.org>2001-06-08 13:38:02 +0000
commitc107f3268b6b2bd96a4bea565df2d6a46d18282d (patch)
tree41777182f0bb40e515340aee00301b2f9eeffdaa
parent9079964eda336913df098484d0efe6facaeb8f6f (diff)
downloadFreeBSD-src-c107f3268b6b2bd96a4bea565df2d6a46d18282d.zip
FreeBSD-src-c107f3268b6b2bd96a4bea565df2d6a46d18282d.tar.gz
Sync up to v 1.9 of NetBSD's db_trace.c to get access to the
greatly improved traceback code from Ross Harvey. This code requires the use of more traceback friendly temporary labels at kernel entry points, hence the changes to exception.s and asm.h Reviewed by: jhb, dfr Obtained from: NetBSD MFC after: 1 week
-rw-r--r--sys/alpha/alpha/db_trace.c384
-rw-r--r--sys/alpha/alpha/exception.s12
-rw-r--r--sys/alpha/include/asm.h4
3 files changed, 328 insertions, 72 deletions
diff --git a/sys/alpha/alpha/db_trace.c b/sys/alpha/alpha/db_trace.c
index 2df25c1..a459b5c 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;
-
- 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) {
- /* 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;
+ long signed_immediate;
+ alpha_instruction ins;
+ db_expr_t pc;
+
+ pi->pi_regmask = 0;
+ pi->pi_frame_size = 0;
+
+#define CHECK_FRAMESIZE \
+do { \
+ if (pi->pi_frame_size != 0) { \
+ printf("frame size botch: adjust register offsets?\n"); \
+ } \
+} while (0)
+
+ 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;
+
+ db_symbol_values(sym, &symname, (db_expr_t *)&symval);
- sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
- db_symbol_values(sym, &name, NULL);
+ 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 31665c8..c7119b0 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 b6cc41e..4a9963c 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_) \
OpenPOWER on IntegriCloud