| @@ -1,333 +1,333 @@ | | | @@ -1,333 +1,333 @@ |
1 | /* | | 1 | /* |
2 | * CDDL HEADER START | | 2 | * CDDL HEADER START |
3 | * | | 3 | * |
4 | * The contents of this file are subject to the terms of the | | 4 | * The contents of this file are subject to the terms of the |
5 | * Common Development and Distribution License, Version 1.0 only | | 5 | * Common Development and Distribution License, Version 1.0 only |
6 | * (the "License"). You may not use this file except in compliance | | 6 | * (the "License"). You may not use this file except in compliance |
7 | * with the License. | | 7 | * with the License. |
8 | * | | 8 | * |
9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | | 9 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
10 | * or http://www.opensolaris.org/os/licensing. | | 10 | * or http://www.opensolaris.org/os/licensing. |
11 | * See the License for the specific language governing permissions | | 11 | * See the License for the specific language governing permissions |
12 | * and limitations under the License. | | 12 | * and limitations under the License. |
13 | * | | 13 | * |
14 | * When distributing Covered Code, include this CDDL HEADER in each | | 14 | * When distributing Covered Code, include this CDDL HEADER in each |
15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | | 15 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
16 | * If applicable, add the following below this CDDL HEADER, with the | | 16 | * If applicable, add the following below this CDDL HEADER, with the |
17 | * fields enclosed by brackets "[]" replaced with your own identifying | | 17 | * fields enclosed by brackets "[]" replaced with your own identifying |
18 | * information: Portions Copyright [yyyy] [name of copyright owner] | | 18 | * information: Portions Copyright [yyyy] [name of copyright owner] |
19 | * | | 19 | * |
20 | * CDDL HEADER END | | 20 | * CDDL HEADER END |
21 | * | | 21 | * |
22 | * $FreeBSD$ | | 22 | * $FreeBSD$ |
23 | * | | 23 | * |
24 | */ | | 24 | */ |
25 | /* | | 25 | /* |
26 | * Copyright 2005 Sun Microsystems, Inc. All rights reserved. | | 26 | * Copyright 2005 Sun Microsystems, Inc. All rights reserved. |
27 | * Use is subject to license terms. | | 27 | * Use is subject to license terms. |
28 | */ | | 28 | */ |
29 | | | 29 | |
30 | #include <sys/cdefs.h> | | 30 | #include <sys/cdefs.h> |
31 | __KERNEL_RCSID(0, "$NetBSD: dtrace_subr.c,v 1.5 2021/04/06 12:48:36 simonb Exp $"); | | 31 | __KERNEL_RCSID(0, "$NetBSD: dtrace_subr.c,v 1.6 2023/04/17 06:57:02 skrll Exp $"); |
32 | | | 32 | |
33 | #include <sys/param.h> | | 33 | #include <sys/param.h> |
34 | #include <sys/systm.h> | | 34 | #include <sys/systm.h> |
35 | #include <sys/types.h> | | 35 | #include <sys/types.h> |
36 | #include <sys/kernel.h> | | 36 | #include <sys/kernel.h> |
37 | #include <sys/malloc.h> | | 37 | #include <sys/malloc.h> |
38 | #include <sys/kmem.h> | | 38 | #include <sys/kmem.h> |
39 | #include <sys/xcall.h> | | 39 | #include <sys/xcall.h> |
40 | #include <sys/cpu.h> | | 40 | #include <sys/cpu.h> |
41 | #include <sys/cpuvar.h> | | 41 | #include <sys/cpuvar.h> |
42 | #include <sys/dtrace_impl.h> | | 42 | #include <sys/dtrace_impl.h> |
43 | #include <sys/dtrace_bsd.h> | | 43 | #include <sys/dtrace_bsd.h> |
44 | #include <machine/cpu.h> | | 44 | #include <machine/cpu.h> |
45 | #include <machine/frame.h> | | 45 | #include <machine/frame.h> |
46 | #include <machine/vmparam.h> | | 46 | #include <machine/vmparam.h> |
47 | #include <uvm/uvm_pglist.h> | | 47 | #include <uvm/uvm_pglist.h> |
48 | #include <uvm/uvm_prot.h> | | 48 | #include <uvm/uvm_prot.h> |
49 | #include <uvm/uvm_pmap.h> | | 49 | #include <uvm/uvm_pmap.h> |
50 | | | 50 | |
51 | #define CURRENT_CPU cpu_index(curcpu()) | | 51 | #define CURRENT_CPU cpu_index(curcpu()) |
52 | #define OFFSET_MASK ((1 << OFFSET_SIZE) - 1) | | 52 | #define OFFSET_MASK ((1 << OFFSET_SIZE) - 1) |
53 | | | 53 | |
54 | extern dtrace_id_t dtrace_probeid_error; | | 54 | extern dtrace_id_t dtrace_probeid_error; |
55 | extern int (*dtrace_invop_jump_addr)(struct trapframe *); | | 55 | extern int (*dtrace_invop_jump_addr)(struct trapframe *); |
56 | extern void dtrace_getnanotime(struct timespec *tsp); | | 56 | extern void dtrace_getnanotime(struct timespec *tsp); |
57 | | | 57 | |
58 | int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t); | | 58 | int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t); |
59 | void dtrace_invop_init(void); | | 59 | void dtrace_invop_init(void); |
60 | void dtrace_invop_uninit(void); | | 60 | void dtrace_invop_uninit(void); |
61 | | | 61 | |
62 | void dtrace_gethrtime_init(void); | | 62 | void dtrace_gethrtime_init(void); |
63 | | | 63 | |
64 | typedef struct dtrace_invop_hdlr { | | 64 | typedef struct dtrace_invop_hdlr { |
65 | int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t); | | 65 | int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t); |
66 | struct dtrace_invop_hdlr *dtih_next; | | 66 | struct dtrace_invop_hdlr *dtih_next; |
67 | } dtrace_invop_hdlr_t; | | 67 | } dtrace_invop_hdlr_t; |
68 | | | 68 | |
69 | dtrace_invop_hdlr_t *dtrace_invop_hdlr; | | 69 | dtrace_invop_hdlr_t *dtrace_invop_hdlr; |
70 | | | 70 | |
71 | int | | 71 | int |
72 | dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t r0) | | 72 | dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t r0) |
73 | { | | 73 | { |
74 | dtrace_invop_hdlr_t *hdlr; | | 74 | dtrace_invop_hdlr_t *hdlr; |
75 | int rval; | | 75 | int rval; |
76 | | | 76 | |
77 | for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) | | 77 | for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) |
78 | if ((rval = hdlr->dtih_func(addr, frame, r0)) != 0) | | 78 | if ((rval = hdlr->dtih_func(addr, frame, r0)) != 0) |
79 | return (rval); | | 79 | return (rval); |
80 | | | 80 | |
81 | return (0); | | 81 | return (0); |
82 | } | | 82 | } |
83 | | | 83 | |
84 | | | 84 | |
85 | void | | 85 | void |
86 | dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) | | 86 | dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) |
87 | { | | 87 | { |
88 | dtrace_invop_hdlr_t *hdlr; | | 88 | dtrace_invop_hdlr_t *hdlr; |
89 | | | 89 | |
90 | hdlr = kmem_alloc(sizeof(*hdlr), KM_SLEEP); | | 90 | hdlr = kmem_alloc(sizeof(*hdlr), KM_SLEEP); |
91 | hdlr->dtih_func = func; | | 91 | hdlr->dtih_func = func; |
92 | hdlr->dtih_next = dtrace_invop_hdlr; | | 92 | hdlr->dtih_next = dtrace_invop_hdlr; |
93 | dtrace_invop_hdlr = hdlr; | | 93 | dtrace_invop_hdlr = hdlr; |
94 | } | | 94 | } |
95 | | | 95 | |
96 | void | | 96 | void |
97 | dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) | | 97 | dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) |
98 | { | | 98 | { |
99 | dtrace_invop_hdlr_t *hdlr, *prev; | | 99 | dtrace_invop_hdlr_t *hdlr, *prev; |
100 | | | 100 | |
101 | hdlr = dtrace_invop_hdlr; | | 101 | hdlr = dtrace_invop_hdlr; |
102 | prev = NULL; | | 102 | prev = NULL; |
103 | | | 103 | |
104 | for (;;) { | | 104 | for (;;) { |
105 | if (hdlr == NULL) | | 105 | if (hdlr == NULL) |
106 | panic("attempt to remove non-existent invop handler"); | | 106 | panic("attempt to remove non-existent invop handler"); |
107 | | | 107 | |
108 | if (hdlr->dtih_func == func) | | 108 | if (hdlr->dtih_func == func) |
109 | break; | | 109 | break; |
110 | | | 110 | |
111 | prev = hdlr; | | 111 | prev = hdlr; |
112 | hdlr = hdlr->dtih_next; | | 112 | hdlr = hdlr->dtih_next; |
113 | } | | 113 | } |
114 | | | 114 | |
115 | if (prev == NULL) { | | 115 | if (prev == NULL) { |
116 | ASSERT(dtrace_invop_hdlr == hdlr); | | 116 | ASSERT(dtrace_invop_hdlr == hdlr); |
117 | dtrace_invop_hdlr = hdlr->dtih_next; | | 117 | dtrace_invop_hdlr = hdlr->dtih_next; |
118 | } else { | | 118 | } else { |
119 | ASSERT(dtrace_invop_hdlr != hdlr); | | 119 | ASSERT(dtrace_invop_hdlr != hdlr); |
120 | prev->dtih_next = hdlr->dtih_next; | | 120 | prev->dtih_next = hdlr->dtih_next; |
121 | } | | 121 | } |
122 | | | 122 | |
123 | kmem_free(hdlr, sizeof(*hdlr)); | | 123 | kmem_free(hdlr, sizeof(*hdlr)); |
124 | } | | 124 | } |
125 | | | 125 | |
126 | /*ARGSUSED*/ | | 126 | /*ARGSUSED*/ |
127 | void | | 127 | void |
128 | dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) | | 128 | dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) |
129 | { | | 129 | { |
130 | | | 130 | |
131 | (*func)(0, (uintptr_t)AARCH64_DIRECTMAP_START); | | 131 | (*func)(0, (uintptr_t)AARCH64_DIRECTMAP_START); |
132 | (*func)((uintptr_t)VM_KERNEL_IO_ADDRESS, ~(uintptr_t)0); | | 132 | (*func)((uintptr_t)VM_KERNEL_IO_BASE, ~(uintptr_t)0); |
133 | } | | 133 | } |
134 | | | 134 | |
135 | static void | | 135 | static void |
136 | xcall_func(void *arg0, void *arg1) | | 136 | xcall_func(void *arg0, void *arg1) |
137 | { | | 137 | { |
138 | dtrace_xcall_t func = arg0; | | 138 | dtrace_xcall_t func = arg0; |
139 | | | 139 | |
140 | (*func)(arg1); | | 140 | (*func)(arg1); |
141 | } | | 141 | } |
142 | | | 142 | |
143 | void | | 143 | void |
144 | dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) | | 144 | dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) |
145 | { | | 145 | { |
146 | uint64_t where; | | 146 | uint64_t where; |
147 | | | 147 | |
148 | if (cpu == DTRACE_CPUALL) { | | 148 | if (cpu == DTRACE_CPUALL) { |
149 | where = xc_broadcast(0, xcall_func, func, arg); | | 149 | where = xc_broadcast(0, xcall_func, func, arg); |
150 | } else { | | 150 | } else { |
151 | struct cpu_info *ci = cpu_lookup(cpu); | | 151 | struct cpu_info *ci = cpu_lookup(cpu); |
152 | | | 152 | |
153 | KASSERT(ci != NULL); | | 153 | KASSERT(ci != NULL); |
154 | where = xc_unicast(0, xcall_func, func, arg, ci); | | 154 | where = xc_unicast(0, xcall_func, func, arg, ci); |
155 | } | | 155 | } |
156 | xc_wait(where); | | 156 | xc_wait(where); |
157 | } | | 157 | } |
158 | | | 158 | |
159 | static void | | 159 | static void |
160 | dtrace_sync_func(void) | | 160 | dtrace_sync_func(void) |
161 | { | | 161 | { |
162 | | | 162 | |
163 | } | | 163 | } |
164 | | | 164 | |
165 | void | | 165 | void |
166 | dtrace_sync(void) | | 166 | dtrace_sync(void) |
167 | { | | 167 | { |
168 | | | 168 | |
169 | dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); | | 169 | dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); |
170 | } | | 170 | } |
171 | | | 171 | |
172 | /* | | 172 | /* |
173 | * DTrace needs a high resolution time function which can | | 173 | * DTrace needs a high resolution time function which can |
174 | * be called from a probe context and guaranteed not to have | | 174 | * be called from a probe context and guaranteed not to have |
175 | * instrumented with probes itself. | | 175 | * instrumented with probes itself. |
176 | * | | 176 | * |
177 | * Returns nanoseconds since boot. | | 177 | * Returns nanoseconds since boot. |
178 | */ | | 178 | */ |
179 | uint64_t | | 179 | uint64_t |
180 | dtrace_gethrtime() | | 180 | dtrace_gethrtime() |
181 | { | | 181 | { |
182 | struct timespec curtime; | | 182 | struct timespec curtime; |
183 | | | 183 | |
184 | nanouptime(&curtime); | | 184 | nanouptime(&curtime); |
185 | | | 185 | |
186 | return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); | | 186 | return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); |
187 | | | 187 | |
188 | } | | 188 | } |
189 | | | 189 | |
190 | void | | 190 | void |
191 | dtrace_gethrtime_init(void) | | 191 | dtrace_gethrtime_init(void) |
192 | { | | 192 | { |
193 | } | | 193 | } |
194 | | | 194 | |
195 | uint64_t | | 195 | uint64_t |
196 | dtrace_gethrestime(void) | | 196 | dtrace_gethrestime(void) |
197 | { | | 197 | { |
198 | struct timespec current_time; | | 198 | struct timespec current_time; |
199 | | | 199 | |
200 | dtrace_getnanotime(¤t_time); | | 200 | dtrace_getnanotime(¤t_time); |
201 | | | 201 | |
202 | return (current_time.tv_sec * 1000000000UL + current_time.tv_nsec); | | 202 | return (current_time.tv_sec * 1000000000UL + current_time.tv_nsec); |
203 | } | | 203 | } |
204 | | | 204 | |
205 | /* Function to handle DTrace traps during probes. See arm64/arm64/trap.c */ | | 205 | /* Function to handle DTrace traps during probes. See arm64/arm64/trap.c */ |
206 | int | | 206 | int |
207 | dtrace_trap(struct trapframe *frame, u_int type) | | 207 | dtrace_trap(struct trapframe *frame, u_int type) |
208 | { | | 208 | { |
209 | /* | | 209 | /* |
210 | * A trap can occur while DTrace executes a probe. Before | | 210 | * A trap can occur while DTrace executes a probe. Before |
211 | * executing the probe, DTrace blocks re-scheduling and sets | | 211 | * executing the probe, DTrace blocks re-scheduling and sets |
212 | * a flag in its per-cpu flags to indicate that it doesn't | | 212 | * a flag in its per-cpu flags to indicate that it doesn't |
213 | * want to fault. On returning from the probe, the no-fault | | 213 | * want to fault. On returning from the probe, the no-fault |
214 | * flag is cleared and finally re-scheduling is enabled. | | 214 | * flag is cleared and finally re-scheduling is enabled. |
215 | * | | 215 | * |
216 | * Check if DTrace has enabled 'no-fault' mode: | | 216 | * Check if DTrace has enabled 'no-fault' mode: |
217 | * | | 217 | * |
218 | */ | | 218 | */ |
219 | | | 219 | |
220 | if ((cpu_core[CURRENT_CPU].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { | | 220 | if ((cpu_core[CURRENT_CPU].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { |
221 | /* | | 221 | /* |
222 | * There are only a couple of trap types that are expected. | | 222 | * There are only a couple of trap types that are expected. |
223 | * All the rest will be handled in the usual way. | | 223 | * All the rest will be handled in the usual way. |
224 | */ | | 224 | */ |
225 | switch (type) { | | 225 | switch (type) { |
226 | case ESR_EC_DATA_ABT_EL1: | | 226 | case ESR_EC_DATA_ABT_EL1: |
227 | /* Flag a bad address. */ | | 227 | /* Flag a bad address. */ |
228 | cpu_core[CURRENT_CPU].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; | | 228 | cpu_core[CURRENT_CPU].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; |
229 | cpu_core[CURRENT_CPU].cpuc_dtrace_illval = 0; | | 229 | cpu_core[CURRENT_CPU].cpuc_dtrace_illval = 0; |
230 | | | 230 | |
231 | /* | | 231 | /* |
232 | * Offset the instruction pointer to the instruction | | 232 | * Offset the instruction pointer to the instruction |
233 | * following the one causing the fault. | | 233 | * following the one causing the fault. |
234 | */ | | 234 | */ |
235 | frame->tf_pc += 4; | | 235 | frame->tf_pc += 4; |
236 | return (1); | | 236 | return (1); |
237 | default: | | 237 | default: |
238 | /* Handle all other traps in the usual way. */ | | 238 | /* Handle all other traps in the usual way. */ |
239 | break; | | 239 | break; |
240 | } | | 240 | } |
241 | } | | 241 | } |
242 | | | 242 | |
243 | /* Handle the trap in the usual way. */ | | 243 | /* Handle the trap in the usual way. */ |
244 | return (0); | | 244 | return (0); |
245 | } | | 245 | } |
246 | | | 246 | |
247 | void | | 247 | void |
248 | dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, | | 248 | dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, |
249 | int fault, int fltoffs, uintptr_t illval) | | 249 | int fault, int fltoffs, uintptr_t illval) |
250 | { | | 250 | { |
251 | | | 251 | |
252 | dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, | | 252 | dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, |
253 | (uintptr_t)epid, | | 253 | (uintptr_t)epid, |
254 | (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); | | 254 | (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); |
255 | } | | 255 | } |
256 | | | 256 | |
257 | static int | | 257 | static int |
258 | dtrace_invop_start(struct trapframe *frame) | | 258 | dtrace_invop_start(struct trapframe *frame) |
259 | { | | 259 | { |
260 | int data, invop, reg, update_sp; | | 260 | int data, invop, reg, update_sp; |
261 | register_t arg1, arg2; | | 261 | register_t arg1, arg2; |
262 | register_t *sp; | | 262 | register_t *sp; |
263 | int offs; | | 263 | int offs; |
264 | int tmp; | | 264 | int tmp; |
265 | int i; | | 265 | int i; |
266 | | | 266 | |
267 | invop = dtrace_invop(frame->tf_pc, frame, frame->tf_regs.r_reg[0]); | | 267 | invop = dtrace_invop(frame->tf_pc, frame, frame->tf_regs.r_reg[0]); |
268 | | | 268 | |
269 | tmp = (invop & LDP_STP_MASK); | | 269 | tmp = (invop & LDP_STP_MASK); |
270 | if (tmp == STP_64 || tmp == LDP_64) { | | 270 | if (tmp == STP_64 || tmp == LDP_64) { |
271 | sp = (register_t *)frame->tf_sp; | | 271 | sp = (register_t *)frame->tf_sp; |
272 | data = invop; | | 272 | data = invop; |
273 | arg1 = (data >> ARG1_SHIFT) & ARG1_MASK; | | 273 | arg1 = (data >> ARG1_SHIFT) & ARG1_MASK; |
274 | arg2 = (data >> ARG2_SHIFT) & ARG2_MASK; | | 274 | arg2 = (data >> ARG2_SHIFT) & ARG2_MASK; |
275 | | | 275 | |
276 | offs = (data >> OFFSET_SHIFT) & OFFSET_MASK; | | 276 | offs = (data >> OFFSET_SHIFT) & OFFSET_MASK; |
277 | | | 277 | |
278 | switch (tmp) { | | 278 | switch (tmp) { |
279 | case STP_64: | | 279 | case STP_64: |
280 | if (offs >> (OFFSET_SIZE - 1)) | | 280 | if (offs >> (OFFSET_SIZE - 1)) |
281 | sp -= (~offs & OFFSET_MASK) + 1; | | 281 | sp -= (~offs & OFFSET_MASK) + 1; |
282 | else | | 282 | else |
283 | sp += (offs); | | 283 | sp += (offs); |
284 | *(sp + 0) = frame->tf_regs.r_reg[arg1]; | | 284 | *(sp + 0) = frame->tf_regs.r_reg[arg1]; |
285 | *(sp + 1) = frame->tf_regs.r_reg[arg2]; | | 285 | *(sp + 1) = frame->tf_regs.r_reg[arg2]; |
286 | break; | | 286 | break; |
287 | case LDP_64: | | 287 | case LDP_64: |
288 | frame->tf_regs.r_reg[arg1] = *(sp + 0); | | 288 | frame->tf_regs.r_reg[arg1] = *(sp + 0); |
289 | frame->tf_regs.r_reg[arg2] = *(sp + 1); | | 289 | frame->tf_regs.r_reg[arg2] = *(sp + 1); |
290 | if (offs >> (OFFSET_SIZE - 1)) | | 290 | if (offs >> (OFFSET_SIZE - 1)) |
291 | sp -= (~offs & OFFSET_MASK) + 1; | | 291 | sp -= (~offs & OFFSET_MASK) + 1; |
292 | else | | 292 | else |
293 | sp += (offs); | | 293 | sp += (offs); |
294 | break; | | 294 | break; |
295 | default: | | 295 | default: |
296 | break; | | 296 | break; |
297 | } | | 297 | } |
298 | | | 298 | |
299 | /* Update the stack pointer and program counter to continue */ | | 299 | /* Update the stack pointer and program counter to continue */ |
300 | frame->tf_sp = (register_t)sp; | | 300 | frame->tf_sp = (register_t)sp; |
301 | frame->tf_pc += INSN_SIZE; | | 301 | frame->tf_pc += INSN_SIZE; |
302 | return (0); | | 302 | return (0); |
303 | } | | 303 | } |
304 | | | 304 | |
305 | if ((invop & B_MASK) == B_INSTR) { | | 305 | if ((invop & B_MASK) == B_INSTR) { |
306 | data = (invop & B_DATA_MASK); | | 306 | data = (invop & B_DATA_MASK); |
307 | /* The data is the number of 4-byte words to change the pc */ | | 307 | /* The data is the number of 4-byte words to change the pc */ |
308 | data *= 4; | | 308 | data *= 4; |
309 | frame->tf_pc += data; | | 309 | frame->tf_pc += data; |
310 | return (0); | | 310 | return (0); |
311 | } | | 311 | } |
312 | | | 312 | |
313 | if (invop == RET_INSTR) { | | 313 | if (invop == RET_INSTR) { |
314 | frame->tf_pc = frame->tf_lr; | | 314 | frame->tf_pc = frame->tf_lr; |
315 | return (0); | | 315 | return (0); |
316 | } | | 316 | } |
317 | | | 317 | |
318 | return (-1); | | 318 | return (-1); |
319 | } | | 319 | } |
320 | | | 320 | |
321 | void | | 321 | void |
322 | dtrace_invop_init(void) | | 322 | dtrace_invop_init(void) |
323 | { | | 323 | { |
324 | | | 324 | |
325 | dtrace_invop_jump_addr = dtrace_invop_start; | | 325 | dtrace_invop_jump_addr = dtrace_invop_start; |
326 | } | | 326 | } |
327 | | | 327 | |
328 | void | | 328 | void |
329 | dtrace_invop_uninit(void) | | 329 | dtrace_invop_uninit(void) |
330 | { | | 330 | { |
331 | | | 331 | |
332 | dtrace_invop_jump_addr = 0; | | 332 | dtrace_invop_jump_addr = 0; |
333 | } | | 333 | } |