xref: /netbsd/sys/arch/arm/arm/db_trace.c (revision bf9ec67e)
1 /*	$NetBSD: db_trace.c,v 1.7 2002/04/10 19:35:22 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2000, 2001 Ben Harris
5  * Copyright (c) 1996 Scott K. Stevens
6  *
7  * Mach Operating System
8  * Copyright (c) 1991,1990 Carnegie Mellon University
9  * All Rights Reserved.
10  *
11  * Permission to use, copy, modify and distribute this software and its
12  * documentation is hereby granted, provided that both the copyright
13  * notice and this permission notice appear in all copies of the
14  * software, derivative works or modified versions, and any portions
15  * thereof, and that both notices appear in supporting documentation.
16  *
17  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
18  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
19  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
20  *
21  * Carnegie Mellon requests users of this software to return to
22  *
23  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
24  *  School of Computer Science
25  *  Carnegie Mellon University
26  *  Pittsburgh PA 15213-3890
27  *
28  * any improvements or extensions that they make and grant Carnegie the
29  * rights to redistribute these changes.
30  */
31 
32 #include <sys/param.h>
33 
34 __KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.7 2002/04/10 19:35:22 thorpej Exp $");
35 
36 #include <sys/proc.h>
37 #include <sys/user.h>
38 #include <arm/armreg.h>
39 #include <arm/cpufunc.h>
40 #include <machine/db_machdep.h>
41 
42 #include <ddb/db_access.h>
43 #include <ddb/db_interface.h>
44 #include <ddb/db_sym.h>
45 #include <ddb/db_output.h>
46 
47 #define INKERNEL(va)	(((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
48 
49 /*
50  * APCS stack frames are awkward beasts, so I don't think even trying to use
51  * a structure to represent them is a good idea.
52  *
53  * Here's the diagram from the APCS.  Increasing address is _up_ the page.
54  *
55  *          save code pointer       [fp]        <- fp points to here
56  *          return link value       [fp, #-4]
57  *          return sp value         [fp, #-8]
58  *          return fp value         [fp, #-12]
59  *          [saved v7 value]
60  *          [saved v6 value]
61  *          [saved v5 value]
62  *          [saved v4 value]
63  *          [saved v3 value]
64  *          [saved v2 value]
65  *          [saved v1 value]
66  *          [saved a4 value]
67  *          [saved a3 value]
68  *          [saved a2 value]
69  *          [saved a1 value]
70  *
71  * The save code pointer points twelve bytes beyond the start of the
72  * code sequence (usually a single STM) that created the stack frame.
73  * We have to disassemble it if we want to know which of the optional
74  * fields are actually present.
75  */
76 
77 #define FR_SCP	(0)
78 #define FR_RLV	(-1)
79 #define FR_RSP	(-2)
80 #define FR_RFP	(-3)
81 
82 void
83 db_stack_trace_print(addr, have_addr, count, modif, pr)
84 	db_expr_t       addr;
85 	int             have_addr;
86 	db_expr_t       count;
87 	char            *modif;
88 	void		(*pr) __P((const char *, ...));
89 {
90 	u_int32_t	*frame, *lastframe;
91 	char c, *cp = modif;
92 	boolean_t	kernel_only = TRUE;
93 	boolean_t	trace_thread = FALSE;
94 	int	scp_offset;
95 
96 	while ((c = *cp++) != 0) {
97 		if (c == 'u')
98 			kernel_only = FALSE;
99 		if (c == 't')
100 			trace_thread = TRUE;
101 	}
102 
103 	if (!have_addr)
104 		frame = (u_int32_t *)(DDB_REGS->tf_r11);
105 	else {
106 		if (trace_thread) {
107 			struct proc *p;
108 			struct user *u;
109 			(*pr) ("trace: pid %d ", (int)addr);
110 			p = pfind(addr);
111 			if (p == NULL) {
112 				(*pr)("not found\n");
113 				return;
114 			}
115 			if (!(p->p_flag & P_INMEM)) {
116 				(*pr)("swapped out\n");
117 				return;
118 			}
119 			u = p->p_addr;
120 #ifdef acorn26
121 			frame = (u_int32_t *)(u->u_pcb.pcb_sf->sf_r11);
122 #else
123 			frame = (u_int32_t *)(u->u_pcb.pcb_un.un_32.pcb32_r11);
124 #endif
125 			(*pr)("at %p\n", frame);
126 		} else
127 			frame = (u_int32_t *)(addr);
128 	}
129 	lastframe = NULL;
130 	scp_offset = -(get_pc_str_offset() >> 2);
131 
132 	while (count-- && frame != NULL) {
133 		db_addr_t	scp;
134 		u_int32_t	savecode;
135 		int		r;
136 		u_int32_t	*rp;
137 		const char	*sep;
138 
139 		/*
140 		 * In theory, the SCP isn't guaranteed to be in the function
141 		 * that generated the stack frame.  We hope for the best.
142 		 */
143 #ifdef __PROG26
144 		scp = frame[FR_SCP] & R15_PC;
145 #else
146 		scp = frame[FR_SCP];
147 #endif
148 
149 		db_printsym(scp, DB_STGY_PROC, pr);
150 		(*pr)("\n\t");
151 #ifdef __PROG26
152 		(*pr)("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC);
153 		db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC, pr);
154 		(*pr)(")\n");
155 #else
156 		(*pr)("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]);
157 		db_printsym(frame[FR_RLV], DB_STGY_PROC, pr);
158 		(*pr)(")\n");
159 #endif
160 		(*pr)("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]);
161 
162 		savecode = ((u_int32_t *)scp)[scp_offset];
163 		if ((savecode & 0x0e100000) == 0x08000000) {
164 			/* Looks like an STM */
165 			rp = frame - 4;
166 			sep = "\n\t";
167 			for (r = 10; r >= 0; r--) {
168 				if (savecode & (1 << r)) {
169 					(*pr)("%sr%d=0x%08x",
170 					    sep, r, *rp--);
171 					sep = (frame - rp) % 4 == 2 ?
172 					    "\n\t" : " ";
173 				}
174 			}
175 		}
176 
177 		(*pr)("\n");
178 
179 		/*
180 		 * Switch to next frame up
181 		 */
182 		if (frame[FR_RFP] == 0)
183 			break; /* Top of stack */
184 
185 		lastframe = frame;
186 		frame = (u_int32_t *)(frame[FR_RFP]);
187 
188 		if (INKERNEL((int)frame)) {
189 			/* staying in kernel */
190 			if (frame <= lastframe) {
191 				(*pr)("Bad frame pointer: %p\n", frame);
192 				break;
193 			}
194 		} else if (INKERNEL((int)lastframe)) {
195 			/* switch from user to kernel */
196 			if (kernel_only)
197 				break;	/* kernel stack only */
198 		} else {
199 			/* in user */
200 			if (frame <= lastframe) {
201 				(*pr)("Bad user frame pointer: %p\n",
202 					  frame);
203 				break;
204 			}
205 		}
206 	}
207 }
208