static void wip_add_work(wip_t *slot, tdata_t *pow) { if (slot->wip_td == NULL) { slot->wip_td = pow; slot->wip_nmerged = 1; } else { debug(2, "%d: merging %p into %p\n", pthread_self(), (void *)pow, (void *)slot->wip_td); merge_into_master(pow, slot->wip_td, NULL, 0); tdata_free(pow); slot->wip_nmerged++; } }
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); }
static void worker_runphase2(workqueue_t *wq) { tdata_t *pow1, *pow2; int batchid; for (;;) { pthread_mutex_lock(&wq->wq_queue_lock); if (wq->wq_ninqueue == 1) { pthread_cond_broadcast(&wq->wq_work_avail); pthread_mutex_unlock(&wq->wq_queue_lock); debug(2, "%d: entering p2 completion barrier\n", pthread_self()); if (barrier_wait(&wq->wq_bar1)) { pthread_mutex_lock(&wq->wq_queue_lock); wq->wq_alldone = 1; pthread_cond_signal(&wq->wq_alldone_cv); pthread_mutex_unlock(&wq->wq_queue_lock); } return; } if (fifo_len(wq->wq_queue) < 2) { pthread_cond_wait(&wq->wq_work_avail, &wq->wq_queue_lock); pthread_mutex_unlock(&wq->wq_queue_lock); continue; } /* there's work to be done! */ pow1 = fifo_remove(wq->wq_queue); pow2 = fifo_remove(wq->wq_queue); wq->wq_ninqueue -= 2; batchid = wq->wq_next_batchid++; pthread_mutex_unlock(&wq->wq_queue_lock); debug(2, "%d: merging %p into %p\n", pthread_self(), (void *)pow1, (void *)pow2); merge_into_master(pow1, pow2, NULL, 0); tdata_free(pow1); /* * merging is complete. place at the tail of the queue in * proper order. */ pthread_mutex_lock(&wq->wq_queue_lock); while (wq->wq_lastdonebatch + 1 != batchid) { pthread_cond_wait(&wq->wq_done_cv, &wq->wq_queue_lock); } wq->wq_lastdonebatch = batchid; fifo_add(wq->wq_queue, pow2); debug(2, "%d: added %p to queue, len now %d, ninqueue %d\n", pthread_self(), (void *)pow2, fifo_len(wq->wq_queue), wq->wq_ninqueue); pthread_cond_broadcast(&wq->wq_done_cv); pthread_cond_signal(&wq->wq_work_avail); pthread_mutex_unlock(&wq->wq_queue_lock); } }
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); }