xref: /netbsd/sys/arch/ia64/ia64/db_trace.c (revision 6550d01e)
1 /*	$NetBSD: db_trace.c,v 1.4 2008/04/28 20:23:25 martin 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 		patchunwindframe(&current_frame, ip - kernstart, kernstart);
103 #ifdef UNWIND_DIAGNOSTIC
104 		debug_frame_dump_XXX(uwf);
105 #endif
106 		/* Get into unwind loop. */
107 
108 		while(ip) {
109 			sym = db_search_symbol(ip, DB_STGY_ANY, &offset);
110 			db_symbol_values(sym, &name, NULL);
111 			(*pr)("%s(...)\n", name);
112 
113 			ip = current_frame.rp;
114 
115 			if(!ip) break;
116 
117 			rewindframe(&current_frame, ip);
118 		}
119 
120 		return;
121 
122 
123 	} else (*pr) ("Unwind from arbitrary addresses unimplemented. \n");
124 
125 
126 		if (trace_thread) {
127 			(*pr)("trace by pid unimplemented. \n");
128 			return;
129 		}
130 		else {
131 			(*pr)("trace from arbitrary trap frame address unimplemented. \n");
132 		}
133 
134 }
135 
136 extern db_addr_t ia64_unwindtab;
137 extern vsize_t ia64_unwindtablen;
138 
139 
140 /* Generates initial unwind frame context based on the contents
141  * of the trap frame, by consulting the Unwind library
142  * staterecord. If a register is of type enum UNSAVED, we fetch
143  * the live value of the register from the trapframe.
144  */
145 
146 void
147 initunwindframe(struct unwind_frame *uwf, struct trapframe *tf)
148 
149 {
150 
151 	uwf->rp = tf->tf_special.rp;
152 
153 	/* ndirty = bsp - bspstore: , not the same as the definition in the spec.
154 	 * Gave me hell for a day!
155 	 * see: ia64/exception.S: exception_save_restore: */
156 
157 	uwf->bsp = tf->tf_special.bspstore + tf->tf_special.ndirty;
158 	uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOF(tf->tf_special.cfm));
159 #ifdef UNWIND_DIAGNOSTIC
160 	printf("inituwframe(): SOF(cfm) = %lu \n", IA64_CFM_SOF(tf->tf_special.cfm));
161 #endif
162 	uwf->pfs = tf->tf_special.pfs;
163 	uwf->sp = uwf->psp = tf->tf_special.sp;
164 
165 
166 }
167 
168 
169 
170 /* Single step the frame backward.
171  * Assumes unwind_frame is setup already.
172  */
173 
174 void
175 rewindframe(struct unwind_frame *uwf, db_addr_t ip)
176 {
177 /* XXX: Check for a stack switch */
178 
179 	uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOL(uwf->pfs));
180 	uwf->sp = uwf->psp;
181 
182 	/* Pre-stomp frame dump */
183 #ifdef UNWIND_DIAGNOSTIC
184 	debug_frame_dump_XXX(uwf);
185 #endif
186 
187 	/* Stomp on rp and pfs
188 	 */
189 	patchunwindframe(uwf, ip - kernstart, kernstart);
190 
191 #ifdef UNWIND_DIAGNOSTIC
192 	debug_frame_dump_XXX(uwf);
193 #endif
194 
195 }
196