/* $NetBSD: db_trace.c,v 1.5 2016/07/31 19:10:54 dholland Exp $ */ /* Inspired by reading alpha/db_trace.c */ /*- * Copyright (c) 2006 The NetBSD Foundation, Inc. * All rights reserved. * * Author: Cherry G. Mathew * * 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. * * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if 0 #define UNWIND_DIAGNOSTIC #endif #define debug_frame_dump_XXX(uwf) \ printf("Frame Dump: \n bsp = 0x%lx \n pfs = 0x%lx, SOL(pfs) = %lu \n rp = 0x%lx \n", \ uwf->bsp, uwf->pfs, IA64_CFM_SOL(uwf->pfs), uwf->rp); \ void initunwindframe(struct unwind_frame *uwf, struct trapframe *tf); void rewindframe(struct unwind_frame *uwf, db_addr_t ip); void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { char c; const char *cp = modif; bool trace_thread = false; bool trace_user = false; struct trapframe *tf; struct unwind_frame current_frame; db_addr_t ip; const char *name; db_sym_t sym; db_expr_t offset; while ((c = *cp++) != 0) { trace_thread |= c == 't'; trace_user |= c == 'u'; } if (trace_user) { (*pr)("User-space stack tracing not implemented yet. \n"); return; } if (!have_addr) { (*pr)("--Kernel Call Trace-- \n"); tf = DDB_REGS; ip = tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3); initunwindframe(¤t_frame, tf); #ifdef UNWIND_DIAGNOSTIC struct unwind_frame *uwf = ¤t_frame; debug_frame_dump_XXX(uwf); #endif KASSERT(ip >= kernstart); patchunwindframe(¤t_frame, ip - kernstart, kernstart); #ifdef UNWIND_DIAGNOSTIC debug_frame_dump_XXX(uwf); #endif /* Get into unwind loop. */ while(ip) { sym = db_search_symbol(ip, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); (*pr)("%s(...)\n", name); ip = current_frame.rp; if(!ip) break; rewindframe(¤t_frame, ip); } return; } else (*pr) ("Unwind from arbitrary addresses unimplemented. \n"); if (trace_thread) { (*pr)("trace by pid unimplemented. \n"); return; } else { (*pr)("trace from arbitrary trap frame address unimplemented. \n"); } } extern db_addr_t ia64_unwindtab; extern vsize_t ia64_unwindtablen; /* Generates initial unwind frame context based on the contents * of the trap frame, by consulting the Unwind library * staterecord. If a register is of type enum UNSAVED, we fetch * the live value of the register from the trapframe. */ void initunwindframe(struct unwind_frame *uwf, struct trapframe *tf) { uwf->rp = tf->tf_special.rp; /* ndirty = bsp - bspstore: , not the same as the definition in the spec. * Gave me hell for a day! * see: ia64/exception.S: exception_save_restore: */ uwf->bsp = tf->tf_special.bspstore + tf->tf_special.ndirty; uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOF(tf->tf_special.cfm)); #ifdef UNWIND_DIAGNOSTIC printf("inituwframe(): SOF(cfm) = %lu \n", IA64_CFM_SOF(tf->tf_special.cfm)); #endif uwf->pfs = tf->tf_special.pfs; uwf->sp = uwf->psp = tf->tf_special.sp; } /* Single step the frame backward. * Assumes unwind_frame is setup already. */ void rewindframe(struct unwind_frame *uwf, db_addr_t ip) { /* XXX: Check for a stack switch */ uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOL(uwf->pfs)); uwf->sp = uwf->psp; /* Pre-stomp frame dump */ #ifdef UNWIND_DIAGNOSTIC debug_frame_dump_XXX(uwf); #endif /* Stomp on rp and pfs */ KASSERT(ip >= kernstart); patchunwindframe(uwf, ip - kernstart, kernstart); #ifdef UNWIND_DIAGNOSTIC debug_frame_dump_XXX(uwf); #endif }