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