Exemplo n.º 1
0
/*
 * execute() does an execvp using the argv passed to it.  If the parameter
 * verbose is non-zero the command is printed to stderr.  A non-zero return
 * value indicates success zero indicates failure.
 */
__private_extern__
int
execute(
char **argv,
long verbose)
{
    char *name, **p;
    int forkpid, waitpid, termsig;
#ifndef __OPENSTEP__
    int waitstatus;
#else
    union wait waitstatus;
#endif

	name = argv[0];

	if(verbose){
	    fprintf(stderr, "+ %s ", name);
	    p = &(argv[1]);
	    while(*p != (char *)0)
		    fprintf(stderr, "%s ", *p++);
	    fprintf(stderr, "\n");
	}

	forkpid = fork();
	if(forkpid == -1)
	    system_fatal("can't fork a new process to execute: %s", name);

	if(forkpid == 0){
	    if(execvp(name, argv) == -1)
		system_fatal("can't find or exec: %s", name);
	    return(1); /* can't get here, removes a warning from the compiler */
	}
	else{
	    waitpid = wait(&waitstatus);
	    if(waitpid == -1)
		system_fatal("wait on forked process %d failed", forkpid);
#ifndef __OPENSTEP__
	    termsig = WTERMSIG(waitstatus);
#else
	    termsig = waitstatus.w_termsig;
#endif
	    if(termsig != 0 && termsig != SIGINT)
		fatal("fatal error in %s", name);
	    return(
#ifndef __OPENSTEP__
		WEXITSTATUS(waitstatus) == 0 &&
#else
		waitstatus.w_retcode == 0 &&
#endif
		termsig == 0);
	}
}
Exemplo n.º 2
0
Arquivo: pass2.c Projeto: bihai/xchain
/*
 * final_output_flush() flushes the last part of the last page of the object
 * file if it does not round out to exactly a page.
 */
static
void
final_output_flush(void)
{ 
    struct block *block;
    unsigned long write_offset, write_size;
    kern_return_t r;

#ifdef DEBUG
	/* The compiler "warning: `write_offset' may be used uninitialized in */
	/* this function" can safely be ignored */
	write_offset = 0;
	if((debug & (1 << 11)) || (debug & (1 << 10))){
	    print("final_output_flush block_list:\n");
	    print_block_list();
	}
#endif /* DEBUG */

	write_size = 0;
	block = output_blocks;
	if(block != NULL){
	    if(block->offset != 0)
		fatal("internal error: first block not at offset 0");
	    if(block->written_size != 0){
		if(block->written_offset != 0)
		    fatal("internal error: first block written_offset not 0");
		write_offset = block->written_size;
		write_size = block->size - block->written_size;
	    }
	    else{
		write_offset = block->offset;
		write_size = block->size;
	    }
	    if(block->next != NULL)
		fatal("internal error: more than one block in final list");
	}
	if(write_size != 0){
#ifdef DEBUG
	    if((debug & (1 << 11)) || (debug & (1 << 10)))
		print(" writing (write_offset = %lu write_size = %lu)\n",
		       write_offset, write_size);
#endif /* DEBUG */
	    lseek(fd, write_offset, L_SET);
	    if(write(fd, output_addr + write_offset, write_size) !=
	       (int)write_size)
		system_fatal("can't write to output file");
	    if((r = vm_deallocate(mach_task_self(), (vm_address_t)(output_addr +
				  write_offset), write_size)) != KERN_SUCCESS)
		mach_fatal(r, "can't vm_deallocate() buffer for output file");
	}
}
/*
 * 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);
}
Exemplo n.º 4
0
Arquivo: pass2.c Projeto: bihai/xchain
/*
 * output_flush() takes an offset and a size of part of the output file, known
 * in the comments as the new area, and causes any fully flushed pages to be
 * written to the output file the new area in combination with previous areas
 * creates.  The data structure output_blocks has ordered blocks of areas that
 * have been flushed which are maintained by this routine.  Any area can only
 * be flushed once and an error will result is the new area overlaps with a
 * previously flushed area.
 *
 * The goal of this is to again minimize the number of dirty pages the link
 * editor has and hopfully improve performance in a memory starved system and
 * to prevent these pages to be written to the swap area when they could just be
 * written to the output file (if only external pagers worked well ...).
 */
