xref: /netbsd-src/sys/arch/ia64/ia64/db_trace.c (revision 6ec65fcfd4fc14dd006a1488ebb10c8b067ba270)
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
db_stack_trace_print(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif,void (* pr)(const char *,...))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
initunwindframe(struct unwind_frame * uwf,struct trapframe * tf)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
rewindframe(struct unwind_frame * uwf,db_addr_t ip)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