1 /*- 2 * Copyright (c) 2003-2008 Joseph Koshy 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 #include <sys/cpuset.h> 32 #include <sys/param.h> 33 #include <sys/endian.h> 34 #include <sys/pmc.h> 35 #include <sys/sysctl.h> 36 #include <sys/imgact_aout.h> 37 #include <sys/imgact_elf.h> 38 39 #include <netinet/in.h> 40 41 #include <assert.h> 42 #include <err.h> 43 #include <fcntl.h> 44 #include <pmc.h> 45 #include <pmclog.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <sysexits.h> 50 #include <unistd.h> 51 52 #include "libpmcstat.h" 53 54 #define min(A,B) ((A) < (B) ? (A) : (B)) 55 #define max(A,B) ((A) > (B) ? (A) : (B)) 56 57 /* 58 * Add the list of symbols in the given section to the list associated 59 * with the object. 60 */ 61 void 62 pmcstat_image_add_symbols(struct pmcstat_image *image, Elf *e, 63 Elf_Scn *scn, GElf_Shdr *sh) 64 { 65 int firsttime; 66 size_t n, newsyms, nshsyms, nfuncsyms; 67 struct pmcstat_symbol *symptr; 68 char *fnname; 69 GElf_Sym sym; 70 Elf_Data *data; 71 72 if ((data = elf_getdata(scn, NULL)) == NULL) 73 return; 74 75 /* 76 * Determine the number of functions named in this 77 * section. 78 */ 79 80 nshsyms = sh->sh_size / sh->sh_entsize; 81 for (n = nfuncsyms = 0; n < nshsyms; n++) { 82 if (gelf_getsym(data, (int) n, &sym) != &sym) 83 return; 84 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC) 85 nfuncsyms++; 86 } 87 88 if (nfuncsyms == 0) 89 return; 90 91 /* 92 * Allocate space for the new entries. 93 */ 94 firsttime = image->pi_symbols == NULL; 95 symptr = reallocarray(image->pi_symbols, 96 image->pi_symcount + nfuncsyms, sizeof(*symptr)); 97 if (symptr == image->pi_symbols) /* realloc() failed. */ 98 return; 99 image->pi_symbols = symptr; 100 101 /* 102 * Append new symbols to the end of the current table. 103 */ 104 symptr += image->pi_symcount; 105 106 for (n = newsyms = 0; n < nshsyms; n++) { 107 if (gelf_getsym(data, (int) n, &sym) != &sym) 108 return; 109 if (GELF_ST_TYPE(sym.st_info) != STT_FUNC) 110 continue; 111 112 if (sym.st_shndx == STN_UNDEF) 113 continue; 114 115 if (!firsttime && pmcstat_symbol_search(image, sym.st_value)) 116 continue; /* We've seen this symbol already. */ 117 118 if ((fnname = elf_strptr(e, sh->sh_link, sym.st_name)) 119 == NULL) 120 continue; 121 #ifdef __arm__ 122 /* Remove spurious ARM function name. */ 123 if (fnname[0] == '$' && 124 (fnname[1] == 'a' || fnname[1] == 't' || 125 fnname[1] == 'd') && 126 fnname[2] == '\0') 127 continue; 128 #endif 129 130 symptr->ps_name = pmcstat_string_intern(fnname); 131 symptr->ps_start = sym.st_value - image->pi_vaddr; 132 symptr->ps_end = symptr->ps_start + sym.st_size; 133 134 symptr++; 135 newsyms++; 136 } 137 138 image->pi_symcount += newsyms; 139 if (image->pi_symcount == 0) 140 return; 141 142 assert(newsyms <= nfuncsyms); 143 144 /* 145 * Return space to the system if there were duplicates. 146 */ 147 if (newsyms < nfuncsyms) 148 image->pi_symbols = reallocarray(image->pi_symbols, 149 image->pi_symcount, sizeof(*symptr)); 150 151 /* 152 * Keep the list of symbols sorted. 153 */ 154 qsort(image->pi_symbols, image->pi_symcount, sizeof(*symptr), 155 pmcstat_symbol_compare); 156 157 /* 158 * Deal with function symbols that have a size of 'zero' by 159 * making them extend to the next higher address. These 160 * symbols are usually defined in assembly code. 161 */ 162 for (symptr = image->pi_symbols; 163 symptr < image->pi_symbols + (image->pi_symcount - 1); 164 symptr++) 165 if (symptr->ps_start == symptr->ps_end) 166 symptr->ps_end = (symptr+1)->ps_start; 167 } 168 169 /* 170 * Record the fact that PC values from 'start' to 'end' come from 171 * image 'image'. 172 */ 173 174 void 175 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, 176 uintfptr_t start) 177 { 178 struct pmcstat_pcmap *pcm, *pcmnew; 179 uintfptr_t offset; 180 #ifdef __powerpc__ 181 unsigned long kernbase; 182 size_t kernbase_len; 183 #endif 184 185 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN && 186 image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE); 187 188 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) 189 err(EX_OSERR, "ERROR: Cannot create a map entry"); 190 191 /* 192 * PowerPC kernel is of DYN type and it has a base address 193 * where it is initially loaded, before being relocated. 194 * As the address in 'start' is where the kernel was relocated to, 195 * but the symbols always use the original base address, we need to 196 * subtract it to get the correct offset. 197 */ 198 #ifdef __powerpc__ 199 if (pp->pp_pid == -1) { 200 kernbase = 0; 201 kernbase_len = sizeof(kernbase); 202 if (sysctlbyname("kern.base_address", &kernbase, &kernbase_len, 203 NULL, 0) == -1) 204 warnx( 205 "WARNING: Could not retrieve kernel base address"); 206 else 207 start -= kernbase; 208 } 209 #endif 210 211 /* 212 * Adjust the map entry to only cover the text portion 213 * of the object. 214 */ 215 216 offset = start - image->pi_vaddr; 217 pcmnew->ppm_lowpc = image->pi_start + offset; 218 pcmnew->ppm_highpc = image->pi_end + offset; 219 pcmnew->ppm_image = image; 220 221 assert(pcmnew->ppm_lowpc < pcmnew->ppm_highpc); 222 223 /* Overlapped mmap()'s are assumed to never occur. */ 224 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next) 225 if (pcm->ppm_lowpc >= pcmnew->ppm_highpc) 226 break; 227 228 if (pcm == NULL) 229 TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next); 230 else 231 TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next); 232 } 233 234 /* 235 * Determine whether a given executable image is an A.OUT object, and 236 * if so, fill in its parameters from the text file. 237 * Sets image->pi_type. 238 */ 239 240 void 241 pmcstat_image_get_aout_params(struct pmcstat_image *image, 242 struct pmcstat_args *args) 243 { 244 int fd; 245 ssize_t nbytes; 246 struct exec ex; 247 const char *path; 248 char buffer[PATH_MAX]; 249 250 path = pmcstat_string_unintern(image->pi_execpath); 251 assert(path != NULL); 252 253 if (image->pi_iskernelmodule) 254 errx(EX_SOFTWARE, 255 "ERROR: a.out kernel modules are unsupported \"%s\"", path); 256 257 (void) snprintf(buffer, sizeof(buffer), "%s%s", 258 args->pa_fsroot, path); 259 260 if ((fd = open(buffer, O_RDONLY, 0)) < 0 || 261 (nbytes = read(fd, &ex, sizeof(ex))) < 0) { 262 if (args->pa_verbosity >= 2) 263 warn("WARNING: Cannot determine type of \"%s\"", 264 path); 265 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 266 if (fd != -1) 267 (void) close(fd); 268 return; 269 } 270 271 (void) close(fd); 272 273 if ((unsigned) nbytes != sizeof(ex) || 274 N_BADMAG(ex)) 275 return; 276 277 image->pi_type = PMCSTAT_IMAGE_AOUT; 278 279 /* TODO: the rest of a.out processing */ 280 281 return; 282 } 283 284 /* 285 * Examine an ELF file to determine the size of its text segment. 286 * Sets image->pi_type if anything conclusive can be determined about 287 * this image. 288 */ 289 290 void 291 pmcstat_image_get_elf_params(struct pmcstat_image *image, 292 struct pmcstat_args *args) 293 { 294 int fd; 295 size_t i, nph, nsh; 296 const char *path, *elfbase; 297 char *p, *endp; 298 uintfptr_t minva, maxva; 299 Elf *e; 300 Elf_Scn *scn; 301 GElf_Ehdr eh; 302 GElf_Phdr ph; 303 GElf_Shdr sh; 304 enum pmcstat_image_type image_type; 305 char buffer[PATH_MAX]; 306 char buffer_modules[PATH_MAX]; 307 308 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 309 310 image->pi_start = minva = ~(uintfptr_t) 0; 311 image->pi_end = maxva = (uintfptr_t) 0; 312 image->pi_type = image_type = PMCSTAT_IMAGE_INDETERMINABLE; 313 image->pi_isdynamic = 0; 314 image->pi_dynlinkerpath = NULL; 315 image->pi_vaddr = 0; 316 317 path = pmcstat_string_unintern(image->pi_execpath); 318 assert(path != NULL); 319 320 /* 321 * Look for kernel modules under FSROOT/KERNELPATH/NAME and 322 * FSROOT/boot/modules/NAME, and user mode executable objects 323 * under FSROOT/PATHNAME. 324 */ 325 if (image->pi_iskernelmodule) { 326 (void) snprintf(buffer, sizeof(buffer), "%s%s/%s", 327 args->pa_fsroot, args->pa_kernel, path); 328 (void) snprintf(buffer_modules, sizeof(buffer_modules), 329 "%s/boot/modules/%s", args->pa_fsroot, path); 330 } else { 331 (void) snprintf(buffer, sizeof(buffer), "%s%s", 332 args->pa_fsroot, path); 333 } 334 335 e = NULL; 336 fd = open(buffer, O_RDONLY, 0); 337 if (fd < 0 && !image->pi_iskernelmodule) { 338 warnx("WARNING: Cannot open \"%s\".", 339 buffer); 340 goto done; 341 } 342 if (fd < 0 && (fd = open(buffer_modules, O_RDONLY, 0)) < 0) { 343 warnx("WARNING: Cannot open \"%s\" or \"%s\".", 344 buffer, buffer_modules); 345 goto done; 346 } 347 if (elf_version(EV_CURRENT) == EV_NONE) { 348 warnx("WARNING: failed to init elf\n"); 349 goto done; 350 } 351 352 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 353 warnx("WARNING: Cannot read \"%s\".", 354 buffer); 355 goto done; 356 } 357 358 if (elf_kind(e) != ELF_K_ELF) { 359 if (args->pa_verbosity >= 2) 360 warnx("WARNING: Cannot determine the type of \"%s\".", 361 buffer); 362 goto done; 363 } 364 365 if (gelf_getehdr(e, &eh) != &eh) { 366 warnx( 367 "WARNING: Cannot retrieve the ELF Header for \"%s\": %s.", 368 buffer, elf_errmsg(-1)); 369 goto done; 370 } 371 372 if (eh.e_type != ET_EXEC && eh.e_type != ET_DYN && 373 !(image->pi_iskernelmodule && eh.e_type == ET_REL)) { 374 warnx("WARNING: \"%s\" is of an unsupported ELF type.", 375 buffer); 376 goto done; 377 } 378 379 image_type = eh.e_ident[EI_CLASS] == ELFCLASS32 ? 380 PMCSTAT_IMAGE_ELF32 : PMCSTAT_IMAGE_ELF64; 381 382 /* 383 * Determine the virtual address where an executable would be 384 * loaded. Additionally, for dynamically linked executables, 385 * save the pathname to the runtime linker. 386 */ 387 if (eh.e_type == ET_EXEC) { 388 if (elf_getphnum(e, &nph) == 0) { 389 warnx( 390 "WARNING: Could not determine the number of program headers in \"%s\": %s.", 391 buffer, 392 elf_errmsg(-1)); 393 goto done; 394 } 395 for (i = 0; i < eh.e_phnum; i++) { 396 if (gelf_getphdr(e, i, &ph) != &ph) { 397 warnx( 398 "WARNING: Retrieval of PHDR entry #%ju in \"%s\" failed: %s.", 399 (uintmax_t) i, buffer, elf_errmsg(-1)); 400 goto done; 401 } 402 switch (ph.p_type) { 403 case PT_DYNAMIC: 404 image->pi_isdynamic = 1; 405 break; 406 case PT_INTERP: 407 if ((elfbase = elf_rawfile(e, NULL)) == NULL) { 408 warnx( 409 "WARNING: Cannot retrieve the interpreter for \"%s\": %s.", 410 buffer, elf_errmsg(-1)); 411 goto done; 412 } 413 image->pi_dynlinkerpath = 414 pmcstat_string_intern(elfbase + 415 ph.p_offset); 416 break; 417 case PT_LOAD: 418 if ((ph.p_flags & PF_X) != 0 && 419 (ph.p_offset & (-ph.p_align)) == 0) 420 image->pi_vaddr = ph.p_vaddr & (-ph.p_align); 421 break; 422 } 423 } 424 } 425 426 /* 427 * Get the min and max VA associated with this ELF object. 428 */ 429 if (elf_getshnum(e, &nsh) == 0) { 430 warnx( 431 "WARNING: Could not determine the number of sections for \"%s\": %s.", 432 buffer, elf_errmsg(-1)); 433 goto done; 434 } 435 436 for (i = 0; i < nsh; i++) { 437 if ((scn = elf_getscn(e, i)) == NULL || 438 gelf_getshdr(scn, &sh) != &sh) { 439 warnx( 440 "WARNING: Could not retrieve section header #%ju in \"%s\": %s.", 441 (uintmax_t) i, buffer, elf_errmsg(-1)); 442 goto done; 443 } 444 if (sh.sh_flags & SHF_EXECINSTR) { 445 minva = min(minva, sh.sh_addr); 446 maxva = max(maxva, sh.sh_addr + sh.sh_size); 447 } 448 if (sh.sh_type == SHT_SYMTAB || sh.sh_type == SHT_DYNSYM) 449 pmcstat_image_add_symbols(image, e, scn, &sh); 450 } 451 452 image->pi_start = minva; 453 image->pi_end = maxva; 454 image->pi_type = image_type; 455 image->pi_fullpath = pmcstat_string_intern(buffer); 456 457 /* Build display name 458 */ 459 endp = buffer; 460 for (p = buffer; *p; p++) 461 if (*p == '/') 462 endp = p+1; 463 image->pi_name = pmcstat_string_intern(endp); 464 465 done: 466 (void) elf_end(e); 467 if (fd >= 0) 468 (void) close(fd); 469 return; 470 } 471 472 /* 473 * Given an image descriptor, determine whether it is an ELF, or AOUT. 474 * If no handler claims the image, set its type to 'INDETERMINABLE'. 475 */ 476 477 void 478 pmcstat_image_determine_type(struct pmcstat_image *image, 479 struct pmcstat_args *args) 480 { 481 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 482 483 /* Try each kind of handler in turn */ 484 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 485 pmcstat_image_get_elf_params(image, args); 486 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 487 pmcstat_image_get_aout_params(image, args); 488 489 /* 490 * Otherwise, remember that we tried to determine 491 * the object's type and had failed. 492 */ 493 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 494 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE; 495 } 496 497 /* 498 * Locate an image descriptor given an interned path, adding a fresh 499 * descriptor to the cache if necessary. This function also finds a 500 * suitable name for this image's sample file. 501 * 502 * We defer filling in the file format specific parts of the image 503 * structure till the time we actually see a sample that would fall 504 * into this image. 505 */ 506 507 struct pmcstat_image * 508 pmcstat_image_from_path(pmcstat_interned_string internedpath, 509 int iskernelmodule, struct pmcstat_args *args, 510 struct pmc_plugins *plugins) 511 { 512 int hash; 513 struct pmcstat_image *pi; 514 515 hash = pmcstat_string_lookup_hash(internedpath); 516 517 /* First, look for an existing entry. */ 518 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) 519 if (pi->pi_execpath == internedpath && 520 pi->pi_iskernelmodule == iskernelmodule) 521 return (pi); 522 523 /* 524 * Allocate a new entry and place it at the head of the hash 525 * and LRU lists. 526 */ 527 pi = malloc(sizeof(*pi)); 528 if (pi == NULL) 529 return (NULL); 530 531 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN; 532 pi->pi_execpath = internedpath; 533 pi->pi_start = ~0; 534 pi->pi_end = 0; 535 pi->pi_entry = 0; 536 pi->pi_vaddr = 0; 537 pi->pi_isdynamic = 0; 538 pi->pi_iskernelmodule = iskernelmodule; 539 pi->pi_dynlinkerpath = NULL; 540 pi->pi_symbols = NULL; 541 pi->pi_symcount = 0; 542 pi->pi_addr2line = NULL; 543 544 if (plugins[args->pa_pplugin].pl_initimage != NULL) 545 plugins[args->pa_pplugin].pl_initimage(pi); 546 if (plugins[args->pa_plugin].pl_initimage != NULL) 547 plugins[args->pa_plugin].pl_initimage(pi); 548 549 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 550 551 return (pi); 552 } 553