extern
void
output_flush(
unsigned long offset,
unsigned long size)
{ 
    unsigned long write_offset, write_size;
    struct block **p, *block, *before, *after;
    kern_return_t r;

	if(flush == FALSE)
	    return;

/*
if(offset == 588824 && size != 0)
printf("in output_flush() offset = %lu size = %lu\n", offset, size);
*/

	if(offset + size > output_size)
	    fatal("internal error: output_flush(offset = %lu, size = %lu) out "
		  "of range for output_size = %lu", offset, size, output_size);

#ifdef DEBUG
	if(debug & (1 << 12))
	    print_block_list();
	if(debug & (1 << 11))
	    print("output_flush(offset = %lu, size %lu)", offset, size);
#endif /* DEBUG */

	if(size == 0){
#ifdef DEBUG
	if(debug & (1 << 11))
	    print("\n");
#endif /* DEBUG */
	    return;
	}

	/*
	 * Search through the ordered output blocks to find the block before the
	 * new area and after the new area if any exist.
	 */
	before = NULL;
	after = NULL;
	p = &(output_blocks);
	while(*p){
	    block = *p;
	    if(offset < block->offset){
		after = block;
		break;
	    }
	    else{
		before = block;
	    }
	    p = &(block->next);
	}

	/*
	 * Check for overlap of the new area with the block before and after the
	 * new area if there are such blocks.
	 */
	if(before != NULL){
	    if(before->offset + before->size > offset){
		warning("internal error: output_flush(offset = %lu, size = %lu) "
		      "overlaps with flushed block(offset = %lu, size = %lu)",
		      offset, size, before->offset, before->size);
		printf("calling abort()\n");	
		abort();
	    }
	}
	if(after != NULL){
	    if(offset + size > after->offset){
		warning("internal error: output_flush(offset = %lu, size = %lu) "
		      "overlaps with flushed block(offset = %lu, size = %lu)",
		      offset, size, after->offset, after->size);
		printf("calling abort()\n");	
		abort();
	    }
	}

	/*
	 * Now see how the new area fits in with the blocks before and after it
	 * (that is does it touch both, one or the other or neither blocks).
	 * For each case first the offset and size to write (write_offset and
	 * write_size) are set for the area of full pages that can now be
	 * written from the block.  Then the area written in the block
	 * (->written_offset and ->written_size) are set to reflect the total
	 * area in the block now written.  Then offset and size the block
	 * refers to (->offset and ->size) are set to total area of the block.
	 * Finally the links to others blocks in the list are adjusted if a
	 * block is added or removed.
	 *
	 * See if there is a block before the new area and the new area
	 * starts at the end of that block.
	 */
	if(before != NULL && before->offset + before->size == offset){
	    /*
	     * See if there is also a block after the new area and the new area
	     * ends at the start of that block.
	     */
	    if(after != NULL && offset + size == after->offset){
		/*
		 * This is the case where the new area exactly fill the area
		 * between two existing blocks.  The total area is folded into
		 * the block before the new area and the block after the new
		 * area is removed from the list.
		 */
		if(before->offset == 0 && before->written_size == 0){
		    write_offset = 0;
		    before->written_offset = 0;
		}
		else
		    write_offset =before->written_offset + before->written_size;
		if(after->written_size == 0)
		    write_size = trunc(after->offset + after->size -
				       write_offset, host_pagesize);
		else
		    write_size = trunc(after->written_offset - write_offset,
				       host_pagesize);
		if(write_size != 0){
		    before->written_size += write_size;
		}
		if(after->written_size != 0)
		    before->written_size += after->written_size;
		before->size += size + after->size;

		/* remove the block after the new area */
		before->next = after->next;
		remove_block(after);
	    }
	    else{
		/*
		 * This is the case where the new area starts at the end of the
		 * block just before it but does not end where the block after
		 * it (if any) starts.  The new area is folded into the block
		 * before the new area.
		 */
		write_offset = before->written_offset + before->written_size;
		write_size = trunc(offset + size - write_offset, host_pagesize);
		if(write_size != 0)
		    before->written_size += write_size;
		before->size += size;
	    }
	}
	/*
	 * See if the new area and the new area ends at the start of the block
	 * after it (if any).
	 */
	else if(after != NULL && offset + size == after->offset){
	    /*
	     * This is the case where the new area ends at the begining of the
	     * block just after it but does not start where the block before it.
	     * (if any) ends.  The new area is folded into this block after the
	     * new area.
	     */
	    write_offset = round(offset, host_pagesize);
	    if(after->written_size == 0)
		write_size = trunc(after->offset + after->size - write_offset,
				   host_pagesize);
	    else
		write_size = trunc(after->written_offset - write_offset,
				   host_pagesize);
	    if(write_size != 0){
		after->written_offset = write_offset;
		after->written_size += write_size;
	    }
	    else if(write_offset != after->written_offset){
		after->written_offset = write_offset;
	    }
	    after->offset = offset;
	    after->size += size;
	}
	else{
	    /*
	     * This is the case where the new area neither starts at the end of
	     * the block just before it (if any) or ends where the block after
	     * it (if any) starts.  A new block is created and the new area is
	     * is placed in it.
	     */
	    write_offset = round(offset, host_pagesize);
	    write_size = trunc(offset + size - write_offset, host_pagesize);
	    block = get_block();
	    block->offset = offset;
	    block->size = size;
	    block->written_offset = write_offset;
	    block->written_size = write_size;
	    /*
	     * Insert this block in the ordered list in the correct place.
	     */
	    if(before != NULL){
		block->next = before->next;
		before->next = block;
	    }
	    else{
		block->next = output_blocks;
		output_blocks = block;
	    }
	}

	/*
	 * Now if there are full pages to write write them to the output file.
	 */
	if(write_size != 0){
#ifdef DEBUG
	if((debug & (1 << 11)) || (debug & (1 << 10)))
	    print(" writing (write_offset = %lu write_size = %lu)\n",
		   write_offset, write_size);
#endif /* DEBUG */
	    lseek(fd, write_offset, L_SET);
	    if(write(fd, output_addr + write_offset, write_size) !=
	       (int)write_size)
		system_fatal("can't write to output file");
	    if((r = vm_deallocate(mach_task_self(), (vm_address_t)(output_addr +
				  write_offset), write_size)) != KERN_SUCCESS)
		mach_fatal(r, "can't vm_deallocate() buffer for output file");
	}
#ifdef DEBUG
	else{
	    if(debug & (1 << 11))
		print(" no write\n");
	}
#endif /* DEBUG */
}
Exemplo n.º 5
0
Arquivo: pass2.c Projeto: bihai/xchain
/*
 * pass2() creates the output file and the memory buffer to create the file
 * into.  It drives the process to get everything copied into the buffer for
 * the output file.  It then writes the output file and deallocates the buffer.
 */ 
