xref: /freebsd/usr.sbin/pmcstat/pmcstat_log.c (revision ea8cbba64fcbb6b3f2fec5d8aea8f92a5f8fcdda)
1 /*-
2  * Copyright (c) 2005, 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 /*
31  * Transform a hwpmc(4) log into human readable form and into gprof(1)
32  * compatible profiles.
33  *
34  * Each executable object encountered in the log gets one 'gmon.out'
35  * profile per PMC.  We currently track:
36  * 	- program executables
37  *	- shared libraries loaded by the runtime loader
38  *	- the runtime loader itself
39  *	- the kernel.
40  * We do not track shared objects mapped in by dlopen() yet (this
41  * needs additional support from hwpmc(4)).
42  *
43  * 'gmon.out' profiles generated for a given sampling PMC are
44  * aggregates of all the samples for that particular executable
45  * object.
46  */
47 
48 #include <sys/param.h>
49 #include <sys/endian.h>
50 #include <sys/gmon.h>
51 #include <sys/imgact_aout.h>
52 #include <sys/imgact_elf.h>
53 #include <sys/mman.h>
54 #include <sys/pmc.h>
55 #include <sys/queue.h>
56 #include <sys/stat.h>
57 #include <sys/wait.h>
58 
59 #include <netinet/in.h>
60 
61 #include <assert.h>
62 #include <err.h>
63 #include <fcntl.h>
64 #include <libgen.h>
65 #include <limits.h>
66 #include <pmc.h>
67 #include <pmclog.h>
68 #include <sysexits.h>
69 #include <stdint.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 
75 #include "pmcstat.h"
76 
77 #define	min(A,B)		((A) < (B) ? (A) : (B))
78 #define	max(A,B)		((A) > (B) ? (A) : (B))
79 
80 /*
81  * A simple implementation of interned strings.  Each interned string
82  * is assigned a unique address, so that subsequent string compares
83  * can be done by a simple pointer comparision instead of with
84  * strcmp().
85  */
86 struct pmcstat_string {
87 	LIST_ENTRY(pmcstat_string)	ps_next;	/* hash link */
88 	int		ps_len;
89 	int		ps_hash;
90 	const char	*ps_string;
91 };
92 
93 static LIST_HEAD(,pmcstat_string)	pmcstat_string_hash[PMCSTAT_NHASH];
94 
95 /*
96  * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable
97  * names.
98  */
99 
100 struct pmcstat_pmcrecord {
101 	LIST_ENTRY(pmcstat_pmcrecord)	pr_next;
102 	pmc_id_t	pr_pmcid;
103 	const char 	*pr_pmcname;
104 };
105 
106 static LIST_HEAD(,pmcstat_pmcrecord)	pmcstat_pmcs =
107 	LIST_HEAD_INITIALIZER(&pmcstat_pmcs);
108 
109 
110 /*
111  * struct pmcstat_gmonfile tracks a given 'gmon.out' file.  These
112  * files are mmap()'ed in as needed.
113  */
114 
115 struct pmcstat_gmonfile {
116 	LIST_ENTRY(pmcstat_gmonfile)	pgf_next; /* list of entries */
117 	pmc_id_t	pgf_pmcid;	/* id of the associated pmc */
118 	size_t		pgf_nbuckets;	/* #buckets in this gmon.out */
119 	const char	*pgf_name;	/* pathname of gmon.out file */
120 	size_t		pgf_ndatabytes;	/* number of bytes mapped */
121 	void		*pgf_gmondata;	/* pointer to mmap'ed data */
122 };
123 
124 static TAILQ_HEAD(,pmcstat_gmonfile)	pmcstat_gmonfiles =
125 	TAILQ_HEAD_INITIALIZER(pmcstat_gmonfiles);
126 
127 /*
128  * A 'pmcstat_image' structure describes an executable program on
129  * disk.  'pi_internedpath' is a cookie representing the pathname of
130  * the executable.  'pi_start' and 'pi_end' are the least and greatest
131  * virtual addresses for the text segments in the executable.
132  * 'pi_gmonlist' contains a linked list of gmon.out files associated
133  * with this image.
134  */
135 
136 enum pmcstat_image_type {
137 	PMCSTAT_IMAGE_UNKNOWN = 0,
138 	PMCSTAT_IMAGE_ELF,
139 	PMCSTAT_IMAGE_AOUT
140 };
141 
142 struct pmcstat_image {
143 	LIST_ENTRY(pmcstat_image) pi_next;	/* hash link */
144 	TAILQ_ENTRY(pmcstat_image) pi_lru;	/* LRU list */
145 	const char	*pi_internedpath;	/* cookie */
146 	const char	*pi_samplename;		/* sample path name */
147 
148 	enum pmcstat_image_type pi_type;	/* executable type */
149 	uintfptr_t	pi_start;		/* start address (inclusive) */
150 	uintfptr_t	pi_end;			/* end address (exclusive) */
151 	uintfptr_t	pi_entry;		/* entry address */
152 	int		pi_isdynamic;		/* whether a dynamic object */
153 	const char	*pi_dynlinkerpath;	/* path in .interp section */
154 
155 	LIST_HEAD(,pmcstat_gmonfile) pi_gmlist;
156 };
157 
158 static LIST_HEAD(,pmcstat_image)	pmcstat_image_hash[PMCSTAT_NHASH];
159 static TAILQ_HEAD(,pmcstat_image)	pmcstat_image_lru =
160 	TAILQ_HEAD_INITIALIZER(pmcstat_image_lru);
161 
162 struct pmcstat_pcmap {
163 	TAILQ_ENTRY(pmcstat_pcmap) ppm_next;
164 	uintfptr_t	ppm_lowpc;
165 	uintfptr_t	ppm_highpc;
166 	struct pmcstat_image *ppm_image;
167 };
168 
169 /*
170  * A 'pmcstat_process' structure tracks processes.
171  */
172 
173 struct pmcstat_process {
174 	LIST_ENTRY(pmcstat_process) pp_next;	/* hash-next */
175 	pid_t			pp_pid;		/* associated pid */
176 	int			pp_isactive;	/* whether active */
177 	uintfptr_t		pp_entryaddr;	/* entry address */
178 	TAILQ_HEAD(,pmcstat_pcmap) pp_map;	/* address range map */
179 };
180 
181 static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH];
182 
183 static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */
184 
185 /*
186  * Prototypes
187  */
188 
189 static void	pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf,
190     struct pmcstat_image *_image);
191 static const char *pmcstat_gmon_create_name(const char *_sd,
192     struct pmcstat_image *_img, pmc_id_t _pmcid);
193 static void	pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf);
194 static void	pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf);
195 
196 static struct pmcstat_image *pmcstat_image_from_path(const char *_path);
197 static enum pmcstat_image_type pmcstat_image_get_type(const char *_p);
198 static void pmcstat_image_get_elf_params(struct pmcstat_image *_image);
199 static void	pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm,
200     uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a);
201 static void	pmcstat_image_link(struct pmcstat_process *_pp,
202     struct pmcstat_image *_i, uintfptr_t _lpc, uintfptr_t _hpc);
203 
204 static void	pmcstat_pmcid_add(pmc_id_t _pmcid, const char *_name,
205     struct pmcstat_args *_a);
206 static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid);
207 
208 static void	pmcstat_process_add_elf_image(struct pmcstat_process *_pp,
209     const char *_path, uintfptr_t _entryaddr);
210 static void	pmcstat_process_exec(struct pmcstat_process *_pp,
211     const char *_path, uintfptr_t _entryaddr);
212 static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, int _allocate);
213 static struct pmcstat_pcmap *pmcstat_process_find_map(
214     struct pmcstat_process *_p, uintfptr_t _pc);
215 
216 static int	pmcstat_string_compute_hash(const char *_string);
217 static const char *pmcstat_string_intern(const char *_s);
218 static struct pmcstat_string *pmcstat_string_lookup(const char *_s);
219 
220 
221 /*
222  * Create a gmon.out file and size it.
223  */
224 
225 static void
226 pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf,
227     struct pmcstat_image *image)
228 {
229 	int fd;
230 	size_t count;
231 	struct gmonhdr gm;
232 	char buffer[DEFAULT_BUFFER_SIZE];
233 
234 	if ((fd = open(pgf->pgf_name, O_RDWR|O_NOFOLLOW|O_CREAT,
235 		 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
236 		err(EX_OSERR, "ERROR: Cannot open \"%s\"", pgf->pgf_name);
237 
238 	gm.lpc = image->pi_start;
239 	gm.hpc = image->pi_end;
240 	gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) +
241 	    sizeof(struct gmonhdr);
242 	gm.version = GMONVERSION;
243 	gm.profrate = 0;		/* use ticks */
244 	gm.histcounter_type = 0;	/* compatibility with moncontrol() */
245 	gm.spare[0] = gm.spare[1] = 0;
246 
247 	/* Write out the gmon header */
248 	if (write(fd, &gm, sizeof(gm)) < 0)
249 		goto error;
250 
251 	/* Zero fill the samples[] array */
252 	(void) memset(buffer, 0, sizeof(buffer));
253 
254 	count = pgf->pgf_ndatabytes - sizeof(struct gmonhdr);
255 	while (count > sizeof(buffer)) {
256 		if (write(fd, &buffer, sizeof(buffer)) < 0)
257 			goto error;
258 		count -= sizeof(buffer);
259 	}
260 
261 	if (write(fd, &buffer, count) < 0)
262 		goto error;
263 
264 	(void) close(fd);
265 
266 	return;
267 
268  error:
269 	err(EX_OSERR, "ERROR: Cannot write \"%s\"", pgf->pgf_name);
270 }
271 
272 const char *
273 pmcstat_gmon_create_name(const char *samplesdir, struct pmcstat_image *image,
274     pmc_id_t pmcid)
275 {
276 	const char *pmcname;
277 	char fullpath[PATH_MAX];
278 
279 	pmcname = pmcstat_pmcid_to_name(pmcid);
280 
281 	(void) snprintf(fullpath, sizeof(fullpath),
282 	    "%s/%s/%s", samplesdir, pmcname, image->pi_samplename);
283 
284 	return pmcstat_string_intern(fullpath);
285 }
286 
287 
288 static void
289 pmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf)
290 {
291 	int fd;
292 
293 	/* the gmon.out file must already exist */
294 	if ((fd = open(pgf->pgf_name, O_RDWR | O_NOFOLLOW, 0)) < 0)
295 		err(EX_OSERR, "ERROR: cannot open \"%s\"",
296 		    pgf->pgf_name);
297 
298 	pgf->pgf_gmondata = mmap(NULL, pgf->pgf_ndatabytes,
299 	    PROT_READ|PROT_WRITE, MAP_NOSYNC|MAP_SHARED, fd, 0);
300 
301 	if (pgf->pgf_gmondata == MAP_FAILED)
302 		/* XXX unmap a few files and try again? */
303 		err(EX_OSERR, "ERROR: cannot map \"%s\"", pgf->pgf_name);
304 
305 	(void) close(fd);
306 }
307 
308 /*
309  * Unmap the data mapped from a gmon.out file.
310  */
311 
312 static void
313 pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *pgf)
314 {
315 	(void) msync(pgf->pgf_gmondata, pgf->pgf_ndatabytes,
316 	    MS_SYNC);
317 	(void) munmap(pgf->pgf_gmondata, pgf->pgf_ndatabytes);
318 	pgf->pgf_gmondata = NULL;
319 }
320 
321 static void
322 pmcstat_image_get_elf_params(struct pmcstat_image *image)
323 {
324 	int fd, i;
325 	struct stat st;
326 	void *mapbase;
327 	uintfptr_t minva, maxva;
328 	const Elf_Ehdr *h;
329 	const Elf_Phdr *ph;
330 	const Elf_Shdr *sh;
331 	const char *path;
332 
333 	assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
334 
335 	minva = ~(uintfptr_t) 0;
336 	maxva = (uintfptr_t) 0;
337 	path = image->pi_internedpath;
338 
339 	if ((fd = open(path, O_RDONLY, 0)) < 0)
340 		err(EX_OSERR, "ERROR: Cannot open \"%s\"", path);
341 
342 	if (fstat(fd, &st) < 0)
343 		err(EX_OSERR, "ERROR: Cannot stat \"%s\"", path);
344 
345 	if ((mapbase = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
346 	    MAP_FAILED)
347 		err(EX_OSERR, "ERROR: Cannot mmap \"%s\"", path);
348 
349 	(void) close(fd);
350 
351 	h = (const Elf_Ehdr *) mapbase;
352 	if (!IS_ELF(*h))
353 		err(EX_SOFTWARE, "ERROR: \"%s\" not an ELF file", path);
354 
355 	sh = (const Elf_Shdr *)((uintptr_t) mapbase + h->e_shoff);
356 
357 	if (h->e_type == ET_EXEC || h->e_type == ET_DYN) {
358 		/*
359 		 * Some kind of executable object: find the min,max va
360 		 * for its executable sections.
361 		 */
362 		for (i = 0; i < h->e_shnum; i++)
363 			if (sh[i].sh_flags & SHF_EXECINSTR) { /* code */
364 				minva = min(minva, sh[i].sh_addr);
365 				maxva = max(maxva, sh[i].sh_addr +
366 				    sh[i].sh_size);
367 			}
368 	} else
369 		err(EX_DATAERR, "ERROR: Unknown file type for \"%s\"",
370 		    image->pi_internedpath);
371 
372 	image->pi_type = PMCSTAT_IMAGE_ELF;
373 	image->pi_start = minva;
374 	image->pi_entry = h->e_entry;
375 	image->pi_end = maxva;
376 	image->pi_isdynamic = 0;
377 	image->pi_dynlinkerpath = NULL;
378 
379 
380 	if (h->e_type == ET_EXEC) {
381 		ph = (const Elf_Phdr *)((uintptr_t) mapbase + h->e_phoff);
382 		for (i = 0; i < h->e_phnum; i++) {
383 			switch (ph[i].p_type) {
384 			case PT_DYNAMIC:
385 				image->pi_isdynamic = 1;
386 				break;
387 			case PT_INTERP:
388 				image->pi_dynlinkerpath =
389 				    pmcstat_string_intern((char *) mapbase +
390 							      ph[i].p_offset);
391 				break;
392 			}
393 		}
394 	}
395 
396 	if (munmap(mapbase, st.st_size) < 0)
397 		err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path);
398 
399 }
400 
401 /*
402  * Locate an image descriptor given an interned path, adding a fresh
403  * descriptor to the cache if necessary.  This function also finds a
404  * suitable name for this image's sample file.
405  */
406 
407 static struct pmcstat_image *
408 pmcstat_image_from_path(const char *internedpath)
409 {
410 	int count, hash, nlen;
411 	struct pmcstat_image *pi;
412 	char *sn;
413 	char name[NAME_MAX];
414 
415 	hash = pmcstat_string_compute_hash(internedpath);
416 
417 	/* Look for an existing entry. */
418 	LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next)
419 	    if (pi->pi_internedpath == internedpath) {
420 		    /* move descriptor to the head of the lru list */
421 		    TAILQ_REMOVE(&pmcstat_image_lru, pi, pi_lru);
422 		    TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru);
423 		    return pi;
424 	    }
425 
426 	/*
427 	 * Allocate a new entry and place at the head of the hash and
428 	 * LRU lists.
429 	 */
430 	pi = malloc(sizeof(*pi));
431 	if (pi == NULL)
432 		return NULL;
433 
434 	pi->pi_type = PMCSTAT_IMAGE_UNKNOWN;
435 	pi->pi_internedpath = internedpath;
436 	pi->pi_start = ~0;
437 	pi->pi_entry = ~0;
438 	pi->pi_end = 0;
439 
440 	/*
441 	 * Look for a suitable name for the sample files associated
442 	 * with this image: if `basename(path)`+".gmon" is available,
443 	 * we use that, otherwise we try iterating through
444 	 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free
445 	 * entry.
446 	 */
447 	if ((sn = basename(internedpath)) == NULL)
448 		err(EX_OSERR, "ERROR: Cannot process \"%s\"", internedpath);
449 
450 	nlen = strlen(sn);
451 	nlen = min(nlen, (int) sizeof(name) - 6);	/* ".gmon\0" */
452 
453 	snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn);
454 
455 	if (pmcstat_string_lookup(name) == NULL)
456 		pi->pi_samplename = pmcstat_string_intern(name);
457 	else {
458 		nlen = strlen(sn);
459 		nlen = min(nlen, (int) sizeof(name)-10); /* "~ddd.gmon\0" */
460 		count = 0;
461 		do {
462 			count++;
463 			snprintf(name, sizeof(name), "%.*s~%3.3d",
464 			    nlen, sn, count);
465 			if (pmcstat_string_lookup(name) == NULL) {
466 				pi->pi_samplename = pmcstat_string_intern(name);
467 				count = 0;
468 			}
469 		} while (count > 0);
470 	}
471 
472 	LIST_INIT(&pi->pi_gmlist);
473 
474 	LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next);
475 	TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru);
476 
477 	return pi;
478 }
479 
480 /*
481  * Given an open file, determine its file type.
482  */
483 
484 static enum pmcstat_image_type
485 pmcstat_image_get_type(const char *path)
486 {
487 	int fd;
488 	Elf_Ehdr eh;
489 	struct exec ex;
490 	ssize_t nbytes;
491 	char buffer[DEFAULT_BUFFER_SIZE];
492 
493 	if ((fd = open(path, O_RDONLY)) < 0)
494 		err(EX_OSERR, "ERROR: Cannot open \"%s\"", path);
495 
496 	nbytes = max(sizeof(eh), sizeof(ex));
497 	if ((nbytes = pread(fd, buffer, nbytes, 0)) < 0)
498 		err(EX_OSERR, "ERROR: Cannot read \"%s\"", path);
499 
500 	(void) close(fd);
501 
502 	/* check if its an ELF file */
503 	if ((unsigned) nbytes >= sizeof(Elf_Ehdr)) {
504 		bcopy(buffer, &eh, sizeof(eh));
505 		if (IS_ELF(eh))
506 			return PMCSTAT_IMAGE_ELF;
507 	}
508 
509 	/* Look for an A.OUT header */
510 	if ((unsigned) nbytes >= sizeof(struct exec)) {
511 		bcopy(buffer, &ex, sizeof(ex));
512 		if (!N_BADMAG(ex))
513 			return PMCSTAT_IMAGE_AOUT;
514 	}
515 
516 	return PMCSTAT_IMAGE_UNKNOWN;
517 }
518 
519 /*
520  * Increment the bucket in the gmon.out file corresponding to 'pmcid'
521  * and 'pc'.
522  */
523 
524 static void
525 pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc,
526     pmc_id_t pmcid, struct pmcstat_args *a)
527 {
528 	struct pmcstat_image *image;
529 	struct pmcstat_gmonfile *pgf;
530 	uintfptr_t bucket;
531 	HISTCOUNTER *hc;
532 
533 	assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc);
534 
535 	/*
536 	 * Find the gmon file corresponding to 'pmcid', creating it if
537 	 * needed.
538 	 */
539 
540 	image = map->ppm_image;
541 
542 	LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next)
543 	    if (pgf->pgf_pmcid == pmcid)
544 		    break;
545 
546 	/* If we don't have a gmon.out file for this PMCid, create one */
547 	if (pgf == NULL) {
548 		if ((pgf = calloc(1, sizeof(*pgf))) == NULL)
549 			err(EX_OSERR, "ERROR:");
550 
551 		pgf->pgf_gmondata = NULL;	/* mark as unmapped */
552 		pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir,
553 		    image, pmcid);
554 		pgf->pgf_pmcid = pmcid;
555 		assert(image->pi_end > image->pi_start);
556 		pgf->pgf_nbuckets = (image->pi_end - image->pi_start) /
557 		    FUNCTION_ALIGNMENT;	/* see <machine/profile.h> */
558 		pgf->pgf_ndatabytes = sizeof(struct gmonhdr) +
559 		    pgf->pgf_nbuckets * sizeof(HISTCOUNTER);
560 
561 		pmcstat_gmon_create_file(pgf, image);
562 
563 		LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next);
564 	}
565 
566 	/*
567 	 * Map the gmon file in if needed.  It may have been mapped
568 	 * out under memory pressure.
569 	 */
570 	if (pgf->pgf_gmondata == NULL)
571 		pmcstat_gmon_map_file(pgf);
572 
573 	bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT;
574 
575 	assert(bucket < pgf->pgf_nbuckets);
576 
577 	hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
578 	    sizeof(struct gmonhdr));
579 
580 	/* saturating add */
581 	if (hc[bucket] < 0xFFFF)
582 		hc[bucket]++;
583 
584 }
585 
586 /*
587  * Record the fact that PC values from 'lowpc' to 'highpc' come from
588  * image 'image'.
589  */
590 
591 static void
592 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image,
593     uintfptr_t lowpc, uintfptr_t highpc)
594 {
595 	struct pmcstat_pcmap *pcm, *pcmnew;
596 
597 	if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL)
598 		err(EX_OSERR, "ERROR: ");
599 
600 	pcmnew->ppm_lowpc  = lowpc;
601 	pcmnew->ppm_highpc = highpc;
602 	pcmnew->ppm_image  = image;
603 
604 	TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next)
605 	    if (pcm->ppm_lowpc < lowpc)
606 		    break;
607 
608 	if (pcm == NULL)
609 		TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next);
610 	else
611 		TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next);
612 }
613 
614 /*
615  * Add a {pmcid,name} mapping.
616  */
617 
618 static void
619 pmcstat_pmcid_add(pmc_id_t pmcid, const char *name, struct pmcstat_args *a)
620 {
621 	struct pmcstat_pmcrecord *pr;
622 	struct stat st;
623 	char fullpath[PATH_MAX];
624 
625 	LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
626 	    if (pr->pr_pmcid == pmcid) {
627 		    pr->pr_pmcname = name;
628 		    return;
629 	    }
630 
631 	if ((pr = malloc(sizeof(*pr))) == NULL)
632 		err(EX_OSERR, "ERROR: Cannot allocate pmc record");
633 
634 	pr->pr_pmcid = pmcid;
635 	pr->pr_pmcname = name;
636 	LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next);
637 
638 	(void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir,
639 	    name);
640 
641 	/* If the path name exists, it should be a directory */
642 	if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode))
643 		return;
644 
645 	if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0)
646 		err(EX_OSERR, "ERROR: Cannot create directory \"%s\"",
647 		    fullpath);
648 }
649 
650 /*
651  * Given a pmcid in use, find its human-readable name, or a
652  */
653 
654 static const char *
655 pmcstat_pmcid_to_name(pmc_id_t pmcid)
656 {
657 	struct pmcstat_pmcrecord *pr;
658 	char fullpath[PATH_MAX];
659 
660 	LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
661 	    if (pr->pr_pmcid == pmcid)
662 		    return pr->pr_pmcname;
663 
664 	/* create a default name and add this entry */
665 	if ((pr = malloc(sizeof(*pr))) == NULL)
666 		err(EX_OSERR, "ERROR: ");
667 	pr->pr_pmcid = pmcid;
668 
669 	(void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid);
670 	pr->pr_pmcname = pmcstat_string_intern(fullpath);
671 
672 	LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next);
673 
674 	return pr->pr_pmcname;
675 }
676 
677 /*
678  * Associate an ELF image with a process.  Argument 'path' names the
679  * executable while 'fd' is an already open descriptor to it.
680  */
681 
682 static void
683 pmcstat_process_add_elf_image(struct pmcstat_process *pp, const char *path,
684     uintfptr_t entryaddr)
685 {
686 	size_t linelen;
687 	FILE *rf;
688 	char *line;
689 	uintmax_t libstart;
690 	struct pmcstat_image *image, *rtldimage;
691 	char libpath[PATH_MAX];
692 	char command[PATH_MAX + sizeof(PMCSTAT_LDD_COMMAND) + 1];
693 
694 	/* Look up path in the cache. */
695 	if ((image = pmcstat_image_from_path(path)) == NULL)
696 		return;
697 
698 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
699 		pmcstat_image_get_elf_params(image);
700 
701 	/* Create a map entry for the base executable. */
702 	pmcstat_image_link(pp, image, image->pi_start, image->pi_end);
703 
704 	/*
705 	 * For dynamically linked executables we need to:
706 	 * (a) find where the dynamic linker was mapped to for this
707 	 *     process,
708 	 * (b) find all the executable objects that the dynamic linker
709 	 *     brought in.
710 	 */
711 	if (image->pi_isdynamic) {
712 
713 		/*
714 		 * The runtime loader gets loaded just after the maximum
715 		 * possible heap address.  Like so:
716 		 *
717 		 * [  TEXT DATA BSS HEAP -->*RTLD  SHLIBS   <--STACK]
718 		 * ^					            ^
719 		 * 0				   VM_MAXUSER_ADDRESS
720 		 *
721 		 * The exact address where the loader gets mapped in
722 		 * will vary according to the size of the executable
723 		 * and the limits on the size of the process'es data
724 		 * segment at the time of exec().  The entry address
725 		 * recorded at process exec time corresponds to the
726 		 * 'start' address inside the dynamic linker.  From
727 		 * this we can figure out the address where the
728 		 * runtime loader's file object had been mapped to.
729 		 */
730 		rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath);
731 		if (rtldimage == NULL)
732 			err(EX_OSERR, "ERROR: Cannot find image for "
733 			    "\"%s\"", image->pi_dynlinkerpath);
734 		if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN)
735 			pmcstat_image_get_elf_params(rtldimage);
736 
737 		libstart = entryaddr - rtldimage->pi_entry;
738 		pmcstat_image_link(pp, rtldimage, libstart,
739 		    libstart + rtldimage->pi_end - rtldimage->pi_start);
740 
741 		/* Process all other objects loaded by this executable. */
742 		(void) snprintf(command, sizeof(command), "%s %s",
743 		    PMCSTAT_LDD_COMMAND, path);
744 
745 		if ((rf = popen(command, "r")) == NULL)
746 			err(EX_OSERR, "ERROR: Cannot create pipe");
747 
748 		(void) fgetln(rf, &linelen);
749 
750 		while (!feof(rf) && !ferror(rf)) {
751 
752 			if ((line = fgetln(rf, &linelen)) == NULL)
753 				continue;
754 			line[linelen-1] = '\0';
755 
756 			if (sscanf(line, "%s %jx",
757 				libpath, &libstart) != 2)
758 				continue;
759 
760 			image = pmcstat_image_from_path(
761 				pmcstat_string_intern(libpath));
762 			if (image == NULL)
763 				err(EX_OSERR, "ERROR: Cannot process "
764 				    "\"%s\"", libpath);
765 
766 			if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
767 				pmcstat_image_get_elf_params(image);
768 
769 			pmcstat_image_link(pp, image, libstart + image->pi_start,
770 			    libstart + image->pi_end);
771 		}
772 
773 		(void) pclose(rf);
774 
775 	}
776 }
777 
778 /*
779  * Find the process descriptor corresponding to a PID.  If 'allocate'
780  * is zero, we return a NULL if a pid descriptor could not be found or
781  * a process descriptor process.  If 'allocate' is non-zero, then we
782  * will attempt to allocate a fresh process descriptor.  Zombie
783  * process descriptors are only removed if a fresh allocation for the
784  * same PID is requested.
785  */
786 
787 static struct pmcstat_process *
788 pmcstat_process_lookup(pid_t pid, int allocate)
789 {
790 	uint32_t hash;
791 	struct pmcstat_pcmap *ppm, *ppmtmp;
792 	struct pmcstat_process *pp, *pptmp;
793 
794 	hash = (uint32_t) pid & PMCSTAT_HASH_MASK;	/* simplicity wins */
795 
796 	LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp)
797 	    if (pp->pp_pid == pid) {
798 		    /* Found a descriptor, check and process zombies */
799 		    if (allocate && !pp->pp_isactive) {
800 			    /* remove maps */
801 			    TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next,
802 				ppmtmp) {
803 				    TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next);
804 				    free(ppm);
805 			    }
806 			    /* remove process entry */
807 			    LIST_REMOVE(pp, pp_next);
808 			    free(pp);
809 			    break;
810 		    }
811 		    return pp;
812 	    }
813 
814 	if (!allocate)
815 		return NULL;
816 
817 	if ((pp = malloc(sizeof(*pp))) == NULL)
818 		err(EX_OSERR, "ERROR: Cannot allocate pid descriptor");
819 
820 	pp->pp_pid = pid;
821 	pp->pp_isactive = 1;
822 
823 	TAILQ_INIT(&pp->pp_map);
824 
825 	LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next);
826 	return pp;
827 }
828 
829 /*
830  * Associate an image and a process.
831  */
832 
833 static void
834 pmcstat_process_exec(struct pmcstat_process *pp, const char *path,
835     uintfptr_t entryaddr)
836 {
837 	enum pmcstat_image_type filetype;
838 	struct pmcstat_image *image;
839 
840 	if ((image = pmcstat_image_from_path(path)) == NULL)
841 		return;
842 
843 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
844 		filetype = pmcstat_image_get_type(path);
845 	else
846 		filetype = image->pi_type;
847 
848 	switch (filetype) {
849 	case PMCSTAT_IMAGE_ELF:
850 		pmcstat_process_add_elf_image(pp, path, entryaddr);
851 		break;
852 
853 	case PMCSTAT_IMAGE_AOUT:
854 		break;
855 
856 	default:
857 		err(EX_SOFTWARE, "ERROR: Unsupported executable type for "
858 		    "\"%s\"", path);
859 	}
860 }
861 
862 
863 /*
864  * Find the map entry associated with process 'p' at PC value 'pc'.
865  */
866 
867 static struct pmcstat_pcmap *
868 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc)
869 {
870 	struct pmcstat_pcmap *ppm;
871 
872 	TAILQ_FOREACH(ppm, &p->pp_map, ppm_next)
873 	    if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc)
874 		    return ppm;
875 
876 	return NULL;
877 }
878 
879 
880 /*
881  * Compute a 'hash' value for a string.
882  */
883 
884 static int
885 pmcstat_string_compute_hash(const char *s)
886 {
887 	int hash;
888 
889 	for (hash = 0; *s; s++)
890 		hash ^= *s;
891 
892 	return hash & PMCSTAT_HASH_MASK;
893 }
894 
895 /*
896  * Intern a copy of string 's', and return a pointer to it.
897  */
898 
899 static const char *
900 pmcstat_string_intern(const char *s)
901 {
902 	struct pmcstat_string *ps;
903 	int hash, len;
904 
905 	hash = pmcstat_string_compute_hash(s);
906 	len  = strlen(s);
907 
908 	if ((ps = pmcstat_string_lookup(s)) != NULL)
909 		return ps->ps_string;
910 
911 	if ((ps = malloc(sizeof(*ps))) == NULL)
912 		err(EX_OSERR, "ERROR: Could not intern string");
913 	ps->ps_len = len;
914 	ps->ps_hash = hash;
915 	ps->ps_string = strdup(s);
916 	LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next);
917 	return ps->ps_string;
918 }
919 
920 static struct pmcstat_string *
921 pmcstat_string_lookup(const char *s)
922 {
923 	struct pmcstat_string *ps;
924 	int hash, len;
925 
926 	hash = pmcstat_string_compute_hash(s);
927 	len = strlen(s);
928 
929 	LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next)
930 	    if (ps->ps_len == len && ps->ps_hash == hash &&
931 		strcmp(ps->ps_string, s) == 0)
932 		    return ps;
933 	return NULL;
934 }
935 
936 /*
937  * Public Interfaces.
938  */
939 
940 /*
941  * Close a logfile, after first flushing all in-module queued data.
942  */
943 
944 int
945 pmcstat_close_log(struct pmcstat_args *a)
946 {
947 	if (pmc_flush_logfile() < 0 ||
948 	    pmc_configure_logfile(-1) < 0)
949 		err(EX_OSERR, "ERROR: logging failed");
950 	a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE);
951 	return a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING :
952 	    PMCSTAT_FINISHED;
953 }
954 
955 
956 int
957 pmcstat_convert_log(struct pmcstat_args *a)
958 {
959 	uintfptr_t pc;
960 	struct pmcstat_process *pp, *ppnew;
961 	struct pmcstat_pcmap *ppm, *ppmtmp;
962 	struct pmclog_ev ev;
963 	const char *image_path;
964 
965 	while (pmclog_read(a->pa_logparser, &ev) == 0) {
966 		assert(ev.pl_state == PMCLOG_OK);
967 
968 		switch (ev.pl_type) {
969 		case PMCLOG_TYPE_MAPPINGCHANGE:
970 			/*
971 			 * Introduce an address range mapping for a
972 			 * process.
973 			 */
974 			break;
975 
976 		case PMCLOG_TYPE_PCSAMPLE:
977 
978 			/*
979 			 * We bring in the gmon file for the image
980 			 * currently associated with the PMC & pid
981 			 * pair and increment the appropriate entry
982 			 * bin inside this.
983 			 */
984 			pc = ev.pl_u.pl_s.pl_pc;
985 			pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1);
986 			if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL &&
987 			    (ppm = pmcstat_process_find_map(pmcstat_kernproc,
988 				pc)) == NULL)
989 				break; /* unknown process,offset pair */
990 
991 			pmcstat_image_increment_bucket(ppm, pc,
992 			    ev.pl_u.pl_s.pl_pmcid, a);
993 
994 			break;
995 
996 		case PMCLOG_TYPE_PMCALLOCATE:
997 			/*
998 			 * Record the association pmc id between this
999 			 * PMC and its name.
1000 			 */
1001 			pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid,
1002 			    pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), a);
1003 			break;
1004 
1005 		case PMCLOG_TYPE_PROCEXEC:
1006 
1007 			/*
1008 			 * Change the executable image associated with
1009 			 * a process.
1010 			 */
1011 			pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1);
1012 
1013 			/* delete the current process map */
1014 			TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) {
1015 				TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next);
1016 				free(ppm);
1017 			}
1018 
1019 			/* locate the descriptor for the new 'base' image */
1020 			image_path = pmcstat_string_intern(
1021 				ev.pl_u.pl_x.pl_pathname);
1022 
1023 			/* link to the new image */
1024 			pmcstat_process_exec(pp, image_path,
1025 			    ev.pl_u.pl_x.pl_entryaddr);
1026 			break;
1027 
1028 		case PMCLOG_TYPE_PROCEXIT:
1029 
1030 			/*
1031 			 * Due to the way the log is generated, the
1032 			 * last few samples corresponding to a process
1033 			 * may appear in the log after the process
1034 			 * exit event is recorded.  Thus we keep the
1035 			 * process' descriptor and associated data
1036 			 * structures around, but mark the process as
1037 			 * having exited.
1038 			 */
1039 			pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0);
1040 			if (pp == NULL)
1041 				break;
1042 			pp->pp_isactive = 0;	/* make a zombie */
1043 			break;
1044 
1045 		case PMCLOG_TYPE_SYSEXIT:
1046 			pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0);
1047 			if (pp == NULL)
1048 				break;
1049 			pp->pp_isactive = 0;	/* make a zombie */
1050 			break;
1051 
1052 		case PMCLOG_TYPE_PROCFORK:
1053 
1054 			/*
1055 			 * If we had been tracking 'oldpid', then clone
1056 			 * its pid descriptor.
1057 			 */
1058 			pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0);
1059 			if (pp == NULL)
1060 				break;
1061 
1062 			ppnew =
1063 			    pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, 1);
1064 
1065 			/* copy the old process' address maps */
1066 			TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next)
1067 			    pmcstat_image_link(ppnew, ppm->ppm_image,
1068 				ppm->ppm_lowpc, ppm->ppm_highpc);
1069 			break;
1070 
1071 		default:	/* other types of entries are not relevant */
1072 			break;
1073 		}
1074 	}
1075 
1076 	if (ev.pl_state == PMCLOG_EOF)
1077 		return PMCSTAT_FINISHED;
1078 	else if (ev.pl_state == PMCLOG_REQUIRE_DATA)
1079 		return PMCSTAT_RUNNING;
1080 
1081 	err(EX_DATAERR, "ERROR: event parsing failed (record %jd, "
1082 	    "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset);
1083 }
1084 
1085 
1086 /*
1087  * Open a log file, for reading or writing.
1088  *
1089  * The function returns the fd of a successfully opened log or -1 in
1090  * case of failure.
1091  */
1092 
1093 int
1094 pmcstat_open(const char *path, int mode)
1095 {
1096 	int fd;
1097 
1098 	/*
1099 	 * If 'path' is "-" then open one of stdin or stdout depending
1100 	 * on the value of 'mode'.  Otherwise, treat 'path' as a file
1101 	 * name and open that.
1102 	 */
1103 	if (path[0] == '-' && path[1] == '\0')
1104 		fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1;
1105 	else
1106 		fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ?
1107 		    O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC),
1108 		    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
1109 
1110 	return fd;
1111 }
1112 
1113 /*
1114  * Print log entries as text.
1115  */
1116 
1117 int
1118 pmcstat_print_log(struct pmcstat_args *a)
1119 {
1120 	struct pmclog_ev ev;
1121 
1122 	while (pmclog_read(a->pa_logparser, &ev) == 0) {
1123 		assert(ev.pl_state == PMCLOG_OK);
1124 		switch (ev.pl_type) {
1125 		case PMCLOG_TYPE_CLOSELOG:
1126 			PMCSTAT_PRINT_ENTRY(a,"closelog",);
1127 			break;
1128 		case PMCLOG_TYPE_DROPNOTIFY:
1129 			PMCSTAT_PRINT_ENTRY(a,"drop",);
1130 			break;
1131 		case PMCLOG_TYPE_INITIALIZE:
1132 			PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"",
1133 			    ev.pl_u.pl_i.pl_version,
1134 			    pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch));
1135 			break;
1136 		case PMCLOG_TYPE_MAPPINGCHANGE:
1137 			PMCSTAT_PRINT_ENTRY(a,"mapping","%s %d %p %p \"%s\"",
1138 			    ev.pl_u.pl_m.pl_type == PMCLOG_MAPPING_INSERT ?
1139 			    	"insert" : "delete",
1140 			    ev.pl_u.pl_m.pl_pid,
1141 			    (void *) ev.pl_u.pl_m.pl_start,
1142 			    (void *) ev.pl_u.pl_m.pl_end,
1143 			    ev.pl_u.pl_m.pl_pathname);
1144 			break;
1145 		case PMCLOG_TYPE_PCSAMPLE:
1146 			PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c",
1147 			    ev.pl_u.pl_s.pl_pmcid,
1148 			    ev.pl_u.pl_s.pl_pid,
1149 			    (void *) ev.pl_u.pl_s.pl_pc,
1150 			    ev.pl_u.pl_s.pl_usermode ? 'u' : 's');
1151 			break;
1152 		case PMCLOG_TYPE_PMCALLOCATE:
1153 			PMCSTAT_PRINT_ENTRY(a,"allocate","0x%x \"%s\" 0x%x",
1154 			    ev.pl_u.pl_a.pl_pmcid,
1155 			    ev.pl_u.pl_a.pl_evname,
1156 			    ev.pl_u.pl_a.pl_flags);
1157 			break;
1158 		case PMCLOG_TYPE_PMCATTACH:
1159 			PMCSTAT_PRINT_ENTRY(a,"attach","0x%x %d \"%s\"",
1160 			    ev.pl_u.pl_t.pl_pmcid,
1161 			    ev.pl_u.pl_t.pl_pid,
1162 			    ev.pl_u.pl_t.pl_pathname);
1163 			break;
1164 		case PMCLOG_TYPE_PMCDETACH:
1165 			PMCSTAT_PRINT_ENTRY(a,"detach","0x%x %d",
1166 			    ev.pl_u.pl_d.pl_pmcid,
1167 			    ev.pl_u.pl_d.pl_pid);
1168 			break;
1169 		case PMCLOG_TYPE_PROCCSW:
1170 			PMCSTAT_PRINT_ENTRY(a,"cswval","0x%x %d %jd",
1171 			    ev.pl_u.pl_c.pl_pmcid,
1172 			    ev.pl_u.pl_c.pl_pid,
1173 			    ev.pl_u.pl_c.pl_value);
1174 			break;
1175 		case PMCLOG_TYPE_PROCEXEC:
1176 			PMCSTAT_PRINT_ENTRY(a,"exec","0x%x %d %p \"%s\"",
1177 			    ev.pl_u.pl_x.pl_pmcid,
1178 			    ev.pl_u.pl_x.pl_pid,
1179 			    (void *) ev.pl_u.pl_x.pl_entryaddr,
1180 			    ev.pl_u.pl_x.pl_pathname);
1181 			break;
1182 		case PMCLOG_TYPE_PROCEXIT:
1183 			PMCSTAT_PRINT_ENTRY(a,"exitval","0x%x %d %jd",
1184 			    ev.pl_u.pl_e.pl_pmcid,
1185 			    ev.pl_u.pl_e.pl_pid,
1186 			    ev.pl_u.pl_e.pl_value);
1187 			break;
1188 		case PMCLOG_TYPE_PROCFORK:
1189 			PMCSTAT_PRINT_ENTRY(a,"fork","%d %d",
1190 			    ev.pl_u.pl_f.pl_oldpid,
1191 			    ev.pl_u.pl_f.pl_newpid);
1192 			break;
1193 		case PMCLOG_TYPE_USERDATA:
1194 			PMCSTAT_PRINT_ENTRY(a,"userdata","0x%x",
1195 			    ev.pl_u.pl_u.pl_userdata);
1196 			break;
1197 		case PMCLOG_TYPE_SYSEXIT:
1198 			PMCSTAT_PRINT_ENTRY(a,"exit","%d",
1199 			    ev.pl_u.pl_se.pl_pid);
1200 			break;
1201 		default:
1202 			fprintf(a->pa_printfile, "unknown %d",
1203 			    ev.pl_type);
1204 		}
1205 	}
1206 
1207 	if (ev.pl_state == PMCLOG_EOF)
1208 		return PMCSTAT_FINISHED;
1209 	else if (ev.pl_state ==  PMCLOG_REQUIRE_DATA)
1210 		return PMCSTAT_RUNNING;
1211 
1212 	err(EX_DATAERR, "ERROR: event parsing failed "
1213 	    "(record %jd, offset 0x%jx)",
1214 	    (uintmax_t) ev.pl_count + 1, ev.pl_offset);
1215 	/*NOTREACHED*/
1216 }
1217 
1218 /*
1219  * Process a log file in offline analysis mode.
1220  */
1221 
1222 int
1223 pmcstat_process_log(struct pmcstat_args *a)
1224 {
1225 
1226 	/*
1227 	 * If gprof style profiles haven't been asked for, just print the
1228 	 * log to the current output file.
1229 	 */
1230 	if (a->pa_flags & FLAG_DO_PRINT)
1231 		return pmcstat_print_log(a);
1232 	else
1233 		/* convert the log to gprof compatible profiles */
1234 		return pmcstat_convert_log(a);
1235 }
1236 
1237 void
1238 pmcstat_initialize_logging(struct pmcstat_args *a)
1239 {
1240 	int i;
1241 	const char *kernpath;
1242 	struct pmcstat_image *img;
1243 
1244 	/* use a convenient format for 'ldd' output */
1245 	if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%p %x\n",1) != 0)
1246 		goto error;
1247 
1248 	/* Initialize hash tables */
1249 	for (i = 0; i < PMCSTAT_NHASH; i++) {
1250 		LIST_INIT(&pmcstat_image_hash[i]);
1251 		LIST_INIT(&pmcstat_process_hash[i]);
1252 		LIST_INIT(&pmcstat_string_hash[i]);
1253 	}
1254 
1255 	/* create a fake 'process' entry for the kernel with pid == -1 */
1256 	if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 1)) == NULL)
1257 		goto error;
1258 
1259 	if ((kernpath = pmcstat_string_intern(a->pa_kernel)) == NULL)
1260 		goto error;
1261 
1262 	img = pmcstat_image_from_path(kernpath);
1263 
1264 	pmcstat_image_get_elf_params(img);
1265 	pmcstat_image_link(pmcstat_kernproc, img, img->pi_start, img->pi_end);
1266 
1267 	return;
1268 
1269  error:
1270 	err(EX_OSERR, "ERROR: Cannot initialize logging");
1271 }
1272 
1273 void
1274 pmcstat_shutdown_logging(void)
1275 {
1276 	int i;
1277 	struct pmcstat_gmonfile *pgf, *pgftmp;
1278 	struct pmcstat_image *pi, *pitmp;
1279 	struct pmcstat_process *pp, *pptmp;
1280 	struct pmcstat_string *ps, *pstmp;
1281 
1282 	for (i = 0; i < PMCSTAT_NHASH; i++) {
1283 		LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) {
1284 			/* flush gmon.out data to disk */
1285 			LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next,
1286 			    pgftmp) {
1287 			    pmcstat_gmon_unmap_file(pgf);
1288 			    LIST_REMOVE(pgf, pgf_next);
1289 			    free(pgf);
1290 			}
1291 
1292 			LIST_REMOVE(pi, pi_next);
1293 			free(pi);
1294 		}
1295 		LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next,
1296 		    pptmp) {
1297 			LIST_REMOVE(pp, pp_next);
1298 			free(pp);
1299 		}
1300 		LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next,
1301 		    pstmp) {
1302 			LIST_REMOVE(ps, ps_next);
1303 			free(ps);
1304 		}
1305 	}
1306 }
1307