/* * Resurrect the labels stored in the CTF data, returning the index associated * with a label provided by the caller. There are several cases, outlined * below. Note that, given two labels, the one associated with the lesser type * index is considered to be older than the other. * * 1. matchlbl == NULL - return the index of the most recent label. * 2. matchlbl == "BASE" - return the index of the oldest label. * 3. matchlbl != NULL, but doesn't match any labels in the section - warn * the user, and proceed as if matchlbl == "BASE" (for safety). * 4. matchlbl != NULL, and matches one of the labels in the section - return * the type index associated with the label. */ static int resurrect_labels(ctf_header_t *h, tdata_t *td, caddr_t ctfdata, char *matchlbl) { caddr_t buf = ctfdata + h->cth_lbloff; caddr_t sbuf = ctfdata + h->cth_stroff; size_t bufsz = h->cth_objtoff - h->cth_lbloff; int lastidx = 0, baseidx = -1; char *baselabel = NULL; ctf_lblent_t *ctl; void *v = (void *) buf; for (ctl = v; (caddr_t)ctl < buf + bufsz; ctl++) { char *label = sbuf + ctl->ctl_label; lastidx = ctl->ctl_typeidx; debug(3, "Resurrected label %s type idx %d\n", label, lastidx); tdata_label_add(td, label, lastidx); if (baseidx == -1) { baseidx = lastidx; baselabel = label; if (matchlbl != NULL && streq(matchlbl, "BASE")) return (lastidx); } if (matchlbl != NULL && streq(label, matchlbl)) return (lastidx); } if (matchlbl != NULL) { /* User provided a label that didn't match */ warning("%s: Cannot find label `%s' - using base (%s)\n", curfile, matchlbl, (baselabel ? baselabel : "NONE")); tdata_label_free(td); tdata_label_add(td, baselabel, baseidx); return (baseidx); } return (lastidx); }
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); }