extern
void
pass2(void)
{
    unsigned long i, j, section_type;
    struct object_list *object_list, **p;
#ifndef RLD
    int mode;
    struct stat stat_buf;
    kern_return_t r;

	/*
	 * In UNIX standard conformance mode we are not allowed to replace
	 * a file that is not writeable.
	 */
	if(get_unix_standard_mode() == TRUE && 
	   access(outputfile, F_OK) == 0 &&
	   access(outputfile, W_OK) == -1)
	    system_fatal("can't write output file: %s", outputfile);

	/*
	 * Create the output file.  The unlink() is done to handle the problem
	 * when the outputfile is not writable but the directory allows the
	 * file to be removed (since the file may not be there the return code
	 * of the unlink() is ignored).
	 */
	(void)unlink(outputfile);
	if((fd = open(outputfile, O_WRONLY | O_CREAT | O_TRUNC, 0777)) == -1)
	    system_fatal("can't create output file: %s", outputfile);
#ifdef F_NOCACHE
        /* tell filesystem to NOT cache the file when reading or writing */
	(void)fcntl(fd, F_NOCACHE, 1);
#endif
	if(fstat(fd, &stat_buf) == -1)
	    system_fatal("can't stat file: %s", outputfile);
	/*
	 * Turn the execute bits on or off depending if there are any undefined
	 * symbols in the output file.  If the file existed before the above
	 * open() call the creation mode in that call would have been ignored
	 * so it has to be set explicitly in any case.
	 */
	if(output_mach_header.flags & MH_NOUNDEFS ||
	   (has_dynamic_linker_command && output_for_dyld))
	    mode = (stat_buf.st_mode & 0777) | (0111 & ~umask(0));
	else
	    mode = (stat_buf.st_mode & 0777) & ~0111;
	if(fchmod(fd, mode) == -1)
	    system_fatal("can't set execution permissions output file: %s",
			 outputfile);

	/*
	 * Create the buffer to copy the parts of the output file into.
	 */
	if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
			    output_size, TRUE)) != KERN_SUCCESS)
	    mach_fatal(r, "can't vm_allocate() buffer for output file of size "
		       "%lu", output_size);

	/*
	 * Set up for flushing pages to the output file as they fill up.
	 */
	if(flush)
	    setup_output_flush();

	/*
	 * Make sure pure_instruction sections are padded with nop's.
	 */
	nop_pure_instruction_scattered_sections();

