]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/ppc/fbt_ppc.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / dev / ppc / fbt_ppc.c
CommitLineData
2d21ac55
A
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/*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/* #pragma ident "@(#)fbt.c 1.15 05/09/19 SMI" */
28
29#ifdef KERNEL
30#ifndef _KERNEL
31#define _KERNEL /* Solaris vs. Darwin */
32#endif
33#endif
34
35#define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
36#include <kern/cpu_data.h>
37#include <kern/thread.h>
38#include <mach/thread_status.h>
39
40#include <mach-o/loader.h>
41#include <mach-o/nlist.h>
42
43extern struct mach_header _mh_execute_header; /* the kernel's mach header */
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/errno.h>
48#include <sys/stat.h>
49#include <sys/ioctl.h>
50#include <sys/conf.h>
51#include <sys/fcntl.h>
52#include <miscfs/devfs/devfs.h>
53
54#include <sys/dtrace.h>
55#include <sys/dtrace_impl.h>
56#include <sys/fbt.h>
57
58#include <sys/dtrace_glue.h>
59#include <machine/cpu_capabilities.h>
60
61#define DTRACE_INVOP_NOP_SKIP 4
62
63#define DTRACE_INVOP_MFLR_R0 11
64#define DTRACE_INVOP_MFLR_R0_SKIP 4
65
66#define FBT_MFLR_R0 0x7c0802a6
67
68#define FBT_MTLR_R0 0x7c0803a6
69#define FBT_BLR 0x4e800020
70#define FBT_BCTR 0x4e800420
71
72#define FBT_LI_MASK 0x03fffffc
73#define FBT_JUMP 0x48000000
74#define IS_JUMP(instr) (((instr) & ~FBT_LI_MASK) == FBT_JUMP) /* Relative, No LR update -- AA == 0b, LK == 0b */
75#define FBT_LI_EXTD64(instr) \
76 (((instr) & 0x02000000) ? \
77 (((uint64_t)((instr) & FBT_LI_MASK)) | 0xfffffffffc000000ULL) : \
78 ((uint64_t)((instr) & FBT_LI_MASK)))
79
80#define FBT_PATCHVAL 0x7c810808
81#define FBT_AFRAMES_ENTRY 6
82#define FBT_AFRAMES_RETURN 6
83
84#define FBT_ENTRY "entry"
85#define FBT_RETURN "return"
86#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
87
88extern dtrace_provider_id_t fbt_id;
89extern fbt_probe_t **fbt_probetab;
90extern int fbt_probetab_mask;
91
b0d623f7
A
92kern_return_t fbt_perfCallback(int, ppc_saved_state_t *, int, int);
93kern_return_t fbt_perfIntCallback(int, ppc_saved_state_t *, int, int);
94
2d21ac55
A
95/*
96 * Critical routines that must not be probed. PR_5221096, PR_5379018.
97 */
98
99static const char * critical_blacklist[] =
100{
101 "bcopy_phys",
102 "bcopy_physvir_32",
103 "cpu_control",
104 "cpu_exit_wait",
105 "cpu_info",
106 "cpu_info_count",
107 "cpu_init",
108 "cpu_machine_init",
109 "cpu_per_proc_alloc",
110 "cpu_per_proc_free",
111 "cpu_signal_handler",
112 "cpu_sleep",
113 "cpu_start",
114 "cpu_subtype",
115 "cpu_threadtype",
116 "cpu_to_processor",
117 "cpu_type",
118 "mapSkipListVerifyC",
119 "ml_nofault_copy",
120 "register_cpu_setup_func",
121 "unregister_cpu_setup_func"
122};
123#define CRITICAL_BLACKLIST_COUNT (sizeof(critical_blacklist)/sizeof(critical_blacklist[0]))
124
125/*
126 * The transitive closure of entry points that can be reached from probe context.
b0d623f7 127 * (Apart from routines whose names begin with dtrace_).
2d21ac55
A
128 */
129static const char * probe_ctx_closure[] =
130{
131 "Debugger",
132 "MapUserMemoryWindow",
133 "OSCompareAndSwap",
134 "absolutetime_to_microtime",
135 "bcopy",
136 "clock_get_calendar_nanotime_nowait",
137 "copyin",
138 "copyinstr",
139 "copyout",
140 "copyoutstr",
141 "cpu_number",
142 "current_proc",
143 "current_processor",
144 "current_task",
145 "current_thread",
146 "debug_enter",
147 "find_user_regs",
148 "getPerProc",
149 "get_bsdtask_info",
150 "get_bsdthread_info",
151 "get_threadtask",
152 "hw_atomic_and",
153 "hw_compare_and_store",
154 "hw_find_map",
155 "kauth_cred_get",
156 "kauth_getgid",
157 "kauth_getuid",
158 "mach_absolute_time",
159 "mapping_drop_busy",
160 "mapping_find",
161 "mapping_phys_lookup",
162 "max_valid_stack_address",
163 "ml_at_interrupt_context",
164 "ml_phys_write_byte_64",
165 "ml_phys_write_half_64",
166 "ml_phys_write_word_64",
167 "ml_set_interrupts_enabled",
168 "panic",
169 "pmap_find_phys",
170 "prf",
171 "proc_is64bit",
172 "proc_selfname",
173 "proc_selfpid",
b0d623f7 174 "proc_selfppid",
2d21ac55 175 "psignal_lock",
b0d623f7 176 "sdt_getargdesc",
2d21ac55
A
177 "splhigh",
178 "splx",
179 "strlcpy",
b0d623f7 180 "systrace_stub",
2d21ac55
A
181 "timer_grab"
182};
183#define PROBE_CTX_CLOSURE_COUNT (sizeof(probe_ctx_closure)/sizeof(probe_ctx_closure[0]))
184
185static int _cmp(const void *a, const void *b)
186{
b0d623f7 187 return strncmp((const char *)a, *(const char **)b, strlen((const char *)a) + 1);
2d21ac55
A
188}
189
190static const void * bsearch(
191 register const void *key,
192 const void *base0,
193 size_t nmemb,
194 register size_t size,
195 register int (*compar)(const void *, const void *)) {
196
197 register const char *base = base0;
198 register size_t lim;
199 register int cmp;
200 register const void *p;
201
202 for (lim = nmemb; lim != 0; lim >>= 1) {
203 p = base + (lim >> 1) * size;
204 cmp = (*compar)(key, p);
205 if (cmp == 0)
206 return p;
207 if (cmp > 0) { /* key > p: move right */
208 base = (const char *)p + size;
209 lim--;
210 } /* else move left */
211 }
212 return (NULL);
213}
214
215int
216fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
217{
218 fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
219 uint64_t mask = (_cpu_capabilities & k64Bit) ? 0xffffffffffffffffULL : 0x00000000ffffffffULL;
220
221 for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
222 if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
223
224 if (fbt->fbtp_roffset == 0) {
225 ppc_saved_state_t *regs = (ppc_saved_state_t *)stack;
226
b0d623f7 227 CPU->cpu_dtrace_caller = regs->save_lr;
2d21ac55
A
228
229 dtrace_probe(fbt->fbtp_id, regs->save_r3 & mask, regs->save_r4 & mask,
230 regs->save_r5 & mask, regs->save_r6 & mask, regs->save_r7 & mask);
231
b0d623f7 232 CPU->cpu_dtrace_caller = (uintptr_t)NULL;
2d21ac55
A
233 } else {
234
235 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, rval, 0, 0, 0);
236
237 if (fbt->fbtp_rval == DTRACE_INVOP_TAILJUMP) {
238 ppc_saved_state_t *regs = (ppc_saved_state_t *)stack;
239
240 regs->save_srr0 = (uint64_t)fbt->fbtp_patchpoint + FBT_LI_EXTD64(fbt->fbtp_savedval);
241 regs->save_srr0 &= mask;
242 }
243
b0d623f7 244 CPU->cpu_dtrace_caller = (uintptr_t)NULL;
2d21ac55
A
245 }
246
247 return (fbt->fbtp_rval);
248 }
249 }
250
251 return (0);
252}
253
254#include <ppc/proc_reg.h> /* For USER_MODE */
255#define IS_USER_TRAP(regs) USER_MODE((regs)->save_srr1)
256#define T_VECTOR_SIZE 4 /* function pointer size */
257#define T_PROGRAM (0x07 * T_VECTOR_SIZE)
258#define FBT_EXCEPTION_CODE T_PROGRAM
259
260kern_return_t
261fbt_perfCallback(
262 int trapno,
263 ppc_saved_state_t *regs,
264 int unused1,
265 int unused2)
266{
267#pragma unused (unused1)
268#pragma unused (unused2)
269 kern_return_t retval = KERN_FAILURE;
270
271 if (!IS_USER_TRAP(regs) && FBT_EXCEPTION_CODE == trapno) {
272 boolean_t oldlevel;
273
274 oldlevel = ml_set_interrupts_enabled(FALSE);
275
276 switch (dtrace_invop( regs->save_srr0, (uintptr_t *)regs, regs->save_r3 )) {
277 case DTRACE_INVOP_NOP:
278 regs->save_srr0 += DTRACE_INVOP_NOP_SKIP; /* Skip over the bytes of the patched NOP */
279 retval = KERN_SUCCESS;
280 break;
281
282 case DTRACE_INVOP_MFLR_R0:
283 regs->save_r0 = regs->save_lr; /* Emulate patched mflr r0 */
284 regs->save_srr0 += DTRACE_INVOP_MFLR_R0_SKIP; /* Skip over the bytes of the patched mflr r0 */
285 retval = KERN_SUCCESS;
286 break;
287
288 case DTRACE_INVOP_RET:
289 regs->save_srr0 = regs->save_lr; /* Emulate patched blr by resuming execution at the LR */
290 retval = KERN_SUCCESS;
291 break;
292
293 case DTRACE_INVOP_BCTR:
294 regs->save_srr0 = regs->save_ctr; /* Emulate patched bctr by resuming execution at the CTR */
295 retval = KERN_SUCCESS;
296 break;
297
298 case DTRACE_INVOP_TAILJUMP:
299 retval = KERN_SUCCESS;
300 break;
301
302 default:
303 retval = KERN_FAILURE;
304 break;
305 }
306 ml_set_interrupts_enabled(oldlevel);
307 }
308
309 return retval;
310}
311
312kern_return_t
313fbt_perfIntCallback(
314 int trapno,
315 ppc_saved_state_t *regs,
316 int unused1,
317 int unused2)
318{
319 kern_return_t retval = KERN_FAILURE;
320
321 if (KERN_SUCCESS == (retval = fbt_perfCallback(trapno, regs, unused1, unused2)))
322 enable_preemption();
323
324 return retval;
325}
326
327/*ARGSUSED*/
328static void
329__fbt_provide_module(void *arg, struct modctl *ctl)
330{
331#pragma unused(arg)
332 struct mach_header *mh;
333 struct load_command *cmd;
334 struct segment_command *orig_ts = NULL, *orig_le = NULL;
335 struct symtab_command *orig_st = NULL;
336 struct nlist *sym = NULL;
337 char *strings;
338 uintptr_t instrLow, instrHigh;
339 char *modname;
340 unsigned int i;
341
593a1d5f
A
342 int gIgnoreFBTBlacklist = 0;
343 PE_parse_boot_argn("IgnoreFBTBlacklist", &gIgnoreFBTBlacklist, sizeof (gIgnoreFBTBlacklist));
2d21ac55
A
344
345 mh = (struct mach_header *)(ctl->address);
346 modname = ctl->mod_modname;
347
348 if (0 == ctl->address || 0 == ctl->size) /* Has the linker been jettisoned? */
349 return;
350
351 /*
352 * Employees of dtrace and their families are ineligible. Void
353 * where prohibited.
354 */
355
b0d623f7 356 if (LIT_STRNEQL(modname, "com.apple.driver.dtrace"))
2d21ac55
A
357 return;
358
359 if (strstr(modname, "CHUD") != NULL)
360 return;
361
362 if (mh->magic != MH_MAGIC)
363 return;
364
365 cmd = (struct load_command *) &mh[1];
366 for (i = 0; i < mh->ncmds; i++) {
367 if (cmd->cmd == LC_SEGMENT) {
368 struct segment_command *orig_sg = (struct segment_command *) cmd;
369
b0d623f7 370 if (LIT_STRNEQL(orig_sg->segname, SEG_TEXT))
2d21ac55 371 orig_ts = orig_sg;
b0d623f7 372 else if (LIT_STRNEQL(orig_sg->segname, SEG_LINKEDIT))
2d21ac55 373 orig_le = orig_sg;
b0d623f7 374 else if (LIT_STRNEQL(orig_sg->segname, ""))
2d21ac55
A
375 orig_ts = orig_sg; /* kexts have a single unnamed segment */
376 }
377 else if (cmd->cmd == LC_SYMTAB)
378 orig_st = (struct symtab_command *) cmd;
379
380 cmd = (struct load_command *) ((caddr_t) cmd + cmd->cmdsize);
381 }
382
383 if ((orig_ts == NULL) || (orig_st == NULL) || (orig_le == NULL))
384 return;
385
b0d623f7
A
386 sym = (struct nlist *)(orig_le->vmaddr + orig_st->symoff - orig_le->fileoff);
387 strings = (char *)(orig_le->vmaddr + orig_st->stroff - orig_le->fileoff);
2d21ac55
A
388
389 /* Find extent of the TEXT section */
390 instrLow = (uintptr_t)orig_ts->vmaddr;
391 instrHigh = (uintptr_t)(orig_ts->vmaddr + orig_ts->vmsize);
392
393 for (i = 0; i < orig_st->nsyms; i++) {
394 fbt_probe_t *fbt, *retfbt;
395 machine_inst_t *instr, *limit, theInstr;
396 uint8_t n_type = sym[i].n_type & (N_TYPE | N_EXT);
397 char *name = strings + sym[i].n_un.n_strx;
398 int j;
399
400 /* Check that the symbol is a global and that it has a name. */
401 if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type))
402 continue;
403
404 if (0 == sym[i].n_un.n_strx) /* iff a null, "", name. */
405 continue;
406
407 /* Lop off omnipresent leading underscore. */
408 if (*name == '_')
409 name += 1;
410
b0d623f7 411 if (LIT_STRNSTART(name, "dtrace_") && !LIT_STRNSTART(name, "dtrace_safe_")) {
2d21ac55
A
412 /*
413 * Anything beginning with "dtrace_" may be called
414 * from probe context unless it explitly indicates
415 * that it won't be called from probe context by
416 * using the prefix "dtrace_safe_".
417 */
418 continue;
419 }
420
b0d623f7
A
421 if (LIT_STRNSTART(name, "fasttrap_") ||
422 LIT_STRNSTART(name, "fuword") ||
423 LIT_STRNSTART(name, "suword") ||
424 LIT_STRNEQL(name, "sprlock") ||
425 LIT_STRNEQL(name, "sprunlock") ||
426 LIT_STRNEQL(name, "uread") ||
427 LIT_STRNEQL(name, "uwrite"))
428 continue; /* Fasttrap inner-workings. */
429
430 if (LIT_STRNSTART(name, "dsmos_"))
2d21ac55
A
431 continue; /* Don't Steal Mac OS X! */
432
b0d623f7 433 if (LIT_STRNSTART(name, "_dtrace"))
2d21ac55
A
434 continue; /* Shims in dtrace.c */
435
b0d623f7 436 if (LIT_STRNSTART(name, "chud"))
2d21ac55
A
437 continue; /* Professional courtesy. */
438
b0d623f7 439 if (LIT_STRNSTART(name, "hibernate_"))
2d21ac55
A
440 continue; /* Let sleeping dogs lie. */
441
b0d623f7
A
442 if (LIT_STRNEQL(name, "_ZN9IOService14newTemperatureElPS_") || /* IOService::newTemperature */
443 LIT_STRNEQL(name, "_ZN9IOService26temperatureCriticalForZoneEPS_")) /* IOService::temperatureCriticalForZone */
2d21ac55
A
444 continue; /* Per the fire code */
445
446 /*
447 * Place no probes (illegal instructions) in the exception handling path!
448 */
b0d623f7
A
449 if (LIT_STRNEQL(name, "L_handler700") ||
450 LIT_STRNEQL(name, "save_get_phys_64") ||
451 LIT_STRNEQL(name, "save_get_phys_32") ||
452 LIT_STRNEQL(name, "EmulExit") ||
453 LIT_STRNEQL(name, "Emulate") ||
454 LIT_STRNEQL(name, "Emulate64") ||
455 LIT_STRNEQL(name, "switchSegs") ||
456 LIT_STRNEQL(name, "save_ret_phys"))
2d21ac55
A
457 continue;
458
b0d623f7
A
459 if (LIT_STRNEQL(name, "thandler") ||
460 LIT_STRNEQL(name, "versave") ||
461 LIT_STRNEQL(name, "timer_event") ||
462 LIT_STRNEQL(name, "hw_atomic_or") ||
463 LIT_STRNEQL(name, "trap"))
2d21ac55
A
464 continue;
465
b0d623f7
A
466 if (LIT_STRNEQL(name, "fbt_perfCallback") ||
467 LIT_STRNEQL(name, "fbt_perfIntCallback") ||
468 LIT_STRNEQL(name, "ml_set_interrupts_enabled") ||
469 LIT_STRNEQL(name, "dtrace_invop") ||
470 LIT_STRNEQL(name, "fbt_invop") ||
471 LIT_STRNEQL(name, "sdt_invop") ||
472 LIT_STRNEQL(name, "max_valid_stack_address"))
2d21ac55
A
473 continue;
474
475 /*
476 * Probes encountered while we're on the interrupt stack are routed along
477 * the interrupt handling path. No probes allowed there either!
478 */
b0d623f7
A
479 if (LIT_STRNEQL(name, "ihandler") ||
480 LIT_STRNEQL(name, "interrupt") ||
481 LIT_STRNEQL(name, "disable_preemption"))
2d21ac55
A
482 continue;
483
484 /*
485 * Avoid weird stack voodoo in and under machine_stack_handoff et al
486 */
b0d623f7
A
487 if (LIT_STRNSTART(name, "machine_stack") ||
488 LIT_STRNEQL(name, "getPerProc") || /* Called in machine_stack_handoff with weird stack state */
489 LIT_STRNEQL(name, "fpu_save") || /* Called in machine_stack_handoff with weird stack state */
490 LIT_STRNEQL(name, "vec_save") || /* Called in machine_stack_handoff with weird stack state */
491 LIT_STRNEQL(name, "pmap_switch")) /* Called in machine_stack_handoff with weird stack state */
2d21ac55
A
492 continue;
493
494 /*
495 * Avoid machine_ routines. PR_5346750.
496 */
b0d623f7 497 if (LIT_STRNSTART(name, "machine_"))
2d21ac55
A
498 continue;
499
500 /*
501 * Avoid low level pmap and virtual machine monitor PowerPC routines. See PR_5379018.
502 */
503
b0d623f7
A
504 if (LIT_STRNSTART(name, "hw_") ||
505 LIT_STRNSTART(name, "mapping_") ||
506 LIT_STRNSTART(name, "commpage_") ||
507 LIT_STRNSTART(name, "pmap_") ||
508 LIT_STRNSTART(name, "vmm_"))
2d21ac55
A
509 continue;
510 /*
511 * Place no probes on critical routines. PR_5221096
512 */
513 if (!gIgnoreFBTBlacklist &&
514 bsearch( name, critical_blacklist, CRITICAL_BLACKLIST_COUNT, sizeof(name), _cmp ) != NULL)
515 continue;
516
517 /*
518 * Place no probes that could be hit in probe context.
519 */
520 if (!gIgnoreFBTBlacklist &&
521 bsearch( name, probe_ctx_closure, PROBE_CTX_CLOSURE_COUNT, sizeof(name), _cmp ) != NULL)
522 continue;
523
524 /*
525 * Place no probes that could be hit on the way to the debugger.
526 */
b0d623f7
A
527 if (LIT_STRNSTART(name, "kdp_") ||
528 LIT_STRNSTART(name, "kdb_") ||
529 LIT_STRNSTART(name, "kdbg_") ||
530 LIT_STRNSTART(name, "kdebug_") ||
531 LIT_STRNEQL(name, "kernel_debug") ||
532 LIT_STRNEQL(name, "Debugger") ||
533 LIT_STRNEQL(name, "Call_DebuggerC") ||
534 LIT_STRNEQL(name, "lock_debugger") ||
535 LIT_STRNEQL(name, "unlock_debugger") ||
536 LIT_STRNEQL(name, "SysChoked"))
2d21ac55
A
537 continue;
538
539 /*
540 * Place no probes that could be hit on the way to a panic.
541 */
542 if (NULL != strstr(name, "panic_") ||
b0d623f7
A
543 LIT_STRNEQL(name, "panic") ||
544 LIT_STRNEQL(name, "handleMck") ||
545 LIT_STRNEQL(name, "unresolved_kernel_trap"))
2d21ac55
A
546 continue;
547
548 if (dtrace_probe_lookup(fbt_id, modname, name, NULL) != 0)
549 continue;
550
551 /*
552 * Scan forward for mflr r0.
553 */
554 for (j = 0, instr = (machine_inst_t *)sym[i].n_value, theInstr = 0;
555 (j < 4) && ((uintptr_t)instr >= instrLow) && (instrHigh > (uintptr_t)instr);
556 j++, instr++)
557 {
558 theInstr = *instr;
559 if (theInstr == FBT_MFLR_R0) /* Place the entry probe here. */
560 break;
561 if (theInstr == FBT_MTLR_R0) /* We've gone too far, bail. */
562 break;
563 if (theInstr == FBT_BLR) /* We've gone too far, bail. */
564 break;
565 }
566
567 if (theInstr != FBT_MFLR_R0)
568 continue;
569
570 limit = (machine_inst_t *)instrHigh;
571
572 fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
573 strlcpy( (char *)&(fbt->fbtp_name), name, MAX_FBTP_NAME_CHARS );
574 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, name, FBT_ENTRY, FBT_AFRAMES_ENTRY, fbt);
575 fbt->fbtp_patchpoint = instr;
576 fbt->fbtp_ctl = ctl;
577 fbt->fbtp_loadcnt = ctl->mod_loadcnt;
578 fbt->fbtp_rval = DTRACE_INVOP_MFLR_R0;
579 fbt->fbtp_savedval = theInstr;
580 fbt->fbtp_patchval = FBT_PATCHVAL;
581
582 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
583 fbt->fbtp_symndx = i;
584 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
585
586 instr++; /* Move on down the line */
587 retfbt = NULL;
588again:
589 if (instr >= limit)
590 continue;
591
592 /*
593 * We (desperately) want to avoid erroneously instrumenting a
594 * jump table. To determine if we're looking at a true instruction
595 * or an inline jump table that happens to contain the same
596 * byte sequences, we resort to some heuristic sleeze: we
597 * treat this instruction as being contained within a pointer,
598 * and see if that pointer points to within the body of the
599 * function. If it does, we refuse to instrument it.
600 */
601 {
602 machine_inst_t *ptr = *(machine_inst_t **)instr;
603
604 if (ptr >= (machine_inst_t *)sym[i].n_value && ptr < limit) {
605 instr++;
606 goto again;
607 }
608 }
609
610 /*
611 * OK, it's an instruction.
612 */
613 theInstr = *instr;
614
615 /* Walked onto the start of the next routine? If so, bail out from this function. */
616 if (theInstr == FBT_MFLR_R0)
617 continue;
618
619 if (theInstr != FBT_MTLR_R0) {
620 instr++;
621 goto again;
622 }
623
624 /*
625 * Found mtlr r0;
626 * Scan forward for a blr, bctr, or a jump (relative, no LR change).
627 */
628 instr++;
629 for (j = 0; (j < 12) && (instr < limit); j++, instr++) {
630 theInstr = *instr;
631 if (theInstr == FBT_BLR || theInstr == FBT_BCTR || IS_JUMP(theInstr) ||
632 theInstr == FBT_MFLR_R0 || theInstr == FBT_MTLR_R0)
633 break;
634 }
635
636 if (!(theInstr == FBT_BLR || theInstr == FBT_BCTR || IS_JUMP(theInstr)))
637 goto again;
638
639 /*
640 * We have a winner: "mtlr r0; ... ; {blr, bctr, j}" !
641 */
642 fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
643 strlcpy( (char *)&(fbt->fbtp_name), name, MAX_FBTP_NAME_CHARS );
644
645 if (retfbt == NULL) {
646 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
647 name, FBT_RETURN, FBT_AFRAMES_RETURN, fbt);
648 } else {
649 retfbt->fbtp_next = fbt;
650 fbt->fbtp_id = retfbt->fbtp_id;
651 }
652
653 retfbt = fbt;
654 fbt->fbtp_patchpoint = instr;
655 fbt->fbtp_ctl = ctl;
656 fbt->fbtp_loadcnt = ctl->mod_loadcnt;
657
658 if (theInstr == FBT_BLR)
659 fbt->fbtp_rval = DTRACE_INVOP_RET;
660 else if (theInstr == FBT_BCTR)
661 fbt->fbtp_rval = DTRACE_INVOP_BCTR;
662 else
663 fbt->fbtp_rval = DTRACE_INVOP_TAILJUMP;
664
665 fbt->fbtp_roffset =
666 (uintptr_t)((uint8_t *)instr - (uint8_t *)sym[i].n_value);
667
668 fbt->fbtp_savedval = *instr;
669 fbt->fbtp_patchval = FBT_PATCHVAL;
670 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
671 fbt->fbtp_symndx = i;
672 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
673 instr++;
674 goto again;
675 }
676}
677
678extern struct modctl g_fbt_kernctl;
679#undef kmem_alloc /* from its binding to dt_kmem_alloc glue */
680#undef kmem_free /* from its binding to dt_kmem_free glue */
681#include <vm/vm_kern.h>
682
683/*ARGSUSED*/
684void
685fbt_provide_module(void *arg, struct modctl *ctl)
686{
687#pragma unused(ctl)
688 __fbt_provide_module(arg, &g_fbt_kernctl);
689
b0d623f7
A
690 if ( (vm_offset_t)g_fbt_kernctl.address != (vm_offset_t )NULL )
691 kmem_free(kernel_map, (vm_offset_t)g_fbt_kernctl.address, round_page(g_fbt_kernctl.size));
2d21ac55
A
692 g_fbt_kernctl.address = 0;
693 g_fbt_kernctl.size = 0;
694}