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 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * ELF support routines for processing versioned mon.out files.
37 is_shared_obj(char *name
)
43 if ((fd
= open(name
, O_RDONLY
)) == -1) {
44 (void) fprintf(stderr
, "%s: can't open `%s'\n", cmdname
, name
);
48 if (elf_version(EV_CURRENT
) == EV_NONE
) {
49 (void) fprintf(stderr
, "%s: libelf out of date\n", cmdname
);
53 if ((elf
= elf_begin(fd
, ELF_C_READ
, NULL
)) == NULL
) {
54 (void) fprintf(stderr
, "%s: elf_begin failed\n", cmdname
);
58 if (gelf_getehdr(elf
, &ehdr
) == NULL
) {
59 (void) fprintf(stderr
, "%s: can't read ELF header of %s\n",
67 if (ehdr
.e_type
== ET_DYN
)
74 rm_dups(nltype
*nl
, size_t *nfuncs
)
76 size_t i
, prev
= 0, ndx
= 0;
77 int prev_type
, prev_bind
, cur_type
;
79 for (i
= 1; i
< *nfuncs
; i
++) {
81 * If current value is different from prev, proceed.
83 if (nl
[prev
].value
< nl
[i
].value
) {
89 * If current and prev have the syminfo, rm the latter.
91 if (nl
[prev
].info
== nl
[i
].info
) {
96 prev_type
= ELF_ST_TYPE(nl
[prev
].info
);
97 prev_bind
= ELF_ST_BIND(nl
[prev
].info
);
98 cur_type
= ELF_ST_TYPE(nl
[i
].info
);
101 * Remove the one with STT_NOTYPE and keep the other.
103 if (prev_type
!= cur_type
) {
104 if (prev_type
!= STT_NOTYPE
)
107 nl
[prev
].name
= NULL
;
114 * If they have the same type, take the stronger bound
117 if (prev_bind
!= STB_WEAK
)
120 nl
[prev
].name
= NULL
;
127 * Actually remove the cleared symbols from namelist. We're not
128 * truncating namelist by realloc, though.
130 for (i
= 0; (i
< *nfuncs
) && (nl
[i
].name
!= NULL
); i
++)
134 for (i
= ndx
+ 1; i
< *nfuncs
; i
++) {
145 cmp_by_address(const void *arg1
, const void *arg2
)
147 nltype
*a
= (nltype
*)arg1
;
148 nltype
*b
= (nltype
*)arg2
;
150 if (a
->value
< b
->value
)
152 else if (a
->value
> b
->value
)
159 is_function(Elf
*elf
, GElf_Sym
*sym
)
165 * With dynamic linking, it is possible that certain undefined
166 * symbols exist in the objects. The actual definition will be
167 * found elsewhere, so we'll just skip it for this object.
169 if (sym
->st_shndx
== SHN_UNDEF
)
172 if (GELF_ST_TYPE(sym
->st_info
) == STT_FUNC
) {
173 if (GELF_ST_BIND(sym
->st_info
) == STB_GLOBAL
)
176 if (GELF_ST_BIND(sym
->st_info
) == STB_WEAK
)
179 if (gflag
&& GELF_ST_BIND(sym
->st_info
) == STB_LOCAL
)
184 * It's not a function; determine if it's in an executable section.
186 if (GELF_ST_TYPE(sym
->st_info
) != STT_NOTYPE
)
190 * If it isn't global, and it isn't weak, and it isn't
191 * a 'local with the gflag set', then get out.
193 if (GELF_ST_BIND(sym
->st_info
) != STB_GLOBAL
&&
194 GELF_ST_BIND(sym
->st_info
) != STB_WEAK
&&
195 !(gflag
&& GELF_ST_BIND(sym
->st_info
) == STB_LOCAL
))
198 if (sym
->st_shndx
>= SHN_LORESERVE
)
201 scn
= elf_getscn(elf
, sym
->st_shndx
);
202 (void) gelf_getshdr(scn
, &shdr
);
204 if (!(shdr
.sh_flags
& SHF_EXECINSTR
))
211 fetch_symtab(Elf
*elf
, char *filename
, mod_info_t
*module
)
213 Elf_Scn
*scn
= NULL
, *sym_pri
= NULL
, *sym_aux
= NULL
;
214 GElf_Word strndx
= 0;
215 size_t i
, nsyms
, nfuncs
;
216 GElf_Xword nsyms_pri
, nsyms_aux
= 0;
217 Elf_Data
*symdata_pri
, *symdata_aux
;
219 int symtab_found
= 0;
223 * Scan the section headers looking for a symbol table. Our
224 * preference is to use .symtab, because it contains the full
225 * set of symbols. If we find it, we stop looking immediately
226 * and use it. In the absence of a .symtab section, we are
227 * willing to use the dynamic symbol table (.dynsym), possibly
228 * augmented by the .SUNW_ldynsym, which contains local symbols.
230 while ((symtab_found
== 0) && ((scn
= elf_nextscn(elf
, scn
)) != NULL
)) {
234 if (gelf_getshdr(scn
, &shdr
) == NULL
)
237 switch (shdr
.sh_type
) {
239 nsyms_pri
= shdr
.sh_size
/ shdr
.sh_entsize
;
240 strndx
= shdr
.sh_link
;
242 /* Throw away .SUNW_ldynsym. It is for .dynsym only */
245 /* We have found the best symbol table. Stop looking */
250 /* We will use .dynsym if no .symtab is found */
251 nsyms_pri
= shdr
.sh_size
/ shdr
.sh_entsize
;
252 strndx
= shdr
.sh_link
;
256 case SHT_SUNW_LDYNSYM
:
257 /* Auxiliary table, used with .dynsym */
258 nsyms_aux
= shdr
.sh_size
/ shdr
.sh_entsize
;
264 if (sym_pri
== NULL
|| strndx
== 0) {
265 (void) fprintf(stderr
, "%s: missing symbol table in %s\n",
270 nsyms
= (size_t)(nsyms_pri
+ nsyms_aux
);
271 if ((nsyms_pri
+ nsyms_aux
) != (GElf_Xword
)nsyms
) {
272 (void) fprintf(stderr
,
273 "%s: can't handle more than 2^32 symbols", cmdname
);
277 if ((symdata_pri
= elf_getdata(sym_pri
, NULL
)) == NULL
) {
278 (void) fprintf(stderr
, "%s: can't read symbol data from %s\n",
283 if ((sym_aux
!= NULL
) &&
284 ((symdata_aux
= elf_getdata(sym_aux
, NULL
)) == NULL
)) {
285 (void) fprintf(stderr
,
286 "%s: can't read .SUNW_ldynsym symbol data from %s\n",
291 if ((npe
= nl
= (nltype
*) calloc(nsyms
, sizeof (nltype
))) == NULL
) {
292 (void) fprintf(stderr
, "%s: can't alloc %x bytes for symbols\n",
293 cmdname
, nsyms
* sizeof (nltype
));
298 * Now we need to cruise through the symbol table eliminating
299 * all non-functions from consideration, and making strings
304 for (i
= 1; i
< nsyms
; i
++) {
309 * Look up the symbol. In the case where we have a
310 * .SUNW_ldynsym/.dynsym pair, we treat them as a single
311 * logical table, with the data in .SUNW_ldynsym coming
312 * before the data in .dynsym.
315 (void) gelf_getsym(symdata_pri
, i
- nsyms_aux
, &gsym
);
317 (void) gelf_getsym(symdata_aux
, i
, &gsym
);
319 name
= elf_strptr(elf
, strndx
, gsym
.st_name
);
322 * We're interested in this symbol if it's a function
324 if (is_function(elf
, &gsym
)) {
327 npe
->value
= gsym
.st_value
;
328 npe
->size
= gsym
.st_size
;
329 npe
->info
= gsym
.st_info
;
335 if (strcmp(name
, PRF_END
) == 0)
336 module
->data_end
= gsym
.st_value
;
340 (void) fprintf(stderr
, "%s: no valid functions in %s\n",
346 * And finally, sort the symbols by increasing address
347 * and remove the duplicates.
349 qsort(nl
, nfuncs
, sizeof (nltype
), cmp_by_address
);
350 rm_dups(nl
, &nfuncs
);
353 module
->nfuncs
= nfuncs
;
357 get_txtorigin(Elf
*elf
, char *filename
)
362 GElf_Addr txt_origin
= 0;
363 bool first_load_seg
= TRUE
;
365 if (gelf_getehdr(elf
, &ehdr
) == NULL
) {
366 (void) fprintf(stderr
, "%s: can't read ELF header of %s\n",
371 for (ndx
= 0; ndx
< ehdr
.e_phnum
; ndx
++) {
372 if (gelf_getphdr(elf
, ndx
, &phdr
) == NULL
)
375 if ((phdr
.p_type
== PT_LOAD
) && !(phdr
.p_flags
& PF_W
)) {
376 if (first_load_seg
|| phdr
.p_vaddr
< txt_origin
)
377 txt_origin
= phdr
.p_vaddr
;
380 first_load_seg
= FALSE
;
388 get_syms(char *filename
, mod_info_t
*mi
)
393 if ((fd
= open(filename
, O_RDONLY
)) == -1) {
398 if (elf_version(EV_CURRENT
) == EV_NONE
) {
399 (void) fprintf(stderr
, "%s: libelf out of date\n", cmdname
);
403 if ((elf
= elf_begin(fd
, ELF_C_READ
, NULL
)) == NULL
) {
404 (void) fprintf(stderr
, "%s: elf_begin failed\n", cmdname
);
408 if (gelf_getclass(elf
) != ELFCLASS64
) {
409 (void) fprintf(stderr
, "%s: unsupported mon.out format for "
410 "this class of object\n", cmdname
);
414 mi
->txt_origin
= get_txtorigin(elf
, filename
);
416 fetch_symtab(elf
, filename
, mi
);