#endif /* !defined(RLD) */

	/*
	 * The strings indexes for the merged string blocks need to be set
	 * before the dylib tables are output because the module names are in
	 * them as well as the merged symbol names.
	 */
	set_merged_string_block_indexes();

#ifndef RLD
	/*
	 * Copy the dylib tables into the output file.  This is done before the
	 * sections are outputted so that the indexes to the local and external
	 * relocation entries for each object can be used as running indexes as
	 * each section in the object is outputted.
	 */
	if(filetype == MH_DYLIB)
	    output_dylib_tables();
#endif /* !defined(RLD) */

	/*
	 * Create the array of pointers to merged sections in the output file
	 * so the relocation routines can use it to set the 'referenced' fields
	 * in the merged section structures.
	 */
	create_output_sections_array();

	/*
	 * Copy the merged literal sections and the sections created from files
	 * into the output object file.
	 */
	output_literal_sections();
#ifndef RLD
	output_sections_from_files();
#endif /* !defined(RLD) */

	/*
	 * For each non-literal content section in each object file loaded 
	 * relocate it into the output file (along with the relocation entries).
	 * Then relocate local symbols into the output file for the loaded
	 * objects.
	 */
	for(p = &objects; *p; p = &(object_list->next)){
	    object_list = *p;
	    for(i = 0; i < object_list->used; i++){
		cur_obj = &(object_list->object_files[i]);
		/* print the object file name if tracing */
		if(trace){
		    print_obj_name(cur_obj);
		    print("\n");
		}
		if(cur_obj->dylib)
		    continue;
		if(cur_obj->bundle_loader)
		    continue;
		if(cur_obj->dylinker)
		    continue;
		if(cur_obj != base_obj){
		    for(j = 0; j < cur_obj->nsection_maps; j++){
			if(cur_obj->section_maps[j].s->flags & S_ATTR_DEBUG)
			    continue;
#ifdef RLD
			if(cur_obj->set_num == cur_set)
#endif /* RLD */
			{
			    section_type = (cur_obj->section_maps[j].s->flags &
                                                   SECTION_TYPE);
			    if(section_type == S_REGULAR ||
			       section_type == S_SYMBOL_STUBS ||
			       section_type == S_NON_LAZY_SYMBOL_POINTERS ||
			       section_type == S_LAZY_SYMBOL_POINTERS ||
			       section_type == S_COALESCED ||
			       section_type == S_MOD_INIT_FUNC_POINTERS ||
			       section_type == S_MOD_TERM_FUNC_POINTERS){
				output_section(&(cur_obj->section_maps[j]));
			    }
			}
		    }
		}
		output_local_symbols();
#if defined(VM_SYNC_DEACTIVATE) && !defined(_POSIX_C_SOURCE) && !defined(__CYGWIN__)
		vm_msync(mach_task_self(), (vm_address_t)cur_obj->obj_addr,
			 (vm_size_t)cur_obj->obj_size, VM_SYNC_DEACTIVATE);
#endif /* VM_SYNC_DEACTIVATE */
	    }
	}
	/*
	 * If there were errors in output_section() then return as so not
	 * to cause later internal errors.
	 */
	if(errors != 0)
	    return;

#ifdef RLD
	/*
	 * For each content section clean up the data structures not needed
	 * after rld is run.  This must be done after ALL the sections are
	 * output'ed because the fine relocation entries could be used by any
	 * of the sections.
	 */
	for(p = &objects; *p; p = &(object_list->next)){
	    object_list = *p;
	    for(i = 0; i < object_list->used; i++){
		cur_obj = &(object_list->object_files[i]);
		for(j = 0; j < cur_obj->nsection_maps; j++){
		    if(cur_obj->section_maps[j].nfine_relocs != 0){
			free(cur_obj->section_maps[j].fine_relocs);
			cur_obj->section_maps[j].fine_relocs = NULL;
			cur_obj->section_maps[j].nfine_relocs = 0;
		    }
		}
		if(cur_obj->nundefineds != 0){
		    free(cur_obj->undefined_maps);
		    cur_obj->undefined_maps = NULL;
		    cur_obj->nundefineds = 0;
		}
	    }
	}
