1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright (c) 2015 Joyent, Inc.
14 */
15
16 /*
17 * To perform a merge of two CTF containers, we first diff the two containers
18 * types. For every type that's in the src container, but not in the dst
19 * container, we note it and add it to dst container. If there are any objects
20 * or functions associated with src, we go through and update the types that
21 * they refer to such that they all refer to types in the dst container.
22 *
23 * The bulk of the logic for the merge, after we've run the diff, occurs in
24 * ctf_merge_common().
25 *
26 * In terms of exported APIs, we don't really export a simple merge two
27 * containers, as the general way this is used, in something like ctfmerge(1),
28 * is to add all the containers and then let us figure out the best way to merge
29 * it.
30 */
31
32 #include <libctf_impl.h>
33 #include <sys/debug.h>
43 uint16_t cmt_map; /* Map to the type in out */
44 boolean_t cmt_fixup;
45 boolean_t cmt_forward;
46 boolean_t cmt_missing;
47 } ctf_merge_tinfo_t;
48
49 /*
50 * State required for doing an individual merge of two containers.
51 */
52 typedef struct ctf_merge_types {
53 ctf_file_t *cm_out; /* Output CTF file */
54 ctf_file_t *cm_src; /* Input CTF file */
55 ctf_merge_tinfo_t *cm_tmap; /* Type state information */
56 boolean_t cm_dedup; /* Are we doing a dedup? */
57 boolean_t cm_unique; /* are we doing a uniquify? */
58 } ctf_merge_types_t;
59
60 typedef struct ctf_merge_objmap {
61 list_node_t cmo_node;
62 const char *cmo_name; /* Symbol name */
63 ulong_t cmo_idx; /* Symbol ID */
64 ctf_id_t cmo_tid; /* Type ID */
65 } ctf_merge_objmap_t;
66
67 typedef struct ctf_merge_funcmap {
68 list_node_t cmf_node;
69 const char *cmf_name; /* Symbol name */
70 ulong_t cmf_idx; /* Symbol ID */
71 ctf_id_t cmf_rtid; /* Type ID */
72 uint_t cmf_flags; /* ctf_funcinfo_t ctc_flags */
73 uint_t cmf_argc; /* Number of arguments */
74 ctf_id_t cmf_args[]; /* Types of arguments */
75 } ctf_merge_funcmap_t;
76
77 typedef struct ctf_merge_input {
78 list_node_t cmi_node;
79 ctf_file_t *cmi_input;
80 list_t cmi_omap;
81 list_t cmi_fmap;
82 boolean_t cmi_created;
83 } ctf_merge_input_t;
84
85 struct ctf_merge_handle {
86 list_t cmh_inputs; /* Input list */
87 uint_t cmh_ninputs; /* Number of inputs */
88 uint_t cmh_nthreads; /* Number of threads to use */
89 ctf_file_t *cmh_unique; /* ctf to uniquify against */
90 boolean_t cmh_msyms; /* Should we merge symbols/funcs? */
91 int cmh_ofd; /* FD for output file */
92 int cmh_flags; /* Flags that control merge behavior */
93 char *cmh_label; /* Optional label */
94 char *cmh_pname; /* Parent name */
95 };
96
97 static int ctf_merge_add_type(ctf_merge_types_t *, ctf_id_t);
98
99 static ctf_id_t
100 ctf_merge_gettype(ctf_merge_types_t *cmp, ctf_id_t id)
101 {
102 if (cmp->cm_dedup == B_FALSE) {
103 VERIFY(cmp->cm_tmap[id].cmt_map != 0);
104 return (cmp->cm_tmap[id].cmt_map);
105 }
106
107 while (cmp->cm_tmap[id].cmt_missing == B_FALSE) {
108 VERIFY(cmp->cm_tmap[id].cmt_map != 0);
109 id = cmp->cm_tmap[id].cmt_map;
110 }
111 VERIFY(cmp->cm_tmap[id].cmt_map != 0);
112 return (cmp->cm_tmap[id].cmt_map);
113 }
114
115 static void
116 ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
644 *
645 * Pass 1 checks for forward references in the output container that we know
646 * exist in the source container.
647 *
648 * Pass 2 adds all the missing types from the source container. As part of this
649 * we may be adding a type as a forward reference that doesn't exist yet.
650 * Any types that we encounter in this form, we need to add to a third pass.
651 *
652 * Pass 3 is the fixup pass. Here we go through and find all the types that were
653 * missing in the first.
654 *
655 * Importantly, we *must* call ctf_update between the second and third pass,
656 * otherwise several of the libctf functions will not properly find the data in
657 * the container. If we're doing a dedup we also fix up the type mapping.
658 */
659 static int
660 ctf_merge_common(ctf_merge_types_t *cmp)
661 {
662 int ret, i;
663
664 ctf_phase_dump(cmp->cm_src, "merge-common-src");
665 ctf_phase_dump(cmp->cm_out, "merge-common-dest");
666
667 /* Pass 1 */
668 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
669 if (cmp->cm_tmap[i].cmt_forward == B_TRUE) {
670 ret = ctf_merge_add_sou(cmp, i, B_TRUE);
671 if (ret != 0) {
672 return (ret);
673 }
674 }
675 }
676
677 /* Pass 2 */
678 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
679 if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
680 ret = ctf_merge_add_type(cmp, i);
681 if (ret != 0) {
682 ctf_dprintf("Failed to merge type %d\n", i);
683 return (ret);
684 }
685 }
747 static int
748 ctf_merge_types_init(ctf_merge_types_t *cmp)
749 {
750 cmp->cm_tmap = ctf_alloc(sizeof (ctf_merge_tinfo_t) *
751 (cmp->cm_src->ctf_typemax + 1));
752 if (cmp->cm_tmap == NULL)
753 return (ctf_set_errno(cmp->cm_out, ENOMEM));
754 bzero(cmp->cm_tmap, sizeof (ctf_merge_tinfo_t) *
755 (cmp->cm_src->ctf_typemax + 1));
756 return (0);
757 }
758
759 static void
760 ctf_merge_types_fini(ctf_merge_types_t *cmp)
761 {
762 ctf_free(cmp->cm_tmap, sizeof (ctf_merge_tinfo_t) *
763 (cmp->cm_src->ctf_typemax + 1));
764 }
765
766 /*
767 * Merge the types contained inside of two input files. The second input file is
768 * always going to be the destination. We're guaranteed that it's always
769 * writeable.
770 */
771 static int
772 ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
773 {
774 int ret;
775 ctf_merge_types_t cm;
776 ctf_diff_t *cdp;
777 ctf_merge_objmap_t *cmo;
778 ctf_merge_funcmap_t *cmf;
779 ctf_merge_input_t *scmi = arg;
780 ctf_merge_input_t *dcmi = arg2;
781 ctf_file_t *out = dcmi->cmi_input;
782 ctf_file_t *source = scmi->cmi_input;
783
784 ctf_dprintf("merging %p->%p\n", source, out);
785
786 if (!(out->ctf_flags & LCTF_RDWR))
787 return (ctf_set_errno(out, ECTF_RDONLY));
788
789 if (ctf_getmodel(out) != ctf_getmodel(source))
790 return (ctf_set_errno(out, ECTF_DMODEL));
791
792 if ((ret = ctf_diff_init(out, source, &cdp)) != 0)
793 return (ret);
794
795 cm.cm_out = out;
796 cm.cm_src = source;
797 cm.cm_dedup = B_FALSE;
798 cm.cm_unique = B_FALSE;
800 if (ret != 0) {
801 ctf_diff_fini(cdp);
802 return (ctf_set_errno(out, ret));
803 }
804
805 ret = ctf_diff_types(cdp, ctf_merge_diffcb, &cm);
806 if (ret != 0)
807 goto cleanup;
808 ret = ctf_merge_common(&cm);
809 ctf_dprintf("merge common returned with %d\n", ret);
810 if (ret == 0) {
811 ret = ctf_update(out);
812 ctf_dprintf("update returned with %d\n", ret);
813 } else {
814 goto cleanup;
815 }
816
817 /*
818 * Now we need to fix up the object and function maps.
819 */
820 for (cmo = list_head(&scmi->cmi_omap); cmo != NULL;
821 cmo = list_next(&scmi->cmi_omap, cmo)) {
822 if (cmo->cmo_tid == 0)
823 continue;
824 VERIFY(cm.cm_tmap[cmo->cmo_tid].cmt_map != 0);
825 cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
826 }
827
828 for (cmf = list_head(&scmi->cmi_fmap); cmf != NULL;
829 cmf = list_next(&scmi->cmi_fmap, cmf)) {
830 int i;
831
832 VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
833 cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
834 for (i = 0; i < cmf->cmf_argc; i++) {
835 VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
836 cmf->cmf_args[i] = cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
837 }
838 }
839
840 /*
841 * Now that we've fixed things up, we need to give our function and
842 * object maps to the destination, such that it can continue to update
843 * them going forward.
844 */
845 list_move_tail(&dcmi->cmi_fmap, &scmi->cmi_fmap);
846 list_move_tail(&dcmi->cmi_omap, &scmi->cmi_omap);
847
848 cleanup:
849 if (ret == 0)
850 *outp = dcmi;
851 ctf_merge_types_fini(&cm);
852 ctf_diff_fini(cdp);
853 if (ret != 0)
854 return (ctf_errno(out));
855 return (0);
856 }
857
858 /*
859 * After performing a pass, we need to go through the object and function type
860 * maps and potentially fix them up based on the new maps that we haev.
861 */
862 static void
863 ctf_merge_fixup_nontypes(ctf_merge_types_t *cmp, ctf_merge_input_t *cmi)
864 {
865 ctf_merge_objmap_t *cmo;
866 ctf_merge_funcmap_t *cmf;
867
868 for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
869 cmo = list_next(&cmi->cmi_omap, cmo)) {
870 if (cmo->cmo_tid == 0)
871 continue;
872 VERIFY(cmp->cm_tmap[cmo->cmo_tid].cmt_map != 0);
873 cmo->cmo_tid = cmp->cm_tmap[cmo->cmo_tid].cmt_map;
874 }
875
876 for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
877 cmf = list_next(&cmi->cmi_fmap, cmf)) {
878 int i;
879
880 VERIFY(cmp->cm_tmap[cmf->cmf_rtid].cmt_map != 0);
881 cmf->cmf_rtid = cmp->cm_tmap[cmf->cmf_rtid].cmt_map;
882 for (i = 0; i < cmf->cmf_argc; i++) {
883 VERIFY(cmp->cm_tmap[cmf->cmf_args[i]].cmt_map !=
884 0);
885 cmf->cmf_args[i] =
886 cmp->cm_tmap[cmf->cmf_args[i]].cmt_map;
887 }
888 }
889 }
890
891 static int
892 ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
893 {
894 int err, ret;
895 ctf_file_t *out;
896 ctf_merge_types_t cm;
897 ctf_diff_t *cdp;
898 ctf_merge_input_t *cmi;
899 ctf_file_t *parent = cmh->cmh_unique;
900
901 *outp = NULL;
902 out = ctf_fdcreate(cmh->cmh_ofd, &err);
903 if (out == NULL)
904 return (ctf_set_errno(src, err));
905
906 out->ctf_parname = cmh->cmh_pname;
907 if (ctf_setmodel(out, ctf_getmodel(parent)) != 0) {
908 (void) ctf_set_errno(src, ctf_errno(out));
909 ctf_close(out);
910 return (CTF_ERR);
931 ctf_diff_fini(cdp);
932 return (ctf_set_errno(src, ret));
933 }
934
935 ret = ctf_diff_types(cdp, ctf_merge_diffcb, &cm);
936 if (ret == 0) {
937 cm.cm_out = out;
938 ret = ctf_merge_uniquify_types(&cm);
939 if (ret == 0)
940 ret = ctf_update(out);
941 }
942
943 if (ret != 0) {
944 ctf_merge_types_fini(&cm);
945 ctf_diff_fini(cdp);
946 return (ctf_set_errno(src, ctf_errno(cm.cm_out)));
947 }
948
949 for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
950 cmi = list_next(&cmh->cmh_inputs, cmi)) {
951 ctf_merge_fixup_nontypes(&cm, cmi);
952 }
953
954 ctf_merge_types_fini(&cm);
955 ctf_diff_fini(cdp);
956 *outp = out;
957 return (0);
958 }
959
960 static void
961 ctf_merge_fini_input(ctf_merge_input_t *cmi)
962 {
963 ctf_merge_objmap_t *cmo;
964 ctf_merge_funcmap_t *cmf;
965
966 while ((cmo = list_remove_head(&cmi->cmi_omap)) != NULL)
967 ctf_free(cmo, sizeof (ctf_merge_objmap_t));
968
969 while ((cmf = list_remove_head(&cmi->cmi_fmap)) != NULL)
970 ctf_free(cmf, sizeof (ctf_merge_funcmap_t) +
971 sizeof (ctf_id_t) * cmf->cmf_argc);
1043 {
1044 char *dup;
1045
1046 if (label == NULL)
1047 return (EINVAL);
1048
1049 dup = ctf_strdup(label);
1050 if (dup == NULL)
1051 return (EAGAIN);
1052
1053 if (cmh->cmh_label != NULL) {
1054 size_t len = strlen(cmh->cmh_label) + 1;
1055 ctf_free(cmh->cmh_label, len);
1056 }
1057
1058 cmh->cmh_label = dup;
1059 return (0);
1060 }
1061
1062 static int
1063 ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
1064 void *arg)
1065 {
1066 ctf_merge_input_t *cmi = arg;
1067 ctf_merge_funcmap_t *fmap;
1068
1069 fmap = ctf_alloc(sizeof (ctf_merge_funcmap_t) +
1070 sizeof (ctf_id_t) * fip->ctc_argc);
1071 if (fmap == NULL)
1072 return (ENOMEM);
1073
1074 fmap->cmf_idx = idx;
1075 fmap->cmf_rtid = fip->ctc_return;
1076 fmap->cmf_flags = fip->ctc_flags;
1077 fmap->cmf_argc = fip->ctc_argc;
1078 fmap->cmf_name = name;
1079
1080 if (ctf_func_args(cmi->cmi_input, idx, fmap->cmf_argc,
1081 fmap->cmf_args) != 0) {
1082 ctf_free(fmap, sizeof (ctf_merge_funcmap_t) +
1083 sizeof (ctf_id_t) * fip->ctc_argc);
1084 return (ctf_errno(cmi->cmi_input));
1085 }
1086
1087 list_insert_tail(&cmi->cmi_fmap, fmap);
1088 return (0);
1089 }
1090
1091 static int
1092 ctf_merge_add_objs_cb(const char *name, ctf_id_t id, ulong_t idx, void *arg)
1093 {
1094 ctf_merge_input_t *cmi = arg;
1095 ctf_merge_objmap_t *cmo;
1096
1097 cmo = ctf_alloc(sizeof (ctf_merge_objmap_t));
1098 if (cmo == NULL)
1099 return (ENOMEM);
1100
1101 cmo->cmo_name = name;
1102 cmo->cmo_idx = idx;
1103 cmo->cmo_tid = id;
1104 list_insert_tail(&cmi->cmi_omap, cmo);
1105 return (0);
1106 }
1107
1108 /*
1109 * Whenever we create an entry to merge, we then go and add a second empty
1110 * ctf_file_t which we use for the purposes of our merging. It's not the best,
1111 * but it's the best that we've got at the moment.
1112 */
1113 int
1114 ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
1115 {
1116 int ret;
1117 ctf_merge_input_t *cmi;
1118 ctf_file_t *empty;
1119
1120 if (input->ctf_flags & LCTF_CHILD)
1121 return (ECTF_MCHILD);
1122
1123 cmi = ctf_alloc(sizeof (ctf_merge_input_t));
1124 if (cmi == NULL)
1125 return (ENOMEM);
1126
1127 cmi->cmi_created = B_FALSE;
1128 cmi->cmi_input = input;
1129 list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
1130 offsetof(ctf_merge_funcmap_t, cmf_node));
1131 list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
1132 offsetof(ctf_merge_objmap_t, cmo_node));
1133
1134 if (cmh->cmh_msyms == B_TRUE) {
1135 if ((ret = ctf_function_iter(input, ctf_merge_add_funcs_cb,
1136 cmi)) != 0) {
1137 ctf_merge_fini_input(cmi);
1138 return (ret);
1139 }
1140
1141 if ((ret = ctf_object_iter(input, ctf_merge_add_objs_cb,
1142 cmi)) != 0) {
1143 ctf_merge_fini_input(cmi);
1144 return (ret);
1145 }
1146 }
1147
1148 list_insert_tail(&cmh->cmh_inputs, cmi);
1149 cmh->cmh_ninputs++;
1150
1151 /* And now the empty one to merge into this */
1152 cmi = ctf_alloc(sizeof (ctf_merge_input_t));
1153 if (cmi == NULL)
1154 return (ENOMEM);
1155 list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
1156 offsetof(ctf_merge_funcmap_t, cmf_node));
1157 list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
1158 offsetof(ctf_merge_objmap_t, cmo_node));
1159
1160 empty = ctf_fdcreate(cmh->cmh_ofd, &ret);
1161 if (empty == NULL)
1162 return (ret);
1163 cmi->cmi_input = empty;
1164 cmi->cmi_created = B_TRUE;
1165
1166 if (ctf_setmodel(empty, ctf_getmodel(input)) == CTF_ERR) {
1177 ctf_merge_uniquify(ctf_merge_t *cmh, ctf_file_t *u, const char *pname)
1178 {
1179 char *dup;
1180
1181 if (u->ctf_flags & LCTF_CHILD)
1182 return (ECTF_MCHILD);
1183 if (pname == NULL)
1184 return (EINVAL);
1185 dup = ctf_strdup(pname);
1186 if (dup == NULL)
1187 return (EINVAL);
1188 if (cmh->cmh_pname != NULL) {
1189 size_t len = strlen(cmh->cmh_pname) + 1;
1190 ctf_free(cmh->cmh_pname, len);
1191 }
1192 cmh->cmh_pname = dup;
1193 cmh->cmh_unique = u;
1194 return (0);
1195 }
1196
1197 static int
1198 ctf_merge_symbols(ctf_merge_t *cmh, ctf_file_t *fp)
1199 {
1200 int err;
1201 ulong_t i;
1202
1203 uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
1204 uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
1205
1206 for (i = 0; i < fp->ctf_nsyms; i++) {
1207 const char *name;
1208 ctf_merge_input_t *cmi;
1209 ctf_merge_objmap_t *cmo;
1210
1211 if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
1212 const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
1213 int type = ELF32_ST_TYPE(symp->st_info);
1214 if (type != STT_OBJECT)
1215 continue;
1216 if (ctf_sym_valid(strbase, type, symp->st_shndx,
1217 symp->st_value, symp->st_name) == B_FALSE)
1218 continue;
1219 name = (char *)(strbase + symp->st_name);
1220 } else {
1221 const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
1222 int type = ELF64_ST_TYPE(symp->st_info);
1223 if (type != STT_OBJECT)
1224 continue;
1225 if (ctf_sym_valid(strbase, type, symp->st_shndx,
1226 symp->st_value, symp->st_name) == B_FALSE)
1227 continue;
1228 name = (char *)(strbase + symp->st_name);
1229 }
1230
1231 cmo = NULL;
1232 for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
1233 cmi = list_next(&cmh->cmh_inputs, cmi)) {
1234 for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
1235 cmo = list_next(&cmi->cmi_omap, cmo)) {
1236 if (strcmp(cmo->cmo_name, name) == 0)
1237 goto found;
1238 }
1239 }
1240 found:
1241 if (cmo != NULL) {
1242 if (cmo->cmo_tid == 0)
1243 continue;
1244 if ((err = ctf_add_object(fp, i, cmo->cmo_tid)) != 0) {
1245 ctf_dprintf("Failed to add symbol %s->%d: %s\n",
1246 name, cmo->cmo_tid,
1247 ctf_errmsg(ctf_errno(fp)));
1248 return (err);
1249 }
1250 }
1251 }
1252
1253 return (0);
1254 }
1255
1256 static int
1257 ctf_merge_functions(ctf_merge_t *cmh, ctf_file_t *fp)
1258 {
1259 int err;
1260 ulong_t i;
1261 ctf_funcinfo_t fi;
1262
1263 uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
1264 uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
1265
1266 for (i = 0; i < fp->ctf_nsyms; i++) {
1267 const char *name;
1268 ctf_merge_input_t *cmi;
1269 ctf_merge_funcmap_t *cmf;
1270
1271 if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
1272 const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
1273 int type = ELF32_ST_TYPE(symp->st_info);
1274 if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
1275 continue;
1276 if (ctf_sym_valid(strbase, type, symp->st_shndx,
1277 symp->st_value, symp->st_name) == B_FALSE)
1278 continue;
1279 name = (char *)(strbase + symp->st_name);
1280 } else {
1281 const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
1282 int type = ELF64_ST_TYPE(symp->st_info);
1283 if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
1284 continue;
1285 if (ctf_sym_valid(strbase, type, symp->st_shndx,
1286 symp->st_value, symp->st_name) == B_FALSE)
1287 continue;
1288 name = (char *)(strbase + symp->st_name);
1289 }
1290
1291 cmf = NULL;
1292 for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
1293 cmi = list_next(&cmh->cmh_inputs, cmi)) {
1294 for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
1295 cmf = list_next(&cmi->cmi_fmap, cmf)) {
1296 if (strcmp(cmf->cmf_name, name) == 0)
1297 goto found;
1298 }
1299 }
1300 found:
1301 if (cmf != NULL) {
1302 fi.ctc_return = cmf->cmf_rtid;
1303 fi.ctc_argc = cmf->cmf_argc;
1304 fi.ctc_flags = cmf->cmf_flags;
1305 if ((err = ctf_add_function(fp, i, &fi,
1306 cmf->cmf_args)) != 0)
1307 return (err);
1308 }
1309 }
1310
1311 return (0);
1312
1313 }
1314
1315 int
1316 ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
1317 {
1318 int err, merr;
1319 ctf_merge_input_t *cmi;
1320 ctf_id_t ltype;
1321 mergeq_t *mqp;
1322 ctf_merge_input_t *final;
1323 ctf_file_t *out;
1324
1325 if (cmh->cmh_label != NULL && cmh->cmh_unique != NULL) {
1326 const char *label = ctf_label_topmost(cmh->cmh_unique);
1327 if (label == NULL)
1328 return (ECTF_NOLABEL);
1329 if (strcmp(label, cmh->cmh_label) != 0)
1330 return (ECTF_LCONFLICT);
1331 }
1332
1333 if (mergeq_init(&mqp, cmh->cmh_nthreads) == -1) {
1334 return (errno);
1335 }
1336
1337 VERIFY(cmh->cmh_ninputs % 2 == 0);
1338 for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
1339 cmi = list_next(&cmh->cmh_inputs, cmi)) {
1340 if (mergeq_add(mqp, cmi) == -1) {
1341 err = errno;
1342 mergeq_fini(mqp);
1343 }
1344 }
1370 err = ctf_errno(out);
1371 ctf_close(out);
1372 return (err);
1373 }
1374 ctf_close(out);
1375 out = u;
1376 }
1377
1378 ltype = out->ctf_typemax;
1379 if ((out->ctf_flags & LCTF_CHILD) && ltype != 0)
1380 ltype += CTF_CHILD_START;
1381 ctf_dprintf("trying to add the label\n");
1382 if (cmh->cmh_label != NULL &&
1383 ctf_add_label(out, cmh->cmh_label, ltype, 0) != 0) {
1384 ctf_close(out);
1385 return (ctf_errno(out));
1386 }
1387
1388 ctf_dprintf("merging symbols and the like\n");
1389 if (cmh->cmh_msyms == B_TRUE) {
1390 err = ctf_merge_symbols(cmh, out);
1391 if (err != 0) {
1392 ctf_close(out);
1393 return (ctf_errno(out));
1394 }
1395
1396 err = ctf_merge_functions(cmh, out);
1397 if (err != 0) {
1398 ctf_close(out);
1399 return (ctf_errno(out));
1400 }
1401 }
1402
1403 err = ctf_update(out);
1404 if (err != 0) {
1405 ctf_close(out);
1406 return (ctf_errno(out));
1407 }
1408
1409 *outp = out;
1410 return (0);
1411 }
1412
1413 /*
1414 * When we get told that something is unique, eg. same is B_FALSE, then that
1415 * tells us that we need to add it to the output. If same is B_TRUE, then we'll
1416 * want to record it in the mapping table so that we know how to redirect types
1417 * to the extant ones.
1418 */
1419 static void
1420 ctf_dedup_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
1421 ctf_id_t oid, void *arg)
1422 {
1423 ctf_merge_types_t *cmp = arg;
1424 ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
1425
1426 if (same == B_TRUE) {
1488 if ((ret = ctf_merge_types_init(&cm)) != 0) {
1489 return (ret);
1490 }
1491
1492 if ((ret = ctf_diff_init(ifp, ifp, &cdp)) != 0)
1493 goto err;
1494
1495 ctf_dprintf("Successfully initialized dedup\n");
1496 if ((ret = ctf_diff_self(cdp, ctf_dedup_cb, &cm)) != 0)
1497 goto err;
1498
1499 ctf_dprintf("Successfully diffed types\n");
1500 ret = ctf_merge_common(&cm);
1501 ctf_dprintf("deduping types result: %d\n", ret);
1502 if (ret == 0)
1503 ret = ctf_update(cm.cm_out);
1504 if (ret != 0)
1505 goto err;
1506
1507 ctf_dprintf("Successfully deduped types\n");
1508 ctf_phase_dump(cm.cm_out, "dedup-pre-syms");
1509
1510 /*
1511 * Now we need to fix up the object and function maps.
1512 */
1513 ctf_merge_fixup_nontypes(&cm, cmi);
1514
1515 if (cmp->cmh_msyms == B_TRUE) {
1516 ret = ctf_merge_symbols(cmp, cm.cm_out);
1517 if (ret != 0) {
1518 ret = ctf_errno(cm.cm_out);
1519 ctf_dprintf("failed to dedup symbols: %s\n",
1520 ctf_errmsg(ret));
1521 goto err;
1522 }
1523
1524 ret = ctf_merge_functions(cmp, cm.cm_out);
1525 if (ret != 0) {
1526 ret = ctf_errno(cm.cm_out);
1527 ctf_dprintf("failed to dedup functions: %s\n",
1528 ctf_errmsg(ret));
1529 goto err;
1530 }
1531 }
1532
1533 ret = ctf_update(cm.cm_out);
1534 if (ret == 0) {
1535 cmc->cmi_input = NULL;
1536 *outp = cm.cm_out;
1537 }
1538 err:
1539 ctf_merge_types_fini(&cm);
1540 ctf_diff_fini(cdp);
1541 return (ret);
1542 }
1543
1544 int
1545 ctf_merge_set_nthreads(ctf_merge_t *cmp, const uint_t nthrs)
1546 {
1547 if (nthrs == 0)
1548 return (EINVAL);
1549 cmp->cmh_nthreads = nthrs;
1550 return (0);
1551 }
|
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright (c) 2019 Joyent, Inc.
14 */
15
16 /*
17 * To perform a merge of two CTF containers, we first diff the two containers
18 * types. For every type that's in the src container, but not in the dst
19 * container, we note it and add it to dst container. If there are any objects
20 * or functions associated with src, we go through and update the types that
21 * they refer to such that they all refer to types in the dst container.
22 *
23 * The bulk of the logic for the merge, after we've run the diff, occurs in
24 * ctf_merge_common().
25 *
26 * In terms of exported APIs, we don't really export a simple merge two
27 * containers, as the general way this is used, in something like ctfmerge(1),
28 * is to add all the containers and then let us figure out the best way to merge
29 * it.
30 */
31
32 #include <libctf_impl.h>
33 #include <sys/debug.h>
43 uint16_t cmt_map; /* Map to the type in out */
44 boolean_t cmt_fixup;
45 boolean_t cmt_forward;
46 boolean_t cmt_missing;
47 } ctf_merge_tinfo_t;
48
49 /*
50 * State required for doing an individual merge of two containers.
51 */
52 typedef struct ctf_merge_types {
53 ctf_file_t *cm_out; /* Output CTF file */
54 ctf_file_t *cm_src; /* Input CTF file */
55 ctf_merge_tinfo_t *cm_tmap; /* Type state information */
56 boolean_t cm_dedup; /* Are we doing a dedup? */
57 boolean_t cm_unique; /* are we doing a uniquify? */
58 } ctf_merge_types_t;
59
60 typedef struct ctf_merge_objmap {
61 list_node_t cmo_node;
62 const char *cmo_name; /* Symbol name */
63 const char *cmo_file; /* Symbol file */
64 ulong_t cmo_idx; /* Symbol ID */
65 Elf64_Sym cmo_sym; /* Symbol Entry */
66 ctf_id_t cmo_tid; /* Type ID */
67 } ctf_merge_objmap_t;
68
69 typedef struct ctf_merge_funcmap {
70 list_node_t cmf_node;
71 const char *cmf_name; /* Symbol name */
72 const char *cmf_file; /* Symbol file */
73 ulong_t cmf_idx; /* Symbol ID */
74 Elf64_Sym cmf_sym; /* Symbol Entry */
75 ctf_id_t cmf_rtid; /* Type ID */
76 uint_t cmf_flags; /* ctf_funcinfo_t ctc_flags */
77 uint_t cmf_argc; /* Number of arguments */
78 ctf_id_t cmf_args[]; /* Types of arguments */
79 } ctf_merge_funcmap_t;
80
81 typedef struct ctf_merge_input {
82 list_node_t cmi_node;
83 ctf_file_t *cmi_input;
84 list_t cmi_omap;
85 list_t cmi_fmap;
86 boolean_t cmi_created;
87 } ctf_merge_input_t;
88
89 struct ctf_merge_handle {
90 list_t cmh_inputs; /* Input list */
91 uint_t cmh_ninputs; /* Number of inputs */
92 uint_t cmh_nthreads; /* Number of threads to use */
93 ctf_file_t *cmh_unique; /* ctf to uniquify against */
94 boolean_t cmh_msyms; /* Should we merge symbols/funcs? */
95 int cmh_ofd; /* FD for output file */
96 int cmh_flags; /* Flags that control merge behavior */
97 char *cmh_label; /* Optional label */
98 char *cmh_pname; /* Parent name */
99 };
100
101 typedef struct ctf_merge_symbol_arg {
102 list_t *cmsa_objmap;
103 list_t *cmsa_funcmap;
104 ctf_file_t *cmsa_out;
105 boolean_t cmsa_dedup;
106 } ctf_merge_symbol_arg_t;
107
108 static int ctf_merge_add_type(ctf_merge_types_t *, ctf_id_t);
109
110 static ctf_id_t
111 ctf_merge_gettype(ctf_merge_types_t *cmp, ctf_id_t id)
112 {
113 if (cmp->cm_dedup == B_FALSE) {
114 VERIFY(cmp->cm_tmap[id].cmt_map != 0);
115 return (cmp->cm_tmap[id].cmt_map);
116 }
117
118 while (cmp->cm_tmap[id].cmt_missing == B_FALSE) {
119 VERIFY(cmp->cm_tmap[id].cmt_map != 0);
120 id = cmp->cm_tmap[id].cmt_map;
121 }
122 VERIFY(cmp->cm_tmap[id].cmt_map != 0);
123 return (cmp->cm_tmap[id].cmt_map);
124 }
125
126 static void
127 ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
655 *
656 * Pass 1 checks for forward references in the output container that we know
657 * exist in the source container.
658 *
659 * Pass 2 adds all the missing types from the source container. As part of this
660 * we may be adding a type as a forward reference that doesn't exist yet.
661 * Any types that we encounter in this form, we need to add to a third pass.
662 *
663 * Pass 3 is the fixup pass. Here we go through and find all the types that were
664 * missing in the first.
665 *
666 * Importantly, we *must* call ctf_update between the second and third pass,
667 * otherwise several of the libctf functions will not properly find the data in
668 * the container. If we're doing a dedup we also fix up the type mapping.
669 */
670 static int
671 ctf_merge_common(ctf_merge_types_t *cmp)
672 {
673 int ret, i;
674
675 ctf_phase_dump(cmp->cm_src, "merge-common-src", NULL);
676 ctf_phase_dump(cmp->cm_out, "merge-common-dest", NULL);
677
678 /* Pass 1 */
679 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
680 if (cmp->cm_tmap[i].cmt_forward == B_TRUE) {
681 ret = ctf_merge_add_sou(cmp, i, B_TRUE);
682 if (ret != 0) {
683 return (ret);
684 }
685 }
686 }
687
688 /* Pass 2 */
689 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
690 if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
691 ret = ctf_merge_add_type(cmp, i);
692 if (ret != 0) {
693 ctf_dprintf("Failed to merge type %d\n", i);
694 return (ret);
695 }
696 }
758 static int
759 ctf_merge_types_init(ctf_merge_types_t *cmp)
760 {
761 cmp->cm_tmap = ctf_alloc(sizeof (ctf_merge_tinfo_t) *
762 (cmp->cm_src->ctf_typemax + 1));
763 if (cmp->cm_tmap == NULL)
764 return (ctf_set_errno(cmp->cm_out, ENOMEM));
765 bzero(cmp->cm_tmap, sizeof (ctf_merge_tinfo_t) *
766 (cmp->cm_src->ctf_typemax + 1));
767 return (0);
768 }
769
770 static void
771 ctf_merge_types_fini(ctf_merge_types_t *cmp)
772 {
773 ctf_free(cmp->cm_tmap, sizeof (ctf_merge_tinfo_t) *
774 (cmp->cm_src->ctf_typemax + 1));
775 }
776
777 /*
778 * After performing a pass, we need to go through the object and function type
779 * maps and potentially fix them up based on the new maps that we have.
780 */
781 static void
782 ctf_merge_fixup_symmaps(ctf_merge_types_t *cmp, ctf_merge_input_t *cmi)
783 {
784 ctf_merge_objmap_t *cmo;
785 ctf_merge_funcmap_t *cmf;
786
787 for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
788 cmo = list_next(&cmi->cmi_omap, cmo)) {
789 VERIFY3S(cmo->cmo_tid, !=, 0);
790 VERIFY(cmp->cm_tmap[cmo->cmo_tid].cmt_map != 0);
791 cmo->cmo_tid = cmp->cm_tmap[cmo->cmo_tid].cmt_map;
792 }
793
794 for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
795 cmf = list_next(&cmi->cmi_fmap, cmf)) {
796 int i;
797
798 VERIFY(cmp->cm_tmap[cmf->cmf_rtid].cmt_map != 0);
799 cmf->cmf_rtid = cmp->cm_tmap[cmf->cmf_rtid].cmt_map;
800 for (i = 0; i < cmf->cmf_argc; i++) {
801 VERIFY(cmp->cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
802 cmf->cmf_args[i] =
803 cmp->cm_tmap[cmf->cmf_args[i]].cmt_map;
804 }
805 }
806 }
807
808 /*
809 * Merge the types contained inside of two input files. The second input file is
810 * always going to be the destination. We're guaranteed that it's always
811 * writeable.
812 */
813 static int
814 ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
815 {
816 int ret;
817 ctf_merge_types_t cm;
818 ctf_diff_t *cdp;
819 ctf_merge_input_t *scmi = arg;
820 ctf_merge_input_t *dcmi = arg2;
821 ctf_file_t *out = dcmi->cmi_input;
822 ctf_file_t *source = scmi->cmi_input;
823
824 ctf_dprintf("merging %p->%p\n", source, out);
825
826 if (!(out->ctf_flags & LCTF_RDWR))
827 return (ctf_set_errno(out, ECTF_RDONLY));
828
829 if (ctf_getmodel(out) != ctf_getmodel(source))
830 return (ctf_set_errno(out, ECTF_DMODEL));
831
832 if ((ret = ctf_diff_init(out, source, &cdp)) != 0)
833 return (ret);
834
835 cm.cm_out = out;
836 cm.cm_src = source;
837 cm.cm_dedup = B_FALSE;
838 cm.cm_unique = B_FALSE;
840 if (ret != 0) {
841 ctf_diff_fini(cdp);
842 return (ctf_set_errno(out, ret));
843 }
844
845 ret = ctf_diff_types(cdp, ctf_merge_diffcb, &cm);
846 if (ret != 0)
847 goto cleanup;
848 ret = ctf_merge_common(&cm);
849 ctf_dprintf("merge common returned with %d\n", ret);
850 if (ret == 0) {
851 ret = ctf_update(out);
852 ctf_dprintf("update returned with %d\n", ret);
853 } else {
854 goto cleanup;
855 }
856
857 /*
858 * Now we need to fix up the object and function maps.
859 */
860 ctf_merge_fixup_symmaps(&cm, scmi);
861
862 /*
863 * Now that we've fixed things up, we need to give our function and
864 * object maps to the destination, such that it can continue to update
865 * them going forward.
866 */
867 list_move_tail(&dcmi->cmi_fmap, &scmi->cmi_fmap);
868 list_move_tail(&dcmi->cmi_omap, &scmi->cmi_omap);
869
870 cleanup:
871 if (ret == 0)
872 *outp = dcmi;
873 ctf_merge_types_fini(&cm);
874 ctf_diff_fini(cdp);
875 if (ret != 0)
876 return (ctf_errno(out));
877 ctf_phase_bump();
878 return (0);
879 }
880
881 static int
882 ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
883 {
884 int err, ret;
885 ctf_file_t *out;
886 ctf_merge_types_t cm;
887 ctf_diff_t *cdp;
888 ctf_merge_input_t *cmi;
889 ctf_file_t *parent = cmh->cmh_unique;
890
891 *outp = NULL;
892 out = ctf_fdcreate(cmh->cmh_ofd, &err);
893 if (out == NULL)
894 return (ctf_set_errno(src, err));
895
896 out->ctf_parname = cmh->cmh_pname;
897 if (ctf_setmodel(out, ctf_getmodel(parent)) != 0) {
898 (void) ctf_set_errno(src, ctf_errno(out));
899 ctf_close(out);
900 return (CTF_ERR);
921 ctf_diff_fini(cdp);
922 return (ctf_set_errno(src, ret));
923 }
924
925 ret = ctf_diff_types(cdp, ctf_merge_diffcb, &cm);
926 if (ret == 0) {
927 cm.cm_out = out;
928 ret = ctf_merge_uniquify_types(&cm);
929 if (ret == 0)
930 ret = ctf_update(out);
931 }
932
933 if (ret != 0) {
934 ctf_merge_types_fini(&cm);
935 ctf_diff_fini(cdp);
936 return (ctf_set_errno(src, ctf_errno(cm.cm_out)));
937 }
938
939 for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
940 cmi = list_next(&cmh->cmh_inputs, cmi)) {
941 ctf_merge_fixup_symmaps(&cm, cmi);
942 }
943
944 ctf_merge_types_fini(&cm);
945 ctf_diff_fini(cdp);
946 *outp = out;
947 return (0);
948 }
949
950 static void
951 ctf_merge_fini_input(ctf_merge_input_t *cmi)
952 {
953 ctf_merge_objmap_t *cmo;
954 ctf_merge_funcmap_t *cmf;
955
956 while ((cmo = list_remove_head(&cmi->cmi_omap)) != NULL)
957 ctf_free(cmo, sizeof (ctf_merge_objmap_t));
958
959 while ((cmf = list_remove_head(&cmi->cmi_fmap)) != NULL)
960 ctf_free(cmf, sizeof (ctf_merge_funcmap_t) +
961 sizeof (ctf_id_t) * cmf->cmf_argc);
1033 {
1034 char *dup;
1035
1036 if (label == NULL)
1037 return (EINVAL);
1038
1039 dup = ctf_strdup(label);
1040 if (dup == NULL)
1041 return (EAGAIN);
1042
1043 if (cmh->cmh_label != NULL) {
1044 size_t len = strlen(cmh->cmh_label) + 1;
1045 ctf_free(cmh->cmh_label, len);
1046 }
1047
1048 cmh->cmh_label = dup;
1049 return (0);
1050 }
1051
1052 static int
1053 ctf_merge_add_function(ctf_merge_input_t *cmi, ctf_funcinfo_t *fip, ulong_t idx,
1054 const char *file, const char *name, const Elf64_Sym *symp)
1055 {
1056 ctf_merge_funcmap_t *fmap;
1057
1058 fmap = ctf_alloc(sizeof (ctf_merge_funcmap_t) +
1059 sizeof (ctf_id_t) * fip->ctc_argc);
1060 if (fmap == NULL)
1061 return (ENOMEM);
1062
1063 fmap->cmf_idx = idx;
1064 fmap->cmf_sym = *symp;
1065 fmap->cmf_rtid = fip->ctc_return;
1066 fmap->cmf_flags = fip->ctc_flags;
1067 fmap->cmf_argc = fip->ctc_argc;
1068 fmap->cmf_name = name;
1069 if (ELF64_ST_BIND(symp->st_info) == STB_LOCAL) {
1070 fmap->cmf_file = file;
1071 } else {
1072 fmap->cmf_file = NULL;
1073 }
1074
1075 if (ctf_func_args(cmi->cmi_input, idx, fmap->cmf_argc,
1076 fmap->cmf_args) != 0) {
1077 ctf_free(fmap, sizeof (ctf_merge_funcmap_t) +
1078 sizeof (ctf_id_t) * fip->ctc_argc);
1079 return (ctf_errno(cmi->cmi_input));
1080 }
1081
1082 ctf_dprintf("added initial function %s, %lu, %s %u\n", name, idx,
1083 fmap->cmf_file != NULL ? fmap->cmf_file : "global",
1084 ELF64_ST_BIND(symp->st_info));
1085 list_insert_tail(&cmi->cmi_fmap, fmap);
1086 return (0);
1087 }
1088
1089 static int
1090 ctf_merge_add_object(ctf_merge_input_t *cmi, ctf_id_t id, ulong_t idx,
1091 const char *file, const char *name, const Elf64_Sym *symp)
1092 {
1093 ctf_merge_objmap_t *cmo;
1094
1095 cmo = ctf_alloc(sizeof (ctf_merge_objmap_t));
1096 if (cmo == NULL)
1097 return (ENOMEM);
1098
1099 cmo->cmo_name = name;
1100 if (ELF64_ST_BIND(symp->st_info) == STB_LOCAL) {
1101 cmo->cmo_file = file;
1102 } else {
1103 cmo->cmo_file = NULL;
1104 }
1105 cmo->cmo_idx = idx;
1106 cmo->cmo_tid = id;
1107 cmo->cmo_sym = *symp;
1108 list_insert_tail(&cmi->cmi_omap, cmo);
1109
1110 ctf_dprintf("added initial object %s, %lu, %ld, %s\n", name, idx, id,
1111 cmo->cmo_file != NULL ? cmo->cmo_file : "global");
1112
1113 return (0);
1114 }
1115
1116 static int
1117 ctf_merge_add_symbol(const Elf64_Sym *symp, ulong_t idx, const char *file,
1118 const char *name, boolean_t primary, void *arg)
1119 {
1120 ctf_merge_input_t *cmi = arg;
1121 ctf_file_t *fp = cmi->cmi_input;
1122 ushort_t *data, funcbase;
1123 uint_t type;
1124 ctf_funcinfo_t fi;
1125
1126 /*
1127 * See if there is type information for this. If there is no
1128 * type information for this entry or no translation, then we
1129 * will find the value zero. This indicates no type ID for
1130 * objects and encodes unknown information for functions.
1131 */
1132 if (fp->ctf_sxlate[idx] == -1u)
1133 return (0);
1134 data = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[idx]);
1135 if (*data == 0)
1136 return (0);
1137
1138 type = ELF64_ST_TYPE(symp->st_info);
1139
1140 switch (type) {
1141 case STT_FUNC:
1142 funcbase = *data;
1143 if (LCTF_INFO_KIND(fp, funcbase) != CTF_K_FUNCTION)
1144 return (0);
1145 data++;
1146 fi.ctc_return = *data;
1147 data++;
1148 fi.ctc_argc = LCTF_INFO_VLEN(fp, funcbase);
1149 fi.ctc_flags = 0;
1150
1151 if (fi.ctc_argc != 0 && data[fi.ctc_argc - 1] == 0) {
1152 fi.ctc_flags |= CTF_FUNC_VARARG;
1153 fi.ctc_argc--;
1154 }
1155 return (ctf_merge_add_function(cmi, &fi, idx, file, name,
1156 symp));
1157 case STT_OBJECT:
1158 return (ctf_merge_add_object(cmi, *data, idx, file, name,
1159 symp));
1160 default:
1161 return (0);
1162 }
1163 }
1164
1165 /*
1166 * Whenever we create an entry to merge, we then go and add a second empty
1167 * ctf_file_t which we use for the purposes of our merging. It's not the best,
1168 * but it's the best that we've got at the moment.
1169 */
1170 int
1171 ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
1172 {
1173 int ret;
1174 ctf_merge_input_t *cmi;
1175 ctf_file_t *empty;
1176
1177 ctf_dprintf("adding input %p\n", input);
1178
1179 if (input->ctf_flags & LCTF_CHILD)
1180 return (ECTF_MCHILD);
1181
1182 cmi = ctf_alloc(sizeof (ctf_merge_input_t));
1183 if (cmi == NULL)
1184 return (ENOMEM);
1185
1186 cmi->cmi_created = B_FALSE;
1187 cmi->cmi_input = input;
1188 list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
1189 offsetof(ctf_merge_funcmap_t, cmf_node));
1190 list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
1191 offsetof(ctf_merge_objmap_t, cmo_node));
1192
1193 if (cmh->cmh_msyms == B_TRUE) {
1194 if ((ret = ctf_symtab_iter(input, ctf_merge_add_symbol,
1195 cmi)) != 0) {
1196 ctf_merge_fini_input(cmi);
1197 return (ret);
1198 }
1199 }
1200
1201 list_insert_tail(&cmh->cmh_inputs, cmi);
1202 cmh->cmh_ninputs++;
1203
1204 /* And now the empty one to merge into this */
1205 cmi = ctf_alloc(sizeof (ctf_merge_input_t));
1206 if (cmi == NULL)
1207 return (ENOMEM);
1208 list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
1209 offsetof(ctf_merge_funcmap_t, cmf_node));
1210 list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
1211 offsetof(ctf_merge_objmap_t, cmo_node));
1212
1213 empty = ctf_fdcreate(cmh->cmh_ofd, &ret);
1214 if (empty == NULL)
1215 return (ret);
1216 cmi->cmi_input = empty;
1217 cmi->cmi_created = B_TRUE;
1218
1219 if (ctf_setmodel(empty, ctf_getmodel(input)) == CTF_ERR) {
1230 ctf_merge_uniquify(ctf_merge_t *cmh, ctf_file_t *u, const char *pname)
1231 {
1232 char *dup;
1233
1234 if (u->ctf_flags & LCTF_CHILD)
1235 return (ECTF_MCHILD);
1236 if (pname == NULL)
1237 return (EINVAL);
1238 dup = ctf_strdup(pname);
1239 if (dup == NULL)
1240 return (EINVAL);
1241 if (cmh->cmh_pname != NULL) {
1242 size_t len = strlen(cmh->cmh_pname) + 1;
1243 ctf_free(cmh->cmh_pname, len);
1244 }
1245 cmh->cmh_pname = dup;
1246 cmh->cmh_unique = u;
1247 return (0);
1248 }
1249
1250 /*
1251 * Symbol matching rules: the purpose of this is to verify that the type
1252 * information that we have for a given symbol actually matches the output
1253 * symbol. This is unfortunately complicated by several different factors:
1254 *
1255 * 1. When merging multiple .o's into a single item, the symbol table index will
1256 * not match.
1257 *
1258 * 2. Visibility of a symbol may not be identical to the object file or the
1259 * DWARF information due to symbol reduction via a mapfile.
1260 *
1261 * As such, we have to employ the following rules:
1262 *
1263 * 1. A global symbol table entry always matches a global CTF symbol with the
1264 * same name.
1265 *
1266 * 2. A local symbol table entry always matches a local CTF symbol if they have
1267 * the same name and they belong to the same file.
1268 *
1269 * 3. A weak symbol matches a non-weak symbol. This happens if we find that the
1270 * types match, the values match, the sizes match, and the section indexes
1271 * match. This happens when we do a conversion in one pass, it almost never
1272 * happens when we're merging multiple object files. If we match a CTF global
1273 * symbol, that's a fixed match, otherwise it's a fuzzy match.
1274 *
1275 * 4. A local symbol table entry matches a global CTF entry if the
1276 * other pieces fail, but they have the same name. This is considered a fuzzy
1277 * match and is not used unless we have no other options.
1278 *
1279 * 5. A weak symbol table entry matches a weak CTF entry if the other pieces
1280 * fail, but they have the same name. This is considered a fuzzy match and is
1281 * not used unless we have no other options. When merging independent .o files,
1282 * this is often the only recourse we have to matching weak symbols.
1283 *
1284 * In the end, this would all be much simpler if we were able to do this as part
1285 * of libld which would be able to do all the symbol transformations.
1286 */
1287 static boolean_t
1288 ctf_merge_symbol_match(const char *ctf_file, const char *ctf_name,
1289 const Elf64_Sym *ctf_symp, const char *symtab_file, const char *symtab_name,
1290 const Elf64_Sym *symtab_symp, boolean_t *is_fuzzy)
1291 {
1292 *is_fuzzy = B_FALSE;
1293 uint_t symtab_bind, ctf_bind;
1294
1295 symtab_bind = ELF64_ST_BIND(symtab_symp->st_info);
1296 ctf_bind = ELF64_ST_BIND(ctf_symp->st_info);
1297
1298 ctf_dprintf("comparing merge match for %s/%s/%u->%s/%s/%u\n",
1299 symtab_file, symtab_name, symtab_bind,
1300 ctf_file, ctf_name, ctf_bind);
1301 if (strcmp(ctf_name, symtab_name) != 0) {
1302 return (B_FALSE);
1303 }
1304
1305 if (symtab_bind == STB_GLOBAL && ctf_bind == STB_GLOBAL) {
1306 return (B_TRUE);
1307 } else if (symtab_bind == STB_GLOBAL) {
1308 return (B_FALSE);
1309 }
1310
1311 if (ctf_bind == STB_LOCAL && ctf_bind == symtab_bind &&
1312 ctf_file != NULL && symtab_file != NULL &&
1313 strcmp(ctf_file, symtab_file) == 0) {
1314 return (B_TRUE);
1315 }
1316
1317 if (symtab_bind == STB_WEAK && ctf_bind != STB_WEAK &&
1318 ELF64_ST_TYPE(symtab_symp->st_info) ==
1319 ELF64_ST_TYPE(ctf_symp->st_info) &&
1320 symtab_symp->st_value == ctf_symp->st_value &&
1321 symtab_symp->st_size == ctf_symp->st_size &&
1322 symtab_symp->st_shndx == ctf_symp->st_shndx) {
1323 if (ctf_bind == STB_GLOBAL) {
1324 return (B_TRUE);
1325 }
1326
1327 if (ctf_bind == STB_LOCAL && ctf_file != NULL &&
1328 symtab_file != NULL && strcmp(ctf_file, symtab_file) == 0) {
1329 *is_fuzzy = B_TRUE;
1330 return (B_TRUE);
1331 }
1332 }
1333
1334 if (ctf_bind == STB_GLOBAL ||
1335 (ctf_bind == STB_WEAK && symtab_bind == STB_WEAK)) {
1336 *is_fuzzy = B_TRUE;
1337 return (B_TRUE);
1338 }
1339
1340 return (B_FALSE);
1341 }
1342
1343 /*
1344 * For each symbol, try and find a match. We will attempt to find an exact
1345 * match; however, we will settle for a fuzzy match in general. There is one
1346 * case where we will not opt to use a fuzzy match, which is when performing the
1347 * deduplication of a container. In such a case we are trying to reduce common
1348 * types and a fuzzy match would be inappropriate as if we're in the context of
1349 * a single container, the conversion process should have identified any exact
1350 * or fuzzy matches that were required.
1351 */
1352 static int
1353 ctf_merge_symbols(const Elf64_Sym *symp, ulong_t idx, const char *file,
1354 const char *name, boolean_t primary, void *arg)
1355 {
1356 int err;
1357 uint_t type, bind;
1358 ctf_merge_symbol_arg_t *csa = arg;
1359 ctf_file_t *fp = csa->cmsa_out;
1360
1361 type = ELF64_ST_TYPE(symp->st_info);
1362 bind = ELF64_ST_BIND(symp->st_info);
1363
1364 ctf_dprintf("Trying to find match for %s/%s/%u\n", file, name,
1365 ELF64_ST_BIND(symp->st_info));
1366
1367 if (type == STT_OBJECT) {
1368 ctf_merge_objmap_t *cmo, *match = NULL;
1369
1370 for (cmo = list_head(csa->cmsa_objmap); cmo != NULL;
1371 cmo = list_next(csa->cmsa_objmap, cmo)) {
1372 boolean_t is_fuzzy = B_FALSE;
1373 if (ctf_merge_symbol_match(cmo->cmo_file, cmo->cmo_name,
1374 &cmo->cmo_sym, file, name, symp, &is_fuzzy)) {
1375 if (is_fuzzy && csa->cmsa_dedup &&
1376 bind != STB_WEAK) {
1377 continue;
1378 }
1379 match = cmo;
1380 if (is_fuzzy) {
1381 continue;
1382 }
1383 break;
1384 }
1385 }
1386
1387 if (match == NULL) {
1388 return (0);
1389 }
1390
1391 if ((err = ctf_add_object(fp, idx, match->cmo_tid)) != 0) {
1392 ctf_dprintf("Failed to add symbol %s->%d: %s\n", name,
1393 match->cmo_tid, ctf_errmsg(ctf_errno(fp)));
1394 return (ctf_errno(fp));
1395 }
1396 ctf_dprintf("mapped object into output %s/%s->%ld\n", file,
1397 name, match->cmo_tid);
1398 } else {
1399 ctf_merge_funcmap_t *cmf, *match = NULL;
1400 ctf_funcinfo_t fi;
1401
1402 for (cmf = list_head(csa->cmsa_funcmap); cmf != NULL;
1403 cmf = list_next(csa->cmsa_funcmap, cmf)) {
1404 boolean_t is_fuzzy = B_FALSE;
1405 if (ctf_merge_symbol_match(cmf->cmf_file, cmf->cmf_name,
1406 &cmf->cmf_sym, file, name, symp, &is_fuzzy)) {
1407 if (is_fuzzy && csa->cmsa_dedup &&
1408 bind != STB_WEAK) {
1409 continue;
1410 }
1411 match = cmf;
1412 if (is_fuzzy) {
1413 continue;
1414 }
1415 break;
1416 }
1417 }
1418
1419 if (match == NULL) {
1420 return (0);
1421 }
1422
1423 fi.ctc_return = match->cmf_rtid;
1424 fi.ctc_argc = match->cmf_argc;
1425 fi.ctc_flags = match->cmf_flags;
1426 if ((err = ctf_add_function(fp, idx, &fi, match->cmf_args)) !=
1427 0) {
1428 ctf_dprintf("Failed to add function %s: %s\n", name,
1429 ctf_errmsg(ctf_errno(fp)));
1430 return (ctf_errno(fp));
1431 }
1432 ctf_dprintf("mapped function into output %s/%s\n", file,
1433 name);
1434 }
1435
1436 return (0);
1437 }
1438
1439 int
1440 ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
1441 {
1442 int err, merr;
1443 ctf_merge_input_t *cmi;
1444 ctf_id_t ltype;
1445 mergeq_t *mqp;
1446 ctf_merge_input_t *final;
1447 ctf_file_t *out;
1448
1449 ctf_dprintf("Beginning ctf_merge_merge()\n");
1450 if (cmh->cmh_label != NULL && cmh->cmh_unique != NULL) {
1451 const char *label = ctf_label_topmost(cmh->cmh_unique);
1452 if (label == NULL)
1453 return (ECTF_NOLABEL);
1454 if (strcmp(label, cmh->cmh_label) != 0)
1455 return (ECTF_LCONFLICT);
1456 }
1457
1458 if (mergeq_init(&mqp, cmh->cmh_nthreads) == -1) {
1459 return (errno);
1460 }
1461
1462 VERIFY(cmh->cmh_ninputs % 2 == 0);
1463 for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
1464 cmi = list_next(&cmh->cmh_inputs, cmi)) {
1465 if (mergeq_add(mqp, cmi) == -1) {
1466 err = errno;
1467 mergeq_fini(mqp);
1468 }
1469 }
1495 err = ctf_errno(out);
1496 ctf_close(out);
1497 return (err);
1498 }
1499 ctf_close(out);
1500 out = u;
1501 }
1502
1503 ltype = out->ctf_typemax;
1504 if ((out->ctf_flags & LCTF_CHILD) && ltype != 0)
1505 ltype += CTF_CHILD_START;
1506 ctf_dprintf("trying to add the label\n");
1507 if (cmh->cmh_label != NULL &&
1508 ctf_add_label(out, cmh->cmh_label, ltype, 0) != 0) {
1509 ctf_close(out);
1510 return (ctf_errno(out));
1511 }
1512
1513 ctf_dprintf("merging symbols and the like\n");
1514 if (cmh->cmh_msyms == B_TRUE) {
1515 ctf_merge_symbol_arg_t arg;
1516 arg.cmsa_objmap = &final->cmi_omap;
1517 arg.cmsa_funcmap = &final->cmi_fmap;
1518 arg.cmsa_out = out;
1519 arg.cmsa_dedup = B_FALSE;
1520 err = ctf_symtab_iter(out, ctf_merge_symbols, &arg);
1521 if (err != 0) {
1522 ctf_close(out);
1523 return (err);
1524 }
1525 }
1526
1527 err = ctf_update(out);
1528 if (err != 0) {
1529 err = ctf_errno(out);
1530 ctf_close(out);
1531 return (err);
1532 }
1533
1534 *outp = out;
1535 return (0);
1536 }
1537
1538 /*
1539 * When we get told that something is unique, eg. same is B_FALSE, then that
1540 * tells us that we need to add it to the output. If same is B_TRUE, then we'll
1541 * want to record it in the mapping table so that we know how to redirect types
1542 * to the extant ones.
1543 */
1544 static void
1545 ctf_dedup_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
1546 ctf_id_t oid, void *arg)
1547 {
1548 ctf_merge_types_t *cmp = arg;
1549 ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
1550
1551 if (same == B_TRUE) {
1613 if ((ret = ctf_merge_types_init(&cm)) != 0) {
1614 return (ret);
1615 }
1616
1617 if ((ret = ctf_diff_init(ifp, ifp, &cdp)) != 0)
1618 goto err;
1619
1620 ctf_dprintf("Successfully initialized dedup\n");
1621 if ((ret = ctf_diff_self(cdp, ctf_dedup_cb, &cm)) != 0)
1622 goto err;
1623
1624 ctf_dprintf("Successfully diffed types\n");
1625 ret = ctf_merge_common(&cm);
1626 ctf_dprintf("deduping types result: %d\n", ret);
1627 if (ret == 0)
1628 ret = ctf_update(cm.cm_out);
1629 if (ret != 0)
1630 goto err;
1631
1632 ctf_dprintf("Successfully deduped types\n");
1633 ctf_phase_dump(cm.cm_out, "dedup-pre-syms", NULL);
1634
1635 /*
1636 * Now we need to fix up the object and function maps.
1637 */
1638 ctf_merge_fixup_symmaps(&cm, cmi);
1639
1640 if (cmp->cmh_msyms == B_TRUE) {
1641 ctf_merge_symbol_arg_t arg;
1642 arg.cmsa_objmap = &cmi->cmi_omap;
1643 arg.cmsa_funcmap = &cmi->cmi_fmap;
1644 arg.cmsa_out = cm.cm_out;
1645 arg.cmsa_dedup = B_TRUE;
1646 ret = ctf_symtab_iter(cm.cm_out, ctf_merge_symbols, &arg);
1647 if (ret != 0) {
1648 ctf_dprintf("failed to dedup symbols: %s\n",
1649 ctf_errmsg(ret));
1650 goto err;
1651 }
1652 }
1653
1654 ret = ctf_update(cm.cm_out);
1655 if (ret == 0) {
1656 cmc->cmi_input = NULL;
1657 *outp = cm.cm_out;
1658 }
1659 ctf_phase_dump(cm.cm_out, "dedup-post-syms", NULL);
1660 err:
1661 ctf_merge_types_fini(&cm);
1662 ctf_diff_fini(cdp);
1663 return (ret);
1664 }
1665
1666 int
1667 ctf_merge_set_nthreads(ctf_merge_t *cmp, const uint_t nthrs)
1668 {
1669 if (nthrs == 0)
1670 return (EINVAL);
1671 cmp->cmh_nthreads = nthrs;
1672 return (0);
1673 }
|