Example #1
0
static void
copy_ctf_data(char *srcfile, char *destfile)
{
	tdata_t *srctd;

	if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0)
		terminate("No CTF data found in source file %s\n", srcfile);

	tmpname = mktmpname(destfile, ".ctf");
	write_ctf(srctd, destfile, tmpname, CTF_COMPRESS);
	if (rename(tmpname, destfile) != 0) {
		terminate("Couldn't rename temp file %s to %s", tmpname,
		    destfile);
	}
	free(tmpname);
	tdata_free(srctd);
}
Example #2
0
int
main(int argc, char **argv)
{
	tdata_t *mstrtd, *savetd;
	char *uniqfile = NULL, *uniqlabel = NULL;
	char *withfile = NULL;
	char *label = NULL;
	char **ifiles, **tifiles;
	int verbose = 0, docopy = 0;
	int write_fuzzy_match = 0;
	int require_ctf = 0;
	int nifiles, nielems;
	int c, i, idx, tidx, err;

	progname = basename(argv[0]);

	if (getenv("CTFMERGE_DEBUG_LEVEL"))
		debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL"));

	err = 0;
	while ((c = getopt(argc, argv, ":cd:D:fl:L:o:tvw:s")) != EOF) {
		switch (c) {
		case 'c':
			docopy = 1;
			break;
		case 'd':
			/* Uniquify against `uniqfile' */
			uniqfile = optarg;
			break;
		case 'D':
			/* Uniquify against label `uniqlabel' in `uniqfile' */
			uniqlabel = optarg;
			break;
		case 'f':
			write_fuzzy_match = CTF_FUZZY_MATCH;
			break;
		case 'l':
			/* Label merged types with `label' */
			label = optarg;
			break;
		case 'L':
			/* Label merged types with getenv(`label`) */
			if ((label = getenv(optarg)) == NULL)
				label = CTF_DEFAULT_LABEL;
			break;
		case 'o':
			/* Place merged types in CTF section in `outfile' */
			outfile = optarg;
			break;
		case 't':
			/* Insist *all* object files built from C have CTF */
			require_ctf = 1;
			break;
		case 'v':
			/* More debugging information */
			verbose = 1;
			break;
		case 'w':
			/* Additive merge with data from `withfile' */
			withfile = optarg;
			break;
		case 's':
			/* use the dynsym rather than the symtab */
			dynsym = CTF_USE_DYNSYM;
			break;
		default:
			usage();
			exit(2);
		}
	}

	/* Validate arguments */
	if (docopy) {
		if (uniqfile != NULL || uniqlabel != NULL || label != NULL ||
		    outfile != NULL || withfile != NULL || dynsym != 0)
			err++;

		if (argc - optind != 2)
			err++;
	} else {
		if (uniqfile != NULL && withfile != NULL)
			err++;

		if (uniqlabel != NULL && uniqfile == NULL)
			err++;

		if (outfile == NULL || label == NULL)
			err++;

		if (argc - optind == 0)
			err++;
	}

	if (err) {
		usage();
		exit(2);
	}

	if (uniqfile && access(uniqfile, R_OK) != 0) {
		warning("Uniquification file %s couldn't be opened and "
		    "will be ignored.\n", uniqfile);
		uniqfile = NULL;
	}
	if (withfile && access(withfile, R_OK) != 0) {
		warning("With file %s couldn't be opened and will be "
		    "ignored.\n", withfile);
		withfile = NULL;
	}
	if (outfile && access(outfile, R_OK|W_OK) != 0)
		terminate("Cannot open output file %s for r/w", outfile);

	/*
	 * This is ugly, but we don't want to have to have a separate tool
	 * (yet) just for copying an ELF section with our specific requirements,
	 * so we shoe-horn a copier into ctfmerge.
	 */
	if (docopy) {
		copy_ctf_data(argv[optind], argv[optind + 1]);

		exit(0);
	}

	set_terminate_cleanup(terminate_cleanup);

	/* Sort the input files and strip out duplicates */
	nifiles = argc - optind;
	ifiles = xmalloc(sizeof (char *) * nifiles);
	tifiles = xmalloc(sizeof (char *) * nifiles);

	for (i = 0; i < nifiles; i++)
		tifiles[i] = argv[optind + i];
	qsort(tifiles, nifiles, sizeof (char *), (int (*)())strcompare);

	ifiles[0] = tifiles[0];
	for (idx = 0, tidx = 1; tidx < nifiles; tidx++) {
		if (strcmp(ifiles[idx], tifiles[tidx]) != 0)
			ifiles[++idx] = tifiles[tidx];
	}
	nifiles = idx + 1;

	/* Make sure they all exist */
	if ((nielems = count_files(ifiles, nifiles)) < 0)
		terminate("Some input files were inaccessible\n");

	/* Prepare for the merge */
	wq_init(&wq, nielems);

	start_threads(&wq);

	/*
	 * Start the merge
	 *
	 * We're reading everything from each of the object files, so we
	 * don't need to specify labels.
	 */
	if (read_ctf(ifiles, nifiles, NULL, merge_ctf_cb,
	    &wq, require_ctf) == 0) {
		/*
		 * If we're verifying that C files have CTF, it's safe to
		 * assume that in this case, we're building only from assembly
		 * inputs.
		 */
		if (require_ctf)
			exit(0);
		terminate("No ctf sections found to merge\n");
	}

	pthread_mutex_lock(&wq.wq_queue_lock);
	wq.wq_nomorefiles = 1;
	pthread_cond_broadcast(&wq.wq_work_avail);
	pthread_mutex_unlock(&wq.wq_queue_lock);

	pthread_mutex_lock(&wq.wq_queue_lock);
	while (wq.wq_alldone == 0)
		pthread_cond_wait(&wq.wq_alldone_cv, &wq.wq_queue_lock);
	pthread_mutex_unlock(&wq.wq_queue_lock);

	join_threads(&wq);

	/*
	 * All requested files have been merged, with the resulting tree in
	 * mstrtd.  savetd is the tree that will be placed into the output file.
	 *
	 * Regardless of whether we're doing a normal uniquification or an
	 * additive merge, we need a type tree that has been uniquified
	 * against uniqfile or withfile, as appropriate.
	 *
	 * If we're doing a uniquification, we stuff the resulting tree into
	 * outfile.  Otherwise, we add the tree to the tree already in withfile.
	 */
	assert(fifo_len(wq.wq_queue) == 1);
	mstrtd = fifo_remove(wq.wq_queue);

	if (verbose || debug_level) {
		debug(2, "Statistics for td %p\n", (void *)mstrtd);

		iidesc_stats(mstrtd->td_iihash);
	}

	if (uniqfile != NULL || withfile != NULL) {
		char *reffile, *reflabel = NULL;
		tdata_t *reftd;

		if (uniqfile != NULL) {
			reffile = uniqfile;
			reflabel = uniqlabel;
		} else
			reffile = withfile;

		if (read_ctf(&reffile, 1, reflabel, read_ctf_save_cb,
		    &reftd, require_ctf) == 0) {
			terminate("No CTF data found in reference file %s\n",
			    reffile);
		}

		savetd = tdata_new();

		if (CTF_TYPE_ISCHILD(reftd->td_nextid))
			terminate("No room for additional types in master\n");

		savetd->td_nextid = withfile ? reftd->td_nextid :
		    CTF_INDEX_TO_TYPE(1, TRUE);
		merge_into_master(mstrtd, reftd, savetd, 0);

		tdata_label_add(savetd, label, CTF_LABEL_LASTIDX);

		if (withfile) {
			/*
			 * savetd holds the new data to be added to the withfile
			 */
			tdata_t *withtd = reftd;

			tdata_merge(withtd, savetd);

			savetd = withtd;
		} else {
			char uniqname[MAXPATHLEN];
			labelent_t *parle;

			parle = tdata_label_top(reftd);

			savetd->td_parlabel = xstrdup(parle->le_name);

			strncpy(uniqname, reffile, sizeof (uniqname));
			uniqname[MAXPATHLEN - 1] = '\0';
			savetd->td_parname = xstrdup(basename(uniqname));
		}

	} else {
		/*
		 * No post processing.  Write the merged tree as-is into the
		 * output file.
		 */
		tdata_label_free(mstrtd);
		tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);

		savetd = mstrtd;
	}

	tmpname = mktmpname(outfile, ".ctf");
	write_ctf(savetd, outfile, tmpname,
	    CTF_COMPRESS | write_fuzzy_match | dynsym);
	if (rename(tmpname, outfile) != 0)
		terminate("Couldn't rename output temp file %s", tmpname);
	free(tmpname);

	return (0);
}
Example #3
0
int
main(int argc, char **argv)
{
    tdata_t *filetd, *mstrtd;
    const char *label = NULL;
    int verbose = 0;
    int ignore_non_c = 0;
    int keep_stabs = 0;
    int c;

#ifdef illumos
    sighold(SIGINT);
    sighold(SIGQUIT);
    sighold(SIGTERM);
#endif

    progname = basename(argv[0]);

    if (getenv("CTFCONVERT_DEBUG_LEVEL"))
        debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL"));
    if (getenv("CTFCONVERT_DEBUG_PARSE"))
        debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE"));

    while ((c = getopt(argc, argv, ":l:L:o:givs")) != EOF) {
        switch (c) {
        case 'l':
            label = optarg;
            break;
        case 'L':
            if ((label = getenv(optarg)) == NULL)
                label = CTF_DEFAULT_LABEL;
            break;
        case 'o':
            outfile = optarg;
            break;
        case 's':
            dynsym = CTF_USE_DYNSYM;
            break;
        case 'i':
            ignore_non_c = 1;
            break;
        case 'g':
            keep_stabs = CTF_KEEP_STABS;
            break;
        case 'v':
            verbose = 1;
            break;
        default:
            usage();
            exit(2);
        }
    }

    if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
        keep_stabs = CTF_KEEP_STABS;

    if (argc - optind != 1 || label == NULL) {
        usage();
        exit(2);
    }

    infile = argv[optind];
    if (access(infile, R_OK) != 0)
        terminate("Can't access %s", infile);

    /*
     * Upon receipt of a signal, we want to clean up and exit.  Our
     * primary goal during cleanup is to restore the system to a state
     * such that a subsequent make will eventually cause this command to
     * be re-run.  If we remove the input file (which we do if we get a
     * signal and the user didn't specify a separate output file), make
     * will need to rebuild the input file, and will then need to re-run
     * ctfconvert, which is what we want.
     */
    set_terminate_cleanup(terminate_cleanup);

#ifdef illumos
    sigset(SIGINT, handle_sig);
    sigset(SIGQUIT, handle_sig);
    sigset(SIGTERM, handle_sig);
#else
    signal(SIGINT, handle_sig);
    signal(SIGQUIT, handle_sig);
    signal(SIGTERM, handle_sig);
#endif

    filetd = tdata_new();

    if (!file_read(filetd, infile, ignore_non_c))
        terminate("%s doesn't have type data to convert\n", infile);

    if (verbose)
        iidesc_stats(filetd->td_iihash);

    mstrtd = tdata_new();
    merge_into_master(filetd, mstrtd, NULL, 1);

    tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);

    /*
     * If the user supplied an output file that is different from the
     * input file, write directly to the output file.  Otherwise, write
     * to a temporary file, and replace the input file when we're done.
     */
    if (outfile && strcmp(infile, outfile) != 0) {
        write_ctf(mstrtd, infile, outfile, dynsym | keep_stabs);
    } else {
        char *tmpname = mktmpname(infile, ".ctf");
        write_ctf(mstrtd, infile, tmpname, dynsym | keep_stabs);
        if (rename(tmpname, infile) != 0)
            terminate("Couldn't rename temp file %s", tmpname);
        free(tmpname);
    }

    return (0);
}