#endif /* RLD */

	/*
	 * Set the SG_NORELOC flag in the segments that had no relocation to
	 * or for them.
	 */
	set_SG_NORELOC_flags();

#ifndef SA_RLD
	/*
	 * Copy the indirect symbol table into the output file.
	 */
	output_indirect_symbols();
#endif /* SA_RLD */

	/*
	 * Copy the merged symbol table into the output file.
	 */
	output_merged_symbols();

	/*
	 * Copy the headers into the output file.
	 */
	output_headers();

#ifndef RLD
	if(flush){
	    /*
	     * Flush the sections that have been scatter loaded.
	     */
	    flush_scatter_copied_sections();
	    /*
	     * flush the remaining part of the object file that is not a full
	     * page.
	     */
	    final_output_flush();
	}
	else{
	    /*
	     * Write the entire object file.
	     */
	    if(write(fd, output_addr, output_size) != (int)output_size)
		system_fatal("can't write output file");

	    if((r = vm_deallocate(mach_task_self(), (vm_address_t)output_addr,
				  output_size)) != KERN_SUCCESS)
		mach_fatal(r, "can't vm_deallocate() buffer for output file");
	}
#ifdef F_NOCACHE
	/* re-enable caching of file reads/writes */
	(void)fcntl(fd, F_NOCACHE, 0);
#endif
	if(close(fd) == -1)
	    system_fatal("can't close output file");
#endif /* RLD */
}
Exemplo n.º 6
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);
}
Exemplo n.º 7
0
/*
 * The ctf_insert(1) tool has the following usage:
 *
 *	ctf_insert input -arch arch ctf_file ...  -o output
 * 
 * Where the input is a Mach-O file that is the ctf_file(s) are to be inserted
 * into and output is the file to be created.
 */
