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 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 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 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 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 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 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 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