17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7a5d89c4Sab196087 * Common Development and Distribution License (the "License").
6*7a5d89c4Sab196087 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*7a5d89c4Sab196087 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2392ed1782Smike_s * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
2592ed1782Smike_s
267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * ELF support routines for processing versioned mon.out files.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
3292ed1782Smike_s #include <stdlib.h>
3392ed1782Smike_s #include <string.h>
347c478bd9Sstevel@tonic-gate #include "profv.h"
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate bool
is_shared_obj(char * name)377c478bd9Sstevel@tonic-gate is_shared_obj(char *name)
387c478bd9Sstevel@tonic-gate {
397c478bd9Sstevel@tonic-gate int fd;
407c478bd9Sstevel@tonic-gate Elf *elf;
417c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate if ((fd = open(name, O_RDONLY)) == -1) {
4492ed1782Smike_s (void) fprintf(stderr, "%s: can't open `%s'\n", cmdname, name);
457c478bd9Sstevel@tonic-gate exit(ERR_ELF);
467c478bd9Sstevel@tonic-gate }
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) {
4992ed1782Smike_s (void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
507c478bd9Sstevel@tonic-gate exit(ERR_ELF);
517c478bd9Sstevel@tonic-gate }
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
5492ed1782Smike_s (void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
557c478bd9Sstevel@tonic-gate exit(ERR_ELF);
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) {
5992ed1782Smike_s (void) fprintf(stderr, "%s: can't read ELF header of %s\n",
607c478bd9Sstevel@tonic-gate cmdname, name);
617c478bd9Sstevel@tonic-gate exit(ERR_ELF);
627c478bd9Sstevel@tonic-gate }
637c478bd9Sstevel@tonic-gate
6492ed1782Smike_s (void) elf_end(elf);
6592ed1782Smike_s (void) close(fd);
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate if (ehdr.e_type == ET_DYN)
687c478bd9Sstevel@tonic-gate return (TRUE);
697c478bd9Sstevel@tonic-gate else
707c478bd9Sstevel@tonic-gate return (FALSE);
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate static void
rm_dups(nltype * nl,size_t * nfuncs)747c478bd9Sstevel@tonic-gate rm_dups(nltype *nl, size_t *nfuncs)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate size_t i, prev = 0, ndx = 0;
777c478bd9Sstevel@tonic-gate int prev_type, prev_bind, cur_type;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate for (i = 1; i < *nfuncs; i++) {
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * If current value is different from prev, proceed.
827c478bd9Sstevel@tonic-gate */
837c478bd9Sstevel@tonic-gate if (nl[prev].value < nl[i].value) {
847c478bd9Sstevel@tonic-gate prev = i;
857c478bd9Sstevel@tonic-gate continue;
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate * If current and prev have the syminfo, rm the latter.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate if (nl[prev].info == nl[i].info) {
927c478bd9Sstevel@tonic-gate nl[i].name = NULL;
937c478bd9Sstevel@tonic-gate continue;
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate prev_type = ELF_ST_TYPE(nl[prev].info);
977c478bd9Sstevel@tonic-gate prev_bind = ELF_ST_BIND(nl[prev].info);
987c478bd9Sstevel@tonic-gate cur_type = ELF_ST_TYPE(nl[i].info);
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate * Remove the one with STT_NOTYPE and keep the other.
1027c478bd9Sstevel@tonic-gate */
1037c478bd9Sstevel@tonic-gate if (prev_type != cur_type) {
1047c478bd9Sstevel@tonic-gate if (prev_type != STT_NOTYPE)
1057c478bd9Sstevel@tonic-gate nl[i].name = NULL;
1067c478bd9Sstevel@tonic-gate else {
1077c478bd9Sstevel@tonic-gate nl[prev].name = NULL;
1087c478bd9Sstevel@tonic-gate prev = i;
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate continue;
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate * If they have the same type, take the stronger bound
1157c478bd9Sstevel@tonic-gate * function
1167c478bd9Sstevel@tonic-gate */
1177c478bd9Sstevel@tonic-gate if (prev_bind != STB_WEAK)
1187c478bd9Sstevel@tonic-gate nl[i].name = NULL;
1197c478bd9Sstevel@tonic-gate else {
1207c478bd9Sstevel@tonic-gate nl[prev].name = NULL;
1217c478bd9Sstevel@tonic-gate prev = i;
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate * Actually remove the cleared symbols from namelist. We're not
1287c478bd9Sstevel@tonic-gate * truncating namelist by realloc, though.
1297c478bd9Sstevel@tonic-gate */
1307c478bd9Sstevel@tonic-gate for (i = 0; (i < *nfuncs) && (nl[i].name != NULL); i++)
1317c478bd9Sstevel@tonic-gate ;
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate ndx = i;
1347c478bd9Sstevel@tonic-gate for (i = ndx + 1; i < *nfuncs; i++) {
1357c478bd9Sstevel@tonic-gate if (nl[i].name) {
1367c478bd9Sstevel@tonic-gate nl[ndx] = nl[i];
1377c478bd9Sstevel@tonic-gate ndx++;
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate *nfuncs = ndx;
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate int
cmp_by_address(const void * arg1,const void * arg2)14592ed1782Smike_s cmp_by_address(const void *arg1, const void *arg2)
1467c478bd9Sstevel@tonic-gate {
14792ed1782Smike_s nltype *a = (nltype *)arg1;
14892ed1782Smike_s nltype *b = (nltype *)arg2;
14992ed1782Smike_s
1507c478bd9Sstevel@tonic-gate if (a->value < b->value)
1517c478bd9Sstevel@tonic-gate return (-1);
1527c478bd9Sstevel@tonic-gate else if (a->value > b->value)
1537c478bd9Sstevel@tonic-gate return (1);
1547c478bd9Sstevel@tonic-gate else
1557c478bd9Sstevel@tonic-gate return (0);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate static int
is_function(Elf * elf,GElf_Sym * sym)1597c478bd9Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate Elf_Scn *scn;
1627c478bd9Sstevel@tonic-gate GElf_Shdr shdr;
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate * With dynamic linking, it is possible that certain undefined
1667c478bd9Sstevel@tonic-gate * symbols exist in the objects. The actual definition will be
1677c478bd9Sstevel@tonic-gate * found elsewhere, so we'll just skip it for this object.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate if (sym->st_shndx == SHN_UNDEF)
1707c478bd9Sstevel@tonic-gate return (0);
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
1737c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
1747c478bd9Sstevel@tonic-gate return (1);
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
1777c478bd9Sstevel@tonic-gate return (1);
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
1807c478bd9Sstevel@tonic-gate return (1);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate * It's not a function; determine if it's in an executable section.
1857c478bd9Sstevel@tonic-gate */
1867c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
1877c478bd9Sstevel@tonic-gate return (0);
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate * If it isn't global, and it isn't weak, and it isn't
1917c478bd9Sstevel@tonic-gate * a 'local with the gflag set', then get out.
1927c478bd9Sstevel@tonic-gate */
1937c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
1947c478bd9Sstevel@tonic-gate GELF_ST_BIND(sym->st_info) != STB_WEAK &&
1957c478bd9Sstevel@tonic-gate !(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL))
1967c478bd9Sstevel@tonic-gate return (0);
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate if (sym->st_shndx >= SHN_LORESERVE)
1997c478bd9Sstevel@tonic-gate return (0);
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate scn = elf_getscn(elf, sym->st_shndx);
20292ed1782Smike_s (void) gelf_getshdr(scn, &shdr);
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate if (!(shdr.sh_flags & SHF_EXECINSTR))
2057c478bd9Sstevel@tonic-gate return (0);
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate return (1);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate static void
fetch_symtab(Elf * elf,char * filename,mod_info_t * module)2117c478bd9Sstevel@tonic-gate fetch_symtab(Elf *elf, char *filename, mod_info_t *module)
2127c478bd9Sstevel@tonic-gate {
213*7a5d89c4Sab196087 Elf_Scn *scn = NULL, *sym_pri = NULL, *sym_aux = NULL;
2147c478bd9Sstevel@tonic-gate GElf_Word strndx = 0;
2157c478bd9Sstevel@tonic-gate size_t i, nsyms, nfuncs;
216*7a5d89c4Sab196087 GElf_Xword nsyms_pri, nsyms_aux = 0;
217*7a5d89c4Sab196087 Elf_Data *symdata_pri, *symdata_aux;
2187c478bd9Sstevel@tonic-gate nltype *nl, *npe;
219*7a5d89c4Sab196087 int symtab_found = 0;
2207c478bd9Sstevel@tonic-gate
221*7a5d89c4Sab196087
222*7a5d89c4Sab196087 /*
223*7a5d89c4Sab196087 * Scan the section headers looking for a symbol table. Our
224*7a5d89c4Sab196087 * preference is to use .symtab, because it contains the full
225*7a5d89c4Sab196087 * set of symbols. If we find it, we stop looking immediately
226*7a5d89c4Sab196087 * and use it. In the absence of a .symtab section, we are
227*7a5d89c4Sab196087 * willing to use the dynamic symbol table (.dynsym), possibly
228*7a5d89c4Sab196087 * augmented by the .SUNW_ldynsym, which contains local symbols.
229*7a5d89c4Sab196087 */
230*7a5d89c4Sab196087 while ((symtab_found == 0) && ((scn = elf_nextscn(elf, scn)) != NULL)) {
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate GElf_Shdr shdr;
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL)
2357c478bd9Sstevel@tonic-gate continue;
2367c478bd9Sstevel@tonic-gate
237*7a5d89c4Sab196087 switch (shdr.sh_type) {
238*7a5d89c4Sab196087 case SHT_SYMTAB:
239*7a5d89c4Sab196087 nsyms_pri = shdr.sh_size / shdr.sh_entsize;
2407c478bd9Sstevel@tonic-gate strndx = shdr.sh_link;
241*7a5d89c4Sab196087 sym_pri = scn;
242*7a5d89c4Sab196087 /* Throw away .SUNW_ldynsym. It is for .dynsym only */
243*7a5d89c4Sab196087 nsyms_aux = 0;
244*7a5d89c4Sab196087 sym_aux = NULL;
245*7a5d89c4Sab196087 /* We have found the best symbol table. Stop looking */
246*7a5d89c4Sab196087 symtab_found = 1;
247*7a5d89c4Sab196087 break;
2487c478bd9Sstevel@tonic-gate
249*7a5d89c4Sab196087 case SHT_DYNSYM:
250*7a5d89c4Sab196087 /* We will use .dynsym if no .symtab is found */
251*7a5d89c4Sab196087 nsyms_pri = shdr.sh_size / shdr.sh_entsize;
252*7a5d89c4Sab196087 strndx = shdr.sh_link;
253*7a5d89c4Sab196087 sym_pri = scn;
254*7a5d89c4Sab196087 break;
255*7a5d89c4Sab196087
256*7a5d89c4Sab196087 case SHT_SUNW_LDYNSYM:
257*7a5d89c4Sab196087 /* Auxiliary table, used with .dynsym */
258*7a5d89c4Sab196087 nsyms_aux = shdr.sh_size / shdr.sh_entsize;
259*7a5d89c4Sab196087 sym_aux = scn;
2607c478bd9Sstevel@tonic-gate break;
2617c478bd9Sstevel@tonic-gate }
262*7a5d89c4Sab196087 }
2637c478bd9Sstevel@tonic-gate
264*7a5d89c4Sab196087 if (sym_pri == NULL || strndx == 0) {
26592ed1782Smike_s (void) fprintf(stderr, "%s: missing symbol table in %s\n",
2667c478bd9Sstevel@tonic-gate cmdname, filename);
2677c478bd9Sstevel@tonic-gate exit(ERR_ELF);
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate
270*7a5d89c4Sab196087 nsyms = (size_t)(nsyms_pri + nsyms_aux);
271*7a5d89c4Sab196087 if ((nsyms_pri + nsyms_aux) != (GElf_Xword)nsyms) {
272*7a5d89c4Sab196087 (void) fprintf(stderr,
273*7a5d89c4Sab196087 "%s: can't handle more than 2^32 symbols", cmdname);
274*7a5d89c4Sab196087 exit(ERR_INPUT);
275*7a5d89c4Sab196087 }
276*7a5d89c4Sab196087
277*7a5d89c4Sab196087 if ((symdata_pri = elf_getdata(sym_pri, NULL)) == NULL) {
27892ed1782Smike_s (void) fprintf(stderr, "%s: can't read symbol data from %s\n",
2797c478bd9Sstevel@tonic-gate cmdname, filename);
2807c478bd9Sstevel@tonic-gate exit(ERR_ELF);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate
283*7a5d89c4Sab196087 if ((sym_aux != NULL) &&
284*7a5d89c4Sab196087 ((symdata_aux = elf_getdata(sym_aux, NULL)) == NULL)) {
285*7a5d89c4Sab196087 (void) fprintf(stderr,
286*7a5d89c4Sab196087 "%s: can't read .SUNW_ldynsym symbol data from %s\n",
287*7a5d89c4Sab196087 cmdname, filename);
288*7a5d89c4Sab196087 exit(ERR_ELF);
289*7a5d89c4Sab196087 }
290*7a5d89c4Sab196087
2917c478bd9Sstevel@tonic-gate if ((npe = nl = (nltype *) calloc(nsyms, sizeof (nltype))) == NULL) {
29292ed1782Smike_s (void) fprintf(stderr, "%s: can't alloc %x bytes for symbols\n",
2937c478bd9Sstevel@tonic-gate cmdname, nsyms * sizeof (nltype));
2947c478bd9Sstevel@tonic-gate exit(ERR_ELF);
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate * Now we need to cruise through the symbol table eliminating
2997c478bd9Sstevel@tonic-gate * all non-functions from consideration, and making strings
3007c478bd9Sstevel@tonic-gate * real.
3017c478bd9Sstevel@tonic-gate */
3027c478bd9Sstevel@tonic-gate nfuncs = 0;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate for (i = 1; i < nsyms; i++) {
3057c478bd9Sstevel@tonic-gate GElf_Sym gsym;
3067c478bd9Sstevel@tonic-gate char *name;
3077c478bd9Sstevel@tonic-gate
308*7a5d89c4Sab196087 /*
309*7a5d89c4Sab196087 * Look up the symbol. In the case where we have a
310*7a5d89c4Sab196087 * .SUNW_ldynsym/.dynsym pair, we treat them as a single
311*7a5d89c4Sab196087 * logical table, with the data in .SUNW_ldynsym coming
312*7a5d89c4Sab196087 * before the data in .dynsym.
313*7a5d89c4Sab196087 */
314*7a5d89c4Sab196087 if (i >= nsyms_aux)
315*7a5d89c4Sab196087 (void) gelf_getsym(symdata_pri, i - nsyms_aux, &gsym);
316*7a5d89c4Sab196087 else
317*7a5d89c4Sab196087 (void) gelf_getsym(symdata_aux, i, &gsym);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate name = elf_strptr(elf, strndx, gsym.st_name);
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate * We're interested in this symbol if it's a function
3237c478bd9Sstevel@tonic-gate */
3247c478bd9Sstevel@tonic-gate if (is_function(elf, &gsym)) {
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate npe->name = name;
3277c478bd9Sstevel@tonic-gate npe->value = gsym.st_value;
3287c478bd9Sstevel@tonic-gate npe->size = gsym.st_size;
3297c478bd9Sstevel@tonic-gate npe->info = gsym.st_info;
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate npe++;
3327c478bd9Sstevel@tonic-gate nfuncs++;
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate if (strcmp(name, PRF_END) == 0)
3367c478bd9Sstevel@tonic-gate module->data_end = gsym.st_value;
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate if (npe == nl) {
34092ed1782Smike_s (void) fprintf(stderr, "%s: no valid functions in %s\n",
3417c478bd9Sstevel@tonic-gate cmdname, filename);
3427c478bd9Sstevel@tonic-gate exit(ERR_INPUT);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate * And finally, sort the symbols by increasing address
3477c478bd9Sstevel@tonic-gate * and remove the duplicates.
3487c478bd9Sstevel@tonic-gate */
34992ed1782Smike_s qsort(nl, nfuncs, sizeof (nltype), cmp_by_address);
3507c478bd9Sstevel@tonic-gate rm_dups(nl, &nfuncs);
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate module->nl = nl;
3537c478bd9Sstevel@tonic-gate module->nfuncs = nfuncs;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate static GElf_Addr
get_txtorigin(Elf * elf,char * filename)3577c478bd9Sstevel@tonic-gate get_txtorigin(Elf *elf, char *filename)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
3607c478bd9Sstevel@tonic-gate GElf_Phdr phdr;
3617c478bd9Sstevel@tonic-gate GElf_Half ndx;
3627c478bd9Sstevel@tonic-gate GElf_Addr txt_origin = 0;
3637c478bd9Sstevel@tonic-gate bool first_load_seg = TRUE;
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) {
36692ed1782Smike_s (void) fprintf(stderr, "%s: can't read ELF header of %s\n",
3677c478bd9Sstevel@tonic-gate cmdname, filename);
3687c478bd9Sstevel@tonic-gate exit(ERR_ELF);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate for (ndx = 0; ndx < ehdr.e_phnum; ndx++) {
3727c478bd9Sstevel@tonic-gate if (gelf_getphdr(elf, ndx, &phdr) == NULL)
3737c478bd9Sstevel@tonic-gate continue;
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) {
3767c478bd9Sstevel@tonic-gate if (first_load_seg || phdr.p_vaddr < txt_origin)
3777c478bd9Sstevel@tonic-gate txt_origin = phdr.p_vaddr;
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate if (first_load_seg)
3807c478bd9Sstevel@tonic-gate first_load_seg = FALSE;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate return (txt_origin);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate void
get_syms(char * filename,mod_info_t * mi)3887c478bd9Sstevel@tonic-gate get_syms(char *filename, mod_info_t *mi)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate int fd;
3917c478bd9Sstevel@tonic-gate Elf *elf;
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate if ((fd = open(filename, O_RDONLY)) == -1) {
3947c478bd9Sstevel@tonic-gate perror(filename);
3957c478bd9Sstevel@tonic-gate exit(ERR_SYSCALL);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) {
39992ed1782Smike_s (void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
4007c478bd9Sstevel@tonic-gate exit(ERR_ELF);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
40492ed1782Smike_s (void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
4057c478bd9Sstevel@tonic-gate exit(ERR_ELF);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate if (gelf_getclass(elf) != ELFCLASS64) {
40992ed1782Smike_s (void) fprintf(stderr, "%s: unsupported mon.out format for "
4107c478bd9Sstevel@tonic-gate "this class of object\n", cmdname);
4117c478bd9Sstevel@tonic-gate exit(ERR_ELF);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate mi->txt_origin = get_txtorigin(elf, filename);
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate fetch_symtab(elf, filename, mi);
4177c478bd9Sstevel@tonic-gate }
418