1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * Routines for preparing tdata trees for conversion into CTF data, and
30 * for placing the resulting data into an output file.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <strings.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <libelf.h>
40 #include <gelf.h>
41 #include <unistd.h>
42
43 #include "ctftools.h"
44 #include "list.h"
45 #include "memory.h"
46 #include "traverse.h"
47 #include "symbol.h"
48
49 typedef struct iidesc_match {
50 int iim_fuzzy;
51 iidesc_t *iim_ret;
52 char *iim_name;
53 char *iim_file;
54 uchar_t iim_bind;
55 } iidesc_match_t;
56
57 static int
burst_iitypes(void * data,void * arg)58 burst_iitypes(void *data, void *arg)
59 {
60 iidesc_t *ii = data;
61 iiburst_t *iiburst = arg;
62
63 switch (ii->ii_type) {
64 case II_GFUN:
65 case II_SFUN:
66 case II_GVAR:
67 case II_SVAR:
68 if (!(ii->ii_flags & IIDESC_F_USED))
69 return (0);
70 break;
71 default:
72 break;
73 }
74
75 ii->ii_dtype->t_flags |= TDESC_F_ISROOT;
76 (void) iitraverse_td(ii, iiburst->iib_tdtd);
77 return (1);
78 }
79
80 /*ARGSUSED1*/
81 static int
save_type_by_id(tdesc_t * tdp,tdesc_t ** tdpp,void * private)82 save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp, void *private)
83 {
84 iiburst_t *iiburst = private;
85
86 /*
87 * Doing this on every node is horribly inefficient, but given that
88 * we may be suppressing some types, we can't trust nextid in the
89 * tdata_t.
90 */
91 if (tdp->t_id > iiburst->iib_maxtypeid)
92 iiburst->iib_maxtypeid = tdp->t_id;
93
94 slist_add(&iiburst->iib_types, tdp, tdesc_idcmp);
95
96 return (1);
97 }
98
99 static tdtrav_cb_f burst_types_cbs[] = {
100 NULL,
101 save_type_by_id, /* intrinsic */
102 save_type_by_id, /* pointer */
103 save_type_by_id, /* array */
104 save_type_by_id, /* function */
105 save_type_by_id, /* struct */
106 save_type_by_id, /* union */
107 save_type_by_id, /* enum */
108 save_type_by_id, /* forward */
109 save_type_by_id, /* typedef */
110 tdtrav_assert, /* typedef_unres */
111 save_type_by_id, /* volatile */
112 save_type_by_id, /* const */
113 save_type_by_id /* restrict */
114 };
115
116
117 static iiburst_t *
iiburst_new(tdata_t * td,int max)118 iiburst_new(tdata_t *td, int max)
119 {
120 iiburst_t *iiburst = xcalloc(sizeof (iiburst_t));
121 iiburst->iib_td = td;
122 iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max);
123 iiburst->iib_nfuncs = 0;
124 iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max);
125 iiburst->iib_nobjts = 0;
126 return (iiburst);
127 }
128
129 static void
iiburst_types(iiburst_t * iiburst)130 iiburst_types(iiburst_t *iiburst)
131 {
132 tdtrav_data_t tdtd;
133
134 tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs,
135 NULL, (void *)iiburst);
136
137 iiburst->iib_tdtd = &tdtd;
138
139 (void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst);
140 }
141
142 static void
iiburst_free(iiburst_t * iiburst)143 iiburst_free(iiburst_t *iiburst)
144 {
145 free(iiburst->iib_funcs);
146 free(iiburst->iib_objts);
147 list_free(iiburst->iib_types, NULL, NULL);
148 free(iiburst);
149 }
150
151 /*
152 * See if this iidesc matches the ELF symbol data we pass in.
153 *
154 * A fuzzy match is where we have a local symbol matching the name of a
155 * global type description. This is common when a mapfile is used for a
156 * DSO, but we don't accept it by default.
157 *
158 * A weak fuzzy match is when a weak symbol was resolved and matched to
159 * a global type description.
160 */
161 static int
matching_iidesc(iidesc_t * iidesc,iidesc_match_t * match)162 matching_iidesc(iidesc_t *iidesc, iidesc_match_t *match)
163 {
164 if (streq(iidesc->ii_name, match->iim_name) == 0)
165 return (0);
166
167 switch (iidesc->ii_type) {
168 case II_GFUN:
169 case II_GVAR:
170 if (match->iim_bind == STB_GLOBAL) {
171 match->iim_ret = iidesc;
172 return (-1);
173 } else if (match->iim_fuzzy && match->iim_ret == NULL) {
174 match->iim_ret = iidesc;
175 /* continue to look for strong match */
176 return (0);
177 }
178 break;
179 case II_SFUN:
180 case II_SVAR:
181 if (match->iim_bind == STB_LOCAL &&
182 match->iim_file != NULL &&
183 streq(iidesc->ii_owner, match->iim_file)) {
184 match->iim_ret = iidesc;
185 return (-1);
186 }
187 break;
188 }
189 return (0);
190 }
191
192 static iidesc_t *
find_iidesc(tdata_t * td,iidesc_match_t * match)193 find_iidesc(tdata_t *td, iidesc_match_t *match)
194 {
195 match->iim_ret = NULL;
196 iter_iidescs_by_name(td, match->iim_name,
197 (int (*)())matching_iidesc, match);
198 return (match->iim_ret);
199 }
200
201 /*
202 * If we have a weak symbol, attempt to find the strong symbol it will
203 * resolve to. Note: the code where this actually happens is in
204 * sym_process() in cmd/sgs/libld/common/syms.c
205 *
206 * Finding the matching symbol is unfortunately not trivial. For a
207 * symbol to be a candidate, it must:
208 *
209 * - have the same type (function, object)
210 * - have the same value (address)
211 * - have the same size
212 * - not be another weak symbol
213 * - belong to the same section (checked via section index)
214 *
215 * If such a candidate is global, then we assume we've found it. The
216 * linker generates the symbol table such that the curfile might be
217 * incorrect; this is OK for global symbols, since find_iidesc() doesn't
218 * need to check for the source file for the symbol.
219 *
220 * We might have found a strong local symbol, where the curfile is
221 * accurate and matches that of the weak symbol. We assume this is a
222 * reasonable match.
223 *
224 * If we've got a local symbol with a non-matching curfile, there are
225 * two possibilities. Either this is a completely different symbol, or
226 * it's a once-global symbol that was scoped to local via a mapfile. In
227 * the latter case, curfile is likely inaccurate since the linker does
228 * not preserve the needed curfile in the order of the symbol table (see
229 * the comments about locally scoped symbols in libld's update_osym()).
230 * As we can't tell this case from the former one, we use this symbol
231 * iff no other matching symbol is found.
232 *
233 * What we really need here is a SUNW section containing weak<->strong
234 * mappings that we can consume.
235 */
236 static int
check_for_weak(GElf_Sym * weak,char const * weakfile,Elf_Data * data,int nent,Elf_Data * strdata,GElf_Sym * retsym,char ** curfilep)237 check_for_weak(GElf_Sym *weak, char const *weakfile,
238 Elf_Data *data, int nent, Elf_Data *strdata,
239 GElf_Sym *retsym, char **curfilep)
240 {
241 char *curfile = NULL;
242 char *tmpfile;
243 GElf_Sym tmpsym;
244 int candidate = 0;
245 int i;
246
247 if (GELF_ST_BIND(weak->st_info) != STB_WEAK)
248 return (0);
249
250 for (i = 0; i < nent; i++) {
251 GElf_Sym sym;
252 uchar_t type;
253
254 if (gelf_getsym(data, i, &sym) == NULL)
255 continue;
256
257 type = GELF_ST_TYPE(sym.st_info);
258
259 if (type == STT_FILE)
260 curfile = (char *)strdata->d_buf + sym.st_name;
261
262 if (GELF_ST_TYPE(weak->st_info) != type ||
263 weak->st_value != sym.st_value)
264 continue;
265
266 if (weak->st_size != sym.st_size)
267 continue;
268
269 if (GELF_ST_BIND(sym.st_info) == STB_WEAK)
270 continue;
271
272 if (sym.st_shndx != weak->st_shndx)
273 continue;
274
275 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
276 (curfile == NULL || weakfile == NULL ||
277 strcmp(curfile, weakfile) != 0)) {
278 candidate = 1;
279 tmpfile = curfile;
280 tmpsym = sym;
281 continue;
282 }
283
284 *curfilep = curfile;
285 *retsym = sym;
286 return (1);
287 }
288
289 if (candidate) {
290 *curfilep = tmpfile;
291 *retsym = tmpsym;
292 return (1);
293 }
294
295 return (0);
296 }
297
298 /*
299 * When we've found the underlying symbol's type description
300 * for a weak symbol, we need to copy it and rename it to match
301 * the weak symbol. We also need to add it to the td so it's
302 * handled along with the others later.
303 */
304 static iidesc_t *
copy_from_strong(tdata_t * td,GElf_Sym * sym,iidesc_t * strongdesc,const char * weakname,const char * weakfile)305 copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc,
306 const char *weakname, const char *weakfile)
307 {
308 iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile);
309 uchar_t type = GELF_ST_TYPE(sym->st_info);
310
311 switch (type) {
312 case STT_OBJECT:
313 new->ii_type = II_GVAR;
314 break;
315 case STT_FUNC:
316 new->ii_type = II_GFUN;
317 break;
318 }
319
320 hash_add(td->td_iihash, new);
321
322 return (new);
323 }
324
325 /*
326 * Process the symbol table of the output file, associating each symbol
327 * with a type description if possible, and sorting them into functions
328 * and data, maintaining symbol table order.
329 */
330 static iiburst_t *
sort_iidescs(Elf * elf,const char * file,tdata_t * td,int fuzzymatch,int dynsym)331 sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
332 int dynsym)
333 {
334 iiburst_t *iiburst;
335 Elf_Scn *scn;
336 GElf_Shdr shdr;
337 Elf_Data *data, *strdata;
338 int i, stidx;
339 int nent;
340 iidesc_match_t match;
341
342 match.iim_fuzzy = fuzzymatch;
343 match.iim_file = NULL;
344
345 if ((stidx = findelfsecidx(elf, file,
346 dynsym ? ".dynsym" : ".symtab")) < 0)
347 terminate("%s: Can't open symbol table\n", file);
348 scn = elf_getscn(elf, stidx);
349 data = elf_getdata(scn, NULL);
350 gelf_getshdr(scn, &shdr);
351 nent = shdr.sh_size / shdr.sh_entsize;
352
353 scn = elf_getscn(elf, shdr.sh_link);
354 strdata = elf_getdata(scn, NULL);
355
356 iiburst = iiburst_new(td, nent);
357
358 for (i = 0; i < nent; i++) {
359 GElf_Sym sym;
360 iidesc_t **tolist;
361 GElf_Sym ssym;
362 iidesc_match_t smatch;
363 int *curr;
364 iidesc_t *iidesc;
365
366 if (gelf_getsym(data, i, &sym) == NULL)
367 elfterminate(file, "Couldn't read symbol %d", i);
368
369 match.iim_name = (char *)strdata->d_buf + sym.st_name;
370 match.iim_bind = GELF_ST_BIND(sym.st_info);
371
372 switch (GELF_ST_TYPE(sym.st_info)) {
373 case STT_FILE:
374 match.iim_file = match.iim_name;
375 continue;
376 case STT_OBJECT:
377 tolist = iiburst->iib_objts;
378 curr = &iiburst->iib_nobjts;
379 break;
380 case STT_FUNC:
381 tolist = iiburst->iib_funcs;
382 curr = &iiburst->iib_nfuncs;
383 break;
384 default:
385 continue;
386 }
387
388 if (ignore_symbol(&sym, match.iim_name))
389 continue;
390
391 iidesc = find_iidesc(td, &match);
392
393 if (iidesc != NULL) {
394 tolist[*curr] = iidesc;
395 iidesc->ii_flags |= IIDESC_F_USED;
396 (*curr)++;
397 continue;
398 }
399
400 if (!check_for_weak(&sym, match.iim_file, data, nent, strdata,
401 &ssym, &smatch.iim_file)) {
402 (*curr)++;
403 continue;
404 }
405
406 smatch.iim_fuzzy = fuzzymatch;
407 smatch.iim_name = (char *)strdata->d_buf + ssym.st_name;
408 smatch.iim_bind = GELF_ST_BIND(ssym.st_info);
409
410 debug(3, "Weak symbol %s resolved to %s\n", match.iim_name,
411 smatch.iim_name);
412
413 iidesc = find_iidesc(td, &smatch);
414
415 if (iidesc != NULL) {
416 tolist[*curr] = copy_from_strong(td, &sym,
417 iidesc, match.iim_name, match.iim_file);
418 tolist[*curr]->ii_flags |= IIDESC_F_USED;
419 }
420
421 (*curr)++;
422 }
423
424 /*
425 * Stabs are generated for every function declared in a given C source
426 * file. When converting an object file, we may encounter a stab that
427 * has no symbol table entry because the optimizer has decided to omit
428 * that item (for example, an unreferenced static function). We may
429 * see iidescs that do not have an associated symtab entry, and so
430 * we do not write records for those functions into the CTF data.
431 * All others get marked as a root by this function.
432 */
433 iiburst_types(iiburst);
434
435 /*
436 * By not adding some of the functions and/or objects, we may have
437 * caused some types that were referenced solely by those
438 * functions/objects to be suppressed. This could cause a label,
439 * generated prior to the evisceration, to be incorrect. Find the
440 * highest type index, and change the label indicies to be no higher
441 * than this value.
442 */
443 tdata_label_newmax(td, iiburst->iib_maxtypeid);
444
445 return (iiburst);
446 }
447
448 static void
write_file(Elf * src,const char * srcname,Elf * dst,const char * dstname,caddr_t ctfdata,size_t ctfsize,int flags)449 write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname,
450 caddr_t ctfdata, size_t ctfsize, int flags)
451 {
452 GElf_Ehdr sehdr, dehdr;
453 Elf_Scn *sscn, *dscn;
454 Elf_Data *sdata, *ddata;
455 GElf_Shdr shdr;
456 GElf_Word symtab_type;
457 int symtab_idx = -1;
458 off_t new_offset = 0;
459 off_t ctfnameoff = 0;
460 int dynsym = (flags & CTF_USE_DYNSYM);
461 int keep_stabs = (flags & CTF_KEEP_STABS);
462 int *secxlate;
463 int srcidx, dstidx;
464 int curnmoff = 0;
465 int changing = 0;
466 int pad;
467 int i;
468
469 if (gelf_newehdr(dst, gelf_getclass(src)) == NULL)
470 elfterminate(dstname, "Cannot copy ehdr to temp file");
471 gelf_getehdr(src, &sehdr);
472 memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
473 gelf_update_ehdr(dst, &dehdr);
474
475 symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
476
477 /*
478 * Neither the existing stab sections nor the SUNW_ctf sections (new or
479 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
480 * program headers. As such, we can just blindly copy the program
481 * headers from the existing file to the new file.
482 */
483 if (sehdr.e_phnum != 0) {
484 (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
485 if (gelf_newphdr(dst, sehdr.e_phnum) == NULL)
486 elfterminate(dstname, "Cannot make phdrs in temp file");
487
488 for (i = 0; i < sehdr.e_phnum; i++) {
489 GElf_Phdr phdr;
490
491 gelf_getphdr(src, i, &phdr);
492 gelf_update_phdr(dst, i, &phdr);
493 }
494 }
495
496 secxlate = xmalloc(sizeof (int) * sehdr.e_shnum);
497 for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) {
498 Elf_Scn *scn = elf_getscn(src, srcidx);
499 GElf_Shdr shdr;
500 char *sname;
501
502 gelf_getshdr(scn, &shdr);
503 sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
504 if (sname == NULL) {
505 elfterminate(srcname, "Can't find string at %u",
506 shdr.sh_name);
507 }
508
509 if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
510 secxlate[srcidx] = -1;
511 } else if (!keep_stabs &&
512 (strncmp(sname, ".stab", 5) == 0 ||
513 strncmp(sname, ".debug", 6) == 0 ||
514 strncmp(sname, ".rel.debug", 10) == 0 ||
515 strncmp(sname, ".rela.debug", 11) == 0)) {
516 secxlate[srcidx] = -1;
517 } else if (dynsym && shdr.sh_type == SHT_SYMTAB) {
518 /*
519 * If we're building CTF against the dynsym,
520 * we'll rip out the symtab so debuggers aren't
521 * confused.
522 */
523 secxlate[srcidx] = -1;
524 } else {
525 secxlate[srcidx] = dstidx++;
526 curnmoff += strlen(sname) + 1;
527 }
528
529 new_offset = (off_t)dehdr.e_phoff;
530 }
531
532 for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) {
533 char *sname;
534
535 sscn = elf_getscn(src, srcidx);
536 gelf_getshdr(sscn, &shdr);
537
538 if (secxlate[srcidx] == -1) {
539 changing = 1;
540 continue;
541 }
542
543 dscn = elf_newscn(dst);
544
545 /*
546 * If this file has program headers, we need to explicitly lay
547 * out sections. If none of the sections prior to this one have
548 * been removed, then we can just use the existing location. If
549 * one or more sections have been changed, then we need to
550 * adjust this one to avoid holes.
551 */
552 if (changing && sehdr.e_phnum != 0) {
553 pad = new_offset % shdr.sh_addralign;
554
555 if (pad)
556 new_offset += shdr.sh_addralign - pad;
557 shdr.sh_offset = new_offset;
558 }
559
560 shdr.sh_link = secxlate[shdr.sh_link];
561
562 if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
563 shdr.sh_info = secxlate[shdr.sh_info];
564
565 sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
566 if (sname == NULL) {
567 elfterminate(srcname, "Can't find string at %u",
568 shdr.sh_name);
569 }
570 if ((sdata = elf_getdata(sscn, NULL)) == NULL)
571 elfterminate(srcname, "Cannot get sect %s data", sname);
572 if ((ddata = elf_newdata(dscn)) == NULL)
573 elfterminate(dstname, "Can't make sect %s data", sname);
574 bcopy(sdata, ddata, sizeof (Elf_Data));
575
576 if (srcidx == sehdr.e_shstrndx) {
577 char seclen = strlen(CTF_ELF_SCN_NAME);
578
579 ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size +
580 seclen + 1);
581 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
582 strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
583 CTF_ELF_SCN_NAME);
584 ctfnameoff = (off_t)shdr.sh_size;
585 shdr.sh_size += seclen + 1;
586 ddata->d_size += seclen + 1;
587
588 if (sehdr.e_phnum != 0)
589 changing = 1;
590 }
591
592 if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) {
593 int nsym = shdr.sh_size / shdr.sh_entsize;
594
595 symtab_idx = secxlate[srcidx];
596
597 ddata->d_buf = xmalloc(shdr.sh_size);
598 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
599
600 for (i = 0; i < nsym; i++) {
601 GElf_Sym sym;
602 short newscn;
603
604 (void) gelf_getsym(ddata, i, &sym);
605
606 if (sym.st_shndx >= SHN_LORESERVE)
607 continue;
608
609 if ((newscn = secxlate[sym.st_shndx]) !=
610 sym.st_shndx) {
611 sym.st_shndx =
612 (newscn == -1 ? 1 : newscn);
613
614 gelf_update_sym(ddata, i, &sym);
615 }
616 }
617 }
618
619 if (gelf_update_shdr(dscn, &shdr) == NULL)
620 elfterminate(dstname, "Cannot update sect %s", sname);
621
622 new_offset = (off_t)shdr.sh_offset;
623 if (shdr.sh_type != SHT_NOBITS)
624 new_offset += shdr.sh_size;
625 }
626
627 if (symtab_idx == -1) {
628 terminate("%s: Cannot find %s section\n", srcname,
629 dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB");
630 }
631
632 /* Add the ctf section */
633 dscn = elf_newscn(dst);
634 gelf_getshdr(dscn, &shdr);
635 shdr.sh_name = ctfnameoff;
636 shdr.sh_type = SHT_PROGBITS;
637 shdr.sh_size = ctfsize;
638 shdr.sh_link = symtab_idx;
639 shdr.sh_addralign = 4;
640 if (changing && sehdr.e_phnum != 0) {
641 pad = new_offset % shdr.sh_addralign;
642
643 if (pad)
644 new_offset += shdr.sh_addralign - pad;
645
646 shdr.sh_offset = new_offset;
647 new_offset += shdr.sh_size;
648 }
649
650 ddata = elf_newdata(dscn);
651 ddata->d_buf = ctfdata;
652 ddata->d_size = ctfsize;
653 ddata->d_align = shdr.sh_addralign;
654
655 gelf_update_shdr(dscn, &shdr);
656
657 /* update the section header location */
658 if (sehdr.e_phnum != 0) {
659 size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
660 size_t r = new_offset % align;
661
662 if (r)
663 new_offset += align - r;
664
665 dehdr.e_shoff = new_offset;
666 }
667
668 /* commit to disk */
669 dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
670 gelf_update_ehdr(dst, &dehdr);
671 if (elf_update(dst, ELF_C_WRITE) < 0)
672 elfterminate(dstname, "Cannot finalize temp file");
673
674 free(secxlate);
675 }
676
677 static caddr_t
make_ctf_data(tdata_t * td,Elf * elf,const char * file,size_t * lenp,int flags)678 make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags)
679 {
680 iiburst_t *iiburst;
681 caddr_t data;
682
683 iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH,
684 flags & CTF_USE_DYNSYM);
685 data = ctf_gen(iiburst, lenp, flags & CTF_COMPRESS);
686
687 iiburst_free(iiburst);
688
689 return (data);
690 }
691
692 void
write_ctf(tdata_t * td,const char * curname,const char * newname,int flags)693 write_ctf(tdata_t *td, const char *curname, const char *newname, int flags)
694 {
695 struct stat st;
696 Elf *elf = NULL;
697 Elf *telf = NULL;
698 caddr_t data;
699 size_t len;
700 int fd = -1;
701 int tfd = -1;
702
703 (void) elf_version(EV_CURRENT);
704 if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
705 terminate("%s: Cannot open for re-reading", curname);
706 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
707 elfterminate(curname, "Cannot re-read");
708
709 if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
710 terminate("Cannot open temp file %s for writing", newname);
711 if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL)
712 elfterminate(curname, "Cannot write");
713
714 data = make_ctf_data(td, elf, curname, &len, flags);
715 write_file(elf, curname, telf, newname, data, len, flags);
716 free(data);
717
718 elf_end(telf);
719 elf_end(elf);
720 (void) close(fd);
721 (void) close(tfd);
722 }
723