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