xref: /netbsd-src/external/cddl/osnet/dev/dtrace/arm/dtrace_isa.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * $FreeBSD$
23  */
24 /*
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 #include <sys/cdefs.h>
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 
34 #include <machine/frame.h>
35 #include <machine/reg.h>
36 
37 #include <machine/db_machdep.h>
38 #include <machine/vmparam.h>
39 #include <ddb/db_sym.h>
40 #include <ddb/ddb.h>
41 
42 uintptr_t kernelbase = (uintptr_t)KERNEL_BASE;
43 
44 /* TODO: support AAPCS */
45 /* XXX: copied from sys/arch/arm/arm/db_trace.c */
46 #define INKERNEL(va)	(((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
47 
48 #define FR_SCP	(0)
49 #define FR_RLV	(-1)
50 #define FR_RSP	(-2)
51 #define FR_RFP	(-3)
52 
53 #include "regset.h"
54 
55 /*
56  * Wee need some reasonable default to prevent backtrace code
57  * from wandering too far
58  */
59 #define	MAX_FUNCTION_SIZE 0x10000
60 #define	MAX_PROLOGUE_SIZE 0x100
61 
62 
63 uint8_t dtrace_fuword8_nocheck(void *);
64 uint16_t dtrace_fuword16_nocheck(void *);
65 uint32_t dtrace_fuword32_nocheck(void *);
66 uint64_t dtrace_fuword64_nocheck(void *);
67 
68 void
69 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
70     uint32_t *intrpc)
71 {
72 	uint32_t	*frame, *lastframe;
73 #if 0
74 	int	scp_offset;
75 #endif
76 	int	depth = 0;
77 	pc_t caller = (pc_t) solaris_cpu[cpu_number()].cpu_dtrace_caller;
78 
79 	if (intrpc != 0)
80 		pcstack[depth++] = (pc_t) intrpc;
81 
82 	aframes++;
83 
84 	frame = (uint32_t *)__builtin_frame_address(0);;
85 	lastframe = NULL;
86 #if 0
87 	scp_offset = -(get_pc_str_offset() >> 2);
88 #endif
89 
90 	while ((frame != NULL) && (depth < pcstack_limit)) {
91 		db_addr_t	scp;
92 #if 0
93 		uint32_t	savecode;
94 		int		r;
95 		uint32_t	*rp;
96 #endif
97 
98 		/*
99 		 * In theory, the SCP isn't guaranteed to be in the function
100 		 * that generated the stack frame.  We hope for the best.
101 		 */
102 		scp = frame[FR_SCP];
103 		printf("--> %08x\n", (uint32_t)scp);
104 
105 		if (aframes > 0) {
106 			aframes--;
107 			if ((aframes == 0) && (caller != 0)) {
108 				pcstack[depth++] = caller;
109 			}
110 		}
111 		else {
112 			printf("++ --> %08x\n", (uint32_t)scp);
113 			pcstack[depth++] = scp;
114 		}
115 
116 #if 0
117 		savecode = ((uint32_t *)scp)[scp_offset];
118 		if ((savecode & 0x0e100000) == 0x08000000) {
119 			/* Looks like an STM */
120 			rp = frame - 4;
121 			for (r = 10; r >= 0; r--) {
122 				if (savecode & (1 << r)) {
123 					/* register r == *rp-- */
124 				}
125 			}
126 		}
127 #endif
128 
129 		/*
130 		 * Switch to next frame up
131 		 */
132 		if (frame[FR_RFP] == 0)
133 			break; /* Top of stack */
134 
135 		lastframe = frame;
136 		frame = (uint32_t *)(frame[FR_RFP]);
137 
138 		if (INKERNEL((int)frame)) {
139 			/* staying in kernel */
140 			if (frame <= lastframe) {
141 				/* bad frame pointer */
142 				break;
143 			}
144 		}
145 		else
146 			break;
147 	}
148 
149 	for (; depth < pcstack_limit; depth++) {
150 		pcstack[depth] = 0;
151 	}
152 }
153 
154 void
155 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
156 {
157 	printf("unimplemented\n");
158 }
159 
160 int
161 dtrace_getustackdepth(void)
162 {
163 	printf("unimplemented\n");
164 	return (0);
165 }
166 
167 void
168 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
169 {
170 	printf("IMPLEMENT ME: %s\n", __func__);
171 }
172 
173 /*ARGSUSED*/
174 uint64_t
175 dtrace_getarg(int arg, int aframes)
176 {
177 	printf("unimplemented\n");
178 
179 	return (0);
180 }
181 
182 int
183 dtrace_getstackdepth(int aframes)
184 {
185 	uint32_t	*frame, *lastframe;
186 	int	depth = 1;
187 
188 	frame = (uint32_t *)__builtin_frame_address(0);;
189 	lastframe = NULL;
190 
191 	while (frame != NULL) {
192 #if 0
193 		uint32_t	savecode;
194 		int		r;
195 		uint32_t	*rp;
196 #endif
197 
198 		depth++;
199 
200 		/*
201 		 * Switch to next frame up
202 		 */
203 		if (frame[FR_RFP] == 0)
204 			break; /* Top of stack */
205 
206 		lastframe = frame;
207 		frame = (uint32_t *)(frame[FR_RFP]);
208 
209 		if (INKERNEL((int)frame)) {
210 			/* staying in kernel */
211 			if (frame <= lastframe) {
212 				/* bad frame pointer */
213 				break;
214 			}
215 		}
216 		else
217 			break;
218 	}
219 
220 	if (depth < aframes)
221 		return 0;
222 	else
223 		return depth - aframes;
224 
225 }
226 
227 ulong_t
228 dtrace_getreg(struct regs *regs, uint_t reg)
229 {
230 
231 	return (0);
232 }
233 
234 static int
235 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
236 {
237 
238 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
239 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
240 		cpu_core[cpu_number()].cpuc_dtrace_illval = uaddr;
241 		return (0);
242 	}
243 
244 	return (1);
245 }
246 
247 void
248 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
249     volatile uint16_t *flags)
250 {
251 	if (dtrace_copycheck(uaddr, kaddr, size))
252 		dtrace_copy(uaddr, kaddr, size);
253 }
254 
255 void
256 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
257     volatile uint16_t *flags)
258 {
259 	if (dtrace_copycheck(uaddr, kaddr, size))
260 		dtrace_copy(kaddr, uaddr, size);
261 }
262 
263 void
264 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
265     volatile uint16_t *flags)
266 {
267 	if (dtrace_copycheck(uaddr, kaddr, size))
268 		dtrace_copystr(uaddr, kaddr, size, flags);
269 }
270 
271 void
272 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
273     volatile uint16_t *flags)
274 {
275 	if (dtrace_copycheck(uaddr, kaddr, size))
276 		dtrace_copystr(kaddr, uaddr, size, flags);
277 }
278 
279 uint8_t
280 dtrace_fuword8(void *uaddr)
281 {
282 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
283 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
284 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
285 		return (0);
286 	}
287 	return (dtrace_fuword8_nocheck(uaddr));
288 }
289 
290 uint16_t
291 dtrace_fuword16(void *uaddr)
292 {
293 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
294 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
295 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
296 		return (0);
297 	}
298 	return (dtrace_fuword16_nocheck(uaddr));
299 }
300 
301 uint32_t
302 dtrace_fuword32(void *uaddr)
303 {
304 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
305 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
306 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
307 		return (0);
308 	}
309 	return (dtrace_fuword32_nocheck(uaddr));
310 }
311 
312 uint64_t
313 dtrace_fuword64(void *uaddr)
314 {
315 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
316 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
317 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
318 		return (0);
319 	}
320 	return (dtrace_fuword64_nocheck(uaddr));
321 }
322