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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Routines for preparing tdata trees for conversion into CTF data, and
28 * for placing the resulting data into an output file.
34 #include <sys/types.h>
47 typedef struct iidesc_match
{
56 burst_iitypes(void *data
, void *arg
)
59 iiburst_t
*iiburst
= arg
;
61 switch (ii
->ii_type
) {
66 if (!(ii
->ii_flags
& IIDESC_F_USED
))
73 ii
->ii_dtype
->t_flags
|= TDESC_F_ISROOT
;
74 (void) iitraverse_td(ii
, iiburst
->iib_tdtd
);
80 save_type_by_id(tdesc_t
*tdp
, tdesc_t
**tdpp
, void *private)
82 iiburst_t
*iiburst
= private;
85 * Doing this on every node is horribly inefficient, but given that
86 * we may be suppressing some types, we can't trust nextid in the
89 if (tdp
->t_id
> iiburst
->iib_maxtypeid
)
90 iiburst
->iib_maxtypeid
= tdp
->t_id
;
92 slist_add(&iiburst
->iib_types
, tdp
, tdesc_idcmp
);
97 static tdtrav_cb_f burst_types_cbs
[] = {
99 save_type_by_id
, /* intrinsic */
100 save_type_by_id
, /* pointer */
101 save_type_by_id
, /* array */
102 save_type_by_id
, /* function */
103 save_type_by_id
, /* struct */
104 save_type_by_id
, /* union */
105 save_type_by_id
, /* enum */
106 save_type_by_id
, /* forward */
107 save_type_by_id
, /* typedef */
108 tdtrav_assert
, /* typedef_unres */
109 save_type_by_id
, /* volatile */
110 save_type_by_id
, /* const */
111 save_type_by_id
/* restrict */
116 iiburst_new(tdata_t
*td
, int max
)
118 iiburst_t
*iiburst
= xcalloc(sizeof (iiburst_t
));
119 iiburst
->iib_td
= td
;
120 iiburst
->iib_funcs
= xcalloc(sizeof (iidesc_t
*) * max
);
121 iiburst
->iib_nfuncs
= 0;
122 iiburst
->iib_objts
= xcalloc(sizeof (iidesc_t
*) * max
);
123 iiburst
->iib_nobjts
= 0;
128 iiburst_types(iiburst_t
*iiburst
)
132 tdtrav_init(&tdtd
, &iiburst
->iib_td
->td_curvgen
, NULL
, burst_types_cbs
,
133 NULL
, (void *)iiburst
);
135 iiburst
->iib_tdtd
= &tdtd
;
137 (void) hash_iter(iiburst
->iib_td
->td_iihash
, burst_iitypes
, iiburst
);
141 iiburst_free(iiburst_t
*iiburst
)
143 free(iiburst
->iib_funcs
);
144 free(iiburst
->iib_objts
);
145 list_free(iiburst
->iib_types
, NULL
, NULL
);
150 * See if this iidesc matches the ELF symbol data we pass in.
152 * A fuzzy match is where we have a local symbol matching the name of a
153 * global type description. This is common when a mapfile is used for a
154 * DSO, but we don't accept it by default.
156 * A weak fuzzy match is when a weak symbol was resolved and matched to
157 * a global type description.
160 matching_iidesc(iidesc_t
*iidesc
, iidesc_match_t
*match
)
162 if (streq(iidesc
->ii_name
, match
->iim_name
) == 0)
165 switch (iidesc
->ii_type
) {
168 if (match
->iim_bind
== STB_GLOBAL
) {
169 match
->iim_ret
= iidesc
;
171 } else if (match
->iim_fuzzy
&& match
->iim_ret
== NULL
) {
172 match
->iim_ret
= iidesc
;
173 /* continue to look for strong match */
179 if (match
->iim_bind
== STB_LOCAL
&&
180 match
->iim_file
!= NULL
&&
181 streq(iidesc
->ii_owner
, match
->iim_file
)) {
182 match
->iim_ret
= iidesc
;
191 find_iidesc(tdata_t
*td
, iidesc_match_t
*match
)
193 match
->iim_ret
= NULL
;
194 iter_iidescs_by_name(td
, match
->iim_name
,
195 (int (*)())matching_iidesc
, match
);
196 return (match
->iim_ret
);
200 * If we have a weak symbol, attempt to find the strong symbol it will
201 * resolve to. Note: the code where this actually happens is in
202 * sym_process() in cmd/sgs/libld/common/syms.c
204 * Finding the matching symbol is unfortunately not trivial. For a
205 * symbol to be a candidate, it must:
207 * - have the same type (function, object)
208 * - have the same value (address)
209 * - have the same size
210 * - not be another weak symbol
211 * - belong to the same section (checked via section index)
213 * If such a candidate is global, then we assume we've found it. The
214 * linker generates the symbol table such that the curfile might be
215 * incorrect; this is OK for global symbols, since find_iidesc() doesn't
216 * need to check for the source file for the symbol.
218 * We might have found a strong local symbol, where the curfile is
219 * accurate and matches that of the weak symbol. We assume this is a
222 * If we've got a local symbol with a non-matching curfile, there are
223 * two possibilities. Either this is a completely different symbol, or
224 * it's a once-global symbol that was scoped to local via a mapfile. In
225 * the latter case, curfile is likely inaccurate since the linker does
226 * not preserve the needed curfile in the order of the symbol table (see
227 * the comments about locally scoped symbols in libld's update_osym()).
228 * As we can't tell this case from the former one, we use this symbol
229 * iff no other matching symbol is found.
231 * What we really need here is a SUNW section containing weak<->strong
232 * mappings that we can consume.
235 check_for_weak(GElf_Sym
*weak
, char const *weakfile
,
236 Elf_Data
*data
, int nent
, Elf_Data
*strdata
,
237 GElf_Sym
*retsym
, char **curfilep
)
239 char *curfile
= NULL
;
245 if (GELF_ST_BIND(weak
->st_info
) != STB_WEAK
)
248 for (i
= 0; i
< nent
; i
++) {
252 if (gelf_getsym(data
, i
, &sym
) == NULL
)
255 type
= GELF_ST_TYPE(sym
.st_info
);
257 if (type
== STT_FILE
)
258 curfile
= (char *)strdata
->d_buf
+ sym
.st_name
;
260 if (GELF_ST_TYPE(weak
->st_info
) != type
||
261 weak
->st_value
!= sym
.st_value
)
264 if (weak
->st_size
!= sym
.st_size
)
267 if (GELF_ST_BIND(sym
.st_info
) == STB_WEAK
)
270 if (sym
.st_shndx
!= weak
->st_shndx
)
273 if (GELF_ST_BIND(sym
.st_info
) == STB_LOCAL
&&
274 (curfile
== NULL
|| weakfile
== NULL
||
275 strcmp(curfile
, weakfile
) != 0)) {
297 * When we've found the underlying symbol's type description
298 * for a weak symbol, we need to copy it and rename it to match
299 * the weak symbol. We also need to add it to the td so it's
300 * handled along with the others later.
303 copy_from_strong(tdata_t
*td
, GElf_Sym
*sym
, iidesc_t
*strongdesc
,
304 const char *weakname
, const char *weakfile
)
306 iidesc_t
*new = iidesc_dup_rename(strongdesc
, weakname
, weakfile
);
307 uchar_t type
= GELF_ST_TYPE(sym
->st_info
);
311 new->ii_type
= II_GVAR
;
314 new->ii_type
= II_GFUN
;
318 hash_add(td
->td_iihash
, new);
324 * Process the symbol table of the output file, associating each symbol
325 * with a type description if possible, and sorting them into functions
326 * and data, maintaining symbol table order.
329 sort_iidescs(Elf
*elf
, const char *file
, tdata_t
*td
, int fuzzymatch
,
335 Elf_Data
*data
, *strdata
;
338 iidesc_match_t match
;
340 match
.iim_fuzzy
= fuzzymatch
;
341 match
.iim_file
= NULL
;
343 if ((stidx
= findelfsecidx(elf
, file
,
344 dynsym
? ".dynsym" : ".symtab")) < 0)
345 terminate("%s: Can't open symbol table\n", file
);
346 scn
= elf_getscn(elf
, stidx
);
347 data
= elf_getdata(scn
, NULL
);
348 gelf_getshdr(scn
, &shdr
);
349 nent
= shdr
.sh_size
/ shdr
.sh_entsize
;
351 scn
= elf_getscn(elf
, shdr
.sh_link
);
352 strdata
= elf_getdata(scn
, NULL
);
354 iiburst
= iiburst_new(td
, nent
);
356 for (i
= 0; i
< nent
; i
++) {
360 iidesc_match_t smatch
;
364 if (gelf_getsym(data
, i
, &sym
) == NULL
)
365 elfterminate(file
, "Couldn't read symbol %d", i
);
367 match
.iim_name
= (char *)strdata
->d_buf
+ sym
.st_name
;
368 match
.iim_bind
= GELF_ST_BIND(sym
.st_info
);
370 switch (GELF_ST_TYPE(sym
.st_info
)) {
372 match
.iim_file
= match
.iim_name
;
375 tolist
= iiburst
->iib_objts
;
376 curr
= &iiburst
->iib_nobjts
;
379 tolist
= iiburst
->iib_funcs
;
380 curr
= &iiburst
->iib_nfuncs
;
386 if (ignore_symbol(&sym
, match
.iim_name
))
389 iidesc
= find_iidesc(td
, &match
);
391 if (iidesc
!= NULL
) {
392 tolist
[*curr
] = iidesc
;
393 iidesc
->ii_flags
|= IIDESC_F_USED
;
398 if (!check_for_weak(&sym
, match
.iim_file
, data
, nent
, strdata
,
399 &ssym
, &smatch
.iim_file
)) {
404 smatch
.iim_fuzzy
= fuzzymatch
;
405 smatch
.iim_name
= (char *)strdata
->d_buf
+ ssym
.st_name
;
406 smatch
.iim_bind
= GELF_ST_BIND(ssym
.st_info
);
408 debug(3, "Weak symbol %s resolved to %s\n", match
.iim_name
,
411 iidesc
= find_iidesc(td
, &smatch
);
413 if (iidesc
!= NULL
) {
414 tolist
[*curr
] = copy_from_strong(td
, &sym
,
415 iidesc
, match
.iim_name
, match
.iim_file
);
416 tolist
[*curr
]->ii_flags
|= IIDESC_F_USED
;
423 * Stabs are generated for every function declared in a given C source
424 * file. When converting an object file, we may encounter a stab that
425 * has no symbol table entry because the optimizer has decided to omit
426 * that item (for example, an unreferenced static function). We may
427 * see iidescs that do not have an associated symtab entry, and so
428 * we do not write records for those functions into the CTF data.
429 * All others get marked as a root by this function.
431 iiburst_types(iiburst
);
434 * By not adding some of the functions and/or objects, we may have
435 * caused some types that were referenced solely by those
436 * functions/objects to be suppressed. This could cause a label,
437 * generated prior to the evisceration, to be incorrect. Find the
438 * highest type index, and change the label indicies to be no higher
441 tdata_label_newmax(td
, iiburst
->iib_maxtypeid
);
447 write_file(Elf
*src
, const char *srcname
, Elf
*dst
, const char *dstname
,
448 caddr_t ctfdata
, size_t ctfsize
, int flags
)
450 GElf_Ehdr sehdr
, dehdr
;
451 Elf_Scn
*sscn
, *dscn
;
452 Elf_Data
*sdata
, *ddata
;
454 GElf_Word symtab_type
;
456 off_t new_offset
= 0;
457 off_t ctfnameoff
= 0;
458 int dynsym
= (flags
& CTF_USE_DYNSYM
);
466 if (gelf_newehdr(dst
, gelf_getclass(src
)) == 0)
467 elfterminate(dstname
, "Cannot copy ehdr to temp file");
468 gelf_getehdr(src
, &sehdr
);
469 memcpy(&dehdr
, &sehdr
, sizeof (GElf_Ehdr
));
470 gelf_update_ehdr(dst
, &dehdr
);
472 symtab_type
= dynsym
? SHT_DYNSYM
: SHT_SYMTAB
;
475 * Neither the existing stab sections nor the SUNW_ctf sections (new or
476 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
477 * program headers. As such, we can just blindly copy the program
478 * headers from the existing file to the new file.
480 if (sehdr
.e_phnum
!= 0) {
481 (void) elf_flagelf(dst
, ELF_C_SET
, ELF_F_LAYOUT
);
482 if (gelf_newphdr(dst
, sehdr
.e_phnum
) == 0)
483 elfterminate(dstname
, "Cannot make phdrs in temp file");
485 for (i
= 0; i
< sehdr
.e_phnum
; i
++) {
488 gelf_getphdr(src
, i
, &phdr
);
489 gelf_update_phdr(dst
, i
, &phdr
);
493 secxlate
= xmalloc(sizeof (int) * sehdr
.e_shnum
);
494 for (srcidx
= dstidx
= 0; srcidx
< sehdr
.e_shnum
; srcidx
++) {
495 Elf_Scn
*scn
= elf_getscn(src
, srcidx
);
499 gelf_getshdr(scn
, &shdr
);
500 sname
= elf_strptr(src
, sehdr
.e_shstrndx
, shdr
.sh_name
);
502 elfterminate(srcname
, "Can't find string at %u",
506 if (strcmp(sname
, CTF_ELF_SCN_NAME
) == 0) {
507 secxlate
[srcidx
] = -1;
508 } else if (dynsym
&& shdr
.sh_type
== SHT_SYMTAB
) {
510 * If we're building CTF against the dynsym,
511 * we'll rip out the symtab so debuggers aren't
514 secxlate
[srcidx
] = -1;
516 secxlate
[srcidx
] = dstidx
++;
517 curnmoff
+= strlen(sname
) + 1;
520 new_offset
= (off_t
)dehdr
.e_phoff
;
523 for (srcidx
= 1; srcidx
< sehdr
.e_shnum
; srcidx
++) {
526 sscn
= elf_getscn(src
, srcidx
);
527 gelf_getshdr(sscn
, &shdr
);
529 if (secxlate
[srcidx
] == -1) {
534 dscn
= elf_newscn(dst
);
537 * If this file has program headers, we need to explicitly lay
538 * out sections. If none of the sections prior to this one have
539 * been removed, then we can just use the existing location. If
540 * one or more sections have been changed, then we need to
541 * adjust this one to avoid holes.
543 if (changing
&& sehdr
.e_phnum
!= 0) {
544 pad
= new_offset
% shdr
.sh_addralign
;
547 new_offset
+= shdr
.sh_addralign
- pad
;
548 shdr
.sh_offset
= new_offset
;
551 shdr
.sh_link
= secxlate
[shdr
.sh_link
];
553 if (shdr
.sh_type
== SHT_REL
|| shdr
.sh_type
== SHT_RELA
)
554 shdr
.sh_info
= secxlate
[shdr
.sh_info
];
556 sname
= elf_strptr(src
, sehdr
.e_shstrndx
, shdr
.sh_name
);
558 elfterminate(srcname
, "Can't find string at %u",
561 if ((sdata
= elf_getdata(sscn
, NULL
)) == NULL
)
562 elfterminate(srcname
, "Cannot get sect %s data", sname
);
563 if ((ddata
= elf_newdata(dscn
)) == NULL
)
564 elfterminate(dstname
, "Can't make sect %s data", sname
);
565 bcopy(sdata
, ddata
, sizeof (Elf_Data
));
567 if (srcidx
== sehdr
.e_shstrndx
) {
568 char seclen
= strlen(CTF_ELF_SCN_NAME
);
570 ddata
->d_buf
= xmalloc(ddata
->d_size
+ shdr
.sh_size
+
572 bcopy(sdata
->d_buf
, ddata
->d_buf
, shdr
.sh_size
);
573 strcpy((caddr_t
)ddata
->d_buf
+ shdr
.sh_size
,
575 ctfnameoff
= (off_t
)shdr
.sh_size
;
576 shdr
.sh_size
+= seclen
+ 1;
577 ddata
->d_size
+= seclen
+ 1;
579 if (sehdr
.e_phnum
!= 0)
583 if (shdr
.sh_type
== symtab_type
&& shdr
.sh_entsize
!= 0) {
584 int nsym
= shdr
.sh_size
/ shdr
.sh_entsize
;
586 symtab_idx
= secxlate
[srcidx
];
588 ddata
->d_buf
= xmalloc(shdr
.sh_size
);
589 bcopy(sdata
->d_buf
, ddata
->d_buf
, shdr
.sh_size
);
591 for (i
= 0; i
< nsym
; i
++) {
595 (void) gelf_getsym(ddata
, i
, &sym
);
597 if (sym
.st_shndx
>= SHN_LORESERVE
)
600 if ((newscn
= secxlate
[sym
.st_shndx
]) !=
603 (newscn
== -1 ? 1 : newscn
);
605 gelf_update_sym(ddata
, i
, &sym
);
610 if (gelf_update_shdr(dscn
, &shdr
) == 0)
611 elfterminate(dstname
, "Cannot update sect %s", sname
);
613 new_offset
= (off_t
)shdr
.sh_offset
;
614 if (shdr
.sh_type
!= SHT_NOBITS
)
615 new_offset
+= shdr
.sh_size
;
618 if (symtab_idx
== -1) {
619 terminate("%s: Cannot find %s section\n", srcname
,
620 dynsym
? "SHT_DYNSYM" : "SHT_SYMTAB");
623 /* Add the ctf section */
624 dscn
= elf_newscn(dst
);
625 gelf_getshdr(dscn
, &shdr
);
626 shdr
.sh_name
= ctfnameoff
;
627 shdr
.sh_type
= SHT_PROGBITS
;
628 shdr
.sh_size
= ctfsize
;
629 shdr
.sh_link
= symtab_idx
;
630 shdr
.sh_addralign
= 4;
631 if (changing
&& sehdr
.e_phnum
!= 0) {
632 pad
= new_offset
% shdr
.sh_addralign
;
635 new_offset
+= shdr
.sh_addralign
- pad
;
637 shdr
.sh_offset
= new_offset
;
638 new_offset
+= shdr
.sh_size
;
641 ddata
= elf_newdata(dscn
);
642 ddata
->d_buf
= ctfdata
;
643 ddata
->d_size
= ctfsize
;
644 ddata
->d_align
= shdr
.sh_addralign
;
646 gelf_update_shdr(dscn
, &shdr
);
648 /* update the section header location */
649 if (sehdr
.e_phnum
!= 0) {
650 size_t align
= gelf_fsize(dst
, ELF_T_ADDR
, 1, EV_CURRENT
);
651 size_t r
= new_offset
% align
;
654 new_offset
+= align
- r
;
656 dehdr
.e_shoff
= new_offset
;
660 dehdr
.e_shstrndx
= secxlate
[sehdr
.e_shstrndx
];
661 gelf_update_ehdr(dst
, &dehdr
);
662 if (elf_update(dst
, ELF_C_WRITE
) < 0)
663 elfterminate(dstname
, "Cannot finalize temp file");
669 make_ctf_data(tdata_t
*td
, Elf
*elf
, const char *file
, size_t *lenp
, int flags
)
674 iiburst
= sort_iidescs(elf
, file
, td
, flags
& CTF_FUZZY_MATCH
,
675 flags
& CTF_USE_DYNSYM
);
676 data
= ctf_gen(iiburst
, lenp
, flags
& CTF_COMPRESS
);
678 iiburst_free(iiburst
);
684 write_ctf(tdata_t
*td
, const char *curname
, const char *newname
, int flags
)
694 (void) elf_version(EV_CURRENT
);
695 if ((fd
= open(curname
, O_RDONLY
)) < 0 || fstat(fd
, &st
) < 0)
696 terminate("%s: Cannot open for re-reading", curname
);
697 if ((elf
= elf_begin(fd
, ELF_C_READ
, NULL
)) == NULL
)
698 elfterminate(curname
, "Cannot re-read");
700 if ((tfd
= open(newname
, O_RDWR
| O_CREAT
| O_TRUNC
, st
.st_mode
)) < 0)
701 terminate("Cannot open temp file %s for writing", newname
);
702 if ((telf
= elf_begin(tfd
, ELF_C_WRITE
, NULL
)) == NULL
)
703 elfterminate(curname
, "Cannot write");
705 data
= make_ctf_data(td
, elf
, curname
, &len
, flags
);
706 write_file(elf
, curname
, telf
, newname
, data
, len
, flags
);