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