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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1998 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * ELF support routines for processing versioned mon.out files. 30 */ 31 32 #include "profv.h" 33 34 bool 35 is_shared_obj(char *name) 36 { 37 int fd; 38 Elf *elf; 39 GElf_Ehdr ehdr; 40 41 if ((fd = open(name, O_RDONLY)) == -1) { 42 fprintf(stderr, "%s: can't open `%s'\n", cmdname, name); 43 exit(ERR_ELF); 44 } 45 46 if (elf_version(EV_CURRENT) == EV_NONE) { 47 fprintf(stderr, "%s: libelf out of date\n", cmdname); 48 exit(ERR_ELF); 49 } 50 51 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 52 fprintf(stderr, "%s: elf_begin failed\n", cmdname); 53 exit(ERR_ELF); 54 } 55 56 if (gelf_getehdr(elf, &ehdr) == NULL) { 57 fprintf(stderr, "%s: can't read ELF header of %s\n", 58 cmdname, name); 59 exit(ERR_ELF); 60 } 61 62 elf_end(elf); 63 close(fd); 64 65 if (ehdr.e_type == ET_DYN) 66 return (TRUE); 67 else 68 return (FALSE); 69 } 70 71 static void 72 rm_dups(nltype *nl, size_t *nfuncs) 73 { 74 size_t i, prev = 0, ndx = 0; 75 int prev_type, prev_bind, cur_type; 76 77 for (i = 1; i < *nfuncs; i++) { 78 /* 79 * If current value is different from prev, proceed. 80 */ 81 if (nl[prev].value < nl[i].value) { 82 prev = i; 83 continue; 84 } 85 86 /* 87 * If current and prev have the syminfo, rm the latter. 88 */ 89 if (nl[prev].info == nl[i].info) { 90 nl[i].name = NULL; 91 continue; 92 } 93 94 prev_type = ELF_ST_TYPE(nl[prev].info); 95 prev_bind = ELF_ST_BIND(nl[prev].info); 96 cur_type = ELF_ST_TYPE(nl[i].info); 97 98 /* 99 * Remove the one with STT_NOTYPE and keep the other. 100 */ 101 if (prev_type != cur_type) { 102 if (prev_type != STT_NOTYPE) 103 nl[i].name = NULL; 104 else { 105 nl[prev].name = NULL; 106 prev = i; 107 } 108 continue; 109 } 110 111 /* 112 * If they have the same type, take the stronger bound 113 * function 114 */ 115 if (prev_bind != STB_WEAK) 116 nl[i].name = NULL; 117 else { 118 nl[prev].name = NULL; 119 prev = i; 120 } 121 } 122 123 124 /* 125 * Actually remove the cleared symbols from namelist. We're not 126 * truncating namelist by realloc, though. 127 */ 128 for (i = 0; (i < *nfuncs) && (nl[i].name != NULL); i++) 129 ; 130 131 ndx = i; 132 for (i = ndx + 1; i < *nfuncs; i++) { 133 if (nl[i].name) { 134 nl[ndx] = nl[i]; 135 ndx++; 136 } 137 } 138 139 *nfuncs = ndx; 140 } 141 142 int 143 cmp_by_address(nltype *a, nltype *b) 144 { 145 if (a->value < b->value) 146 return (-1); 147 else if (a->value > b->value) 148 return (1); 149 else 150 return (0); 151 } 152 153 static int 154 is_function(Elf *elf, GElf_Sym *sym) 155 { 156 Elf_Scn *scn; 157 GElf_Shdr shdr; 158 159 /* 160 * With dynamic linking, it is possible that certain undefined 161 * symbols exist in the objects. The actual definition will be 162 * found elsewhere, so we'll just skip it for this object. 163 */ 164 if (sym->st_shndx == SHN_UNDEF) 165 return (0); 166 167 if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) { 168 if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 169 return (1); 170 171 if (GELF_ST_BIND(sym->st_info) == STB_WEAK) 172 return (1); 173 174 if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL) 175 return (1); 176 } 177 178 /* 179 * It's not a function; determine if it's in an executable section. 180 */ 181 if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE) 182 return (0); 183 184 /* 185 * If it isn't global, and it isn't weak, and it isn't 186 * a 'local with the gflag set', then get out. 187 */ 188 if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL && 189 GELF_ST_BIND(sym->st_info) != STB_WEAK && 190 !(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)) 191 return (0); 192 193 if (sym->st_shndx >= SHN_LORESERVE) 194 return (0); 195 196 scn = elf_getscn(elf, sym->st_shndx); 197 gelf_getshdr(scn, &shdr); 198 199 if (!(shdr.sh_flags & SHF_EXECINSTR)) 200 return (0); 201 202 return (1); 203 } 204 205 static void 206 fetch_symtab(Elf *elf, char *filename, mod_info_t *module) 207 { 208 Elf_Scn *scn = NULL, *sym = NULL; 209 GElf_Word strndx = 0; 210 size_t i, nsyms, nfuncs; 211 Elf_Data *symdata; 212 nltype *nl, *npe; 213 214 while ((scn = elf_nextscn(elf, scn)) != NULL) { 215 216 GElf_Shdr shdr; 217 218 if (gelf_getshdr(scn, &shdr) == NULL) 219 continue; 220 221 if (shdr.sh_type == SHT_SYMTAB || 222 shdr.sh_type == SHT_DYNSYM) { 223 GElf_Xword chk = shdr.sh_size / shdr.sh_entsize; 224 225 nsyms = (size_t) (shdr.sh_size / shdr.sh_entsize); 226 227 if (chk != (GElf_Xword) nsyms) { 228 fprintf(stderr, "%s: can't handle" 229 "more than 2^32 symbols", cmdname); 230 exit(ERR_INPUT); 231 } 232 233 strndx = shdr.sh_link; 234 sym = scn; 235 } 236 237 /* 238 * If we've found a real symbol table, we're done. 239 */ 240 if (shdr.sh_type == SHT_SYMTAB) 241 break; 242 } 243 244 if (sym == NULL || strndx == 0) { 245 fprintf(stderr, "%s: missing symbol table in %s\n", 246 cmdname, filename); 247 exit(ERR_ELF); 248 } 249 250 if ((symdata = elf_getdata(scn, NULL)) == NULL) { 251 fprintf(stderr, "%s: can't read symbol data from %s\n", 252 cmdname, filename); 253 exit(ERR_ELF); 254 } 255 256 if ((npe = nl = (nltype *) calloc(nsyms, sizeof (nltype))) == NULL) { 257 fprintf(stderr, "%s: can't alloc %llx bytes for symbols\n", 258 cmdname, nsyms * sizeof (nltype)); 259 exit(ERR_ELF); 260 } 261 262 /* 263 * Now we need to cruise through the symbol table eliminating 264 * all non-functions from consideration, and making strings 265 * real. 266 */ 267 nfuncs = 0; 268 269 for (i = 1; i < nsyms; i++) { 270 GElf_Sym gsym; 271 char *name; 272 273 gelf_getsym(symdata, i, &gsym); 274 275 name = elf_strptr(elf, strndx, gsym.st_name); 276 277 /* 278 * We're interested in this symbol if it's a function 279 */ 280 if (is_function(elf, &gsym)) { 281 282 npe->name = name; 283 npe->value = gsym.st_value; 284 npe->size = gsym.st_size; 285 npe->info = gsym.st_info; 286 287 npe++; 288 nfuncs++; 289 } 290 291 if (strcmp(name, PRF_END) == 0) 292 module->data_end = gsym.st_value; 293 } 294 295 if (npe == nl) { 296 fprintf(stderr, "%s: no valid functions in %s\n", 297 cmdname, filename); 298 exit(ERR_INPUT); 299 } 300 301 /* 302 * And finally, sort the symbols by increasing address 303 * and remove the duplicates. 304 */ 305 qsort(nl, nfuncs, sizeof (nltype), 306 (int(*)(const void *, const void *)) cmp_by_address); 307 rm_dups(nl, &nfuncs); 308 309 module->nl = nl; 310 module->nfuncs = nfuncs; 311 } 312 313 static GElf_Addr 314 get_txtorigin(Elf *elf, char *filename) 315 { 316 GElf_Ehdr ehdr; 317 GElf_Phdr phdr; 318 GElf_Half ndx; 319 GElf_Addr txt_origin = 0; 320 bool first_load_seg = TRUE; 321 322 if (gelf_getehdr(elf, &ehdr) == NULL) { 323 fprintf(stderr, "%s: can't read ELF header of %s\n", 324 cmdname, filename); 325 exit(ERR_ELF); 326 } 327 328 for (ndx = 0; ndx < ehdr.e_phnum; ndx++) { 329 if (gelf_getphdr(elf, ndx, &phdr) == NULL) 330 continue; 331 332 if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) { 333 if (first_load_seg || phdr.p_vaddr < txt_origin) 334 txt_origin = phdr.p_vaddr; 335 336 if (first_load_seg) 337 first_load_seg = FALSE; 338 } 339 } 340 341 return (txt_origin); 342 } 343 344 void 345 get_syms(char *filename, mod_info_t *mi) 346 { 347 int fd; 348 Elf *elf; 349 350 if ((fd = open(filename, O_RDONLY)) == -1) { 351 perror(filename); 352 exit(ERR_SYSCALL); 353 } 354 355 if (elf_version(EV_CURRENT) == EV_NONE) { 356 fprintf(stderr, "%s: libelf out of date\n", cmdname); 357 exit(ERR_ELF); 358 } 359 360 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 361 fprintf(stderr, "%s: elf_begin failed\n", cmdname); 362 exit(ERR_ELF); 363 } 364 365 if (gelf_getclass(elf) != ELFCLASS64) { 366 fprintf(stderr, "%s: unsupported mon.out format for " 367 "this class of object\n", cmdname); 368 exit(ERR_ELF); 369 } 370 371 mi->txt_origin = get_txtorigin(elf, filename); 372 373 fetch_symtab(elf, filename, mi); 374 } 375