6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * Given several files containing CTF data, merge and uniquify that data into
30 * a single CTF section in an output file.
31 *
32 * Merges can proceed independently. As such, we perform the merges in parallel
33 * using a worker thread model. A given glob of CTF data (either all of the CTF
34 * data from a single input file, or the result of one or more merges) can only
35 * be involved in a single merge at any given time, so the process decreases in
36 * parallelism, especially towards the end, as more and more files are
37 * consolidated, finally resulting in a single merge of two large CTF graphs.
38 * Unfortunately, the last merge is also the slowest, as the two graphs being
39 * merged are each the product of merges of half of the input files.
40 *
41 * The algorithm consists of two phases, described in detail below. The first
42 * phase entails the merging of CTF data in groups of eight. The second phase
43 * takes the results of Phase I, and merges them two at a time. This disparity
44 * is due to an observation that the merge time increases at least quadratically
45 * with the size of the CTF data being merged. As such, merges of CTF graphs
46 * newly read from input files are much faster than merges of CTF graphs that
47 * are themselves the results of prior merges.
585 }
586
587 static void
588 terminate_cleanup(void)
589 {
590 int dounlink = getenv("CTFMERGE_TERMINATE_NO_UNLINK") ? 0 : 1;
591
592 if (tmpname != NULL && dounlink)
593 unlink(tmpname);
594
595 if (outfile == NULL)
596 return;
597
598 if (dounlink) {
599 fprintf(stderr, "Removing %s\n", outfile);
600 unlink(outfile);
601 }
602 }
603
604 static void
605 copy_ctf_data(char *srcfile, char *destfile, int keep_stabs)
606 {
607 tdata_t *srctd;
608
609 if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0)
610 terminate("No CTF data found in source file %s\n", srcfile);
611
612 tmpname = mktmpname(destfile, ".ctf");
613 write_ctf(srctd, destfile, tmpname, CTF_COMPRESS | keep_stabs);
614 if (rename(tmpname, destfile) != 0) {
615 terminate("Couldn't rename temp file %s to %s", tmpname,
616 destfile);
617 }
618 free(tmpname);
619 tdata_free(srctd);
620 }
621
622 static void
623 wq_init(workqueue_t *wq, int nfiles)
624 {
625 int throttle, nslots, i;
626
627 if (getenv("CTFMERGE_MAX_SLOTS"))
628 nslots = atoi(getenv("CTFMERGE_MAX_SLOTS"));
629 else
630 nslots = MERGE_PHASE1_MAX_SLOTS;
631
632 if (getenv("CTFMERGE_PHASE1_BATCH_SIZE"))
633 wq->wq_maxbatchsz = atoi(getenv("CTFMERGE_PHASE1_BATCH_SIZE"));
724
725 /*
726 * Core work queue structure; passed to worker threads on thread creation
727 * as the main point of coordination. Allocate as a static structure; we
728 * could have put this into a local variable in main, but passing a pointer
729 * into your stack to another thread is fragile at best and leads to some
730 * hard-to-debug failure modes.
731 */
732 static workqueue_t wq;
733
734 int
735 main(int argc, char **argv)
736 {
737 tdata_t *mstrtd, *savetd;
738 char *uniqfile = NULL, *uniqlabel = NULL;
739 char *withfile = NULL;
740 char *label = NULL;
741 char **ifiles, **tifiles;
742 int verbose = 0, docopy = 0;
743 int write_fuzzy_match = 0;
744 int keep_stabs = 0;
745 int require_ctf = 0;
746 int nifiles, nielems;
747 int c, i, idx, tidx, err;
748
749 progname = basename(argv[0]);
750
751 if (getenv("CTFMERGE_DEBUG_LEVEL"))
752 debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL"));
753
754 err = 0;
755 while ((c = getopt(argc, argv, ":cd:D:fgl:L:o:tvw:s")) != EOF) {
756 switch (c) {
757 case 'c':
758 docopy = 1;
759 break;
760 case 'd':
761 /* Uniquify against `uniqfile' */
762 uniqfile = optarg;
763 break;
764 case 'D':
765 /* Uniquify against label `uniqlabel' in `uniqfile' */
766 uniqlabel = optarg;
767 break;
768 case 'f':
769 write_fuzzy_match = CTF_FUZZY_MATCH;
770 break;
771 case 'g':
772 keep_stabs = CTF_KEEP_STABS;
773 break;
774 case 'l':
775 /* Label merged types with `label' */
776 label = optarg;
777 break;
778 case 'L':
779 /* Label merged types with getenv(`label`) */
780 if ((label = getenv(optarg)) == NULL)
781 label = CTF_DEFAULT_LABEL;
782 break;
783 case 'o':
784 /* Place merged types in CTF section in `outfile' */
785 outfile = optarg;
786 break;
787 case 't':
788 /* Insist *all* object files built from C have CTF */
789 require_ctf = 1;
790 break;
791 case 'v':
792 /* More debugging information */
793 verbose = 1;
816 err++;
817 } else {
818 if (uniqfile != NULL && withfile != NULL)
819 err++;
820
821 if (uniqlabel != NULL && uniqfile == NULL)
822 err++;
823
824 if (outfile == NULL || label == NULL)
825 err++;
826
827 if (argc - optind == 0)
828 err++;
829 }
830
831 if (err) {
832 usage();
833 exit(2);
834 }
835
836 if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
837 keep_stabs = CTF_KEEP_STABS;
838
839 if (uniqfile && access(uniqfile, R_OK) != 0) {
840 warning("Uniquification file %s couldn't be opened and "
841 "will be ignored.\n", uniqfile);
842 uniqfile = NULL;
843 }
844 if (withfile && access(withfile, R_OK) != 0) {
845 warning("With file %s couldn't be opened and will be "
846 "ignored.\n", withfile);
847 withfile = NULL;
848 }
849 if (outfile && access(outfile, R_OK|W_OK) != 0)
850 terminate("Cannot open output file %s for r/w", outfile);
851
852 /*
853 * This is ugly, but we don't want to have to have a separate tool
854 * (yet) just for copying an ELF section with our specific requirements,
855 * so we shoe-horn a copier into ctfmerge.
856 */
857 if (docopy) {
858 copy_ctf_data(argv[optind], argv[optind + 1], keep_stabs);
859
860 exit(0);
861 }
862
863 set_terminate_cleanup(terminate_cleanup);
864
865 /* Sort the input files and strip out duplicates */
866 nifiles = argc - optind;
867 ifiles = xmalloc(sizeof (char *) * nifiles);
868 tifiles = xmalloc(sizeof (char *) * nifiles);
869
870 for (i = 0; i < nifiles; i++)
871 tifiles[i] = argv[optind + i];
872 qsort(tifiles, nifiles, sizeof (char *), (int (*)())strcompare);
873
874 ifiles[0] = tifiles[0];
875 for (idx = 0, tidx = 1; tidx < nifiles; tidx++) {
876 if (strcmp(ifiles[idx], tifiles[tidx]) != 0)
877 ifiles[++idx] = tifiles[tidx];
878 }
982 savetd->td_parlabel = xstrdup(parle->le_name);
983
984 strncpy(uniqname, reffile, sizeof (uniqname));
985 uniqname[MAXPATHLEN - 1] = '\0';
986 savetd->td_parname = xstrdup(basename(uniqname));
987 }
988
989 } else {
990 /*
991 * No post processing. Write the merged tree as-is into the
992 * output file.
993 */
994 tdata_label_free(mstrtd);
995 tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
996
997 savetd = mstrtd;
998 }
999
1000 tmpname = mktmpname(outfile, ".ctf");
1001 write_ctf(savetd, outfile, tmpname,
1002 CTF_COMPRESS | write_fuzzy_match | dynsym | keep_stabs);
1003 if (rename(tmpname, outfile) != 0)
1004 terminate("Couldn't rename output temp file %s", tmpname);
1005 free(tmpname);
1006
1007 return (0);
1008 }
|
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Given several files containing CTF data, merge and uniquify that data into
28 * a single CTF section in an output file.
29 *
30 * Merges can proceed independently. As such, we perform the merges in parallel
31 * using a worker thread model. A given glob of CTF data (either all of the CTF
32 * data from a single input file, or the result of one or more merges) can only
33 * be involved in a single merge at any given time, so the process decreases in
34 * parallelism, especially towards the end, as more and more files are
35 * consolidated, finally resulting in a single merge of two large CTF graphs.
36 * Unfortunately, the last merge is also the slowest, as the two graphs being
37 * merged are each the product of merges of half of the input files.
38 *
39 * The algorithm consists of two phases, described in detail below. The first
40 * phase entails the merging of CTF data in groups of eight. The second phase
41 * takes the results of Phase I, and merges them two at a time. This disparity
42 * is due to an observation that the merge time increases at least quadratically
43 * with the size of the CTF data being merged. As such, merges of CTF graphs
44 * newly read from input files are much faster than merges of CTF graphs that
45 * are themselves the results of prior merges.
583 }
584
585 static void
586 terminate_cleanup(void)
587 {
588 int dounlink = getenv("CTFMERGE_TERMINATE_NO_UNLINK") ? 0 : 1;
589
590 if (tmpname != NULL && dounlink)
591 unlink(tmpname);
592
593 if (outfile == NULL)
594 return;
595
596 if (dounlink) {
597 fprintf(stderr, "Removing %s\n", outfile);
598 unlink(outfile);
599 }
600 }
601
602 static void
603 copy_ctf_data(char *srcfile, char *destfile)
604 {
605 tdata_t *srctd;
606
607 if (read_ctf(&srcfile, 1, NULL, read_ctf_save_cb, &srctd, 1) == 0)
608 terminate("No CTF data found in source file %s\n", srcfile);
609
610 tmpname = mktmpname(destfile, ".ctf");
611 write_ctf(srctd, destfile, tmpname, CTF_COMPRESS);
612 if (rename(tmpname, destfile) != 0) {
613 terminate("Couldn't rename temp file %s to %s", tmpname,
614 destfile);
615 }
616 free(tmpname);
617 tdata_free(srctd);
618 }
619
620 static void
621 wq_init(workqueue_t *wq, int nfiles)
622 {
623 int throttle, nslots, i;
624
625 if (getenv("CTFMERGE_MAX_SLOTS"))
626 nslots = atoi(getenv("CTFMERGE_MAX_SLOTS"));
627 else
628 nslots = MERGE_PHASE1_MAX_SLOTS;
629
630 if (getenv("CTFMERGE_PHASE1_BATCH_SIZE"))
631 wq->wq_maxbatchsz = atoi(getenv("CTFMERGE_PHASE1_BATCH_SIZE"));
722
723 /*
724 * Core work queue structure; passed to worker threads on thread creation
725 * as the main point of coordination. Allocate as a static structure; we
726 * could have put this into a local variable in main, but passing a pointer
727 * into your stack to another thread is fragile at best and leads to some
728 * hard-to-debug failure modes.
729 */
730 static workqueue_t wq;
731
732 int
733 main(int argc, char **argv)
734 {
735 tdata_t *mstrtd, *savetd;
736 char *uniqfile = NULL, *uniqlabel = NULL;
737 char *withfile = NULL;
738 char *label = NULL;
739 char **ifiles, **tifiles;
740 int verbose = 0, docopy = 0;
741 int write_fuzzy_match = 0;
742 int require_ctf = 0;
743 int nifiles, nielems;
744 int c, i, idx, tidx, err;
745
746 progname = basename(argv[0]);
747
748 if (getenv("CTFMERGE_DEBUG_LEVEL"))
749 debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL"));
750
751 err = 0;
752 while ((c = getopt(argc, argv, ":cd:D:fl:L:o:tvw:s")) != EOF) {
753 switch (c) {
754 case 'c':
755 docopy = 1;
756 break;
757 case 'd':
758 /* Uniquify against `uniqfile' */
759 uniqfile = optarg;
760 break;
761 case 'D':
762 /* Uniquify against label `uniqlabel' in `uniqfile' */
763 uniqlabel = optarg;
764 break;
765 case 'f':
766 write_fuzzy_match = CTF_FUZZY_MATCH;
767 break;
768 case 'l':
769 /* Label merged types with `label' */
770 label = optarg;
771 break;
772 case 'L':
773 /* Label merged types with getenv(`label`) */
774 if ((label = getenv(optarg)) == NULL)
775 label = CTF_DEFAULT_LABEL;
776 break;
777 case 'o':
778 /* Place merged types in CTF section in `outfile' */
779 outfile = optarg;
780 break;
781 case 't':
782 /* Insist *all* object files built from C have CTF */
783 require_ctf = 1;
784 break;
785 case 'v':
786 /* More debugging information */
787 verbose = 1;
810 err++;
811 } else {
812 if (uniqfile != NULL && withfile != NULL)
813 err++;
814
815 if (uniqlabel != NULL && uniqfile == NULL)
816 err++;
817
818 if (outfile == NULL || label == NULL)
819 err++;
820
821 if (argc - optind == 0)
822 err++;
823 }
824
825 if (err) {
826 usage();
827 exit(2);
828 }
829
830 if (uniqfile && access(uniqfile, R_OK) != 0) {
831 warning("Uniquification file %s couldn't be opened and "
832 "will be ignored.\n", uniqfile);
833 uniqfile = NULL;
834 }
835 if (withfile && access(withfile, R_OK) != 0) {
836 warning("With file %s couldn't be opened and will be "
837 "ignored.\n", withfile);
838 withfile = NULL;
839 }
840 if (outfile && access(outfile, R_OK|W_OK) != 0)
841 terminate("Cannot open output file %s for r/w", outfile);
842
843 /*
844 * This is ugly, but we don't want to have to have a separate tool
845 * (yet) just for copying an ELF section with our specific requirements,
846 * so we shoe-horn a copier into ctfmerge.
847 */
848 if (docopy) {
849 copy_ctf_data(argv[optind], argv[optind + 1]);
850
851 exit(0);
852 }
853
854 set_terminate_cleanup(terminate_cleanup);
855
856 /* Sort the input files and strip out duplicates */
857 nifiles = argc - optind;
858 ifiles = xmalloc(sizeof (char *) * nifiles);
859 tifiles = xmalloc(sizeof (char *) * nifiles);
860
861 for (i = 0; i < nifiles; i++)
862 tifiles[i] = argv[optind + i];
863 qsort(tifiles, nifiles, sizeof (char *), (int (*)())strcompare);
864
865 ifiles[0] = tifiles[0];
866 for (idx = 0, tidx = 1; tidx < nifiles; tidx++) {
867 if (strcmp(ifiles[idx], tifiles[tidx]) != 0)
868 ifiles[++idx] = tifiles[tidx];
869 }
973 savetd->td_parlabel = xstrdup(parle->le_name);
974
975 strncpy(uniqname, reffile, sizeof (uniqname));
976 uniqname[MAXPATHLEN - 1] = '\0';
977 savetd->td_parname = xstrdup(basename(uniqname));
978 }
979
980 } else {
981 /*
982 * No post processing. Write the merged tree as-is into the
983 * output file.
984 */
985 tdata_label_free(mstrtd);
986 tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
987
988 savetd = mstrtd;
989 }
990
991 tmpname = mktmpname(outfile, ".ctf");
992 write_ctf(savetd, outfile, tmpname,
993 CTF_COMPRESS | write_fuzzy_match | dynsym);
994 if (rename(tmpname, outfile) != 0)
995 terminate("Couldn't rename output temp file %s", tmpname);
996 free(tmpname);
997
998 return (0);
999 }
|