1/* $NetBSD: db_trace.c,v 1.6 2023/10/06 11:45:16 skrll Exp $ */ 2 3/* Inspired by reading alpha/db_trace.c */ 4 5/*- 6 * Copyright (c) 2006 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * Author: Cherry G. Mathew 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34#include "opt_ddb.h" 35 36#include <sys/param.h> 37#include <sys/proc.h> 38#include <sys/systm.h> 39 40#include <machine/cpufunc.h> 41#include <machine/md_var.h> 42#include <machine/db_machdep.h> 43 44#include <ddb/db_sym.h> 45#include <ddb/db_access.h> 46#include <ddb/db_output.h> 47#include <ddb/db_variables.h> 48#include <ddb/db_interface.h> 49 50#include <ia64/unwind/decode.h> 51#include <ia64/unwind/stackframe.h> 52 53#if 0 54#define UNWIND_DIAGNOSTIC 55#endif 56 57#define debug_frame_dump_XXX(uwf) \ 58 printf("Frame Dump: \n bsp = 0x%lx \n pfs = 0x%lx, SOL(pfs) = %lu \n rp = 0x%lx \n", \ 59 uwf->bsp, uwf->pfs, IA64_CFM_SOL(uwf->pfs), uwf->rp); \ 60 61void 62initunwindframe(struct unwind_frame *uwf, struct trapframe *tf); 63void 64rewindframe(struct unwind_frame *uwf, db_addr_t ip); 65 66void 67db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, 68 const char *modif, void (*pr)(const char *, ...)) 69{ 70 char c; 71 const char *cp = modif; 72 bool trace_thread = false; 73 bool trace_user = false; 74 struct trapframe *tf; 75 struct unwind_frame current_frame; 76 db_addr_t ip; 77 const char *name; 78 db_sym_t sym; 79 db_expr_t offset; 80 81 while ((c = *cp++) != 0) { 82 trace_thread |= c == 't'; 83 trace_user |= c == 'u'; 84 } 85 86 if (trace_user) { 87 (*pr)("User-space stack tracing not implemented yet. \n"); 88 return; 89 } 90 if (!have_addr) { 91 (*pr)("--Kernel Call Trace-- \n"); 92 93 tf = DDB_REGS; 94 ip = tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3); 95 96 initunwindframe(¤t_frame, tf); 97 98#ifdef UNWIND_DIAGNOSTIC 99 struct unwind_frame *uwf = ¤t_frame; 100 debug_frame_dump_XXX(uwf); 101#endif 102 KASSERT(ip >= kernstart); 103 patchunwindframe(¤t_frame, ip - kernstart, kernstart); 104#ifdef UNWIND_DIAGNOSTIC 105 debug_frame_dump_XXX(uwf); 106#endif 107 /* Get into unwind loop. */ 108 109 while(ip) { 110 sym = db_search_symbol(ip, DB_STGY_ANY, &offset); 111 db_symbol_values(sym, &name, NULL); 112 (*pr)("%s(...)\n", name); 113 114 ip = current_frame.rp; 115 116 if(!ip) break; 117 118 rewindframe(¤t_frame, ip); 119 } 120 121 return; 122 123 124 } else (*pr) ("Unwind from arbitrary addresses unimplemented. \n"); 125 126 127 if (trace_thread) { 128 (*pr)("trace by pid unimplemented. \n"); 129 return; 130 } 131 else { 132 (*pr)("trace from arbitrary trap frame address unimplemented. \n"); 133 } 134 135} 136 137extern db_addr_t ia64_unwindtab; 138extern vsize_t ia64_unwindtablen; 139 140 141/* Generates initial unwind frame context based on the contents 142 * of the trap frame, by consulting the Unwind library 143 * staterecord. If a register is of type enum UNSAVED, we fetch 144 * the live value of the register from the trapframe. 145 */ 146 147void 148initunwindframe(struct unwind_frame *uwf, struct trapframe *tf) 149 150{ 151 152 uwf->rp = tf->tf_special.rp; 153 154 /* ndirty = bsp - bspstore: , not the same as the definition in the spec. 155 * Gave me hell for a day! 156 * see: ia64/exception.S: exception_save_restore: */ 157 158 uwf->bsp = tf->tf_special.bspstore + tf->tf_special.ndirty; 159 uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOF(tf->tf_special.cfm)); 160#ifdef UNWIND_DIAGNOSTIC 161 printf("inituwframe(): SOF(cfm) = %lu \n", IA64_CFM_SOF(tf->tf_special.cfm)); 162#endif 163 uwf->pfs = tf->tf_special.pfs; 164 uwf->sp = uwf->psp = tf->tf_special.sp; 165 166 167} 168 169 170 171/* Single step the frame backward. 172 * Assumes unwind_frame is setup already. 173 */ 174 175void 176rewindframe(struct unwind_frame *uwf, db_addr_t ip) 177{ 178/* XXX: Check for a stack switch */ 179 180 uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOL(uwf->pfs)); 181 uwf->sp = uwf->psp; 182 183 /* Pre-stomp frame dump */ 184#ifdef UNWIND_DIAGNOSTIC 185 debug_frame_dump_XXX(uwf); 186#endif 187 188 /* Stomp on rp and pfs 189 */ 190 KASSERT(ip >= kernstart); 191 patchunwindframe(uwf, ip - kernstart, kernstart); 192 193#ifdef UNWIND_DIAGNOSTIC 194 debug_frame_dump_XXX(uwf); 195#endif 196 197} 198