Home | History | Annotate | Line # | Download | only in ia64
      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 
     61 void
     62 initunwindframe(struct unwind_frame *uwf, struct trapframe *tf);
     63 void
     64 rewindframe(struct unwind_frame *uwf, db_addr_t ip);
     65 
     66 void
     67 db_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(&current_frame, tf);
     97 
     98 #ifdef UNWIND_DIAGNOSTIC
     99 		struct unwind_frame *uwf = &current_frame;
    100 		debug_frame_dump_XXX(uwf);
    101 #endif
    102 		KASSERT(ip >= kernstart);
    103 		patchunwindframe(&current_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(&current_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 
    137 extern db_addr_t ia64_unwindtab;
    138 extern 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 
    147 void
    148 initunwindframe(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 
    175 void
    176 rewindframe(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