pmcstat_log.c revision 153710
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: head/usr.sbin/pmcstat/pmcstat_log.c 153710 2005-12-25 05:11:29Z jkoshy $");
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 */
86struct 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
93static 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
100struct pmcstat_pmcrecord {
101	LIST_ENTRY(pmcstat_pmcrecord)	pr_next;
102	pmc_id_t	pr_pmcid;
103	const char 	*pr_pmcname;
104};
105
106static 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
115struct 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
124static 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
136enum pmcstat_image_type {
137	PMCSTAT_IMAGE_UNKNOWN = 0,
138	PMCSTAT_IMAGE_ELF,
139	PMCSTAT_IMAGE_AOUT
140};
141
142struct 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
158static LIST_HEAD(,pmcstat_image)	pmcstat_image_hash[PMCSTAT_NHASH];
159static TAILQ_HEAD(,pmcstat_image)	pmcstat_image_lru =
160	TAILQ_HEAD_INITIALIZER(pmcstat_image_lru);
161
162struct 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
173struct 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
181static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH];
182
183static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */
184
185/*
186 * Prototypes
187 */
188
189static void	pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf,
190    struct pmcstat_image *_image);
191static const char *pmcstat_gmon_create_name(const char *_sd,
192    struct pmcstat_image *_img, pmc_id_t _pmcid);
193static void	pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf);
194static void	pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf);
195
196static struct pmcstat_image *pmcstat_image_from_path(const char *_path);
197static enum pmcstat_image_type pmcstat_image_get_type(const char *_p);
198static void pmcstat_image_get_elf_params(struct pmcstat_image *_image);
199static void	pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm,
200    uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a);
201static void	pmcstat_image_link(struct pmcstat_process *_pp,
202    struct pmcstat_image *_i, uintfptr_t _lpc, uintfptr_t _hpc);
203
204static void	pmcstat_pmcid_add(pmc_id_t _pmcid, const char *_name,
205    struct pmcstat_args *_a);
206static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid);
207
208static void	pmcstat_process_add_elf_image(struct pmcstat_process *_pp,
209    const char *_path, uintfptr_t _entryaddr);
210static void	pmcstat_process_exec(struct pmcstat_process *_pp,
211    const char *_path, uintfptr_t _entryaddr);
212static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, int _allocate);
213static struct pmcstat_pcmap *pmcstat_process_find_map(
214    struct pmcstat_process *_p, uintfptr_t _pc);
215
216static int	pmcstat_string_compute_hash(const char *_string);
217static const char *pmcstat_string_intern(const char *_s);
218static struct pmcstat_string *pmcstat_string_lookup(const char *_s);
219
220
221/*
222 * Create a gmon.out file and size it.
223 */
224
225static void
226pmcstat_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
272const char *
273pmcstat_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
288static void
289pmcstat_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
312static void
313pmcstat_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
321static void
322pmcstat_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
446static struct pmcstat_image *
447pmcstat_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
523static enum pmcstat_image_type
524pmcstat_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
563static void
564pmcstat_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
630static void
631pmcstat_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
657static void
658pmcstat_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
693static const char *
694pmcstat_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
721static void
722pmcstat_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
834static struct pmcstat_process *
835pmcstat_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
880static void
881pmcstat_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
914static struct pmcstat_pcmap *
915pmcstat_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
931static int
932pmcstat_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
946static const char *
947pmcstat_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
967static struct pmcstat_string *
968pmcstat_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
991int
992pmcstat_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
1003int
1004pmcstat_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
1140int
1141pmcstat_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
1164int
1165pmcstat_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
1269int
1270pmcstat_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
1284void
1285pmcstat_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
1320void
1321pmcstat_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