/*  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;
}
Beispiel #4
0
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);
}
Beispiel #7
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;
}