xref: /freebsd/usr.sbin/pmcstat/pmcstat_log.c (revision 87569f75a91f298c52a71823c04d41cf53c88889)
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 #if	defined(__amd64__)
332 	const Elf32_Ehdr *h32;
333 	const Elf32_Phdr *ph32;
334 	const Elf32_Shdr *sh32;
335 #endif
336 	const char *path;
337 
338 	assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
339 
340 	minva = ~(uintfptr_t) 0;
341 	maxva = (uintfptr_t) 0;
342 	path = image->pi_internedpath;
343 
344 	if ((fd = open(path, O_RDONLY, 0)) < 0)
345 		err(EX_OSERR, "ERROR: Cannot open \"%s\"", path);
346 
347 	if (fstat(fd, &st) < 0)
348 		err(EX_OSERR, "ERROR: Cannot stat \"%s\"", path);
349 
350 	if ((mapbase = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
351 	    MAP_FAILED)
352 		err(EX_OSERR, "ERROR: Cannot mmap \"%s\"", path);
353 
354 	(void) close(fd);
355 
356 	h = (const Elf_Ehdr *) mapbase;
357 	if (!IS_ELF(*h))
358 		err(EX_SOFTWARE, "ERROR: \"%s\" not an ELF file", path);
359 
360 	/* we only handle executable objects */
361 	if (h->e_type != ET_EXEC && h->e_type != ET_DYN)
362 		err(EX_DATAERR, "ERROR: Unknown file type for \"%s\"",
363 		    image->pi_internedpath);
364 
365 #define	GET_VA(H, SH, MINVA, MAXVA) do {				\
366 		for (i = 0; i < (H)->e_shnum; i++)			\
367 			if ((SH)[i].sh_flags & SHF_EXECINSTR) {		\
368 				(MINVA) = min((MINVA),(SH)[i].sh_addr);	\
369 				(MAXVA) = max((MAXVA),(SH)[i].sh_addr +	\
370 				    (SH)[i].sh_size);			\
371 			}						\
372 	} while (0)
373 
374 
375 #define	GET_PHDR_INFO(H, PH, IMAGE) do {				\
376 		for (i = 0; i < (H)->e_phnum; i++) {			\
377 			switch ((PH)[i].p_type) {			\
378 			case PT_DYNAMIC:				\
379 				image->pi_isdynamic = 1;		\
380 				break;					\
381 			case PT_INTERP:					\
382 				image->pi_dynlinkerpath =		\
383 				    pmcstat_string_intern(		\
384 				        (char *) mapbase +		\
385 					(PH)[i].p_offset);		\
386 				break;					\
387 			}						\
388 		}							\
389 	} while (0)
390 
391 	image->pi_type = PMCSTAT_IMAGE_ELF;
392 	image->pi_isdynamic = 0;
393 	image->pi_dynlinkerpath = NULL;
394 
395 	switch (h->e_machine) {
396 	case EM_386:
397 	case EM_486:
398 #if	defined(__amd64__)
399 		/* a 32 bit executable */
400 		h32 = (const Elf32_Ehdr *) h;
401 		sh32 = (const Elf32_Shdr *)((uintptr_t) mapbase + h32->e_shoff);
402 
403 		GET_VA(h32, sh32, minva, maxva);
404 
405 		image->pi_entry = h32->e_entry;
406 
407 		if (h32->e_type == ET_EXEC) {
408 			ph32 = (const Elf32_Phdr *)((uintptr_t) mapbase +
409 			    h32->e_phoff);
410 			GET_PHDR_INFO(h32, ph32, image);
411 		}
412 		break;
413 #endif
414 	default:
415 		sh = (const Elf_Shdr *)((uintptr_t) mapbase + h->e_shoff);
416 
417 		GET_VA(h, sh, minva, maxva);
418 
419 		image->pi_entry = h->e_entry;
420 
421 		if (h->e_type == ET_EXEC) {
422 			ph = (const Elf_Phdr *)((uintptr_t) mapbase +
423 			    h->e_phoff);
424 			GET_PHDR_INFO(h, ph, image);
425 		}
426 		break;
427 	}
428 
429 #undef	GET_PHDR_INFO
430 #undef	GET_VA
431 
432 	image->pi_start = minva;
433 	image->pi_end = maxva;
434 
435 	if (munmap(mapbase, st.st_size) < 0)
436 		err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path);
437 
438 }
439 
440 /*
441  * Locate an image descriptor given an interned path, adding a fresh
442  * descriptor to the cache if necessary.  This function also finds a
443  * suitable name for this image's sample file.
444  */
445 
446 static struct pmcstat_image *
447 pmcstat_image_from_path(const char *internedpath)
448 {
449 	int count, hash, nlen;
450 	struct pmcstat_image *pi;
451 	char *sn;
452 	char name[NAME_MAX];
453 
454 	hash = pmcstat_string_compute_hash(internedpath);
455 
456 	/* Look for an existing entry. */
457 	LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next)
458 	    if (pi->pi_internedpath == internedpath) {
459 		    /* move descriptor to the head of the lru list */
460 		    TAILQ_REMOVE(&pmcstat_image_lru, pi, pi_lru);
461 		    TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru);
462 		    return pi;
463 	    }
464 
465 	/*
466 	 * Allocate a new entry and place at the head of the hash and
467 	 * LRU lists.
468 	 */
469 	pi = malloc(sizeof(*pi));
470 	if (pi == NULL)
471 		return NULL;
472 
473 	pi->pi_type = PMCSTAT_IMAGE_UNKNOWN;
474 	pi->pi_internedpath = internedpath;
475 	pi->pi_start = ~0;
476 	pi->pi_entry = ~0;
477 	pi->pi_end = 0;
478 
479 	/*
480 	 * Look for a suitable name for the sample files associated
481 	 * with this image: if `basename(path)`+".gmon" is available,
482 	 * we use that, otherwise we try iterating through
483 	 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free
484 	 * entry.
485 	 */
486 	if ((sn = basename(internedpath)) == NULL)
487 		err(EX_OSERR, "ERROR: Cannot process \"%s\"", internedpath);
488 
489 	nlen = strlen(sn);
490 	nlen = min(nlen, (int) sizeof(name) - 6);	/* ".gmon\0" */
491 
492 	snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn);
493 
494 	if (pmcstat_string_lookup(name) == NULL)
495 		pi->pi_samplename = pmcstat_string_intern(name);
496 	else {
497 		nlen = strlen(sn);
498 		nlen = min(nlen, (int) sizeof(name)-10); /* "~ddd.gmon\0" */
499 		count = 0;
500 		do {
501 			count++;
502 			snprintf(name, sizeof(name), "%.*s~%3.3d",
503 			    nlen, sn, count);
504 			if (pmcstat_string_lookup(name) == NULL) {
505 				pi->pi_samplename = pmcstat_string_intern(name);
506 				count = 0;
507 			}
508 		} while (count > 0);
509 	}
510 
511 	LIST_INIT(&pi->pi_gmlist);
512 
513 	LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next);
514 	TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru);
515 
516 	return pi;
517 }
518 
519 /*
520  * Given an open file, determine its file type.
521  */
522 
523 static enum pmcstat_image_type
524 pmcstat_image_get_type(const char *path)
525 {
526 	int fd;
527 	Elf_Ehdr eh;
528 	struct exec ex;
529 	ssize_t nbytes;
530 	char buffer[DEFAULT_BUFFER_SIZE];
531 
532 	if ((fd = open(path, O_RDONLY)) < 0)
533 		err(EX_OSERR, "ERROR: Cannot open \"%s\"", path);
534 
535 	nbytes = max(sizeof(eh), sizeof(ex));
536 	if ((nbytes = pread(fd, buffer, nbytes, 0)) < 0)
537 		err(EX_OSERR, "ERROR: Cannot read \"%s\"", path);
538 
539 	(void) close(fd);
540 
541 	/* check if its an ELF file */
542 	if ((unsigned) nbytes >= sizeof(Elf_Ehdr)) {
543 		bcopy(buffer, &eh, sizeof(eh));
544 		if (IS_ELF(eh))
545 			return PMCSTAT_IMAGE_ELF;
546 	}
547 
548 	/* Look for an A.OUT header */
549 	if ((unsigned) nbytes >= sizeof(struct exec)) {
550 		bcopy(buffer, &ex, sizeof(ex));
551 		if (!N_BADMAG(ex))
552 			return PMCSTAT_IMAGE_AOUT;
553 	}
554 
555 	return PMCSTAT_IMAGE_UNKNOWN;
556 }
557 
558 /*
559  * Increment the bucket in the gmon.out file corresponding to 'pmcid'
560  * and 'pc'.
561  */
562 
563 static void
564 pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc,
565     pmc_id_t pmcid, struct pmcstat_args *a)
566 {
567 	struct pmcstat_image *image;
568 	struct pmcstat_gmonfile *pgf;
569 	uintfptr_t bucket;
570 	HISTCOUNTER *hc;
571 
572 	assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc);
573 
574 	/*
575 	 * Find the gmon file corresponding to 'pmcid', creating it if
576 	 * needed.
577 	 */
578 
579 	image = map->ppm_image;
580 
581 	LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next)
582 	    if (pgf->pgf_pmcid == pmcid)
583 		    break;
584 
585 	/* If we don't have a gmon.out file for this PMCid, create one */
586 	if (pgf == NULL) {
587 		if ((pgf = calloc(1, sizeof(*pgf))) == NULL)
588 			err(EX_OSERR, "ERROR:");
589 
590 		pgf->pgf_gmondata = NULL;	/* mark as unmapped */
591 		pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir,
592 		    image, pmcid);
593 		pgf->pgf_pmcid = pmcid;
594 		assert(image->pi_end > image->pi_start);
595 		pgf->pgf_nbuckets = (image->pi_end - image->pi_start) /
596 		    FUNCTION_ALIGNMENT;	/* see <machine/profile.h> */
597 		pgf->pgf_ndatabytes = sizeof(struct gmonhdr) +
598 		    pgf->pgf_nbuckets * sizeof(HISTCOUNTER);
599 
600 		pmcstat_gmon_create_file(pgf, image);
601 
602 		LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next);
603 	}
604 
605 	/*
606 	 * Map the gmon file in if needed.  It may have been mapped
607 	 * out under memory pressure.
608 	 */
609 	if (pgf->pgf_gmondata == NULL)
610 		pmcstat_gmon_map_file(pgf);
611 
612 	bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT;
613 
614 	assert(bucket < pgf->pgf_nbuckets);
615 
616 	hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
617 	    sizeof(struct gmonhdr));
618 
619 	/* saturating add */
620 	if (hc[bucket] < 0xFFFF)
621 		hc[bucket]++;
622 
623 }
624 
625 /*
626  * Record the fact that PC values from 'lowpc' to 'highpc' come from
627  * image 'image'.
628  */
629 
630 static void
631 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image,
632     uintfptr_t lowpc, uintfptr_t highpc)
633 {
634 	struct pmcstat_pcmap *pcm, *pcmnew;
635 
636 	if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL)
637 		err(EX_OSERR, "ERROR: ");
638 
639 	pcmnew->ppm_lowpc  = lowpc;
640 	pcmnew->ppm_highpc = highpc;
641 	pcmnew->ppm_image  = image;
642 
643 	TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next)
644 	    if (pcm->ppm_lowpc < lowpc)
645 		    break;
646 
647 	if (pcm == NULL)
648 		TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next);
649 	else
650 		TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next);
651 }
652 
653 /*
654  * Add a {pmcid,name} mapping.
655  */
656 
657 static void
658 pmcstat_pmcid_add(pmc_id_t pmcid, const char *name, struct pmcstat_args *a)
659 {
660 	struct pmcstat_pmcrecord *pr;
661 	struct stat st;
662 	char fullpath[PATH_MAX];
663 
664 	LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
665 	    if (pr->pr_pmcid == pmcid) {
666 		    pr->pr_pmcname = name;
667 		    return;
668 	    }
669 
670 	if ((pr = malloc(sizeof(*pr))) == NULL)
671 		err(EX_OSERR, "ERROR: Cannot allocate pmc record");
672 
673 	pr->pr_pmcid = pmcid;
674 	pr->pr_pmcname = name;
675 	LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next);
676 
677 	(void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir,
678 	    name);
679 
680 	/* If the path name exists, it should be a directory */
681 	if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode))
682 		return;
683 
684 	if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0)
685 		err(EX_OSERR, "ERROR: Cannot create directory \"%s\"",
686 		    fullpath);
687 }
688 
689 /*
690  * Given a pmcid in use, find its human-readable name, or a
691  */
692 
693 static const char *
694 pmcstat_pmcid_to_name(pmc_id_t pmcid)
695 {
696 	struct pmcstat_pmcrecord *pr;
697 	char fullpath[PATH_MAX];
698 
699 	LIST_FOREACH(pr, &pmcstat_pmcs, pr_next)
700 	    if (pr->pr_pmcid == pmcid)
701 		    return pr->pr_pmcname;
702 
703 	/* create a default name and add this entry */
704 	if ((pr = malloc(sizeof(*pr))) == NULL)
705 		err(EX_OSERR, "ERROR: ");
706 	pr->pr_pmcid = pmcid;
707 
708 	(void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid);
709 	pr->pr_pmcname = pmcstat_string_intern(fullpath);
710 
711 	LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next);
712 
713 	return pr->pr_pmcname;
714 }
715 
716 /*
717  * Associate an ELF image with a process.  Argument 'path' names the
718  * executable while 'fd' is an already open descriptor to it.
719  */
720 
721 static void
722 pmcstat_process_add_elf_image(struct pmcstat_process *pp, const char *path,
723     uintfptr_t entryaddr)
724 {
725 	size_t linelen;
726 	FILE *rf;
727 	char *line;
728 	uintmax_t libstart;
729 	struct pmcstat_image *image, *rtldimage;
730 	char libname[PATH_MAX], libpath[PATH_MAX];
731 	char command[PATH_MAX + sizeof(PMCSTAT_LDD_COMMAND) + 1];
732 
733 	/* Look up path in the cache. */
734 	if ((image = pmcstat_image_from_path(path)) == NULL)
735 		return;
736 
737 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
738 		pmcstat_image_get_elf_params(image);
739 
740 	/* Create a map entry for the base executable. */
741 	pmcstat_image_link(pp, image, image->pi_start, image->pi_end);
742 
743 	/*
744 	 * For dynamically linked executables we need to:
745 	 * (a) find where the dynamic linker was mapped to for this
746 	 *     process,
747 	 * (b) find all the executable objects that the dynamic linker
748 	 *     brought in.
749 	 */
750 	if (image->pi_isdynamic) {
751 
752 		/*
753 		 * The runtime loader gets loaded just after the maximum
754 		 * possible heap address.  Like so:
755 		 *
756 		 * [  TEXT DATA BSS HEAP -->*RTLD  SHLIBS   <--STACK]
757 		 * ^					            ^
758 		 * 0				   VM_MAXUSER_ADDRESS
759 		 *
760 		 * The exact address where the loader gets mapped in
761 		 * will vary according to the size of the executable
762 		 * and the limits on the size of the process'es data
763 		 * segment at the time of exec().  The entry address
764 		 * recorded at process exec time corresponds to the
765 		 * 'start' address inside the dynamic linker.  From
766 		 * this we can figure out the address where the
767 		 * runtime loader's file object had been mapped to.
768 		 */
769 		rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath);
770 		if (rtldimage == NULL)
771 			err(EX_OSERR, "ERROR: Cannot find image for "
772 			    "\"%s\"", image->pi_dynlinkerpath);
773 		if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN)
774 			pmcstat_image_get_elf_params(rtldimage);
775 
776 		libstart = entryaddr - rtldimage->pi_entry;
777 		pmcstat_image_link(pp, rtldimage, libstart,
778 		    libstart + rtldimage->pi_end - rtldimage->pi_start);
779 
780 		/* Process all other objects loaded by this executable. */
781 		(void) snprintf(command, sizeof(command), "%s %s",
782 		    PMCSTAT_LDD_COMMAND, path);
783 
784 		if ((rf = popen(command, "r")) == NULL)
785 			err(EX_OSERR, "ERROR: Cannot create pipe");
786 
787 		(void) fgetln(rf, &linelen);
788 
789 		while (!feof(rf) && !ferror(rf)) {
790 
791 			if ((line = fgetln(rf, &linelen)) == NULL)
792 				continue;
793 			line[linelen-1] = '\0';
794 
795 			libstart = 0;
796 			libpath[0] = libname[0] = '\0';
797 			if (sscanf(line, "%s \"%[^\"]\" %jx",
798 				libname, libpath, &libstart) != 3)
799 				continue;
800 
801 			if (libstart == 0) {
802 				warnx("WARNING: object \"%s\" was not found "
803 				    "for program \"%s\".", libname, path);
804 				continue;
805 			}
806 
807 			image = pmcstat_image_from_path(
808 				pmcstat_string_intern(libpath));
809 			if (image == NULL)
810 				err(EX_OSERR, "ERROR: Cannot process "
811 				    "\"%s\"", libpath);
812 
813 			if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
814 				pmcstat_image_get_elf_params(image);
815 
816 			pmcstat_image_link(pp, image, libstart + image->pi_start,
817 			    libstart + image->pi_end);
818 		}
819 
820 		(void) pclose(rf);
821 
822 	}
823 }
824 
825 /*
826  * Find the process descriptor corresponding to a PID.  If 'allocate'
827  * is zero, we return a NULL if a pid descriptor could not be found or
828  * a process descriptor process.  If 'allocate' is non-zero, then we
829  * will attempt to allocate a fresh process descriptor.  Zombie
830  * process descriptors are only removed if a fresh allocation for the
831  * same PID is requested.
832  */
833 
834 static struct pmcstat_process *
835 pmcstat_process_lookup(pid_t pid, int allocate)
836 {
837 	uint32_t hash;
838 	struct pmcstat_pcmap *ppm, *ppmtmp;
839 	struct pmcstat_process *pp, *pptmp;
840 
841 	hash = (uint32_t) pid & PMCSTAT_HASH_MASK;	/* simplicity wins */
842 
843 	LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp)
844 	    if (pp->pp_pid == pid) {
845 		    /* Found a descriptor, check and process zombies */
846 		    if (allocate && !pp->pp_isactive) {
847 			    /* remove maps */
848 			    TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next,
849 				ppmtmp) {
850 				    TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next);
851 				    free(ppm);
852 			    }
853 			    /* remove process entry */
854 			    LIST_REMOVE(pp, pp_next);
855 			    free(pp);
856 			    break;
857 		    }
858 		    return pp;
859 	    }
860 
861 	if (!allocate)
862 		return NULL;
863 
864 	if ((pp = malloc(sizeof(*pp))) == NULL)
865 		err(EX_OSERR, "ERROR: Cannot allocate pid descriptor");
866 
867 	pp->pp_pid = pid;
868 	pp->pp_isactive = 1;
869 
870 	TAILQ_INIT(&pp->pp_map);
871 
872 	LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next);
873 	return pp;
874 }
875 
876 /*
877  * Associate an image and a process.
878  */
879 
880 static void
881 pmcstat_process_exec(struct pmcstat_process *pp, const char *path,
882     uintfptr_t entryaddr)
883 {
884 	enum pmcstat_image_type filetype;
885 	struct pmcstat_image *image;
886 
887 	if ((image = pmcstat_image_from_path(path)) == NULL)
888 		return;
889 
890 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
891 		filetype = pmcstat_image_get_type(path);
892 	else
893 		filetype = image->pi_type;
894 
895 	switch (filetype) {
896 	case PMCSTAT_IMAGE_ELF:
897 		pmcstat_process_add_elf_image(pp, path, entryaddr);
898 		break;
899 
900 	case PMCSTAT_IMAGE_AOUT:
901 		break;
902 
903 	default:
904 		err(EX_SOFTWARE, "ERROR: Unsupported executable type for "
905 		    "\"%s\"", path);
906 	}
907 }
908 
909 
910 /*
911  * Find the map entry associated with process 'p' at PC value 'pc'.
912  */
913 
914 static struct pmcstat_pcmap *
915 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc)
916 {
917 	struct pmcstat_pcmap *ppm;
918 
919 	TAILQ_FOREACH(ppm, &p->pp_map, ppm_next)
920 	    if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc)
921 		    return ppm;
922 
923 	return NULL;
924 }
925 
926 
927 /*
928  * Compute a 'hash' value for a string.
929  */
930 
931 static int
932 pmcstat_string_compute_hash(const char *s)
933 {
934 	int hash;
935 
936 	for (hash = 0; *s; s++)
937 		hash ^= *s;
938 
939 	return hash & PMCSTAT_HASH_MASK;
940 }
941 
942 /*
943  * Intern a copy of string 's', and return a pointer to it.
944  */
945 
946 static const char *
947 pmcstat_string_intern(const char *s)
948 {
949 	struct pmcstat_string *ps;
950 	int hash, len;
951 
952 	hash = pmcstat_string_compute_hash(s);
953 	len  = strlen(s);
954 
955 	if ((ps = pmcstat_string_lookup(s)) != NULL)
956 		return ps->ps_string;
957 
958 	if ((ps = malloc(sizeof(*ps))) == NULL)
959 		err(EX_OSERR, "ERROR: Could not intern string");
960 	ps->ps_len = len;
961 	ps->ps_hash = hash;
962 	ps->ps_string = strdup(s);
963 	LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next);
964 	return ps->ps_string;
965 }
966 
967 static struct pmcstat_string *
968 pmcstat_string_lookup(const char *s)
969 {
970 	struct pmcstat_string *ps;
971 	int hash, len;
972 
973 	hash = pmcstat_string_compute_hash(s);
974 	len = strlen(s);
975 
976 	LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next)
977 	    if (ps->ps_len == len && ps->ps_hash == hash &&
978 		strcmp(ps->ps_string, s) == 0)
979 		    return ps;
980 	return NULL;
981 }
982 
983 /*
984  * Public Interfaces.
985  */
986 
987 /*
988  * Close a logfile, after first flushing all in-module queued data.
989  */
990 
991 int
992 pmcstat_close_log(struct pmcstat_args *a)
993 {
994 	if (pmc_flush_logfile() < 0 ||
995 	    pmc_configure_logfile(-1) < 0)
996 		err(EX_OSERR, "ERROR: logging failed");
997 	a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE);
998 	return a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING :
999 	    PMCSTAT_FINISHED;
1000 }
1001 
1002 
1003 int
1004 pmcstat_convert_log(struct pmcstat_args *a)
1005 {
1006 	uintfptr_t pc;
1007 	struct pmcstat_process *pp, *ppnew;
1008 	struct pmcstat_pcmap *ppm, *ppmtmp;
1009 	struct pmclog_ev ev;
1010 	const char *image_path;
1011 
1012 	while (pmclog_read(a->pa_logparser, &ev) == 0) {
1013 		assert(ev.pl_state == PMCLOG_OK);
1014 
1015 		switch (ev.pl_type) {
1016 		case PMCLOG_TYPE_MAPPINGCHANGE:
1017 			/*
1018 			 * Introduce an address range mapping for a
1019 			 * process.
1020 			 */
1021 			break;
1022 
1023 		case PMCLOG_TYPE_PCSAMPLE:
1024 
1025 			/*
1026 			 * We bring in the gmon file for the image
1027 			 * currently associated with the PMC & pid
1028 			 * pair and increment the appropriate entry
1029 			 * bin inside this.
1030 			 */
1031 			pc = ev.pl_u.pl_s.pl_pc;
1032 			pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1);
1033 			if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL &&
1034 			    (ppm = pmcstat_process_find_map(pmcstat_kernproc,
1035 				pc)) == NULL)
1036 				break; /* unknown process,offset pair */
1037 
1038 			pmcstat_image_increment_bucket(ppm, pc,
1039 			    ev.pl_u.pl_s.pl_pmcid, a);
1040 
1041 			break;
1042 
1043 		case PMCLOG_TYPE_PMCALLOCATE:
1044 			/*
1045 			 * Record the association pmc id between this
1046 			 * PMC and its name.
1047 			 */
1048 			pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid,
1049 			    pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), a);
1050 			break;
1051 
1052 		case PMCLOG_TYPE_PROCEXEC:
1053 
1054 			/*
1055 			 * Change the executable image associated with
1056 			 * a process.
1057 			 */
1058 			pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1);
1059 
1060 			/* delete the current process map */
1061 			TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) {
1062 				TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next);
1063 				free(ppm);
1064 			}
1065 
1066 			/* locate the descriptor for the new 'base' image */
1067 			image_path = pmcstat_string_intern(
1068 				ev.pl_u.pl_x.pl_pathname);
1069 
1070 			/* link to the new image */
1071 			pmcstat_process_exec(pp, image_path,
1072 			    ev.pl_u.pl_x.pl_entryaddr);
1073 			break;
1074 
1075 		case PMCLOG_TYPE_PROCEXIT:
1076 
1077 			/*
1078 			 * Due to the way the log is generated, the
1079 			 * last few samples corresponding to a process
1080 			 * may appear in the log after the process
1081 			 * exit event is recorded.  Thus we keep the
1082 			 * process' descriptor and associated data
1083 			 * structures around, but mark the process as
1084 			 * having exited.
1085 			 */
1086 			pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0);
1087 			if (pp == NULL)
1088 				break;
1089 			pp->pp_isactive = 0;	/* make a zombie */
1090 			break;
1091 
1092 		case PMCLOG_TYPE_SYSEXIT:
1093 			pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0);
1094 			if (pp == NULL)
1095 				break;
1096 			pp->pp_isactive = 0;	/* make a zombie */
1097 			break;
1098 
1099 		case PMCLOG_TYPE_PROCFORK:
1100 
1101 			/*
1102 			 * If we had been tracking 'oldpid', then clone
1103 			 * its pid descriptor.
1104 			 */
1105 			pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0);
1106 			if (pp == NULL)
1107 				break;
1108 
1109 			ppnew =
1110 			    pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, 1);
1111 
1112 			/* copy the old process' address maps */
1113 			TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next)
1114 			    pmcstat_image_link(ppnew, ppm->ppm_image,
1115 				ppm->ppm_lowpc, ppm->ppm_highpc);
1116 			break;
1117 
1118 		default:	/* other types of entries are not relevant */
1119 			break;
1120 		}
1121 	}
1122 
1123 	if (ev.pl_state == PMCLOG_EOF)
1124 		return PMCSTAT_FINISHED;
1125 	else if (ev.pl_state == PMCLOG_REQUIRE_DATA)
1126 		return PMCSTAT_RUNNING;
1127 
1128 	err(EX_DATAERR, "ERROR: event parsing failed (record %jd, "
1129 	    "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset);
1130 }
1131 
1132 
1133 /*
1134  * Open a log file, for reading or writing.
1135  *
1136  * The function returns the fd of a successfully opened log or -1 in
1137  * case of failure.
1138  */
1139 
1140 int
1141 pmcstat_open(const char *path, int mode)
1142 {
1143 	int fd;
1144 
1145 	/*
1146 	 * If 'path' is "-" then open one of stdin or stdout depending
1147 	 * on the value of 'mode'.  Otherwise, treat 'path' as a file
1148 	 * name and open that.
1149 	 */
1150 	if (path[0] == '-' && path[1] == '\0')
1151 		fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1;
1152 	else
1153 		fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ?
1154 		    O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC),
1155 		    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
1156 
1157 	return fd;
1158 }
1159 
1160 /*
1161  * Print log entries as text.
1162  */
1163 
1164 int
1165 pmcstat_print_log(struct pmcstat_args *a)
1166 {
1167 	struct pmclog_ev ev;
1168 
1169 	while (pmclog_read(a->pa_logparser, &ev) == 0) {
1170 		assert(ev.pl_state == PMCLOG_OK);
1171 		switch (ev.pl_type) {
1172 		case PMCLOG_TYPE_CLOSELOG:
1173 			PMCSTAT_PRINT_ENTRY(a,"closelog",);
1174 			break;
1175 		case PMCLOG_TYPE_DROPNOTIFY:
1176 			PMCSTAT_PRINT_ENTRY(a,"drop",);
1177 			break;
1178 		case PMCLOG_TYPE_INITIALIZE:
1179 			PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"",
1180 			    ev.pl_u.pl_i.pl_version,
1181 			    pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch));
1182 			break;
1183 		case PMCLOG_TYPE_MAPPINGCHANGE:
1184 			PMCSTAT_PRINT_ENTRY(a,"mapping","%s %d %p %p \"%s\"",
1185 			    ev.pl_u.pl_m.pl_type == PMCLOG_MAPPING_INSERT ?
1186 			    	"insert" : "delete",
1187 			    ev.pl_u.pl_m.pl_pid,
1188 			    (void *) ev.pl_u.pl_m.pl_start,
1189 			    (void *) ev.pl_u.pl_m.pl_end,
1190 			    ev.pl_u.pl_m.pl_pathname);
1191 			break;
1192 		case PMCLOG_TYPE_PCSAMPLE:
1193 			PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c",
1194 			    ev.pl_u.pl_s.pl_pmcid,
1195 			    ev.pl_u.pl_s.pl_pid,
1196 			    (void *) ev.pl_u.pl_s.pl_pc,
1197 			    ev.pl_u.pl_s.pl_usermode ? 'u' : 's');
1198 			break;
1199 		case PMCLOG_TYPE_PMCALLOCATE:
1200 			PMCSTAT_PRINT_ENTRY(a,"allocate","0x%x \"%s\" 0x%x",
1201 			    ev.pl_u.pl_a.pl_pmcid,
1202 			    ev.pl_u.pl_a.pl_evname,
1203 			    ev.pl_u.pl_a.pl_flags);
1204 			break;
1205 		case PMCLOG_TYPE_PMCATTACH:
1206 			PMCSTAT_PRINT_ENTRY(a,"attach","0x%x %d \"%s\"",
1207 			    ev.pl_u.pl_t.pl_pmcid,
1208 			    ev.pl_u.pl_t.pl_pid,
1209 			    ev.pl_u.pl_t.pl_pathname);
1210 			break;
1211 		case PMCLOG_TYPE_PMCDETACH:
1212 			PMCSTAT_PRINT_ENTRY(a,"detach","0x%x %d",
1213 			    ev.pl_u.pl_d.pl_pmcid,
1214 			    ev.pl_u.pl_d.pl_pid);
1215 			break;
1216 		case PMCLOG_TYPE_PROCCSW:
1217 			PMCSTAT_PRINT_ENTRY(a,"cswval","0x%x %d %jd",
1218 			    ev.pl_u.pl_c.pl_pmcid,
1219 			    ev.pl_u.pl_c.pl_pid,
1220 			    ev.pl_u.pl_c.pl_value);
1221 			break;
1222 		case PMCLOG_TYPE_PROCEXEC:
1223 			PMCSTAT_PRINT_ENTRY(a,"exec","0x%x %d %p \"%s\"",
1224 			    ev.pl_u.pl_x.pl_pmcid,
1225 			    ev.pl_u.pl_x.pl_pid,
1226 			    (void *) ev.pl_u.pl_x.pl_entryaddr,
1227 			    ev.pl_u.pl_x.pl_pathname);
1228 			break;
1229 		case PMCLOG_TYPE_PROCEXIT:
1230 			PMCSTAT_PRINT_ENTRY(a,"exitval","0x%x %d %jd",
1231 			    ev.pl_u.pl_e.pl_pmcid,
1232 			    ev.pl_u.pl_e.pl_pid,
1233 			    ev.pl_u.pl_e.pl_value);
1234 			break;
1235 		case PMCLOG_TYPE_PROCFORK:
1236 			PMCSTAT_PRINT_ENTRY(a,"fork","%d %d",
1237 			    ev.pl_u.pl_f.pl_oldpid,
1238 			    ev.pl_u.pl_f.pl_newpid);
1239 			break;
1240 		case PMCLOG_TYPE_USERDATA:
1241 			PMCSTAT_PRINT_ENTRY(a,"userdata","0x%x",
1242 			    ev.pl_u.pl_u.pl_userdata);
1243 			break;
1244 		case PMCLOG_TYPE_SYSEXIT:
1245 			PMCSTAT_PRINT_ENTRY(a,"exit","%d",
1246 			    ev.pl_u.pl_se.pl_pid);
1247 			break;
1248 		default:
1249 			fprintf(a->pa_printfile, "unknown %d",
1250 			    ev.pl_type);
1251 		}
1252 	}
1253 
1254 	if (ev.pl_state == PMCLOG_EOF)
1255 		return PMCSTAT_FINISHED;
1256 	else if (ev.pl_state ==  PMCLOG_REQUIRE_DATA)
1257 		return PMCSTAT_RUNNING;
1258 
1259 	err(EX_DATAERR, "ERROR: event parsing failed "
1260 	    "(record %jd, offset 0x%jx)",
1261 	    (uintmax_t) ev.pl_count + 1, ev.pl_offset);
1262 	/*NOTREACHED*/
1263 }
1264 
1265 /*
1266  * Process a log file in offline analysis mode.
1267  */
1268 
1269 int
1270 pmcstat_process_log(struct pmcstat_args *a)
1271 {
1272 
1273 	/*
1274 	 * If gprof style profiles haven't been asked for, just print the
1275 	 * log to the current output file.
1276 	 */
1277 	if (a->pa_flags & FLAG_DO_PRINT)
1278 		return pmcstat_print_log(a);
1279 	else
1280 		/* convert the log to gprof compatible profiles */
1281 		return pmcstat_convert_log(a);
1282 }
1283 
1284 void
1285 pmcstat_initialize_logging(struct pmcstat_args *a)
1286 {
1287 	int i;
1288 	const char *kernpath;
1289 	struct pmcstat_image *img;
1290 
1291 	/* use a convenient format for 'ldd' output */
1292 	if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0)
1293 		goto error;
1294 
1295 	/* Initialize hash tables */
1296 	for (i = 0; i < PMCSTAT_NHASH; i++) {
1297 		LIST_INIT(&pmcstat_image_hash[i]);
1298 		LIST_INIT(&pmcstat_process_hash[i]);
1299 		LIST_INIT(&pmcstat_string_hash[i]);
1300 	}
1301 
1302 	/* create a fake 'process' entry for the kernel with pid == -1 */
1303 	if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 1)) == NULL)
1304 		goto error;
1305 
1306 	if ((kernpath = pmcstat_string_intern(a->pa_kernel)) == NULL)
1307 		goto error;
1308 
1309 	img = pmcstat_image_from_path(kernpath);
1310 
1311 	pmcstat_image_get_elf_params(img);
1312 	pmcstat_image_link(pmcstat_kernproc, img, img->pi_start, img->pi_end);
1313 
1314 	return;
1315 
1316  error:
1317 	err(EX_OSERR, "ERROR: Cannot initialize logging");
1318 }
1319 
1320 void
1321 pmcstat_shutdown_logging(void)
1322 {
1323 	int i;
1324 	struct pmcstat_gmonfile *pgf, *pgftmp;
1325 	struct pmcstat_image *pi, *pitmp;
1326 	struct pmcstat_process *pp, *pptmp;
1327 	struct pmcstat_string *ps, *pstmp;
1328 
1329 	for (i = 0; i < PMCSTAT_NHASH; i++) {
1330 		LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) {
1331 			/* flush gmon.out data to disk */
1332 			LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next,
1333 			    pgftmp) {
1334 			    pmcstat_gmon_unmap_file(pgf);
1335 			    LIST_REMOVE(pgf, pgf_next);
1336 			    free(pgf);
1337 			}
1338 
1339 			LIST_REMOVE(pi, pi_next);
1340 			free(pi);
1341 		}
1342 		LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next,
1343 		    pptmp) {
1344 			LIST_REMOVE(pp, pp_next);
1345 			free(pp);
1346 		}
1347 		LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next,
1348 		    pstmp) {
1349 			LIST_REMOVE(ps, ps_next);
1350 			free(ps);
1351 		}
1352 	}
1353 }
1354