int
main(
int argc,
char **argv,
char **envp)
{
    uint32_t i;
    char *input, *output, *contents;
    struct arch *archs;
    uint32_t narchs;
    struct stat stat_buf;
    int fd;

	progname = argv[0];
	input = NULL;
	output = NULL;
	archs = NULL;
	narchs = 0;
	for(i = 1; i < argc; i++){
	    if(strcmp(argv[i], "-o") == 0){
		if(i + 1 == argc){
		    error("missing argument to: %s option", argv[i]);
		    usage();
		}
		if(output != NULL){
		    error("more than one: %s option specified", argv[i]);
		    usage();
		}
		output = argv[i+1];
		i++;
	    }
	    else if(strcmp(argv[i], "-arch") == 0){
		if(i + 2 == argc){
		    error("missing argument(s) to: %s option", argv[i]);
		    usage();
		}
		else{
		    arch_ctfs = reallocate(arch_ctfs,
			    (narch_ctfs + 1) * sizeof(struct arch_ctf));
		    if(get_arch_from_flag(argv[i+1],
				  &(arch_ctfs[narch_ctfs].arch_flag)) == 0){
			error("unknown architecture specification flag: "
			      "%s %s %s", argv[i], argv[i+1], argv[i+2]);
			arch_usage();
			usage();
		    }
		    if((fd = open(argv[i+2], O_RDONLY, 0)) == -1)
			system_fatal("can't open file: %s", argv[i+2]);
		    if(fstat(fd, &stat_buf) == -1)
			system_fatal("can't stat file: %s", argv[i+2]);
		    /*
		     * For some reason mapping files with zero size fails
		     * so it has to be handled specially.
		     */
		    contents = NULL;
		    if(stat_buf.st_size != 0){
			contents = mmap(0, stat_buf.st_size,
					PROT_READ|PROT_WRITE,
				        MAP_FILE|MAP_PRIVATE, fd, 0);
			if((intptr_t)contents == -1)
			    system_error("can't map file : %s", argv[i+2]);
		    }
		    arch_ctfs[narch_ctfs].filename = argv[i+2];
		    arch_ctfs[narch_ctfs].contents = contents;
		    arch_ctfs[narch_ctfs].size = stat_buf.st_size;
		    arch_ctfs[narch_ctfs].arch_found = FALSE;
		    narch_ctfs++;
		    i += 2;
		}
	    }
	    else{
		if(input != NULL){
		    error("more than one input file file: %s specified",
			  input);
		    usage();
		}
		input = argv[i];
	    }
	}
	if(input == NULL || output == NULL || narch_ctfs == 0)
	    usage();

	breakout(input, &archs, &narchs, FALSE);
	if(errors)
	    exit(EXIT_FAILURE);

	checkout(archs, narchs);

	process(archs, narchs);

	for(i = 0; i < narch_ctfs; i++){
	    if(arch_ctfs[i].arch_found == FALSE)
		fatal("input file: %s does not contain a matching architecture "
		      "for specified '-arch %s %s' option", input,
		      arch_ctfs[i].arch_flag.name, arch_ctfs[i].filename);
	}

	writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, FALSE, NULL);

	if(errors)
	    return(EXIT_FAILURE);
	else
	    return(EXIT_SUCCESS);
}
Exemplo n.º 8
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);
}
Exemplo n.º 9
0
static
void
read_dyld_state(
uint32_t type,
int fd,
char *filename,
uint32_t nbytes,
uint32_t magic)
{
    uint32_t i, offset, sizeof_vmaddr, vmaddr32;
    uint64_t vmaddr64;
    char *buf;

	buf = malloc(nbytes);
	if(buf == NULL)
	    fatal("no room for dyld state (malloc failed)");

	if(read(fd, buf, nbytes) != (int)nbytes)
	    system_fatal("malformed gmon.out file: %s (can't read dyld state)",
			 filename);

	offset = 0;
	if(offset + sizeof(uint32_t) > nbytes)
	    fatal("truncated or malformed gmon.out file: %s (image count "
		  "extends past the end of the dyld state)", filename);
	memcpy(&image_count, buf + offset, sizeof(uint32_t));
	offset += sizeof(uint32_t);

	dyld_images = (struct dyld_image *)malloc(sizeof(struct dyld_image) *
						  image_count);
	if(dyld_images == NULL)
	    fatal("no room for dyld images (malloc failed)");

	if(magic == GMON_MAGIC)
	    sizeof_vmaddr = sizeof(uint32_t);
	else
	    sizeof_vmaddr = sizeof(uint64_t);
	for(i = 0; i < image_count; i++){
	    if(offset + sizeof_vmaddr > nbytes)
		fatal("truncated or malformed gmon.out file: %s (vmaddr "
		      "for image %u extends past the end of the dyld state)",
		      filename, i);

	    if(magic == GMON_MAGIC){
		memcpy(&vmaddr32, buf + offset, sizeof_vmaddr);
		vmaddr64 = vmaddr32;
	    }
	    else{
		memcpy(&vmaddr64, buf + offset, sizeof_vmaddr);
	    }
	    offset += sizeof_vmaddr;
	
	    if(type == GMONTYPE_DYLD_STATE){
		dyld_images[i].vmaddr_slide = vmaddr64;
		dyld_images[i].image_header = 0;
	    }
	    else{
		dyld_images[i].image_header = vmaddr64;
		dyld_images[i].vmaddr_slide = 0;
	    }

	    dyld_images[i].name = buf + offset;
	    while(buf[offset] != '\0' && offset < nbytes)
		offset++;
	    if(buf[offset] == '\0' && offset < nbytes)
		offset++;
	    if(offset > nbytes)
		fatal("truncated or malformed gmon.out file: %s (name "
		      "for image %u extends past the end of the dyld state)",
		      filename, i);
	}
#ifdef DEBUG
	if(debug & DYLDDEBUG){
	    printf("image_count = %u\n", image_count);
	    for(i = 0; i < image_count; i++){
		printf("dyld_image[%u].name = %s\n", i, dyld_images[i].name);
		printf("dyld_image[%u].vmaddr_slide = 0x%llx\n", i,
			dyld_images[i].vmaddr_slide);
		printf("dyld_image[%u].image_header = 0x%llx\n", i,
			dyld_images[i].image_header);
	    }
	}
#endif
}
Exemplo n.º 10
0
static
void
read_rld_state(
int fd,
char *filename,
uint32_t nbytes)
{
    uint32_t i, j, size, size_read, str_size;
    char *strings;

	size_read = 0;
	size = sizeof(uint32_t);
	if(read(fd, &grld_nloaded_states, size) != size)
	    system_fatal("malformed gmon.out file: %s (can't read number of "
			 "rld states)", filename);
	size_read += size;

	grld_loaded_state = (struct rld_loaded_state *)
		malloc(grld_nloaded_states * sizeof(struct rld_loaded_state));
	if(grld_loaded_state == NULL)
	    fatal("no room for rld states (malloc failed)");

	for(i = 0; i < grld_nloaded_states; i++){
	    size = sizeof(uint32_t);
	    if(read(fd, &(grld_loaded_state[i].header_addr), size) != size)
		system_fatal("malformed gmon.out file: %s (can't read header "
		    "address of rld state %lu)", filename, i);
	    size_read += size;

	    size = sizeof(uint32_t);
	    if(read(fd, &(grld_loaded_state[i].nobject_filenames), size) != size)
		system_fatal("malformed gmon.out file: %s (can't read number "
		    "of object file names of rld state %lu)", filename, i);
	    size_read += size;

	    grld_loaded_state[i].object_filenames = (char **)
		malloc((grld_loaded_state[i].nobject_filenames + 1) *
		       sizeof(char *));
	    if(grld_loaded_state[i].object_filenames == NULL)
		fatal("no room for rld state %lu object file names (malloc "
		      "failed)", i);

	    size = grld_loaded_state[i].nobject_filenames * sizeof(char *);
	    if(read(fd, grld_loaded_state[i].object_filenames, size) != size)
		system_fatal("malformed gmon.out file: %s (can't read offsets "
		    "to file names of rld state %lu)", filename, i);
	    size_read += size;

	    size = sizeof(uint32_t);
	    if(read(fd, &str_size, size) != size)
		system_fatal("malformed gmon.out file: %s (can't read string "
		    "size of rld state %lu)", filename, i);
	    size_read += size;

	    strings = (char *)malloc(str_size);
	    if(strings == NULL)
		fatal("no room for rld state %lu object file names (malloc "
		      "failed)", i);

	    size = str_size;
	    if(read(fd, strings, size) != size)
		system_fatal("malformed gmon.out file: %s (can't read strings "
		    "of file names of rld state %lu)", filename, i);
	    size_read += size;

	    for(j = 0; j < grld_loaded_state[i].nobject_filenames; j++){
		if((uint32_t)(grld_loaded_state[i].object_filenames[j]) >
		   str_size)
		    fatal("malformed gmon.out file: %s (bad offset to object "
			  "filename %lu of rld state %lu)", filename, j, i);
		grld_loaded_state[i].object_filenames[j] = strings +
		    (uint32_t)(grld_loaded_state[i].object_filenames[j]);
	    }
	    grld_loaded_state[i].object_filenames[j] = NULL;
	}

#ifdef DEBUG
	if(debug & RLDDEBUG){
	    printf("grld_nloaded_states = %lu\n", grld_nloaded_states);
	    printf("grld_loaded_state 0x%x\n", (unsigned int)grld_loaded_state);
	    for(i = 0; i < grld_nloaded_states; i++){
		printf("state %lu\n\tnobject_filenames %lu\n\tobject_filenames "
		      "0x%x\n\theader_addr 0x%x\n", i,
		      grld_loaded_state[i].nobject_filenames,
		      (unsigned int)(grld_loaded_state[i].object_filenames),
		      (unsigned int)(grld_loaded_state[i].header_addr));
		for(j = 0; j < grld_loaded_state[i].nobject_filenames; j++)
		    printf("\t\t%s\n", grld_loaded_state[i].object_filenames[j]);
	    }
	}
#endif
}
Exemplo n.º 11
0
static
void
getpfile(
char *filename)
{
    uint32_t magic, left;
    gmon_data_t data;
    int fd;
    struct stat stat;

	if((fd = open(filename, O_RDONLY)) == -1)
	    system_fatal("can't open: %s", filename);
	if(fstat(fd, &stat) == -1)
	    system_fatal("can't stat: %s", filename);
	/*
	 * See if this gmon.out file is an old format or new format by looking
	 * for the magic number of the new format.
	 */
	if(read(fd, &magic, sizeof(uint32_t)) != sizeof(uint32_t))
	    system_fatal("malformed gmon.out file: %s (can't read magic "
			 "number)", filename);
	if(magic == GMON_MAGIC || magic == GMON_MAGIC_64){
#ifdef DEBUG_GMON_OUT
	    if(magic == GMON_MAGIC)
		printf("GMON_MAGIC\n");
	    else
		printf("GMON_MAGIC_64\n");
#endif
	    /*
	     * This is a new format gmon.out file.  After the magic number comes
	     * any number of pairs of gmon_data structs and some typed data.
	     */
	    left = stat.st_size - sizeof(uint32_t);
	    while(left >= sizeof(struct gmon_data)){
		if(read(fd, &data, sizeof(struct gmon_data)) !=
			sizeof(struct gmon_data))
		    system_fatal("malformed gmon.out file: %s (can't read "
				 "gmon_data struct)", filename);
		left -= sizeof(struct gmon_data);
		if(left < data.size)
		    fatal("truncated or malformed gmon.out file: %s (value in "
			  "size field in gmon_data struct more than left in "
			  "file)", filename);
#ifdef DEBUG_GMON_OUT
		printf("gmon_data struct: type = %u size = %u\n", data.type,
		       data.size);
#endif
		switch(data.type){
		case GMONTYPE_SAMPLES:
#ifdef DEBUG_GMON_OUT
		    printf("GMONTYPE_SAMPLES\n");
#endif
		    new_sample_set(fd, filename, data.size, FALSE, magic);
		    break;
		case GMONTYPE_RAWARCS:
#ifdef DEBUG_GMON_OUT
		    printf("GMONTYPE_RAWARCS\n");
#endif
		    if(magic == GMON_MAGIC)
			readarcs(fd, filename, data.size);
		    else
			readarcs_64(fd, filename, data.size);
		    break;
		case GMONTYPE_ARCS_ORDERS:
#ifdef DEBUG_GMON_OUT
		    printf("GMONTYPE_ARCS_ORDERS\n");
#endif
		    if(magic == GMON_MAGIC)
			readarcs_orders(fd, filename, data.size);
		    else
			readarcs_orders_64(fd, filename, data.size);
		    break;
#ifdef __OPENSTEP__
		case GMONTYPE_RLD_STATE:
#ifdef DEBUG_GMON_OUT
		    printf("GMONTYPE_RLD_STATE\n");
#endif
		    if(grld_nloaded_states == 0){
			read_rld_state(fd, filename, data.size);
			get_rld_state_symbols();
		    }
		    else{
			warning("can't process more than one rld loaded state "
			        "(ignoring rld state from: %s)", filename);
			lseek(fd, data.size, L_INCR);
		    }
		    break;
#endif
		case GMONTYPE_DYLD_STATE:
#ifdef DEBUG_GMON_OUT
		    printf("GMONTYPE_DYLD_STATE\n");
#endif
		    goto setup_dyld_state;
		case GMONTYPE_DYLD2_STATE:
#ifdef DEBUG_GMON_OUT
		    printf("GMONTYPE_DYLD2_STATE\n");
#endif
setup_dyld_state:
		    if(image_count == 0){
			read_dyld_state(data.type, fd, filename, data.size,
					magic);
			get_dyld_state_symbols();
		    }
		    else{
			warning("can't process more than one dyld state "
			        "(ignoring dyld state from: %s)", filename);
			lseek(fd, data.size, L_INCR);
		    }
		    break;
		default:
#ifdef DEBUG_GMON_OUT
		    printf("Unknown data.type = %u\n", data.type);
#endif
		    fatal("truncated or malformed gmon.out file: %s (value in "
			  "type field in gmon_data struct unknown)", filename);
		}
		left -= data.size;
	    }
	    if(left != 0)
		fatal("truncated or malformed gmon.out file: %s (file end in "
		      "the middle of a gmon_data struct %u)", filename, left);
	}
	else{
	    /*
	     * This is an old format gmon.out file.  It has a profile header
	     * then * an array of sampling hits within pc ranges, and then arcs.
	     */
	    lseek(fd, 0, L_SET);
	    left = stat.st_size;
	    left -= new_sample_set(fd, filename, left, TRUE, GMON_MAGIC);
	    readarcs(fd, filename, left);
	}
	close(fd);
}