2 * Copyright (c) 2003-2008 Joseph Koshy
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/cpuset.h>
32 #include <sys/param.h>
33 #include <sys/endian.h>
35 #include <sys/sysctl.h>
36 #include <sys/imgact_aout.h>
37 #include <sys/imgact_elf.h>
39 #include <netinet/in.h>
53 #include "libpmcstat.h"
55 #define min(A,B) ((A) < (B) ? (A) : (B))
56 #define max(A,B) ((A) > (B) ? (A) : (B))
59 * Add the list of symbols in the given section to the list associated
63 pmcstat_image_add_symbols(struct pmcstat_image *image, Elf *e,
64 Elf_Scn *scn, GElf_Shdr *sh)
67 size_t n, newsyms, nshsyms, nfuncsyms;
68 struct pmcstat_symbol *symptr;
73 if ((data = elf_getdata(scn, NULL)) == NULL)
77 * Determine the number of functions named in this
81 nshsyms = sh->sh_size / sh->sh_entsize;
82 for (n = nfuncsyms = 0; n < nshsyms; n++) {
83 if (gelf_getsym(data, (int) n, &sym) != &sym)
85 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC)
93 * Allocate space for the new entries.
95 firsttime = image->pi_symbols == NULL;
96 symptr = reallocarray(image->pi_symbols,
97 image->pi_symcount + nfuncsyms, sizeof(*symptr));
98 if (symptr == image->pi_symbols) /* realloc() failed. */
100 image->pi_symbols = symptr;
103 * Append new symbols to the end of the current table.
105 symptr += image->pi_symcount;
107 for (n = newsyms = 0; n < nshsyms; n++) {
108 if (gelf_getsym(data, (int) n, &sym) != &sym)
110 if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
113 if (sym.st_shndx == STN_UNDEF)
116 if (!firsttime && pmcstat_symbol_search(image, sym.st_value))
117 continue; /* We've seen this symbol already. */
119 if ((fnname = elf_strptr(e, sh->sh_link, sym.st_name))
123 #if defined(__aarch64__) || defined(__arm__)
124 /* Ignore ARM mapping symbols. */
125 if (fnname[0] == '$' &&
126 (fnname[1] == 'a' || fnname[1] == 't' ||
127 fnname[1] == 'd' || fnname[1] == 'x'))
131 * Clear LSB from starting addresses for functions
132 * which execute in Thumb mode. We should perhaps
133 * only do this for functions in a $t mapping symbol
134 * range, but parsing mapping symbols would be a lot
135 * of work and function addresses shouldn't have the
141 symptr->ps_name = pmcstat_string_intern(fnname);
142 symptr->ps_start = sym.st_value - image->pi_vaddr;
143 symptr->ps_end = symptr->ps_start + sym.st_size;
149 image->pi_symcount += newsyms;
150 if (image->pi_symcount == 0)
153 assert(newsyms <= nfuncsyms);
156 * Return space to the system if there were duplicates.
158 if (newsyms < nfuncsyms)
159 image->pi_symbols = reallocarray(image->pi_symbols,
160 image->pi_symcount, sizeof(*symptr));
163 * Keep the list of symbols sorted.
165 qsort(image->pi_symbols, image->pi_symcount, sizeof(*symptr),
166 pmcstat_symbol_compare);
169 * Deal with function symbols that have a size of 'zero' by
170 * making them extend to the next higher address. These
171 * symbols are usually defined in assembly code.
173 for (symptr = image->pi_symbols;
174 symptr < image->pi_symbols + (image->pi_symcount - 1);
176 if (symptr->ps_start == symptr->ps_end)
177 symptr->ps_end = (symptr+1)->ps_start;
181 * Record the fact that PC values from 'start' to 'end' come from
186 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image,
189 struct pmcstat_pcmap *pcm, *pcmnew;
192 unsigned long kernbase;
196 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN &&
197 image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE);
199 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL)
200 err(EX_OSERR, "ERROR: Cannot create a map entry");
203 * PowerPC kernel is of DYN type and it has a base address
204 * where it is initially loaded, before being relocated.
205 * As the address in 'start' is where the kernel was relocated to,
206 * but the symbols always use the original base address, we need to
207 * subtract it to get the correct offset.
210 if (pp->pp_pid == -1) {
212 kernbase_len = sizeof(kernbase);
213 if (sysctlbyname("kern.base_address", &kernbase, &kernbase_len,
216 "WARNING: Could not retrieve kernel base address");
223 * Adjust the map entry to only cover the text portion
227 offset = start - image->pi_vaddr;
228 pcmnew->ppm_lowpc = image->pi_start + offset;
229 pcmnew->ppm_highpc = image->pi_end + offset;
230 pcmnew->ppm_image = image;
232 assert(pcmnew->ppm_lowpc < pcmnew->ppm_highpc);
234 /* Overlapped mmap()'s are assumed to never occur. */
235 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next)
236 if (pcm->ppm_lowpc >= pcmnew->ppm_highpc)
240 TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next);
242 TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next);
246 * Determine whether a given executable image is an A.OUT object, and
247 * if so, fill in its parameters from the text file.
248 * Sets image->pi_type.
252 pmcstat_image_get_aout_params(struct pmcstat_image *image,
253 struct pmcstat_args *args)
259 char buffer[PATH_MAX];
261 path = pmcstat_string_unintern(image->pi_execpath);
262 assert(path != NULL);
264 if (image->pi_iskernelmodule)
266 "ERROR: a.out kernel modules are unsupported \"%s\"", path);
268 (void) snprintf(buffer, sizeof(buffer), "%s%s",
269 args->pa_fsroot, path);
271 if ((fd = open(buffer, O_RDONLY, 0)) < 0 ||
272 (nbytes = read(fd, &ex, sizeof(ex))) < 0) {
273 if (args->pa_verbosity >= 2)
274 warn("WARNING: Cannot determine type of \"%s\"",
276 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE;
284 if ((unsigned) nbytes != sizeof(ex) ||
288 image->pi_type = PMCSTAT_IMAGE_AOUT;
290 /* TODO: the rest of a.out processing */
296 * Examine an ELF file to determine the size of its text segment.
297 * Sets image->pi_type if anything conclusive can be determined about
302 pmcstat_image_get_elf_params(struct pmcstat_image *image,
303 struct pmcstat_args *args)
307 const char *path, *elfbase;
309 bool first_exec_segment;
310 uintfptr_t minva, maxva;
316 enum pmcstat_image_type image_type;
317 char buffer[PATH_MAX];
318 char buffer_modules[PATH_MAX];
320 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
322 image->pi_start = minva = ~(uintfptr_t) 0;
323 image->pi_end = maxva = (uintfptr_t) 0;
324 image->pi_type = image_type = PMCSTAT_IMAGE_INDETERMINABLE;
325 image->pi_isdynamic = 0;
326 image->pi_dynlinkerpath = NULL;
329 path = pmcstat_string_unintern(image->pi_execpath);
330 assert(path != NULL);
333 * Look for kernel modules under FSROOT/KERNELPATH/NAME and
334 * FSROOT/boot/modules/NAME, and user mode executable objects
335 * under FSROOT/PATHNAME.
337 if (image->pi_iskernelmodule) {
338 (void) snprintf(buffer, sizeof(buffer), "%s%s/%s",
339 args->pa_fsroot, args->pa_kernel, path);
340 (void) snprintf(buffer_modules, sizeof(buffer_modules),
341 "%s/boot/modules/%s", args->pa_fsroot, path);
343 (void) snprintf(buffer, sizeof(buffer), "%s%s",
344 args->pa_fsroot, path);
348 fd = open(buffer, O_RDONLY, 0);
349 if (fd < 0 && !image->pi_iskernelmodule) {
350 warnx("WARNING: Cannot open \"%s\".",
354 if (fd < 0 && (fd = open(buffer_modules, O_RDONLY, 0)) < 0) {
355 warnx("WARNING: Cannot open \"%s\" or \"%s\".",
356 buffer, buffer_modules);
359 if (elf_version(EV_CURRENT) == EV_NONE) {
360 warnx("WARNING: failed to init elf\n");
364 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
365 warnx("WARNING: Cannot read \"%s\".",
370 if (elf_kind(e) != ELF_K_ELF) {
371 if (args->pa_verbosity >= 2)
372 warnx("WARNING: Cannot determine the type of \"%s\".",
377 if (gelf_getehdr(e, &eh) != &eh) {
379 "WARNING: Cannot retrieve the ELF Header for \"%s\": %s.",
380 buffer, elf_errmsg(-1));
384 if (eh.e_type != ET_EXEC && eh.e_type != ET_DYN &&
385 !(image->pi_iskernelmodule && eh.e_type == ET_REL)) {
386 warnx("WARNING: \"%s\" is of an unsupported ELF type.",
391 image_type = eh.e_ident[EI_CLASS] == ELFCLASS32 ?
392 PMCSTAT_IMAGE_ELF32 : PMCSTAT_IMAGE_ELF64;
395 * Determine the virtual address where an executable would be
396 * loaded. Additionally, for dynamically linked executables,
397 * save the pathname to the runtime linker.
399 if (eh.e_type != ET_REL) {
400 if (elf_getphnum(e, &nph) == 0) {
402 "WARNING: Could not determine the number of program headers in \"%s\": %s.",
407 first_exec_segment = true;
408 for (i = 0; i < eh.e_phnum; i++) {
409 if (gelf_getphdr(e, i, &ph) != &ph) {
411 "WARNING: Retrieval of PHDR entry #%ju in \"%s\" failed: %s.",
412 (uintmax_t) i, buffer, elf_errmsg(-1));
417 image->pi_isdynamic = 1;
420 if ((elfbase = elf_rawfile(e, NULL)) == NULL) {
422 "WARNING: Cannot retrieve the interpreter for \"%s\": %s.",
423 buffer, elf_errmsg(-1));
426 image->pi_dynlinkerpath =
427 pmcstat_string_intern(elfbase +
431 if ((ph.p_flags & PF_X) != 0 &&
432 first_exec_segment) {
433 image->pi_vaddr = ph.p_vaddr & (-ph.p_align);
434 first_exec_segment = false;
442 * Get the min and max VA associated with this ELF object.
444 if (elf_getshnum(e, &nsh) == 0) {
446 "WARNING: Could not determine the number of sections for \"%s\": %s.",
447 buffer, elf_errmsg(-1));
451 for (i = 0; i < nsh; i++) {
452 if ((scn = elf_getscn(e, i)) == NULL ||
453 gelf_getshdr(scn, &sh) != &sh) {
455 "WARNING: Could not retrieve section header #%ju in \"%s\": %s.",
456 (uintmax_t) i, buffer, elf_errmsg(-1));
459 if (sh.sh_flags & SHF_EXECINSTR) {
460 minva = min(minva, sh.sh_addr);
461 maxva = max(maxva, sh.sh_addr + sh.sh_size);
463 if (sh.sh_type == SHT_SYMTAB || sh.sh_type == SHT_DYNSYM)
464 pmcstat_image_add_symbols(image, e, scn, &sh);
467 image->pi_start = minva;
468 image->pi_end = maxva;
469 image->pi_type = image_type;
470 image->pi_fullpath = pmcstat_string_intern(buffer);
472 /* Build display name
475 for (p = buffer; *p; p++)
478 image->pi_name = pmcstat_string_intern(endp);
488 * Given an image descriptor, determine whether it is an ELF, or AOUT.
489 * If no handler claims the image, set its type to 'INDETERMINABLE'.
493 pmcstat_image_determine_type(struct pmcstat_image *image,
494 struct pmcstat_args *args)
496 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
498 /* Try each kind of handler in turn */
499 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
500 pmcstat_image_get_elf_params(image, args);
501 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
502 pmcstat_image_get_aout_params(image, args);
505 * Otherwise, remember that we tried to determine
506 * the object's type and had failed.
508 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
509 image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE;
513 * Locate an image descriptor given an interned path, adding a fresh
514 * descriptor to the cache if necessary. This function also finds a
515 * suitable name for this image's sample file.
517 * We defer filling in the file format specific parts of the image
518 * structure till the time we actually see a sample that would fall
522 struct pmcstat_image *
523 pmcstat_image_from_path(pmcstat_interned_string internedpath,
524 int iskernelmodule, struct pmcstat_args *args,
525 struct pmc_plugins *plugins)
528 struct pmcstat_image *pi;
530 hash = pmcstat_string_lookup_hash(internedpath);
532 /* First, look for an existing entry. */
533 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next)
534 if (pi->pi_execpath == internedpath &&
535 pi->pi_iskernelmodule == iskernelmodule)
539 * Allocate a new entry and place it at the head of the hash
542 pi = malloc(sizeof(*pi));
546 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN;
547 pi->pi_execpath = internedpath;
552 pi->pi_isdynamic = 0;
553 pi->pi_iskernelmodule = iskernelmodule;
554 pi->pi_dynlinkerpath = NULL;
555 pi->pi_symbols = NULL;
557 pi->pi_addr2line = NULL;
559 if (plugins[args->pa_pplugin].pl_initimage != NULL)
560 plugins[args->pa_pplugin].pl_initimage(pi);
561 if (plugins[args->pa_plugin].pl_initimage != NULL)
562 plugins[args->pa_plugin].pl_initimage(pi);
564 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next);