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#include <sys/stack.h>
34#include <sys/pcpu.h>
35
36#include <machine/frame.h>
37#include <machine/md_var.h>
38#include <machine/reg.h>
39
40#include <vm/vm.h>
41#include <vm/vm_param.h>
42#include <vm/pmap.h>
43
44#include <machine/atomic.h>
45#include <machine/db_machdep.h>
46#include <machine/md_var.h>
47#include <machine/stack.h>
48#include <ddb/db_sym.h>
49#include <ddb/ddb.h>
50#include <sys/kdb.h>
51
52#include "regset.h"
53
54/*
55 * Wee need some reasonable default to prevent backtrace code
56 * from wandering too far
57 */
58#define	MAX_FUNCTION_SIZE 0x10000
59#define	MAX_PROLOGUE_SIZE 0x100
60
61
62uint8_t dtrace_fuword8_nocheck(void *);
63uint16_t dtrace_fuword16_nocheck(void *);
64uint32_t dtrace_fuword32_nocheck(void *);
65uint64_t dtrace_fuword64_nocheck(void *);
66
67void
68dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
69    uint32_t *intrpc)
70{
71	struct unwind_state state;
72	register_t sp;
73	int scp_offset;
74	int depth = 0;
75
76	if (intrpc != 0)
77		pcstack[depth++] = (pc_t) intrpc;
78
79	aframes++;
80
81	__asm __volatile("mov %0, sp" : "=&r" (sp));
82
83	state.registers[FP] = (uint32_t)__builtin_frame_address(0);
84	state.registers[SP] = sp;
85	state.registers[LR] = (uint32_t)__builtin_return_address(0);
86	state.registers[PC] = (uint32_t)dtrace_getpcstack;
87
88	while (depth < pcstack_limit) {
89		int done;
90
91		done = unwind_stack_one(&state, 1);
92
93		/*
94		 * NB: Unlike some other architectures, we don't need to
95		 * explicitly insert cpu_dtrace_caller as it appears in the
96		 * normal kernel stack trace rather than a special trap frame.
97		 */
98		if (aframes > 0) {
99			aframes--;
100		} else {
101			pcstack[depth++] = state.registers[PC];
102		}
103
104		if (done)
105			break;
106	}
107
108	for (; depth < pcstack_limit; depth++) {
109		pcstack[depth] = 0;
110	}
111}
112
113void
114dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
115{
116	printf("IMPLEMENT ME: %s\n", __func__);
117}
118
119int
120dtrace_getustackdepth(void)
121{
122	printf("IMPLEMENT ME: %s\n", __func__);
123	return (0);
124}
125
126void
127dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
128{
129	printf("IMPLEMENT ME: %s\n", __func__);
130}
131
132/*ARGSUSED*/
133uint64_t
134dtrace_getarg(int arg, int aframes)
135{
136/*	struct arm_frame *fp = (struct arm_frame *)dtrace_getfp();*/
137
138	return (0);
139}
140
141int
142dtrace_getstackdepth(int aframes)
143{
144	struct unwind_state state;
145	register_t sp;
146	int scp_offset;
147	int done = 0;
148	int depth = 1;
149
150	__asm __volatile("mov %0, sp" : "=&r" (sp));
151
152	state.registers[FP] = (uint32_t)__builtin_frame_address(0);
153	state.registers[SP] = sp;
154	state.registers[LR] = (uint32_t)__builtin_return_address(0);
155	state.registers[PC] = (uint32_t)dtrace_getstackdepth;
156
157	do {
158		done = unwind_stack_one(&state, 1);
159		depth++;
160	} while (!done);
161
162	if (depth < aframes)
163		return 0;
164	else
165		return depth - aframes;
166}
167
168ulong_t
169dtrace_getreg(struct trapframe *rp, uint_t reg)
170{
171	printf("IMPLEMENT ME: %s\n", __func__);
172
173	return (0);
174}
175
176static int
177dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
178{
179
180	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
181		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
182		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
183		return (0);
184	}
185
186	return (1);
187}
188
189void
190dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
191    volatile uint16_t *flags)
192{
193	if (dtrace_copycheck(uaddr, kaddr, size))
194		dtrace_copy(uaddr, kaddr, size);
195}
196
197void
198dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
199    volatile uint16_t *flags)
200{
201	if (dtrace_copycheck(uaddr, kaddr, size))
202		dtrace_copy(kaddr, uaddr, size);
203}
204
205void
206dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
207    volatile uint16_t *flags)
208{
209	if (dtrace_copycheck(uaddr, kaddr, size))
210		dtrace_copystr(uaddr, kaddr, size, flags);
211}
212
213void
214dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
215    volatile uint16_t *flags)
216{
217	if (dtrace_copycheck(uaddr, kaddr, size))
218		dtrace_copystr(kaddr, uaddr, size, flags);
219}
220
221uint8_t
222dtrace_fuword8(void *uaddr)
223{
224	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
225		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
226		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
227		return (0);
228	}
229	return (dtrace_fuword8_nocheck(uaddr));
230}
231
232uint16_t
233dtrace_fuword16(void *uaddr)
234{
235	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
236		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
237		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
238		return (0);
239	}
240	return (dtrace_fuword16_nocheck(uaddr));
241}
242
243uint32_t
244dtrace_fuword32(void *uaddr)
245{
246	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
247		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
248		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
249		return (0);
250	}
251	return (dtrace_fuword32_nocheck(uaddr));
252}
253
254uint64_t
255dtrace_fuword64(void *uaddr)
256{
257	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
258		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
259		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
260		return (0);
261	}
262	return (dtrace_fuword64_nocheck(uaddr));
263}
264