/* Determines whether an executable's header matches the current architecture, ppc, and/or i386. * Returns true if the header corresponds to a Mach-O, 64-bit Mach-O, or universal binary executable, false otherwise. * Returns by reference the result of matching against a given architecture (matches_current, matches_ppc, matches_i386). * Checks for a given architecture only if the corresponding return-by-reference argument is non-NULL. */ static Boolean examine_header(uint8_t *bytes, ssize_t length, Boolean *matches_current, Boolean *matches_ppc, Boolean *matches_i386) { Boolean retval = false; uint32_t magic = 0, num_fat = 0, max_fat = 0; struct fat_arch one_fat = {0}, *fat = NULL; const NXArchInfo *current_arch, *ppc_arch, *i386_arch; // Look for any of the six magic numbers relevant to Mach-O executables, and swap the header if necessary. if (length >= sizeof(struct mach_header_64)) { magic = *((uint32_t *)bytes); max_fat = (length - sizeof(struct fat_header)) / sizeof(struct fat_arch); if (MH_MAGIC == magic || MH_CIGAM == magic) { struct mach_header *mh = (struct mach_header *)bytes; if (MH_CIGAM == magic) swap_header(bytes, length); one_fat.cputype = mh->cputype; one_fat.cpusubtype = mh->cpusubtype; fat = &one_fat; num_fat = 1; } else if (MH_MAGIC_64 == magic || MH_CIGAM_64 == magic) { struct mach_header_64 *mh = (struct mach_header_64 *)bytes; if (MH_CIGAM_64 == magic) swap_header(bytes, length); one_fat.cputype = mh->cputype; one_fat.cpusubtype = mh->cpusubtype; fat = &one_fat; num_fat = 1; } else if (FAT_MAGIC == magic || FAT_CIGAM == magic) { fat = (struct fat_arch *)(bytes + sizeof(struct fat_header)); if (FAT_CIGAM == magic) swap_header(bytes, length); num_fat = ((struct fat_header *)bytes)->nfat_arch; if (num_fat > max_fat) num_fat = max_fat; } } // Set the return value depending on whether the header appears valid. retval = ((fat && num_fat > 0) ? true : false); // Check for a match against the current architecture specification, if requested. if (matches_current) { current_arch = NXGetLocalArchInfo(); *matches_current = ((retval && current_arch && NXFindBestFatArch(current_arch->cputype, current_arch->cpusubtype, fat, num_fat)) ? true : false); } // Check for a match against the ppc architecture specification, if requested. if (matches_ppc) { ppc_arch = NXGetArchInfoFromName("ppc"); *matches_ppc = ((retval && ppc_arch && NXFindBestFatArch(ppc_arch->cputype, ppc_arch->cpusubtype, fat, num_fat)) ? true : false); } // Check for a match against the i386 architecture specification, if requested. if (matches_i386) { i386_arch = NXGetArchInfoFromName("i386"); *matches_i386 = ((retval && i386_arch && NXFindBestFatArch(i386_arch->cputype, i386_arch->cpusubtype, fat, num_fat)) ? true : false); } return retval; }
static const char * get_arch_name (const char *name) { NXArchInfo * a_info; const NXArchInfo * all_info; cpu_type_t cputype; struct arch_config_guess_map *map; const char *aname; if (name) { /* Find config name based on arch name. */ aname = NULL; map = arch_config_map; while (map->arch_name) { if (!strcmp (map->arch_name, name)) return name; else map++; } a_info = (NXArchInfo *) NXGetArchInfoFromName (name); /* radr://7148788 emit diagnostic for ARM architectures not explicitly * handled by the driver. */ if (a_info && a_info->cputype == CPU_TYPE_ARM) a_info = NULL; } else { a_info = (NXArchInfo *) NXGetLocalArchInfo(); if (a_info) { if (dash_m32_seen) { /* If -m32 is seen then do not change cpu type. */ } else if (dash_m64_seen) { /* If -m64 is seen then enable CPU_ARCH_ABI64. */ a_info->cputype |= CPU_ARCH_ABI64; } else if (sizeof (long) == 8) /* On x86, by default (name is NULL here) enable 64 bit code. */ a_info->cputype |= CPU_ARCH_ABI64; } } if (!a_info) fatal ("Invalid arch name : %s", name); all_info = NXGetAllArchInfos(); if (!all_info) fatal ("Unable to get architecture information"); /* Find first arch. that matches cputype. */ cputype = a_info->cputype; while (all_info->name) { if (all_info->cputype == cputype) break; else all_info++; } return all_info->name; }
const NXArchInfo * addArchForName( KcgenArgs * toolArgs, const char * archname) { const NXArchInfo * result = NULL; result = NXGetArchInfoFromName(archname); if (!result) { goto finish; } addArch(toolArgs, result); finish: return result; }
static const char * get_arch_name (const char *name) { const NXArchInfo * a_info; const NXArchInfo * all_info; cpu_type_t cputype; struct arch_config_guess_map *map; const char *aname; if (name) { /* Find config name based on arch name. */ aname = NULL; map = arch_config_map; while (map->arch_name) { if (!strcmp (map->arch_name, name)) return name; else map++; } a_info = NXGetArchInfoFromName (name); } else a_info = NXGetLocalArchInfo (); if (!a_info) fatal ("Invalid arch name : %s", name); all_info = NXGetAllArchInfos(); if (!all_info) fatal ("Unable to get architecture information"); /* Find first arch. that matches cputype. */ cputype = a_info->cputype; while (all_info->name) { if (all_info->cputype == cputype) break; else all_info++; } return all_info->name; }
int main(int argc, char *argv[]) { dispatch_source_t tmp_ds; int res; pid_t pid = 0; if (argc < 2) { fprintf(stderr, "usage: %s [...]\n", argv[0]); exit(1); } #if HAVE_DECL_POSIX_SPAWN_START_SUSPENDED short spawnflags = POSIX_SPAWN_START_SUSPENDED; #endif #if TARGET_OS_EMBEDDED spawnflags |= POSIX_SPAWN_SETEXEC; #endif posix_spawnattr_t attr; res = posix_spawnattr_init(&attr); assert(res == 0); #if HAVE_DECL_POSIX_SPAWN_START_SUSPENDED res = posix_spawnattr_setflags(&attr, spawnflags); assert(res == 0); #endif uint64_t to = 0; char *tos = getenv("BSDTEST_TIMEOUT"); if (tos) { to = strtoul(tos, NULL, 0); to *= NSEC_PER_SEC; } #if __APPLE__ char *arch = getenv("BSDTEST_ARCH"); if (arch) { const NXArchInfo *ai = NXGetArchInfoFromName(arch); if (ai) { res = posix_spawnattr_setbinpref_np(&attr, 1, (cpu_type_t*)&ai->cputype, NULL); assert(res == 0); } } #endif int i; char** newargv = calloc(argc, sizeof(void*)); for (i = 1; i < argc; ++i) { newargv[i-1] = argv[i]; } newargv[i-1] = NULL; struct timeval tv_start; gettimeofday(&tv_start, NULL); #if HAVE_POSIX_SPAWN_SETEXEC if (spawnflags & POSIX_SPAWN_SETEXEC) { pid = fork(); } #endif if (!pid) { res = posix_spawnp(&pid, newargv[0], NULL, &attr, newargv, environ); if (res) { errno = res; perror(newargv[0]); exit(EXIT_FAILURE); } } //fprintf(stderr, "pid = %d\n", pid); assert(pid > 0); dispatch_queue_t main_q = dispatch_get_main_queue(); tmp_ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, main_q); assert(tmp_ds); dispatch_source_set_event_handler(tmp_ds, ^{ int status; struct rusage usage; struct timeval tv_stop, tv_wall; gettimeofday(&tv_stop, NULL); tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec; tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec); tv_wall.tv_usec = abs(tv_stop.tv_usec - tv_start.tv_usec); int res2 = wait4(pid, &status, 0, &usage); assert(res2 != -1); test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0); printf("[PERF]\twall time: %ld.%06d\n", tv_wall.tv_sec, tv_wall.tv_usec); printf("[PERF]\tuser time: %ld.%06d\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec); printf("[PERF]\tsystem time: %ld.%06d\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); printf("[PERF]\tmax resident set size: %ld\n", usage.ru_maxrss); printf("[PERF]\tpage faults: %ld\n", usage.ru_majflt); printf("[PERF]\tswaps: %ld\n", usage.ru_nswap); printf("[PERF]\tvoluntary context switches: %ld\n", usage.ru_nvcsw); printf("[PERF]\tinvoluntary context switches: %ld\n", usage.ru_nivcsw); exit((WIFEXITED(status) && WEXITSTATUS(status)) || WIFSIGNALED(status)); });
int main(int argc, char * argv[]) { KXKextManagerError err; int fd; const char * output_name = NULL; uint32_t i, zero = 0, num_files = 0; uint32_t filenum; uint32_t strx, strtabsize, strtabpad; struct symbol * import_symbols; struct symbol * export_symbols; uint32_t num_import_syms, num_export_syms, num_removed_syms; uint32_t import_idx, export_idx; const NXArchInfo * host_arch; const NXArchInfo * target_arch; boolean_t require_imports = true; boolean_t diff = false; struct { struct mach_header hdr; struct symtab_command symcmd; } load_cmds; struct file { vm_offset_t mapped; vm_size_t mapped_size; uint32_t nsyms; boolean_t import; const char * path; }; struct file files[64]; host_arch = NXGetLocalArchInfo(); target_arch = host_arch; for( i = 1; i < argc; i += 2) { boolean_t import; if (!strcmp("-sect", argv[i])) { require_imports = false; i--; continue; } if (!strcmp("-diff", argv[i])) { require_imports = false; diff = true; i--; continue; } if (i == (argc - 1)) { fprintf(stderr, "bad arguments: %s\n", argv[i]); exit(1); } if (!strcmp("-arch", argv[i])) { target_arch = NXGetArchInfoFromName(argv[i + 1]); if (!target_arch) { fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]); exit(1); } continue; } if (!strcmp("-output", argv[i])) { output_name = argv[i+1]; continue; } if (!strcmp("-import", argv[i])) import = true; else if (!strcmp("-export", argv[i])) import = false; else { fprintf(stderr, "unknown option: %s\n", argv[i]); exit(1); } err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size); if (kKXKextManagerErrorNone != err) exit(1); if (files[num_files].mapped && files[num_files].mapped_size) { files[num_files].import = import; files[num_files].path = argv[i+1]; num_files++; } } if (!output_name) { fprintf(stderr, "no output file\n"); exit(1); } num_import_syms = 0; num_export_syms = 0; for (filenum = 0; filenum < num_files; filenum++) { files[filenum].nsyms = count_symbols((char *) files[filenum].mapped); if (files[filenum].import) num_import_syms += files[filenum].nsyms; else num_export_syms += files[filenum].nsyms; } if (!num_export_syms) { fprintf(stderr, "no export names\n"); exit(1); } import_symbols = calloc(num_import_syms, sizeof(struct symbol)); export_symbols = calloc(num_export_syms, sizeof(struct symbol)); strtabsize = 4; import_idx = 0; export_idx = 0; for (filenum = 0; filenum < num_files; filenum++) { if (files[filenum].import) { store_symbols((char *) files[filenum].mapped, import_symbols, import_idx, num_import_syms); import_idx += files[filenum].nsyms; } else { strtabsize += store_symbols((char *) files[filenum].mapped, export_symbols, export_idx, num_export_syms); export_idx += files[filenum].nsyms; } if (!files[filenum].nsyms) { fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path); } } qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp); qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp); num_removed_syms = 0; if (num_import_syms) { for (export_idx = 0; export_idx < num_export_syms; export_idx++) { boolean_t found = true; if (!bsearch(export_symbols[export_idx].name, import_symbols, num_import_syms, sizeof(struct symbol), &bsearch_cmp)) { if (require_imports) fprintf(stderr, "exported name not in import list: %s\n", export_symbols[export_idx].name); found = false; } if (export_symbols[export_idx].indirect) { if (!bsearch(export_symbols[export_idx].indirect, import_symbols, num_import_syms, sizeof(struct symbol), &bsearch_cmp)) { if (require_imports) fprintf(stderr, "exported name not in import list: %s\n", export_symbols[export_idx].indirect); found = false; } } if (found && !diff) continue; if (!found && diff) continue; num_removed_syms++; strtabsize -= (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); export_symbols[export_idx].name = 0; } } if (require_imports && num_removed_syms) { err = kKXKextManagerErrorUnspecified; goto finish; } fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755); if (-1 == fd) { perror("couldn't write output"); err = kKXKextManagerErrorFileAccess; goto finish; } strtabpad = (strtabsize + 3) & ~3; load_cmds.hdr.magic = MH_MAGIC; load_cmds.hdr.cputype = target_arch->cputype; load_cmds.hdr.cpusubtype = target_arch->cpusubtype; load_cmds.hdr.filetype = MH_OBJECT; load_cmds.hdr.ncmds = 1; load_cmds.hdr.sizeofcmds = sizeof(load_cmds.symcmd); load_cmds.hdr.flags = MH_INCRLINK; load_cmds.symcmd.cmd = LC_SYMTAB; load_cmds.symcmd.cmdsize = sizeof(load_cmds.symcmd); load_cmds.symcmd.symoff = sizeof(load_cmds); load_cmds.symcmd.nsyms = (num_export_syms - num_removed_syms); load_cmds.symcmd.stroff = (num_export_syms - num_removed_syms) * sizeof(struct nlist) + load_cmds.symcmd.symoff; load_cmds.symcmd.strsize = strtabpad; if (target_arch->byteorder != host_arch->byteorder) { swap_mach_header(&load_cmds.hdr, target_arch->byteorder); swap_symtab_command(&load_cmds.symcmd, target_arch->byteorder); } err = writeFile(fd, &load_cmds, sizeof(load_cmds)); if (kKXKextManagerErrorNone != err) goto finish; strx = 4; for (export_idx = 0; export_idx < num_export_syms; export_idx++) { struct nlist nl; if (!export_symbols[export_idx].name) continue; nl.n_sect = 0; nl.n_desc = 0; nl.n_un.n_strx = strx; strx += export_symbols[export_idx].name_len; if (export_symbols[export_idx].indirect) { nl.n_type = N_INDR | N_EXT; nl.n_value = strx; strx += export_symbols[export_idx].indirect_len; } else { nl.n_type = N_UNDF | N_EXT; nl.n_value = 0; } if (target_arch->byteorder != host_arch->byteorder) swap_nlist(&nl, 1, target_arch->byteorder); err = writeFile(fd, &nl, sizeof(nl)); if (kKXKextManagerErrorNone != err) goto finish; } strx = sizeof(uint32_t); err = writeFile(fd, &zero, strx); if (kKXKextManagerErrorNone != err) goto finish; for (export_idx = 0; export_idx < num_export_syms; export_idx++) { if (!export_symbols[export_idx].name) continue; err = writeFile(fd, export_symbols[export_idx].name, export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); if (kKXKextManagerErrorNone != err) goto finish; } err = writeFile(fd, &zero, strtabpad - strtabsize); if (kKXKextManagerErrorNone != err) goto finish; close(fd); finish: if (kKXKextManagerErrorNone != err) { if (output_name) unlink(output_name); exit(1); } else exit(0); return(0); }
ExitStatus readArgs( int * argc, char * const ** argv, KctoolArgs * toolArgs) { ExitStatus result = EX_USAGE; ExitStatus scratchResult = EX_USAGE; int optchar = 0; int longindex = -1; bzero(toolArgs, sizeof(*toolArgs)); /***** * Process command line arguments. */ while ((optchar = getopt_long_only(*argc, *argv, kOptChars, sOptInfo, &longindex)) != -1) { switch (optchar) { case kOptArch: toolArgs->archInfo = NXGetArchInfoFromName(optarg); if (!toolArgs->archInfo) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "Unknown architecture %s.", optarg); goto finish; } break; case kOptHelp: usage(kUsageLevelFull); result = kKctoolExitHelp; goto finish; default: OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "unrecognized option %s", (*argv)[optind-1]); goto finish; break; } /* Reset longindex, because getopt_long_only() is stupid and doesn't. */ longindex = -1; } /* Update the argc & argv seen by main() so that boot<>root calls * handle remaining args. */ *argc -= optind; *argv += optind; if (*argc != 4) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, "incorrect number of arguments"); goto finish; } /***** * Record remaining args from the command line. */ toolArgs->kernelcachePath = (*argv)[0]; toolArgs->kextID = CFStringCreateWithCString(kCFAllocatorDefault, (*argv)[1], kCFStringEncodingUTF8); if (!toolArgs->kextID) { OSKextLogMemError(); result = EX_OSERR; goto finish; } toolArgs->segmentName = (*argv)[2]; toolArgs->sectionName = (*argv)[3]; result = EX_OK; finish: if (result == EX_USAGE) { usage(kUsageLevelBrief); } return result; }