]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpmcstat/libpmcstat_image.c
rtld-elf: link udivmoddi4 from compiler_rt
[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 <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 }