int sdt_init(void) { int ret; ret = misc_register(&sdt_dev); if (ret) { printk(KERN_WARNING "sdt: Unable to register misc device\n"); return ret; } sdt_attach(); dtrace_printf("sdt loaded: /dev/sdt now available\n"); initted = 1; return 0; }
void sdt_init( void ) { if (0 == gSDTInited) { int majdevno = cdevsw_add(SDT_MAJOR, &sdt_cdevsw); if (majdevno < 0) { printf("sdt_init: failed to allocate a major number!\n"); gSDTInited = 0; return; } if (dtrace_sdt_probes_restricted()) { return; } if (MH_MAGIC_KERNEL != _mh_execute_header.magic) { g_sdt_kernctl.mod_address = (vm_address_t)NULL; g_sdt_kernctl.mod_size = 0; } else { kernel_mach_header_t *mh; struct load_command *cmd; kernel_segment_command_t *orig_ts = NULL, *orig_le = NULL; struct symtab_command *orig_st = NULL; kernel_nlist_t *sym = NULL; char *strings; unsigned int i; g_sdt_mach_module.sdt_nprobes = 0; g_sdt_mach_module.sdt_probes = NULL; g_sdt_kernctl.mod_address = (vm_address_t)&g_sdt_mach_module; g_sdt_kernctl.mod_size = 0; strncpy((char *)&(g_sdt_kernctl.mod_modname), "mach_kernel", KMOD_MAX_NAME); g_sdt_kernctl.mod_next = NULL; g_sdt_kernctl.mod_stale = NULL; g_sdt_kernctl.mod_id = 0; g_sdt_kernctl.mod_loadcnt = 1; g_sdt_kernctl.mod_loaded = 1; g_sdt_kernctl.mod_flags = 0; g_sdt_kernctl.mod_nenabled = 0; mh = &_mh_execute_header; cmd = (struct load_command*) &mh[1]; for (i = 0; i < mh->ncmds; i++) { if (cmd->cmd == LC_SEGMENT_KERNEL) { kernel_segment_command_t *orig_sg = (kernel_segment_command_t *) cmd; if (LIT_STRNEQL(orig_sg->segname, SEG_TEXT)) orig_ts = orig_sg; else if (LIT_STRNEQL(orig_sg->segname, SEG_LINKEDIT)) orig_le = orig_sg; else if (LIT_STRNEQL(orig_sg->segname, "")) orig_ts = orig_sg; /* kexts have a single unnamed segment */ } else if (cmd->cmd == LC_SYMTAB) orig_st = (struct symtab_command *) cmd; cmd = (struct load_command *) ((uintptr_t) cmd + cmd->cmdsize); } if ((orig_ts == NULL) || (orig_st == NULL) || (orig_le == NULL)) return; sym = (kernel_nlist_t *)(orig_le->vmaddr + orig_st->symoff - orig_le->fileoff); strings = (char *)(orig_le->vmaddr + orig_st->stroff - orig_le->fileoff); for (i = 0; i < orig_st->nsyms; i++) { uint8_t n_type = sym[i].n_type & (N_TYPE | N_EXT); char *name = strings + sym[i].n_un.n_strx; const char *prev_name; unsigned long best; unsigned int j; /* Check that the symbol is a global and that it has a name. */ if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)) continue; if (0 == sym[i].n_un.n_strx) /* iff a null, "", name. */ continue; /* Lop off omnipresent leading underscore. */ if (*name == '_') name += 1; if (strncmp(name, DTRACE_PROBE_PREFIX, sizeof(DTRACE_PROBE_PREFIX) - 1) == 0) { sdt_probedesc_t *sdpd = kmem_alloc(sizeof(sdt_probedesc_t), KM_SLEEP); int len = strlen(name) + 1; sdpd->sdpd_name = kmem_alloc(len, KM_SLEEP); strncpy(sdpd->sdpd_name, name, len); /* NUL termination is ensured. */ prev_name = "<unknown>"; best = 0; /* * Find the symbol immediately preceding the sdt probe site just discovered, * that symbol names the function containing the sdt probe. */ for (j = 0; j < orig_st->nsyms; j++) { uint8_t jn_type = sym[j].n_type & (N_TYPE | N_EXT); char *jname = strings + sym[j].n_un.n_strx; if (((N_SECT | N_EXT) != jn_type && (N_ABS | N_EXT) != jn_type)) continue; if (0 == sym[j].n_un.n_strx) /* iff a null, "", name. */ continue; if (*jname == '_') jname += 1; if (*(unsigned long *)sym[i].n_value <= (unsigned long)sym[j].n_value) continue; if ((unsigned long)sym[j].n_value > best) { best = (unsigned long)sym[j].n_value; prev_name = jname; } } sdpd->sdpd_func = kmem_alloc((len = strlen(prev_name) + 1), KM_SLEEP); strncpy(sdpd->sdpd_func, prev_name, len); /* NUL termination is ensured. */ sdpd->sdpd_offset = *(unsigned long *)sym[i].n_value; #if defined(__arm__) /* PR8353094 - mask off thumb-bit */ sdpd->sdpd_offset &= ~0x1U; #elif defined(__arm64__) sdpd->sdpd_offset &= ~0x1LU; #endif /* __arm__ */ #if 0 printf("sdt_init: sdpd_offset=0x%lx, n_value=0x%lx, name=%s\n", sdpd->sdpd_offset, *(unsigned long *)sym[i].n_value, name); #endif sdpd->sdpd_next = g_sdt_mach_module.sdt_probes; g_sdt_mach_module.sdt_probes = sdpd; } else { prev_name = name; } } } sdt_attach( (dev_info_t *)(uintptr_t)majdevno, DDI_ATTACH ); gSDTInited = 1; } else panic("sdt_init: called twice!\n"); }