/*
 * create() takes the file name of a dynamic library (dylib) and creates a
 * gmon.out file (gmon_out).  It checks to see the dylib file is correct and
 * creates the gmon.out file proportional to the size of the (__TEXT,__text)
 * section of the dynamic library.
 */
static
void
create(
char *dylib,
char *gmon_out)
{
    struct arch_flag host_arch_flag;
    struct ofile ofile;
    unsigned long i, j, size;
    struct load_command *lc;
    struct segment_command *sg;
    struct section *s, *text_section;
    kern_return_t r;
    struct phdr *phdr;
    char *pcsample_buffer;
    int fd;

	/*
	 * Open and map in the dylib file and check it for correctness.
	 */
	if(get_arch_from_host(&host_arch_flag, NULL) == 0)
	    fatal("can't determine the host architecture");
	if(ofile_map(dylib, &host_arch_flag, NULL, &ofile, FALSE) == FALSE)
	    exit(EXIT_FAILURE);
	if(ofile.mh == NULL ||
	   (ofile.mh->filetype != MH_DYLIB &&
	    ofile.mh->filetype != MH_DYLINKER))
	    fatal("file: %s is not a Mach-O dynamic shared library file",
		  dylib);

	/*
	 * Get the text section for dynamic library.
	 */
	text_section = NULL;
	lc = ofile.load_commands;
	for(i = 0; i < ofile.mh->ncmds && text_section == NULL; i++){
	    if(lc->cmd == LC_SEGMENT){
		sg = (struct segment_command *)lc;
		s = (struct section *)
		      ((char *)sg + sizeof(struct segment_command));
		for(j = 0; j < sg->nsects; j++){
		    if(strcmp(s->sectname, SECT_TEXT) == 0 &&
		       strcmp(s->segname, SEG_TEXT) == 0){
			text_section = s;
			break;
		    }
		    s++;
		}
	    }
	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
	}
	if(text_section == NULL)
	    fatal("file: %s does not have a (" SEG_TEXT "," SECT_TEXT
		  ") section", dylib);

	/*
	 * Create a pcsample buffer for the text section.
	 */
	size = text_section->size / HASHFRACTION + sizeof(struct phdr);
	size = round(size, sizeof(unsigned short));
	r = vm_allocate(mach_task_self(), (vm_address_t *)&pcsample_buffer,
			(vm_size_t)size, TRUE);
	if(r != KERN_SUCCESS)
	    mach_fatal(r, "can't vm_allocate pcsample buffer of size: %lu",
		       size);

	/*
	 * Create and write the pcsample file. See comments in gmon.h for the
	 * values of the profile header (struct phdr).
	 */
	phdr = (struct phdr *)pcsample_buffer;
	phdr->lpc = (char *)(text_section->addr);
	phdr->hpc = (char *)(text_section->addr + text_section->size);
	phdr->ncnt = (int)size;
	if((fd = open(gmon_out, O_WRONLY | O_CREAT | O_TRUNC, 0777)) == -1)
	    system_fatal("can't create gmon.out file: %s", gmon_out);
	if(write(fd, pcsample_buffer, size) != (int)size)
	    system_fatal("can't write gmon.out file: %s", gmon_out);
	if(close(fd) == -1)
	    system_fatal("can't close gmon.out file: %s", gmon_out);
}
Exemple #2
0
int
main(
int argc,
char **argv,
char **envp)
{
    const char *LIB = "../libexec/as/";
    const char *LOCALLIB = "../local/libexec/as/";
    const char *AS = "/as";
    const char *LLVM_MC = "llvm-mc";

    int i, j;
    uint32_t count, verbose, run_llvm_mc;
    char *p, c, *arch_name, *as, *as_local;
    char **llvm_mc_argv;
    char *prefix, buf[MAXPATHLEN], resolved_name[PATH_MAX];
    unsigned long bufsize;
    struct arch_flag arch_flag;
    const struct arch_flag *arch_flags, *family_arch_flag;
    enum bool oflag_specified;

	progname = argv[0];
	arch_name = NULL;
	verbose = 0;
	run_llvm_mc = 0;
	oflag_specified = FALSE;
	/*
	 * Construct the prefix to the assembler driver.
	 */
	bufsize = MAXPATHLEN;
	p = buf;
	i = _NSGetExecutablePath(p, &bufsize);
	if(i == -1){
	    p = allocate(bufsize);
	    _NSGetExecutablePath(p, &bufsize);
	}
	prefix = realpath(p, resolved_name);
	if(realpath == NULL)
	    system_fatal("realpath(3) for %s failed", p);
	p = rindex(prefix, '/');
	if(p != NULL)
	    p[1] = '\0';
	/*
	 * Process the assembler flags exactly like the assembler would (except
	 * let the assembler complain about multiple flags, bad combinations of
	 * flags, unknown single letter flags and the like).  The main thing
	 * here is to parse out the "-arch <arch_flag>" and to do so the
	 * multiple argument and multiple character flags need to be known how
	 * to be stepped over correctly.
	 */
	for(i = 1; i < argc; i++){
	    /*
	     * The assembler flags start with '-' except that "--" is recognized
	     * as assemble from stdin and that flag "--" is not allowed to be
	     * grouped with other flags (so "-a-" is not the same as "-a --").
	     */
	    if(argv[i][0] == '-' &&
	       !(argv[i][1] == '-' && argv[i][2] == '0')){
		/*
		 * the assembler allows single letter flags to be grouped
		 * together so "-abc" is the same as "-a -b -c".  So that
		 * logic must be followed here.
		 */
		for(p = &(argv[i][1]); (c = *p); p++){
		    /*
		     * The assembler simply ignores the high bit of flag
		     * characters and not treat them as different characters
		     * as they are (but the argument following the flag
		     * character is not treated this way).  So it's done
		     * here as well to match it.
		     */
		    c &= 0x7F;
		    switch(c){
		    /*
		     * Flags that take a single argument.  The argument is the
		     * rest of the current argument if there is any or the it is
		     * the next argument.  Again errors like missing arguments
		     * are not handled here but left to the assembler.
		     */
		    case 'o':	/* -o name */
			oflag_specified = TRUE;
		    case 'I':	/* -I directory */
		    case 'm':	/* -mc68000, -mc68010 and mc68020 */
		    case 'N':	/* -NEXTSTEP-deployment-target */
			if(p[1] == '\0')
			    i++;
			break;

		    case 'a':
			if(strcmp(p, "arch") == 0){
			    if(i + 1 >= argc)
				fatal("missing argument to %s option", argv[i]);
			    if(arch_name != NULL)
				fatal("more than one %s option (not allowed, "
				      "use cc(1) instead)", argv[i]);
			    arch_name = argv[i+1];
			    break;
			}
			/* fall through for non "-arch" */
		    case 'f':
		    case 'k':
		    case 'g':
		    case 'v':
		    case 'W':
		    case 'L':
		    default:
			/* just recognize it, do nothing */
			break;
		    case 'l':
			if(strcmp(p, "llvm-mc") == 0)
			    run_llvm_mc = i;
			/* also just recognize 'l' and do nothing */
			break;
		    case 'V':
			verbose = 1;
			break;
		    }
		}
	    }
	}

	/*
	 * If the -llvm-mc flag was specified then run llvm-mc from the same
	 * directory as the driver.
	 */
	if(run_llvm_mc != 0){
	    as = makestr(prefix, LLVM_MC, NULL);
	    if(access(as, F_OK) != 0){
		printf("%s: assembler (%s) not installed\n", progname, as);
		exit(1);
	    }
	    llvm_mc_argv = allocate(argc + 3);
	    llvm_mc_argv[0] = as;
	    j = 1;
	    for(i = 1; i < argc; i++){
		/*
		 * Do not pass -llvm-mc
		 */
		if(i != run_llvm_mc){
		    /*
		     * Do not pass command line argument that are Unknown to
		     * to llvm-mc.
		     */
		    if(strcmp(argv[i], "-v") != 0 &&
		       strcmp(argv[i], "-V") != 0 &&
		       strcmp(argv[i], "-force_cpusubtype_ALL") != 0){
			llvm_mc_argv[j] = argv[i];
			j++;
		    }
		}
	    }
	    /*
	     * Add -filetype=obj or llvm-mc will write to stdout.
	     */
	    llvm_mc_argv[j] = "-filetype=obj";
	    j++;
	    /*
	     * llvm-mc requires a "-o a.out" if not -o is specified.
	     */
	    if(oflag_specified == FALSE){
		llvm_mc_argv[j] = "-o";
		j++;
		llvm_mc_argv[j] = "a.out";
		j++;
	    }
	    llvm_mc_argv[j] = NULL;
	    if(execute(llvm_mc_argv, verbose))
		exit(0);
	    else
		exit(1);
	}

	/*
	 * Construct the name of the assembler to run from the given -arch
	 * <arch_flag> or if none then from the value returned from
	 * get_arch_from_host().
	 */
	if(arch_name == NULL){
	    if(get_arch_from_host(&arch_flag, NULL)){
#if __LP64__
		/*
		 * If runing as a 64-bit binary and on an Intel x86 host
		 * default to the 64-bit assember.
		 */
		if(arch_flag.cputype == CPU_TYPE_I386)
		    arch_flag = *get_arch_family_from_cputype(CPU_TYPE_X86_64);
#endif /* __LP64__ */
		arch_name = arch_flag.name;
	    }
	    else
		fatal("unknown host architecture (can't determine which "
		      "assembler to run)");
	}
	else{
	    /*
	     * Convert a possible machine specific architecture name to a
	     * family name to base the name of the assembler to run.
	     */
	    if(get_arch_from_flag(arch_name, &arch_flag) != 0){
		family_arch_flag =
			get_arch_family_from_cputype(arch_flag.cputype);
		if(family_arch_flag != NULL)
		    arch_name = (char *)(family_arch_flag->name);
	    }

	}
	/*
	 * If this assembler exist try to run it else print an error message.
	 */
	as = makestr(prefix, LIB, arch_name, AS, NULL);
	if(access(as, F_OK) == 0){
	    argv[0] = as;
	    if(execute(argv, verbose))
		exit(0);
	    else
		exit(1);
	}
	as_local = makestr(prefix, LOCALLIB, arch_name, AS, NULL);
	if(access(as_local, F_OK) == 0){
	    argv[0] = as_local;
	    if(execute(argv, verbose))
		exit(0);
	    else
		exit(1);
	}
	printf("%s: assembler (%s or %s) for architecture %s not installed\n",
	       progname, as, as_local, arch_name);
	arch_flags = get_arch_flags();
	count = 0;
	for(i = 0; arch_flags[i].name != NULL; i++){
	    as = makestr(prefix, LIB, arch_flags[i].name, AS, NULL);
	    if(access(as, F_OK) == 0){
		if(count == 0)
		    printf("Installed assemblers are:\n");
		printf("%s for architecture %s\n", as, arch_flags[i].name);
		count++;
	    }
	    else{
		as_local = makestr(prefix, LOCALLIB, arch_flags[i].name, AS,
				   NULL);
		if(access(as_local, F_OK) == 0){
		    if(count == 0)
			printf("Installed assemblers are:\n");
		    printf("%s for architecture %s\n", as_local,
			   arch_flags[i].name);
		    count++;
		}
	    }
	}
	if(count == 0)
	    printf("%s: no assemblers installed\n", progname);
	exit(1);
}
Exemple #3
0
int
main(
int argc,
char **argv,
char **envp)
{
    const char *LIB = "../libexec/as/";
    const char *LOCALLIB = "../local/libexec/as/";
    const char *AS = "/as";

    int i, j;
    uint32_t count, verbose, run_clang;
    char *p, c, *arch_name, *as, *as_local;
    char **new_argv;
    const char *CLANG = "clang";
    char *prefix, buf[MAXPATHLEN], resolved_name[PATH_MAX];
    uint32_t bufsize;
    struct arch_flag arch_flag;
    const struct arch_flag *arch_flags, *family_arch_flag;
    enum bool oflag_specified, qflag, Qflag, some_input_files;

	progname = argv[0];
	arch_name = NULL;
	verbose = 0;
	run_clang = 0;
	oflag_specified = FALSE;
	qflag = FALSE;
	Qflag = FALSE;
	some_input_files = FALSE;
	/*
	 * Construct the prefix to the assembler driver.
	 */
	bufsize = MAXPATHLEN;
	p = buf;
	i = _NSGetExecutablePath(p, &bufsize);
	if(i == -1){
	    p = allocate(bufsize);
	    _NSGetExecutablePath(p, &bufsize);
	}
	prefix = realpath(p, resolved_name);
	if(realpath == NULL)
	    system_fatal("realpath(3) for %s failed", p);
	p = rindex(prefix, '/');
	if(p != NULL)
	    p[1] = '\0';
	/*
	 * Process the assembler flags exactly like the assembler would (except
	 * let the assembler complain about multiple flags, bad combinations of
	 * flags, unknown single letter flags and the like).  The main thing
	 * here is to parse out the "-arch <arch_flag>" and to do so the
	 * multiple argument and multiple character flags need to be known how
	 * to be stepped over correctly.
	 */
	for(i = 1; i < argc; i++){
	    /*
	     * The assembler flags start with '-' except that "--" is recognized
	     * as assemble from stdin and that flag "--" is not allowed to be
	     * grouped with other flags (so "-a-" is not the same as "-a --").
	     */
	    if(argv[i][0] == '-' &&
	       !(argv[i][1] == '-' && argv[i][2] == '\0')){
		/*
		 * Treat a single "-" as reading from stdin input also.
		 */
		if(argv[i][1] == '\0')
		    some_input_files = TRUE;
		/*
		 * the assembler allows single letter flags to be grouped
		 * together so "-abc" is the same as "-a -b -c".  So that
		 * logic must be followed here.
		 */
		for(p = &(argv[i][1]); (c = *p); p++){
		    /*
		     * The assembler simply ignores the high bit of flag
		     * characters and not treat them as different characters
		     * as they are (but the argument following the flag
		     * character is not treated this way).  So it's done
		     * here as well to match it.
		     */
		    c &= 0x7F;
		    switch(c){
		    /*
		     * Flags that take a single argument.  The argument is the
		     * rest of the current argument if there is any or the it is
		     * the next argument.  Again errors like missing arguments
		     * are not handled here but left to the assembler.
		     */
		    case 'o':	/* -o name */
			oflag_specified = TRUE;
		    case 'I':	/* -I directory */
		    case 'm':	/* -mc68000, -mc68010 and mc68020 */
		    case 'N':	/* -NEXTSTEP-deployment-target */
			/*
			 * We want to skip the next argv if the value is not
			 * contained in this argv eg: -I dir .
			 */
			if(p[1] == '\0')
			    i++;
			/*
			 * And in case the value is contained in this argv
			 * (eg: -Idir), skip the rest.
			 */
			while(p[1])
			    p++;
			p = " "; /* Finished with this arg. */
			break;
	    	    case 'g':
			if(strcmp(p, "gstabs") == 0 ||
	    		   strcmp(p, "gdwarf2") == 0 ||
			   strcmp(p, "gdwarf-2") == 0){
			    p = " "; /* Finished with this arg. */
			}
			break;
		    case 'd':
			if(strcmp(p, "dynamic") == 0){
			    p = " "; /* Finished with this arg. */
			}
			break;
		    case 's':
			if(strcmp(p, "static") == 0){
			    p = " "; /* Finished with this arg. */
			}
			break;
		    case 'a':
		        if(strcmp(p, "arch_multiple") == 0){
			    p = " "; /* Finished with this arg. */
			}
			if(strcmp(p, "arch") == 0){
			    if(i + 1 >= argc)
				fatal("missing argument to %s option", argv[i]);
			    if(arch_name != NULL)
				fatal("more than one %s option (not allowed, "
				      "use cc(1) instead)", argv[i]);
			    arch_name = argv[i+1];
			    p = " "; /* Finished with this arg. */
			    i++;
			    break;
			}
			/* fall through for non "-arch" */
		    case 'f':
			if(strcmp(p, "force_cpusubtype_ALL") == 0){
			    p = " "; /* Finished with this arg. */
			    break;
			}
		    case 'k':
		    case 'v':
		    case 'W':
		    case 'L':
		    case 'l':
		    default:
			/* just recognize it, do nothing */
			break;
		    case 'q':
			qflag = TRUE;
			break;
		    case 'Q':
			Qflag = TRUE;
			break;
		    case 'V':
			verbose = 1;
			break;
		    }
		}
	    }
	    else{
		some_input_files = TRUE;
	    }
	}

	/*
	 * Construct the name of the assembler to run from the given -arch
	 * <arch_flag> or if none then from the value returned from
	 * get_arch_from_host().
	 */
	if(arch_name == NULL){
	    if(get_arch_from_host(&arch_flag, NULL)){
#if __LP64__
		/*
		 * If runing as a 64-bit binary and on an Intel x86 host
		 * default to the 64-bit assember.
		 */
		if(arch_flag.cputype == CPU_TYPE_I386)
		    arch_flag = *get_arch_family_from_cputype(CPU_TYPE_X86_64);
#endif /* __LP64__ */
		arch_name = arch_flag.name;
	    }
	    else
		fatal("unknown host architecture (can't determine which "
		      "assembler to run)");
	}
	else{
	    /*
	     * Convert a possible machine specific architecture name to a
	     * family name to base the name of the assembler to run.
	     */
	    if(get_arch_from_flag(arch_name, &arch_flag) != 0){
		family_arch_flag =
			get_arch_family_from_cputype(arch_flag.cputype);
		if(family_arch_flag != NULL)
		    arch_name = (char *)(family_arch_flag->name);
	    }

	}

	if(qflag == TRUE && Qflag == TRUE){
	    printf("%s: can't specifiy both -q and -Q\n", progname);
	    exit(1);
	}
	/*
	 * If the environment variable AS_INTEGRATED_ASSEMBLER is set then set
	 * the qflag to call clang(1) with -integrated-as unless the -Q flag is
	 * set and do this for the supported architectures.
	 */
	if(Qflag == FALSE &&
           getenv("AS_INTEGRATED_ASSEMBLER") != NULL &&
	   (arch_flag.cputype == CPU_TYPE_X86_64 ||
	    arch_flag.cputype == CPU_TYPE_I386 ||
	    arch_flag.cputype == CPU_TYPE_ARM64 ||
	    arch_flag.cputype == CPU_TYPE_ARM)){
	    qflag = TRUE;
	}
	if(qflag == TRUE &&
	   (arch_flag.cputype != CPU_TYPE_X86_64 &&
	    arch_flag.cputype != CPU_TYPE_I386 &&
	    arch_flag.cputype != CPU_TYPE_ARM64 &&
	    arch_flag.cputype != CPU_TYPE_ARM)){
	    printf("%s: can't specifiy -q with -arch %s\n", progname,
		   arch_flag.name);
	    exit(1);
	}

	/*
	 * When the target assembler is for arm64, for now:
	 *   rdar://8913781 ARM64: cctools 'as' driver should invoke clang
	 *		    for ARM64 assembly files
	 * use clang.  Later for:
	 *   rdar://8928193 ARM64: Standalone 'as' driver
	 * when there is and llvm-mc based standalone 'as' driver and it is
 	 * in the usual place as the other target assemblers this use of clang
	 * will be removed.
	 */ 
	if(arch_flag.cputype == CPU_TYPE_ARM64){
	    if(Qflag == TRUE){
		printf("%s: can't specifiy -Q with -arch arm64\n", progname);
		exit(1);
	    }
	    run_clang = 1;
	}

#if 0
/*
 * See rdar://9801003 where this will be changed before before NMOs and NMiOS.
 */
	/*
	 * Use the LLVM integrated assembler as the default with the as(1)
	 * driver for Intel (64-bit & 32-bit) as well as ARM for 32-bit too
	 * (64-bit ARM handled above) via running clang.
	 */
	if(arch_flag.cputype == CPU_TYPE_X86_64 ||
	   arch_flag.cputype == CPU_TYPE_I386 ||
	   arch_flag.cputype == CPU_TYPE_ARM)
	    run_clang = 1;
#endif

	/*
	 * Use the clang as the assembler if is the default or asked to with
	 * the -q flag. But don't use it asked to use the system assembler
	 * with the -Q flag.
	 */
	if((run_clang || qflag) && !Qflag &&
	   (arch_flag.cputype == CPU_TYPE_X86_64 ||
	    arch_flag.cputype == CPU_TYPE_I386 ||
	    arch_flag.cputype == CPU_TYPE_ARM64 ||
	    arch_flag.cputype == CPU_TYPE_ARM)){
	    as = makestr(prefix, CLANG, NULL);
	    if(access(as, F_OK) != 0){
		printf("%s: assembler (%s) not installed\n", progname, as);
		exit(1);
	    }
	    new_argv = allocate((argc + 8) * sizeof(char *));
	    new_argv[0] = as;
	    j = 1;
	    /*
	     * Add "-x assembler" in case the input does not end in .s this must
	     * come before "-" or the clang driver will issue an error:
	     * "error: -E or -x required when input is from standard input"
	     */
	    new_argv[j] = "-x";
	    j++;
	    new_argv[j] = "assembler";
	    j++;
	    /*
	     * If we have not seen some some_input_files or a "-" or "--" to
	     * indicate we are assembling stdin add a "-" so clang will
	     * assemble stdin as as(1) would.
	     */
	    if(some_input_files == FALSE){
		new_argv[j] = "-";
		j++;
	    }
	    for(i = 1; i < argc; i++){
		/*
		 * Translate as(1) use of "--" for stdin to clang's use of "-".
		 */
		if(strcmp(argv[i], "--") == 0){
		    new_argv[j] = "-";
		    j++;
		}
		/*
		 * Do not pass command line argument that are Unknown to
		 * to clang.
		 */
		else if(strcmp(argv[i], "-V") != 0 &&
		   strcmp(argv[i], "-q") != 0 &&
		   strcmp(argv[i], "-Q") != 0){
		    new_argv[j] = argv[i];
		    j++;
		}
	    }
	    /*
	     * clang requires a "-o a.out" if not -o is specified.
	     */
	    if(oflag_specified == FALSE){
		new_argv[j] = "-o";
		j++;
		new_argv[j] = "a.out";
		j++;
	    }
	    /* Add -integrated-as or clang will run as(1). */
	    new_argv[j] = "-integrated-as";
	    j++;
	    /* Add -c or clang will run ld(1). */
	    new_argv[j] = "-c";
	    j++;
	    new_argv[j] = NULL;
	    if(execute(new_argv, verbose))
		exit(0);
	    else
		exit(1);
	}

	/*
	 * If this assembler exist try to run it else print an error message.
	 */
	as = makestr(prefix, LIB, arch_name, AS, NULL);
	new_argv = allocate((argc + 1) * sizeof(char *));
	new_argv[0] = as;
	j = 1;
	for(i = 1; i < argc; i++){
	    /*
	     * Do not pass command line argument that are unknown to as.
	     */
	    if(strcmp(argv[i], "-q") != 0 &&
	       strcmp(argv[i], "-Q") != 0){
		new_argv[j] = argv[i];
		j++;
	    }
	}
	new_argv[j] = NULL;
	if(access(as, F_OK) == 0){
	    argv[0] = as;
	    if(execute(new_argv, verbose))
		exit(0);
	    else
		exit(1);
	}
	as_local = makestr(prefix, LOCALLIB, arch_name, AS, NULL);
	new_argv[0] = as_local;
	if(access(as_local, F_OK) == 0){
	    argv[0] = as_local;
	    if(execute(new_argv, verbose))
		exit(0);
	    else
		exit(1);
	}
	printf("%s: assembler (%s or %s) for architecture %s not installed\n",
	       progname, as, as_local, arch_name);
	arch_flags = get_arch_flags();
	count = 0;
	for(i = 0; arch_flags[i].name != NULL; i++){
	    as = makestr(prefix, LIB, arch_flags[i].name, AS, NULL);
	    if(access(as, F_OK) == 0){
		if(count == 0)
		    printf("Installed assemblers are:\n");
		printf("%s for architecture %s\n", as, arch_flags[i].name);
		count++;
	    }
	    else{
		as_local = makestr(prefix, LOCALLIB, arch_flags[i].name, AS,
				   NULL);
		if(access(as_local, F_OK) == 0){
		    if(count == 0)
			printf("Installed assemblers are:\n");
		    printf("%s for architecture %s\n", as_local,
			   arch_flags[i].name);
		    count++;
		}
	    }
	}
	if(count == 0)
	    printf("%s: no assemblers installed\n", progname);
	exit(1);
}
Exemple #4
0
void
getnfile(
void)
{
    uint32_t i, j, ncmds;
    uint64_t text_highpc;
    struct load_command *lc;
    struct segment_command *sg;
    struct segment_command_64 *sg64;
    struct section *s;
    struct section_64 *s64;
    struct symtab_command *st;
    struct nlist *symbols;
    struct nlist_64 *symbols64;
#ifdef notdef
    struct ofile lib_ofile;
    unsigned long k;
    struct fvmlib_command *fl;
    struct load_command *lib_lc;
    struct symtab_command *lib_st;
    char *lib_name;
#endif

	nname = 0;
	n_files = 0;

	if(get_arch_from_host(&host_arch_flag, NULL) == 0)
	    fatal("can't determine the host architecture");

	if(ofile_map(a_outname, NULL, NULL, &ofile, FALSE) == FALSE)
	    return;

	/*
	 * Pick the host architecture first if it is there, or the 64-bit
	 * version of the host architecture next if it is there.
	 */
	if(ofile.file_type == OFILE_FAT){
	    (void)ofile_first_arch(&ofile);
	    do{
		if(host_arch_flag.cputype == ofile.mh_cputype)
		    goto good;
	    }while(ofile_next_arch(&ofile) == TRUE);

	    (void)ofile_first_arch(&ofile);
	    do{
		if((host_arch_flag.cputype | CPU_ARCH_ABI64) ==
		   ofile.mh_cputype){
		    host_arch_flag.cputype |= CPU_ARCH_ABI64;
		    goto good;
		}
	    }while(ofile_next_arch(&ofile) == TRUE);

	    error("file: %s does not contain the host architecture", a_outname);
	    return;
	}
	else if(ofile.file_type == OFILE_ARCHIVE){
	    error("file: %s is not an Mach-O file executable", a_outname);
	    return;
	}
	else if(ofile.file_type == OFILE_Mach_O){
	    if(host_arch_flag.cputype == ofile.mh_cputype)
		goto good;
	    if((host_arch_flag.cputype | CPU_ARCH_ABI64) == ofile.mh_cputype){
		host_arch_flag.cputype |= CPU_ARCH_ABI64;
		goto good;
	    }
	    error("file: %s is not of the host architecture", a_outname);
	    return;
	}
	else{ /* ofile.file_type == OFILE_UNKNOWN */
	    error("file: %s is not an Mach-O file executable", a_outname);
	    return;
	}
good:

	if((ofile.mh == NULL && ofile.mh64 == NULL) ||
	   (ofile.mh_filetype != MH_EXECUTE &&
	    ofile.mh_filetype != MH_DYLIB &&
	    ofile.mh_filetype != MH_DYLINKER))
	    fatal("file: %s is not a Mach-O executable file", a_outname);

	/*
	 * Pass 1 count symbols and files.
	 */
	st = NULL;
	lc = ofile.load_commands;
	if(ofile.mh != NULL){
	    text_highpc = 0xfffffffe;
	    ncmds = ofile.mh->ncmds;
	}
	else{
	    text_highpc = 0xfffffffffffffffeULL;
	    ncmds = ofile.mh64->ncmds;
	}
	for(i = 0; i < ncmds; i++){
	    if(lc->cmd == LC_SEGMENT){
		sg = (struct segment_command *)lc;
		s = (struct section *)
		      ((char *)sg + sizeof(struct segment_command));
		for(j = 0; j < sg->nsects; j++){
		    if(strcmp(s->sectname, SECT_TEXT) == 0 &&
		       strcmp(s->segname, SEG_TEXT) == 0){
			textspace = (unsigned char *)ofile.object_addr +
				    s->offset;
			text_highpc = s->addr + s->size;
		    }
		    s++;
		}
	    }
	    else if(lc->cmd == LC_SEGMENT_64){
		sg64 = (struct segment_command_64 *)lc;
		s64 = (struct section_64 *)
		      ((char *)sg64 + sizeof(struct segment_command_64));
		for(j = 0; j < sg64->nsects; j++){
		    if(strcmp(s64->sectname, SECT_TEXT) == 0 &&
		       strcmp(s64->segname, SEG_TEXT) == 0){
			textspace = (unsigned char *)ofile.object_addr +
				    s64->offset;
			text_highpc = s64->addr + s64->size;
		    }
		    s64++;
		}
	    }
#ifdef notdef
	    else if(lc->cmd == LC_LOADFVMLIB){
		fl = (struct fvmlib_command *)lc;
		lib_name = (char *)fl + fl->fvmlib.name.offset;
		if(ofile_map(lib_name, &host_arch_flag, NULL, &lib_ofile,
			     FALSE) == FALSE)
		    goto done1;
		if(lib_ofile.mh == NULL || lib_ofile.mh->filetype != MH_FVMLIB){
		    warning("file: %s is not a shared library file", lib_name);
		    goto done_and_unmap1;
		}
		lib_st = NULL;
		lib_lc = lib_ofile.load_commands;
		for(j = 0; j < lib_ofile.mh->ncmds; j++){
		    if(lib_st == NULL && lib_lc->cmd == LC_SYMTAB){
			lib_st = (struct symtab_command *)lib_lc;
			count_func_symbols((struct nlist *)
				(lib_ofile.object_addr + lib_st->symoff),
				lib_st->nsyms,
				lib_ofile.object_addr + lib_st->stroff,
				lib_st->strsize);
			break;
		    }
		    else if(lib_lc->cmd == LC_SEGMENT){
			sg = (struct segment_command *)lib_lc;
			s = (struct section *)
			      ((char *)sg + sizeof(struct segment_command));
			for(k = 0; k < sg->nsects; k++){
			    if(strcmp(s->sectname, SECT_TEXT) == 0 &&
			       strcmp(s->segname, SEG_TEXT) == 0){
				shlib_text_ranges =
				    reallocate(shlib_text_ranges,
					       (nshlib_text_ranges + 1) *
					       sizeof(struct shlib_text_range));
				shlib_text_ranges[nshlib_text_ranges].lowpc = 
				    s->addr;
				shlib_text_ranges[nshlib_text_ranges].highpc = 
				    s->addr + s->size;
				nshlib_text_ranges++;
			    }
			    s++;
			}
		    }
		    lib_lc = (struct load_command *)
				((char *)lib_lc + lib_lc->cmdsize);
		}
done_and_unmap1:
		ofile_unmap(&lib_ofile);
done1:		;
	    }
#endif
	    else if(st == NULL && lc->cmd == LC_SYMTAB){
		st = (struct symtab_command *)lc;
		if(ofile.mh != NULL){
		    symbols = (struct nlist *)
			      (ofile.object_addr + st->symoff);
		    symbols64 = NULL;
		}
		else{
		    symbols64 = (struct nlist_64 *)
				(ofile.object_addr + st->symoff);
		    symbols = NULL;
		}
		count_func_symbols(symbols, symbols64, st->nsyms,
				   ofile.object_addr + st->stroff, st->strsize);
		count_N_SO_stabs(symbols, symbols64, st->nsyms,
				 ofile.object_addr + st->stroff, st->strsize);
	    }
	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
	}

	if(nname == 0)
	    fatal("executable file %s: has no symbols", a_outname);
	/*
	 * Allocate the data structures for the symbols and files.
	 */
	nl = (nltype *)calloc(nname + 2, sizeof(nltype));
	if(nl == NULL)
	    fatal("No room for %lu bytes of symbol table\n",
		  (nname + 2) * sizeof(nltype));
	npe = nl;
	files = (struct file *)calloc(n_files/2, sizeof(struct file));
	if(files == NULL)
	    fatal("No room for %lu bytes of file table\n",
		  n_files/2 * sizeof(struct file));
	n_files = 0;

	/*
	 * Pass 2 load symbols and files.
	 */
	if(st != NULL){
	    if(ofile.mh != NULL){
		symbols = (struct nlist *)
			  (ofile.object_addr + st->symoff);
		symbols64 = NULL;
	    }
	    else{
		symbols64 = (struct nlist_64 *)
			    (ofile.object_addr + st->symoff);
		symbols = NULL;
	    }
	    load_func_symbols(symbols, symbols64, st->nsyms,
			      ofile.object_addr + st->stroff, st->strsize, 0);
	    load_files(symbols, symbols64, st->nsyms,
		       ofile.object_addr + st->stroff, st->strsize);
	}
#ifdef notdef
	lc = ofile.load_commands;
	for(i = 0; i < ofile.mh->ncmds; i++){
	    if(lc->cmd == LC_LOADFVMLIB){
		fl = (struct fvmlib_command *)lc;
		lib_name = (char *)fl + fl->fvmlib.name.offset;
		if(ofile_map(lib_name, &host_arch_flag, NULL, &lib_ofile, 
			     FALSE) == TRUE){
		    lib_st = NULL;
		    lib_lc = lib_ofile.load_commands;
		    for(j = 0; j < lib_ofile.mh->ncmds; j++){
			lib_lc = (struct load_command *)
				    ((char *)lib_lc + lib_lc->cmdsize);
			if(lib_st == NULL && lib_lc->cmd == LC_SYMTAB){
			    lib_st = (struct symtab_command *)lib_lc;
			    load_func_symbols((struct nlist *)
				    (lib_ofile.object_addr + lib_st->symoff),
				    lib_st->nsyms,
				    lib_ofile.object_addr + lib_st->stroff,
				    lib_st->strsize, 0);
			    break;
			}
		    }
		}
	    }
	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
	}
#endif

	npe->value = text_highpc;
	npe->name = "past end of text";
	npe++;
	nname++;

	if(ofile.mh != NULL)
	    npe->value = npe->svalue = 0xffffffff;
	else
	    npe->value = npe->svalue = 0xffffffffffffffffULL;
	npe->name = "top of memory";

	qsort(nl, nname, sizeof(nltype),
	      (int (*)(const void *, const void *))valcmp);
#ifdef DEBUG
	if(debug & AOUTDEBUG){
	    for(i = 0; i < nname; i++){
		printf("[getnfile] ");
		if(ofile.mh != NULL)
		    printf("0x%08x", (unsigned int)nl[i].value);
		else
		    printf("%016llx", nl[i].value);
		printf("\t%s\n", nl[i].name);
	    }
	}
#endif /* DEBUG */
}