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>
34 #include <sys/list.h>
35 #include <stddef.h>
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <mergeq.h>
40 #include <errno.h>
41
42 typedef struct ctf_merge_tinfo {
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
ctf_merge_gettype(ctf_merge_types_t * cmp,ctf_id_t id)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
ctf_merge_diffcb(ctf_file_t * ifp,ctf_id_t iid,boolean_t same,ctf_file_t * ofp,ctf_id_t oid,void * arg)116 ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
117 ctf_id_t oid, void *arg)
118 {
119 ctf_merge_types_t *cmp = arg;
120 ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
121
122 if (same == B_TRUE) {
123 if (ctf_type_kind(ifp, iid) == CTF_K_FORWARD &&
124 ctf_type_kind(ofp, oid) != CTF_K_FORWARD) {
125 VERIFY(cmt[oid].cmt_map == 0);
126
127 /*
128 * If we're uniquifying types, it's possible for the
129 * container that we're uniquifying against to have a
130 * forward which exists in the container being reduced.
131 * For example, genunix has the machcpu structure as a
132 * forward which is actually in unix and we uniquify
133 * unix against genunix. In such cases, we explicitly do
134 * not do any mapping of the forward information, lest
135 * we risk losing the real definition. Instead, mark
136 * that it's missing.
137 */
138 if (cmp->cm_unique == B_TRUE) {
139 cmt[oid].cmt_missing = B_TRUE;
140 return;
141 }
142
143 cmt[oid].cmt_map = iid;
144 cmt[oid].cmt_forward = B_TRUE;
145 ctf_dprintf("merge diff forward mapped %d->%d\n", oid,
146 iid);
147 return;
148 }
149
150 /*
151 * We could have multiple things that a given type ends up
152 * matching in the world of forwards and pointers to forwards.
153 * For now just take the first one...
154 */
155 if (cmt[oid].cmt_map != 0)
156 return;
157 cmt[oid].cmt_map = iid;
158 ctf_dprintf("merge diff mapped %d->%d\n", oid, iid);
159 } else if (ifp == cmp->cm_src) {
160 VERIFY(cmt[iid].cmt_map == 0);
161 cmt[iid].cmt_missing = B_TRUE;
162 ctf_dprintf("merge diff said %d is missing\n", iid);
163 }
164 }
165
166 static int
ctf_merge_add_number(ctf_merge_types_t * cmp,ctf_id_t id)167 ctf_merge_add_number(ctf_merge_types_t *cmp, ctf_id_t id)
168 {
169 int ret, flags;
170 const ctf_type_t *tp;
171 const char *name;
172 ctf_encoding_t en;
173
174 if (ctf_type_encoding(cmp->cm_src, id, &en) != 0)
175 return (CTF_ERR);
176
177 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
178 name = ctf_strraw(cmp->cm_src, tp->ctt_name);
179 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
180 flags = CTF_ADD_ROOT;
181 else
182 flags = CTF_ADD_NONROOT;
183
184 ret = ctf_add_encoded(cmp->cm_out, flags, name, &en,
185 ctf_type_kind(cmp->cm_src, id));
186
187 if (ret == CTF_ERR)
188 return (ret);
189
190 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
191 cmp->cm_tmap[id].cmt_map = ret;
192 return (0);
193 }
194
195 static int
ctf_merge_add_array(ctf_merge_types_t * cmp,ctf_id_t id)196 ctf_merge_add_array(ctf_merge_types_t *cmp, ctf_id_t id)
197 {
198 int ret, flags;
199 const ctf_type_t *tp;
200 ctf_arinfo_t ar;
201
202 if (ctf_array_info(cmp->cm_src, id, &ar) == CTF_ERR)
203 return (CTF_ERR);
204
205 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
206 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
207 flags = CTF_ADD_ROOT;
208 else
209 flags = CTF_ADD_NONROOT;
210
211 if (cmp->cm_tmap[ar.ctr_contents].cmt_map == 0) {
212 ret = ctf_merge_add_type(cmp, ar.ctr_contents);
213 if (ret != 0)
214 return (ret);
215 ASSERT(cmp->cm_tmap[ar.ctr_contents].cmt_map != 0);
216 }
217 ar.ctr_contents = ctf_merge_gettype(cmp, ar.ctr_contents);
218
219 if (cmp->cm_tmap[ar.ctr_index].cmt_map == 0) {
220 ret = ctf_merge_add_type(cmp, ar.ctr_index);
221 if (ret != 0)
222 return (ret);
223 ASSERT(cmp->cm_tmap[ar.ctr_index].cmt_map != 0);
224 }
225 ar.ctr_index = ctf_merge_gettype(cmp, ar.ctr_index);
226
227 ret = ctf_add_array(cmp->cm_out, flags, &ar);
228 if (ret == CTF_ERR)
229 return (ret);
230
231 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
232 cmp->cm_tmap[id].cmt_map = ret;
233
234 return (0);
235 }
236
237 static int
ctf_merge_add_reftype(ctf_merge_types_t * cmp,ctf_id_t id)238 ctf_merge_add_reftype(ctf_merge_types_t *cmp, ctf_id_t id)
239 {
240 int ret, flags;
241 const ctf_type_t *tp;
242 ctf_id_t reftype;
243 const char *name;
244
245 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
246 name = ctf_strraw(cmp->cm_src, tp->ctt_name);
247 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
248 flags = CTF_ADD_ROOT;
249 else
250 flags = CTF_ADD_NONROOT;
251
252 reftype = ctf_type_reference(cmp->cm_src, id);
253 if (reftype == CTF_ERR)
254 return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
255
256 if (cmp->cm_tmap[reftype].cmt_map == 0) {
257 ret = ctf_merge_add_type(cmp, reftype);
258 if (ret != 0)
259 return (ret);
260 ASSERT(cmp->cm_tmap[reftype].cmt_map != 0);
261 }
262 reftype = ctf_merge_gettype(cmp, reftype);
263
264 ret = ctf_add_reftype(cmp->cm_out, flags, name, reftype,
265 ctf_type_kind(cmp->cm_src, id));
266 if (ret == CTF_ERR)
267 return (ret);
268
269 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
270 cmp->cm_tmap[id].cmt_map = ret;
271 return (0);
272 }
273
274 static int
ctf_merge_add_typedef(ctf_merge_types_t * cmp,ctf_id_t id)275 ctf_merge_add_typedef(ctf_merge_types_t *cmp, ctf_id_t id)
276 {
277 int ret, flags;
278 const ctf_type_t *tp;
279 const char *name;
280 ctf_id_t reftype;
281
282 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
283 name = ctf_strraw(cmp->cm_src, tp->ctt_name);
284 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
285 flags = CTF_ADD_ROOT;
286 else
287 flags = CTF_ADD_NONROOT;
288
289 reftype = ctf_type_reference(cmp->cm_src, id);
290 if (reftype == CTF_ERR)
291 return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
292
293 if (cmp->cm_tmap[reftype].cmt_map == 0) {
294 ret = ctf_merge_add_type(cmp, reftype);
295 if (ret != 0)
296 return (ret);
297 ASSERT(cmp->cm_tmap[reftype].cmt_map != 0);
298 }
299 reftype = ctf_merge_gettype(cmp, reftype);
300
301 ret = ctf_add_typedef(cmp->cm_out, flags, name, reftype);
302 if (ret == CTF_ERR)
303 return (ret);
304
305 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
306 cmp->cm_tmap[id].cmt_map = ret;
307 return (0);
308 }
309
310 typedef struct ctf_merge_enum {
311 ctf_file_t *cme_fp;
312 ctf_id_t cme_id;
313 } ctf_merge_enum_t;
314
315 static int
ctf_merge_add_enumerator(const char * name,int value,void * arg)316 ctf_merge_add_enumerator(const char *name, int value, void *arg)
317 {
318 ctf_merge_enum_t *cmep = arg;
319
320 return (ctf_add_enumerator(cmep->cme_fp, cmep->cme_id, name, value) ==
321 CTF_ERR);
322 }
323
324 static int
ctf_merge_add_enum(ctf_merge_types_t * cmp,ctf_id_t id)325 ctf_merge_add_enum(ctf_merge_types_t *cmp, ctf_id_t id)
326 {
327 int flags;
328 const ctf_type_t *tp;
329 const char *name;
330 ctf_id_t enumid;
331 ctf_merge_enum_t cme;
332
333 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
334 name = ctf_strraw(cmp->cm_src, tp->ctt_name);
335 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
336 flags = CTF_ADD_ROOT;
337 else
338 flags = CTF_ADD_NONROOT;
339
340 enumid = ctf_add_enum(cmp->cm_out, flags, name);
341 if (enumid == CTF_ERR)
342 return (enumid);
343
344 cme.cme_fp = cmp->cm_out;
345 cme.cme_id = enumid;
346 if (ctf_enum_iter(cmp->cm_src, id, ctf_merge_add_enumerator,
347 &cme) != 0)
348 return (CTF_ERR);
349
350 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
351 cmp->cm_tmap[id].cmt_map = enumid;
352 return (0);
353 }
354
355 static int
ctf_merge_add_func(ctf_merge_types_t * cmp,ctf_id_t id)356 ctf_merge_add_func(ctf_merge_types_t *cmp, ctf_id_t id)
357 {
358 int ret, flags, i;
359 const ctf_type_t *tp;
360 ctf_funcinfo_t ctc;
361 ctf_id_t *argv;
362
363 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
364 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
365 flags = CTF_ADD_ROOT;
366 else
367 flags = CTF_ADD_NONROOT;
368
369 if (ctf_func_info_by_id(cmp->cm_src, id, &ctc) == CTF_ERR)
370 return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
371
372 argv = ctf_alloc(sizeof (ctf_id_t) * ctc.ctc_argc);
373 if (argv == NULL)
374 return (ctf_set_errno(cmp->cm_out, ENOMEM));
375 if (ctf_func_args_by_id(cmp->cm_src, id, ctc.ctc_argc, argv) ==
376 CTF_ERR) {
377 ctf_free(argv, sizeof (ctf_id_t) * ctc.ctc_argc);
378 return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
379 }
380
381 if (cmp->cm_tmap[ctc.ctc_return].cmt_map == 0) {
382 ret = ctf_merge_add_type(cmp, ctc.ctc_return);
383 if (ret != 0)
384 return (ret);
385 ASSERT(cmp->cm_tmap[ctc.ctc_return].cmt_map != 0);
386 }
387 ctc.ctc_return = ctf_merge_gettype(cmp, ctc.ctc_return);
388
389 for (i = 0; i < ctc.ctc_argc; i++) {
390 if (cmp->cm_tmap[argv[i]].cmt_map == 0) {
391 ret = ctf_merge_add_type(cmp, argv[i]);
392 if (ret != 0)
393 return (ret);
394 ASSERT(cmp->cm_tmap[argv[i]].cmt_map != 0);
395 }
396 argv[i] = ctf_merge_gettype(cmp, argv[i]);
397 }
398
399 ret = ctf_add_funcptr(cmp->cm_out, flags, &ctc, argv);
400 ctf_free(argv, sizeof (ctf_id_t) * ctc.ctc_argc);
401 if (ret == CTF_ERR)
402 return (ret);
403
404 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
405 cmp->cm_tmap[id].cmt_map = ret;
406 return (0);
407 }
408
409 static int
ctf_merge_add_forward(ctf_merge_types_t * cmp,ctf_id_t id)410 ctf_merge_add_forward(ctf_merge_types_t *cmp, ctf_id_t id)
411 {
412 int ret, flags;
413 const ctf_type_t *tp;
414 const char *name;
415
416 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
417 name = ctf_strraw(cmp->cm_src, tp->ctt_name);
418 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
419 flags = CTF_ADD_ROOT;
420 else
421 flags = CTF_ADD_NONROOT;
422
423 /*
424 * ctf_add_forward tries to check to see if a given forward already
425 * exists in one of its hash tables. If we're here then we know that we
426 * have a forward in a container that isn't present in another.
427 * Therefore, we choose a token hash table to satisfy the API choice
428 * here.
429 */
430 ret = ctf_add_forward(cmp->cm_out, flags, name, CTF_K_STRUCT);
431 if (ret == CTF_ERR)
432 return (CTF_ERR);
433
434 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
435 cmp->cm_tmap[id].cmt_map = ret;
436 return (0);
437 }
438
439 typedef struct ctf_merge_su {
440 ctf_merge_types_t *cms_cm;
441 ctf_id_t cms_id;
442 } ctf_merge_su_t;
443
444 static int
ctf_merge_add_member(const char * name,ctf_id_t type,ulong_t offset,void * arg)445 ctf_merge_add_member(const char *name, ctf_id_t type, ulong_t offset, void *arg)
446 {
447 ctf_merge_su_t *cms = arg;
448
449 VERIFY(cms->cms_cm->cm_tmap[type].cmt_map != 0);
450 type = cms->cms_cm->cm_tmap[type].cmt_map;
451
452 ctf_dprintf("Trying to add member %s to %d\n", name, cms->cms_id);
453 return (ctf_add_member(cms->cms_cm->cm_out, cms->cms_id, name,
454 type, offset) == CTF_ERR);
455 }
456
457 /*
458 * During the first pass, we always add the generic structure and union but none
459 * of its members as they might not all have been mapped yet. Instead we just
460 * mark all structures and unions as needing to be fixed up.
461 */
462 static int
ctf_merge_add_sou(ctf_merge_types_t * cmp,ctf_id_t id,boolean_t forward)463 ctf_merge_add_sou(ctf_merge_types_t *cmp, ctf_id_t id, boolean_t forward)
464 {
465 int flags, kind;
466 const ctf_type_t *tp;
467 const char *name;
468 ctf_id_t suid;
469
470 tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
471 name = ctf_strraw(cmp->cm_src, tp->ctt_name);
472 if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
473 flags = CTF_ADD_ROOT;
474 else
475 flags = CTF_ADD_NONROOT;
476 kind = ctf_type_kind(cmp->cm_src, id);
477
478 if (kind == CTF_K_STRUCT)
479 suid = ctf_add_struct(cmp->cm_out, flags, name);
480 else
481 suid = ctf_add_union(cmp->cm_out, flags, name);
482
483 if (suid == CTF_ERR)
484 return (suid);
485
486 /*
487 * If this is a forward reference then its mapping should already
488 * exist.
489 */
490 if (forward == B_FALSE) {
491 VERIFY(cmp->cm_tmap[id].cmt_map == 0);
492 cmp->cm_tmap[id].cmt_map = suid;
493 ctf_dprintf("added sou \"%s\" as (%d) %d->%d\n", name, kind, id,
494 suid);
495 } else {
496 VERIFY(cmp->cm_tmap[id].cmt_map == suid);
497 }
498 cmp->cm_tmap[id].cmt_fixup = B_TRUE;
499
500 return (0);
501 }
502
503 static int
ctf_merge_add_type(ctf_merge_types_t * cmp,ctf_id_t id)504 ctf_merge_add_type(ctf_merge_types_t *cmp, ctf_id_t id)
505 {
506 int kind, ret;
507
508 /*
509 * We may end up evaluating a type more than once as we may deal with it
510 * as we recursively evaluate some kind of reference and then we may see
511 * it normally.
512 */
513 if (cmp->cm_tmap[id].cmt_map != 0)
514 return (0);
515
516 kind = ctf_type_kind(cmp->cm_src, id);
517 switch (kind) {
518 case CTF_K_INTEGER:
519 case CTF_K_FLOAT:
520 ret = ctf_merge_add_number(cmp, id);
521 break;
522 case CTF_K_ARRAY:
523 ret = ctf_merge_add_array(cmp, id);
524 break;
525 case CTF_K_POINTER:
526 case CTF_K_VOLATILE:
527 case CTF_K_CONST:
528 case CTF_K_RESTRICT:
529 ret = ctf_merge_add_reftype(cmp, id);
530 break;
531 case CTF_K_TYPEDEF:
532 ret = ctf_merge_add_typedef(cmp, id);
533 break;
534 case CTF_K_ENUM:
535 ret = ctf_merge_add_enum(cmp, id);
536 break;
537 case CTF_K_FUNCTION:
538 ret = ctf_merge_add_func(cmp, id);
539 break;
540 case CTF_K_FORWARD:
541 ret = ctf_merge_add_forward(cmp, id);
542 break;
543 case CTF_K_STRUCT:
544 case CTF_K_UNION:
545 ret = ctf_merge_add_sou(cmp, id, B_FALSE);
546 break;
547 case CTF_K_UNKNOWN:
548 /*
549 * We don't add unknown types, and we later assert that nothing
550 * should reference them.
551 */
552 return (0);
553 default:
554 abort();
555 }
556
557 return (ret);
558 }
559
560 static int
ctf_merge_fixup_sou(ctf_merge_types_t * cmp,ctf_id_t id)561 ctf_merge_fixup_sou(ctf_merge_types_t *cmp, ctf_id_t id)
562 {
563 ctf_dtdef_t *dtd;
564 ctf_merge_su_t cms;
565 ctf_id_t mapid;
566 ssize_t size;
567
568 mapid = cmp->cm_tmap[id].cmt_map;
569 VERIFY(mapid != 0);
570 dtd = ctf_dtd_lookup(cmp->cm_out, mapid);
571 VERIFY(dtd != NULL);
572
573 ctf_dprintf("Trying to fix up sou %d\n", id);
574 cms.cms_cm = cmp;
575 cms.cms_id = mapid;
576 if (ctf_member_iter(cmp->cm_src, id, ctf_merge_add_member, &cms) != 0)
577 return (CTF_ERR);
578
579 if ((size = ctf_type_size(cmp->cm_src, id)) == CTF_ERR)
580 return (CTF_ERR);
581 if (ctf_set_size(cmp->cm_out, mapid, size) == CTF_ERR)
582 return (CTF_ERR);
583
584 return (0);
585 }
586
587 static int
ctf_merge_fixup_type(ctf_merge_types_t * cmp,ctf_id_t id)588 ctf_merge_fixup_type(ctf_merge_types_t *cmp, ctf_id_t id)
589 {
590 int kind, ret;
591
592 kind = ctf_type_kind(cmp->cm_src, id);
593 switch (kind) {
594 case CTF_K_STRUCT:
595 case CTF_K_UNION:
596 ret = ctf_merge_fixup_sou(cmp, id);
597 break;
598 default:
599 VERIFY(0);
600 ret = CTF_ERR;
601 }
602
603 return (ret);
604 }
605
606 /*
607 * Now that we've successfully merged everything, we're going to clean
608 * up the merge type table. Traditionally if we had just two different
609 * files that we were working between, the types would be fully
610 * resolved. However, because we were comparing with ourself every step
611 * of the way and not our reduced self, we need to go through and update
612 * every mapped entry to what it now points to in the deduped file.
613 */
614 static void
ctf_merge_fixup_dedup_map(ctf_merge_types_t * cmp)615 ctf_merge_fixup_dedup_map(ctf_merge_types_t *cmp)
616 {
617 int i;
618
619 for (i = 1; i < cmp->cm_src->ctf_typemax + 1; i++) {
620 ctf_id_t tid;
621
622 /*
623 * Missing types always have their id updated to exactly what it
624 * should be.
625 */
626 if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
627 VERIFY(cmp->cm_tmap[i].cmt_map != 0);
628 continue;
629 }
630
631 tid = i;
632 while (cmp->cm_tmap[tid].cmt_missing == B_FALSE) {
633 VERIFY(cmp->cm_tmap[tid].cmt_map != 0);
634 tid = cmp->cm_tmap[tid].cmt_map;
635 }
636 VERIFY(cmp->cm_tmap[tid].cmt_map != 0);
637 cmp->cm_tmap[i].cmt_map = cmp->cm_tmap[tid].cmt_map;
638 }
639 }
640
641
642 /*
643 * We're going to do three passes over the containers.
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
ctf_merge_common(ctf_merge_types_t * cmp)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 }
686 }
687
688 ret = ctf_update(cmp->cm_out);
689 if (ret != 0)
690 return (ret);
691
692 if (cmp->cm_dedup == B_TRUE) {
693 ctf_merge_fixup_dedup_map(cmp);
694 }
695
696 ctf_dprintf("Beginning merge pass 3\n");
697 /* Pass 3 */
698 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
699 if (cmp->cm_tmap[i].cmt_fixup == B_TRUE) {
700 ret = ctf_merge_fixup_type(cmp, i);
701 if (ret != 0)
702 return (ret);
703 }
704 }
705
706 if (cmp->cm_dedup == B_TRUE) {
707 ctf_merge_fixup_dedup_map(cmp);
708 }
709
710 return (0);
711 }
712
713 /*
714 * Uniquification is slightly different from a stock merge. For starters, we
715 * don't need to replace any forward references in the output. In this case
716 * though, the types that already exist are in a parent container to the empty
717 * output container.
718 */
719 static int
ctf_merge_uniquify_types(ctf_merge_types_t * cmp)720 ctf_merge_uniquify_types(ctf_merge_types_t *cmp)
721 {
722 int i, ret;
723
724 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
725 if (cmp->cm_tmap[i].cmt_missing == B_FALSE)
726 continue;
727 ret = ctf_merge_add_type(cmp, i);
728 if (ret != 0)
729 return (ret);
730 }
731
732 ret = ctf_update(cmp->cm_out);
733 if (ret != 0)
734 return (ret);
735
736 for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
737 if (cmp->cm_tmap[i].cmt_fixup == B_FALSE)
738 continue;
739 ret = ctf_merge_fixup_type(cmp, i);
740 if (ret != 0)
741 return (ret);
742 }
743
744 return (0);
745 }
746
747 static int
ctf_merge_types_init(ctf_merge_types_t * cmp)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
ctf_merge_types_fini(ctf_merge_types_t * cmp)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
ctf_merge_types(void * arg,void * arg2,void ** outp,void * unsued)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;
799 ret = ctf_merge_types_init(&cm);
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
ctf_merge_fixup_nontypes(ctf_merge_types_t * cmp,ctf_merge_input_t * cmi)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
ctf_uniquify_types(ctf_merge_t * cmh,ctf_file_t * src,ctf_file_t ** outp)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);
911 }
912
913 if (ctf_import(out, parent) != 0) {
914 (void) ctf_set_errno(src, ctf_errno(out));
915 ctf_close(out);
916 return (CTF_ERR);
917 }
918
919 if ((ret = ctf_diff_init(parent, src, &cdp)) != 0) {
920 ctf_close(out);
921 return (ctf_set_errno(src, ctf_errno(parent)));
922 }
923
924 cm.cm_out = parent;
925 cm.cm_src = src;
926 cm.cm_dedup = B_FALSE;
927 cm.cm_unique = B_TRUE;
928 ret = ctf_merge_types_init(&cm);
929 if (ret != 0) {
930 ctf_close(out);
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
ctf_merge_fini_input(ctf_merge_input_t * cmi)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);
972
973 if (cmi->cmi_created == B_TRUE && cmi->cmi_input != NULL)
974 ctf_close(cmi->cmi_input);
975
976 ctf_free(cmi, sizeof (ctf_merge_input_t));
977 }
978
979 void
ctf_merge_fini(ctf_merge_t * cmh)980 ctf_merge_fini(ctf_merge_t *cmh)
981 {
982 size_t len;
983 ctf_merge_input_t *cmi;
984
985 if (cmh->cmh_label != NULL) {
986 len = strlen(cmh->cmh_label) + 1;
987 ctf_free(cmh->cmh_label, len);
988 }
989
990 if (cmh->cmh_pname != NULL) {
991 len = strlen(cmh->cmh_pname) + 1;
992 ctf_free(cmh->cmh_pname, len);
993 }
994
995 while ((cmi = list_remove_head(&cmh->cmh_inputs)) != NULL)
996 ctf_merge_fini_input(cmi);
997
998 ctf_free(cmh, sizeof (ctf_merge_t));
999 }
1000
1001 ctf_merge_t *
ctf_merge_init(int fd,int * errp)1002 ctf_merge_init(int fd, int *errp)
1003 {
1004 int err;
1005 ctf_merge_t *out;
1006 struct stat st;
1007
1008 if (errp == NULL)
1009 errp = &err;
1010
1011 if (fd != -1 && fstat(fd, &st) != 0) {
1012 *errp = EINVAL;
1013 return (NULL);
1014 }
1015
1016 out = ctf_alloc(sizeof (ctf_merge_t));
1017 if (out == NULL) {
1018 *errp = ENOMEM;
1019 return (NULL);
1020 }
1021
1022 if (fd == -1) {
1023 out->cmh_msyms = B_FALSE;
1024 } else {
1025 out->cmh_msyms = B_TRUE;
1026 }
1027
1028 list_create(&out->cmh_inputs, sizeof (ctf_merge_input_t),
1029 offsetof(ctf_merge_input_t, cmi_node));
1030 out->cmh_ninputs = 0;
1031 out->cmh_nthreads = 1;
1032 out->cmh_unique = NULL;
1033 out->cmh_ofd = fd;
1034 out->cmh_flags = 0;
1035 out->cmh_label = NULL;
1036 out->cmh_pname = NULL;
1037
1038 return (out);
1039 }
1040
1041 int
ctf_merge_label(ctf_merge_t * cmh,const char * label)1042 ctf_merge_label(ctf_merge_t *cmh, const char *label)
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
ctf_merge_add_funcs_cb(const char * name,ulong_t idx,ctf_funcinfo_t * fip,void * arg)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
ctf_merge_add_objs_cb(const char * name,ctf_id_t id,ulong_t idx,void * arg)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
ctf_merge_add(ctf_merge_t * cmh,ctf_file_t * input)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) {
1167 return (ctf_errno(empty));
1168 }
1169
1170 list_insert_tail(&cmh->cmh_inputs, cmi);
1171 cmh->cmh_ninputs++;
1172 ctf_dprintf("added containers %p and %p\n", input, empty);
1173 return (0);
1174 }
1175
1176 int
ctf_merge_uniquify(ctf_merge_t * cmh,ctf_file_t * u,const char * pname)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
ctf_merge_symbols(ctf_merge_t * cmh,ctf_file_t * fp)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
ctf_merge_functions(ctf_merge_t * cmh,ctf_file_t * fp)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
ctf_merge_merge(ctf_merge_t * cmh,ctf_file_t ** outp)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 }
1345
1346 err = mergeq_merge(mqp, ctf_merge_types, NULL, (void **)&final, &merr);
1347 mergeq_fini(mqp);
1348
1349 if (err == MERGEQ_ERROR) {
1350 return (errno);
1351 } else if (err == MERGEQ_UERROR) {
1352 return (merr);
1353 }
1354
1355 /*
1356 * Disassociate the generated ctf_file_t from the original input. That
1357 * way when the input gets cleaned up, we don't accidentally kill the
1358 * final reference to the ctf_file_t. If it gets uniquified then we'll
1359 * kill it.
1360 */
1361 VERIFY(final->cmi_input != NULL);
1362 out = final->cmi_input;
1363 final->cmi_input = NULL;
1364
1365 ctf_dprintf("preparing to uniquify against: %p\n", cmh->cmh_unique);
1366 if (cmh->cmh_unique != NULL) {
1367 ctf_file_t *u;
1368 err = ctf_uniquify_types(cmh, out, &u);
1369 if (err != 0) {
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
ctf_dedup_cb(ctf_file_t * ifp,ctf_id_t iid,boolean_t same,ctf_file_t * ofp,ctf_id_t oid,void * arg)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) {
1427 /*
1428 * The output id here may itself map to something else.
1429 * Therefore, we need to basically walk a chain and see what it
1430 * points to until it itself points to a base type, eg. -1.
1431 * Otherwise we'll dedup to something which no longer exists.
1432 */
1433 while (cmt[oid].cmt_missing == B_FALSE)
1434 oid = cmt[oid].cmt_map;
1435 cmt[iid].cmt_map = oid;
1436 ctf_dprintf("%d->%d \n", iid, oid);
1437 } else {
1438 VERIFY(cmt[iid].cmt_map == 0);
1439 cmt[iid].cmt_missing = B_TRUE;
1440 ctf_dprintf("%d is missing\n", iid);
1441 }
1442 }
1443
1444 /*
1445 * Dedup a CTF container.
1446 *
1447 * DWARF and other encoding formats that we use to create CTF data may create
1448 * multiple copies of a given type. However, after doing a conversion, and
1449 * before doing a merge, we'd prefer, if possible, to have every input container
1450 * to be unique.
1451 *
1452 * Doing a deduplication is like a normal merge. However, when we diff the types
1453 * in the container, rather than doing a normal diff, we instead want to diff
1454 * against any already processed types. eg, for a given type i in a container,
1455 * we want to diff it from 0 to i - 1.
1456 */
1457 int
ctf_merge_dedup(ctf_merge_t * cmp,ctf_file_t ** outp)1458 ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
1459 {
1460 int ret;
1461 ctf_diff_t *cdp = NULL;
1462 ctf_merge_input_t *cmi, *cmc;
1463 ctf_file_t *ifp, *ofp;
1464 ctf_merge_types_t cm;
1465
1466 if (cmp == NULL || outp == NULL)
1467 return (EINVAL);
1468
1469 ctf_dprintf("encountered %d inputs\n", cmp->cmh_ninputs);
1470 if (cmp->cmh_ninputs != 2)
1471 return (EINVAL);
1472
1473 ctf_dprintf("passed argument sanity check\n");
1474
1475 cmi = list_head(&cmp->cmh_inputs);
1476 VERIFY(cmi != NULL);
1477 cmc = list_next(&cmp->cmh_inputs, cmi);
1478 VERIFY(cmc != NULL);
1479 ifp = cmi->cmi_input;
1480 ofp = cmc->cmi_input;
1481 VERIFY(ifp != NULL);
1482 VERIFY(ofp != NULL);
1483 cm.cm_src = ifp;
1484 cm.cm_out = ofp;
1485 cm.cm_dedup = B_TRUE;
1486 cm.cm_unique = B_FALSE;
1487
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
ctf_merge_set_nthreads(ctf_merge_t * cmp,const uint_t nthrs)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 }
1552