/* $NetBSD: db_trace.c,v 1.2 2008/07/02 19:49:58 rmind Exp $ */ /* $OpenBSD: db_interface.c,v 1.16 2001/03/22 23:31:45 mickey Exp $ */ /* * Copyright (c) 1999-2000 Michael Shalayeff * All rights reserved. * * 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 Michael Shalayeff. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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> __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.2 2008/07/02 19:49:58 rmind Exp $"); #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/user.h> #include <machine/db_machdep.h> #include <ddb/db_access.h> #include <ddb/db_sym.h> #include <ddb/db_interface.h> void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { register_t *fp, pc, rp; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; db_sym_t sym; db_expr_t off; const char *name; const char *cp = modif; char c; if (count < 0) count = 65536; while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } if (!have_addr) { fp = (register_t *)ddb_regs.tf_r3; pc = ddb_regs.tf_iioq_head; rp = ddb_regs.tf_rp; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; if (p == curproc && l == curlwp) { fp = (int *)ddb_regs.tf_r3; pc = ddb_regs.tf_iioq_head; rp = ddb_regs.tf_rp; } else { /* cpu_switchto fp, and return point */ fp = (int *)(u->u_pcb.pcb_ksp - (HPPA_FRAME_SIZE + 16*4)); pc = 0; rp = fp[-5]; } (*pr)("at %p\n", fp); } else { pc = 0; fp = (register_t *)addr; rp = fp[-5]; } } while (fp && count--) { #ifdef DDB_DEBUG pr(">> %08x %08x %08x\t", fp, pc, rp); #endif if (USERMODE(pc)) return; sym = db_search_symbol(pc, DB_STGY_ANY, &off); db_symbol_values (sym, &name, NULL); pr("%s() at ", name); db_printsym(pc, DB_STGY_PROC, pr); pr("\n"); /* XXX NH - unwind info here */ /* aue = ue_find(pc); */ /* * get rp? * fp -= ue_total_frame_size(aue) */ /* * if a terminal frame then report the trapframe * and continue after it (if not the last one). */ if (!fp[0]) { register_t *scargs; struct trapframe *tf; int scoff; /* Stack space for syscall args */ scoff = HPPA_FRAME_ROUND(HPPA_FRAME_SIZE + HPPA_FRAME_MAXARGS); scargs = (register_t *)((char *)fp - scoff); tf = (struct trapframe *)((char *)scargs - sizeof(*tf)); if (tf->tf_flags & TFF_SYS) pr("-- syscall #%d(%x, %x, %x, %x, ...)\n", tf->tf_t1, scargs[1], scargs[2], scargs[3], scargs[4]); else pr("-- trap #%d%s\n", tf->tf_flags & 0x3f, (tf->tf_flags & T_USER)? " from user" : ""); if (!(tf->tf_flags & TFF_LAST)) { fp = (register_t *)tf->tf_r3; pc = tf->tf_iioq_head; rp = tf->tf_rp; } else { pc = 0; fp = 0; } } else { /* next frame */ fp = (register_t *)fp[0]; pc = rp; rp = fp[-5]; } } if (count && pc) { db_printsym(pc, DB_STGY_XTRN, pr); pr(":\n"); } }