xref: /freebsd/lib/libpmcstat/libpmcstat_image.c (revision c697fb7f)
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 	char buffer_modules[PATH_MAX];
282 
283 	assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
284 
285 	image->pi_start = minva = ~(uintfptr_t) 0;
286 	image->pi_end = maxva = (uintfptr_t) 0;
287 	image->pi_type = image_type = PMCSTAT_IMAGE_INDETERMINABLE;
288 	image->pi_isdynamic = 0;
289 	image->pi_dynlinkerpath = NULL;
290 	image->pi_vaddr = 0;
291 
292 	path = pmcstat_string_unintern(image->pi_execpath);
293 	assert(path != NULL);
294 
295 	/*
296 	 * Look for kernel modules under FSROOT/KERNELPATH/NAME and
297 	 * FSROOT/boot/modules/NAME, and user mode executable objects
298 	 * under FSROOT/PATHNAME.
299 	 */
300 	if (image->pi_iskernelmodule) {
301 		(void) snprintf(buffer, sizeof(buffer), "%s%s/%s",
302 		    args->pa_fsroot, args->pa_kernel, path);
303 		(void) snprintf(buffer_modules, sizeof(buffer_modules),
304 		    "%s/boot/modules/%s", args->pa_fsroot, path);
305 	} else {
306 		(void) snprintf(buffer, sizeof(buffer), "%s%s",
307 		    args->pa_fsroot, path);
308 	}
309 
310 	e = NULL;
311 	fd = open(buffer, O_RDONLY, 0);
312 	if (fd < 0 && !image->pi_iskernelmodule) {
313 		warnx("WARNING: Cannot open \"%s\".",
314 		    buffer);
315 		goto done;
316 	}
317 	if (fd < 0 && (fd = open(buffer_modules, O_RDONLY, 0)) < 0) {
318 		warnx("WARNING: Cannot open \"%s\" or \"%s\".",
319 		    buffer, buffer_modules);
320 		goto done;
321 	}
322 	if (elf_version(EV_CURRENT) == EV_NONE) {
323 		warnx("WARNING: failed to init elf\n");
324 		goto done;
325 	}
326 
327 	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
328 		warnx("WARNING: Cannot read \"%s\".",
329 		    buffer);
330 		goto done;
331 	}
332 
333 	if (elf_kind(e) != ELF_K_ELF) {
334 		if (args->pa_verbosity >= 2)
335 			warnx("WARNING: Cannot determine the type of \"%s\".",
336 			    buffer);
337 		goto done;
338 	}
339 
340 	if (gelf_getehdr(e, &eh) != &eh) {
341 		warnx(
342 		    "WARNING: Cannot retrieve the ELF Header for \"%s\": %s.",
343 		    buffer, elf_errmsg(-1));
344 		goto done;
345 	}
346 
347 	if (eh.e_type != ET_EXEC && eh.e_type != ET_DYN &&
348 	    !(image->pi_iskernelmodule && eh.e_type == ET_REL)) {
349 		warnx("WARNING: \"%s\" is of an unsupported ELF type.",
350 		    buffer);
351 		goto done;
352 	}
353 
354 	image_type = eh.e_ident[EI_CLASS] == ELFCLASS32 ?
355 	    PMCSTAT_IMAGE_ELF32 : PMCSTAT_IMAGE_ELF64;
356 
357 	/*
358 	 * Determine the virtual address where an executable would be
359 	 * loaded.  Additionally, for dynamically linked executables,
360 	 * save the pathname to the runtime linker.
361 	 */
362 	if (eh.e_type == ET_EXEC) {
363 		if (elf_getphnum(e, &nph) == 0) {
364 			warnx(
365 "WARNING: Could not determine the number of program headers in \"%s\": %s.",
366 			    buffer,
367 			    elf_errmsg(-1));
368 			goto done;
369 		}
370 		for (i = 0; i < eh.e_phnum; i++) {
371 			if (gelf_getphdr(e, i, &ph) != &ph) {
372 				warnx(
373 "WARNING: Retrieval of PHDR entry #%ju in \"%s\" failed: %s.",
374 				    (uintmax_t) i, buffer, elf_errmsg(-1));
375 				goto done;
376 			}
377 			switch (ph.p_type) {
378 			case PT_DYNAMIC:
379 				image->pi_isdynamic = 1;
380 				break;
381 			case PT_INTERP:
382 				if ((elfbase = elf_rawfile(e, NULL)) == NULL) {
383 					warnx(
384 "WARNING: Cannot retrieve the interpreter for \"%s\": %s.",
385 					    buffer, elf_errmsg(-1));
386 					goto done;
387 				}
388 				image->pi_dynlinkerpath =
389 				    pmcstat_string_intern(elfbase +
390 				        ph.p_offset);
391 				break;
392 			case PT_LOAD:
393 				if ((ph.p_flags & PF_X) != 0 &&
394 				    (ph.p_offset & (-ph.p_align)) == 0)
395 					image->pi_vaddr = ph.p_vaddr & (-ph.p_align);
396 				break;
397 			}
398 		}
399 	}
400 
401 	/*
402 	 * Get the min and max VA associated with this ELF object.
403 	 */
404 	if (elf_getshnum(e, &nsh) == 0) {
405 		warnx(
406 "WARNING: Could not determine the number of sections for \"%s\": %s.",
407 		    buffer, elf_errmsg(-1));
408 		goto done;
409 	}
410 
411 	for (i = 0; i < nsh; i++) {
412 		if ((scn = elf_getscn(e, i)) == NULL ||
413 		    gelf_getshdr(scn, &sh) != &sh) {
414 			warnx(
415 "WARNING: Could not retrieve section header #%ju in \"%s\": %s.",
416 			    (uintmax_t) i, buffer, elf_errmsg(-1));
417 			goto done;
418 		}
419 		if (sh.sh_flags & SHF_EXECINSTR) {
420 			minva = min(minva, sh.sh_addr);
421 			maxva = max(maxva, sh.sh_addr + sh.sh_size);
422 		}
423 		if (sh.sh_type == SHT_SYMTAB || sh.sh_type == SHT_DYNSYM)
424 			pmcstat_image_add_symbols(image, e, scn, &sh);
425 	}
426 
427 	image->pi_start = minva;
428 	image->pi_end   = maxva;
429 	image->pi_type  = image_type;
430 	image->pi_fullpath = pmcstat_string_intern(buffer);
431 
432 	/* Build display name
433 	 */
434 	endp = buffer;
435 	for (p = buffer; *p; p++)
436 		if (*p == '/')
437 			endp = p+1;
438 	image->pi_name = pmcstat_string_intern(endp);
439 
440  done:
441 	(void) elf_end(e);
442 	if (fd >= 0)
443 		(void) close(fd);
444 	return;
445 }
446 
447 /*
448  * Given an image descriptor, determine whether it is an ELF, or AOUT.
449  * If no handler claims the image, set its type to 'INDETERMINABLE'.
450  */
451 
452 void
453 pmcstat_image_determine_type(struct pmcstat_image *image,
454     struct pmcstat_args *args)
455 {
456 	assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
457 
458 	/* Try each kind of handler in turn */
459 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
460 		pmcstat_image_get_elf_params(image, args);
461 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
462 		pmcstat_image_get_aout_params(image, args);
463 
464 	/*
465 	 * Otherwise, remember that we tried to determine
466 	 * the object's type and had failed.
467 	 */
468 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
469 		image->pi_type = PMCSTAT_IMAGE_INDETERMINABLE;
470 }
471 
472 /*
473  * Locate an image descriptor given an interned path, adding a fresh
474  * descriptor to the cache if necessary.  This function also finds a
475  * suitable name for this image's sample file.
476  *
477  * We defer filling in the file format specific parts of the image
478  * structure till the time we actually see a sample that would fall
479  * into this image.
480  */
481 
482 struct pmcstat_image *
483 pmcstat_image_from_path(pmcstat_interned_string internedpath,
484     int iskernelmodule, struct pmcstat_args *args,
485     struct pmc_plugins *plugins)
486 {
487 	int hash;
488 	struct pmcstat_image *pi;
489 
490 	hash = pmcstat_string_lookup_hash(internedpath);
491 
492 	/* First, look for an existing entry. */
493 	LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next)
494 	    if (pi->pi_execpath == internedpath &&
495 		  pi->pi_iskernelmodule == iskernelmodule)
496 		    return (pi);
497 
498 	/*
499 	 * Allocate a new entry and place it at the head of the hash
500 	 * and LRU lists.
501 	 */
502 	pi = malloc(sizeof(*pi));
503 	if (pi == NULL)
504 		return (NULL);
505 
506 	pi->pi_type = PMCSTAT_IMAGE_UNKNOWN;
507 	pi->pi_execpath = internedpath;
508 	pi->pi_start = ~0;
509 	pi->pi_end = 0;
510 	pi->pi_entry = 0;
511 	pi->pi_vaddr = 0;
512 	pi->pi_isdynamic = 0;
513 	pi->pi_iskernelmodule = iskernelmodule;
514 	pi->pi_dynlinkerpath = NULL;
515 	pi->pi_symbols = NULL;
516 	pi->pi_symcount = 0;
517 	pi->pi_addr2line = NULL;
518 
519 	if (plugins[args->pa_pplugin].pl_initimage != NULL)
520 		plugins[args->pa_pplugin].pl_initimage(pi);
521 	if (plugins[args->pa_plugin].pl_initimage != NULL)
522 		plugins[args->pa_plugin].pl_initimage(pi);
523 
524 	LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next);
525 
526 	return (pi);
527 }
528