xref: /freebsd/lib/libpmcstat/libpmcstat_process.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
1d27927f7SRuslan Bukin /*-
2d27927f7SRuslan Bukin  * Copyright (c) 2003-2008 Joseph Koshy
3d27927f7SRuslan Bukin  * All rights reserved.
4d27927f7SRuslan Bukin  *
5d27927f7SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
6d27927f7SRuslan Bukin  * modification, are permitted provided that the following conditions
7d27927f7SRuslan Bukin  * are met:
8d27927f7SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
9d27927f7SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
10d27927f7SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
11d27927f7SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
12d27927f7SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
13d27927f7SRuslan Bukin  *
14d27927f7SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15d27927f7SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16d27927f7SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17d27927f7SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18d27927f7SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19d27927f7SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20d27927f7SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21d27927f7SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22d27927f7SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23d27927f7SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24d27927f7SRuslan Bukin  * SUCH DAMAGE.
25d27927f7SRuslan Bukin  */
26d27927f7SRuslan Bukin 
27d27927f7SRuslan Bukin #include <sys/types.h>
28d27927f7SRuslan Bukin #include <sys/cpuset.h>
29d27927f7SRuslan Bukin #include <sys/event.h>
30d27927f7SRuslan Bukin #include <sys/param.h>
31d27927f7SRuslan Bukin #include <sys/socket.h>
32d27927f7SRuslan Bukin #include <sys/stat.h>
33d27927f7SRuslan Bukin #include <sys/module.h>
34d27927f7SRuslan Bukin #include <sys/pmc.h>
35d27927f7SRuslan Bukin 
36d27927f7SRuslan Bukin #include <assert.h>
37d27927f7SRuslan Bukin #include <ctype.h>
38d27927f7SRuslan Bukin #include <err.h>
39d27927f7SRuslan Bukin #include <errno.h>
40d27927f7SRuslan Bukin #include <fcntl.h>
41d27927f7SRuslan Bukin #include <limits.h>
42d27927f7SRuslan Bukin #include <netdb.h>
43d27927f7SRuslan Bukin #include <pmc.h>
44d27927f7SRuslan Bukin #include <pmclog.h>
45d27927f7SRuslan Bukin #include <signal.h>
46d27927f7SRuslan Bukin #include <stdio.h>
47d27927f7SRuslan Bukin #include <stdlib.h>
48d27927f7SRuslan Bukin #include <string.h>
49d27927f7SRuslan Bukin #include <strings.h>
50d27927f7SRuslan Bukin #include <sysexits.h>
51d27927f7SRuslan Bukin #include <unistd.h>
52d27927f7SRuslan Bukin 
53d27927f7SRuslan Bukin #include "libpmcstat.h"
54d27927f7SRuslan Bukin 
55d27927f7SRuslan Bukin /*
56d27927f7SRuslan Bukin  * Associate an AOUT image with a process.
57d27927f7SRuslan Bukin  */
58d27927f7SRuslan Bukin 
59d27927f7SRuslan Bukin void
pmcstat_process_aout_exec(struct pmcstat_process * pp,struct pmcstat_image * image,uintptr_t baseaddr)60d27927f7SRuslan Bukin pmcstat_process_aout_exec(struct pmcstat_process *pp,
61*94426d21SJessica Clarke     struct pmcstat_image *image, uintptr_t baseaddr)
62d27927f7SRuslan Bukin {
63d27927f7SRuslan Bukin 	(void) pp;
64d27927f7SRuslan Bukin 	(void) image;
65*94426d21SJessica Clarke 	(void) baseaddr;
66d27927f7SRuslan Bukin 	/* TODO Implement a.out handling */
67d27927f7SRuslan Bukin }
68d27927f7SRuslan Bukin 
69d27927f7SRuslan Bukin /*
70d27927f7SRuslan Bukin  * Associate an ELF image with a process.
71d27927f7SRuslan Bukin  */
72d27927f7SRuslan Bukin 
73d27927f7SRuslan Bukin void
pmcstat_process_elf_exec(struct pmcstat_process * pp,struct pmcstat_image * image,uintptr_t baseaddr,uintptr_t dynaddr,struct pmcstat_args * args,struct pmc_plugins * plugins,struct pmcstat_stats * pmcstat_stats)74d27927f7SRuslan Bukin pmcstat_process_elf_exec(struct pmcstat_process *pp,
75*94426d21SJessica Clarke     struct pmcstat_image *image, uintptr_t baseaddr, uintptr_t dynaddr,
76d27927f7SRuslan Bukin     struct pmcstat_args *args, struct pmc_plugins *plugins,
77d27927f7SRuslan Bukin     struct pmcstat_stats *pmcstat_stats)
78d27927f7SRuslan Bukin {
79d27927f7SRuslan Bukin 	struct pmcstat_image *rtldimage;
80d27927f7SRuslan Bukin 
81d27927f7SRuslan Bukin 	assert(image->pi_type == PMCSTAT_IMAGE_ELF32 ||
82d27927f7SRuslan Bukin 	    image->pi_type == PMCSTAT_IMAGE_ELF64);
83d27927f7SRuslan Bukin 
84*94426d21SJessica Clarke 	/*
85*94426d21SJessica Clarke 	 * The exact address where the executable gets mapped in will vary for
86*94426d21SJessica Clarke 	 * PIEs.  The dynamic address recorded at process exec time corresponds
87*94426d21SJessica Clarke 	 * to the address where the executable's file object had been mapped to.
88*94426d21SJessica Clarke 	 */
89*94426d21SJessica Clarke 	pmcstat_image_link(pp, image, image->pi_vaddr + dynaddr);
90d27927f7SRuslan Bukin 
91d27927f7SRuslan Bukin 	/*
92d27927f7SRuslan Bukin 	 * For dynamically linked executables we need to determine
93d27927f7SRuslan Bukin 	 * where the dynamic linker was mapped to for this process,
94d27927f7SRuslan Bukin 	 * Subsequent executable objects that are mapped in by the
95d27927f7SRuslan Bukin 	 * dynamic linker will be tracked by log events of type
96d27927f7SRuslan Bukin 	 * PMCLOG_TYPE_MAP_IN.
97d27927f7SRuslan Bukin 	 */
98d27927f7SRuslan Bukin 
99d27927f7SRuslan Bukin 	if (image->pi_isdynamic) {
100d27927f7SRuslan Bukin 
101d27927f7SRuslan Bukin 		/*
102d27927f7SRuslan Bukin 		 * The runtime loader gets loaded just after the maximum
103d27927f7SRuslan Bukin 		 * possible heap address.  Like so:
104d27927f7SRuslan Bukin 		 *
105d27927f7SRuslan Bukin 		 * [  TEXT DATA BSS HEAP -->*RTLD  SHLIBS   <--STACK]
106d27927f7SRuslan Bukin 		 * ^					            ^
107d27927f7SRuslan Bukin 		 * 0				   VM_MAXUSER_ADDRESS
108d27927f7SRuslan Bukin 		 *
109d27927f7SRuslan Bukin 		 * The exact address where the loader gets mapped in
110d27927f7SRuslan Bukin 		 * will vary according to the size of the executable
111d27927f7SRuslan Bukin 		 * and the limits on the size of the process'es data
112*94426d21SJessica Clarke 		 * segment at the time of exec().  The base address
113d27927f7SRuslan Bukin 		 * recorded at process exec time corresponds to the
114*94426d21SJessica Clarke 		 * address where the runtime loader's file object had
115*94426d21SJessica Clarke 		 * been mapped to.
116d27927f7SRuslan Bukin 		 */
117d27927f7SRuslan Bukin 		rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath,
118d27927f7SRuslan Bukin 		    0, args, plugins);
119d27927f7SRuslan Bukin 		if (rtldimage == NULL) {
120d27927f7SRuslan Bukin 			warnx("WARNING: Cannot find image for \"%s\".",
121d27927f7SRuslan Bukin 			    pmcstat_string_unintern(image->pi_dynlinkerpath));
122d27927f7SRuslan Bukin 			pmcstat_stats->ps_exec_errors++;
123d27927f7SRuslan Bukin 			return;
124d27927f7SRuslan Bukin 		}
125d27927f7SRuslan Bukin 
126d27927f7SRuslan Bukin 		if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN)
127d27927f7SRuslan Bukin 			pmcstat_image_get_elf_params(rtldimage, args);
128d27927f7SRuslan Bukin 
129d27927f7SRuslan Bukin 		if (rtldimage->pi_type != PMCSTAT_IMAGE_ELF32 &&
130d27927f7SRuslan Bukin 		    rtldimage->pi_type != PMCSTAT_IMAGE_ELF64) {
131d27927f7SRuslan Bukin 			warnx("WARNING: rtld not an ELF object \"%s\".",
132d27927f7SRuslan Bukin 			    pmcstat_string_unintern(image->pi_dynlinkerpath));
133d27927f7SRuslan Bukin 			return;
134d27927f7SRuslan Bukin 		}
135d27927f7SRuslan Bukin 
136*94426d21SJessica Clarke 		pmcstat_image_link(pp, rtldimage, baseaddr);
137d27927f7SRuslan Bukin 	}
138d27927f7SRuslan Bukin }
139d27927f7SRuslan Bukin 
140d27927f7SRuslan Bukin /*
141d27927f7SRuslan Bukin  * Associate an image and a process.
142d27927f7SRuslan Bukin  */
143d27927f7SRuslan Bukin 
144d27927f7SRuslan Bukin void
pmcstat_process_exec(struct pmcstat_process * pp,pmcstat_interned_string path,uintptr_t baseaddr,uintptr_t dynaddr,struct pmcstat_args * args,struct pmc_plugins * plugins,struct pmcstat_stats * pmcstat_stats)145d27927f7SRuslan Bukin pmcstat_process_exec(struct pmcstat_process *pp,
146*94426d21SJessica Clarke     pmcstat_interned_string path, uintptr_t baseaddr, uintptr_t dynaddr,
147d27927f7SRuslan Bukin     struct pmcstat_args *args, struct pmc_plugins *plugins,
148d27927f7SRuslan Bukin     struct pmcstat_stats *pmcstat_stats)
149d27927f7SRuslan Bukin {
150d27927f7SRuslan Bukin 	struct pmcstat_image *image;
151d27927f7SRuslan Bukin 
152d27927f7SRuslan Bukin 	if ((image = pmcstat_image_from_path(path, 0,
153d27927f7SRuslan Bukin 	    args, plugins)) == NULL) {
154d27927f7SRuslan Bukin 		pmcstat_stats->ps_exec_errors++;
155d27927f7SRuslan Bukin 		return;
156d27927f7SRuslan Bukin 	}
157d27927f7SRuslan Bukin 
158d27927f7SRuslan Bukin 	if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
159d27927f7SRuslan Bukin 		pmcstat_image_determine_type(image, args);
160d27927f7SRuslan Bukin 
161d27927f7SRuslan Bukin 	assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN);
162d27927f7SRuslan Bukin 
163d27927f7SRuslan Bukin 	switch (image->pi_type) {
164d27927f7SRuslan Bukin 	case PMCSTAT_IMAGE_ELF32:
165d27927f7SRuslan Bukin 	case PMCSTAT_IMAGE_ELF64:
166d27927f7SRuslan Bukin 		pmcstat_stats->ps_exec_elf++;
167*94426d21SJessica Clarke 		pmcstat_process_elf_exec(pp, image, baseaddr, dynaddr,
168d27927f7SRuslan Bukin 		    args, plugins, pmcstat_stats);
169d27927f7SRuslan Bukin 		break;
170d27927f7SRuslan Bukin 
171d27927f7SRuslan Bukin 	case PMCSTAT_IMAGE_AOUT:
172d27927f7SRuslan Bukin 		pmcstat_stats->ps_exec_aout++;
173*94426d21SJessica Clarke 		pmcstat_process_aout_exec(pp, image, baseaddr);
174d27927f7SRuslan Bukin 		break;
175d27927f7SRuslan Bukin 
176d27927f7SRuslan Bukin 	case PMCSTAT_IMAGE_INDETERMINABLE:
177d27927f7SRuslan Bukin 		pmcstat_stats->ps_exec_indeterminable++;
178d27927f7SRuslan Bukin 		break;
179d27927f7SRuslan Bukin 
180d27927f7SRuslan Bukin 	default:
181d27927f7SRuslan Bukin 		err(EX_SOFTWARE,
182d27927f7SRuslan Bukin 		    "ERROR: Unsupported executable type for \"%s\"",
183d27927f7SRuslan Bukin 		    pmcstat_string_unintern(path));
184d27927f7SRuslan Bukin 	}
185d27927f7SRuslan Bukin }
186d27927f7SRuslan Bukin 
187d27927f7SRuslan Bukin /*
188d27927f7SRuslan Bukin  * Find the map entry associated with process 'p' at PC value 'pc'.
189d27927f7SRuslan Bukin  */
190d27927f7SRuslan Bukin 
191d27927f7SRuslan Bukin struct pmcstat_pcmap *
pmcstat_process_find_map(struct pmcstat_process * p,uintfptr_t pc)192d27927f7SRuslan Bukin pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc)
193d27927f7SRuslan Bukin {
194d27927f7SRuslan Bukin 	struct pmcstat_pcmap *ppm;
195d27927f7SRuslan Bukin 
196d27927f7SRuslan Bukin 	TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) {
197d27927f7SRuslan Bukin 		if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc)
198d27927f7SRuslan Bukin 			return (ppm);
199d27927f7SRuslan Bukin 		if (pc < ppm->ppm_lowpc)
200d27927f7SRuslan Bukin 			return (NULL);
201d27927f7SRuslan Bukin 	}
202d27927f7SRuslan Bukin 
203d27927f7SRuslan Bukin 	return (NULL);
204d27927f7SRuslan Bukin }
205d27927f7SRuslan Bukin 
206d27927f7SRuslan Bukin /*
207d27927f7SRuslan Bukin  * Find the process descriptor corresponding to a PID.  If 'allocate'
208d27927f7SRuslan Bukin  * is zero, we return a NULL if a pid descriptor could not be found or
209d27927f7SRuslan Bukin  * a process descriptor process.  If 'allocate' is non-zero, then we
210d27927f7SRuslan Bukin  * will attempt to allocate a fresh process descriptor.  Zombie
211d27927f7SRuslan Bukin  * process descriptors are only removed if a fresh allocation for the
212d27927f7SRuslan Bukin  * same PID is requested.
213d27927f7SRuslan Bukin  */
214d27927f7SRuslan Bukin 
215d27927f7SRuslan Bukin struct pmcstat_process *
pmcstat_process_lookup(pid_t pid,int allocate)216d27927f7SRuslan Bukin pmcstat_process_lookup(pid_t pid, int allocate)
217d27927f7SRuslan Bukin {
218d27927f7SRuslan Bukin 	uint32_t hash;
219d27927f7SRuslan Bukin 	struct pmcstat_pcmap *ppm, *ppmtmp;
220d27927f7SRuslan Bukin 	struct pmcstat_process *pp, *pptmp;
221d27927f7SRuslan Bukin 
222d27927f7SRuslan Bukin 	hash = (uint32_t) pid & PMCSTAT_HASH_MASK;	/* simplicity wins */
223d27927f7SRuslan Bukin 
224d27927f7SRuslan Bukin 	LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp)
225d27927f7SRuslan Bukin 		if (pp->pp_pid == pid) {
226d27927f7SRuslan Bukin 			/* Found a descriptor, check and process zombies */
227d27927f7SRuslan Bukin 			if (allocate && pp->pp_isactive == 0) {
228d27927f7SRuslan Bukin 				/* remove maps */
229d27927f7SRuslan Bukin 				TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next,
230d27927f7SRuslan Bukin 				    ppmtmp) {
231d27927f7SRuslan Bukin 					TAILQ_REMOVE(&pp->pp_map, ppm,
232d27927f7SRuslan Bukin 					    ppm_next);
233d27927f7SRuslan Bukin 					free(ppm);
234d27927f7SRuslan Bukin 				}
235d27927f7SRuslan Bukin 				/* remove process entry */
236d27927f7SRuslan Bukin 				LIST_REMOVE(pp, pp_next);
237d27927f7SRuslan Bukin 				free(pp);
238d27927f7SRuslan Bukin 				break;
239d27927f7SRuslan Bukin 			}
240d27927f7SRuslan Bukin 			return (pp);
241d27927f7SRuslan Bukin 		}
242d27927f7SRuslan Bukin 
243d27927f7SRuslan Bukin 	if (!allocate)
244d27927f7SRuslan Bukin 		return (NULL);
245d27927f7SRuslan Bukin 
246d27927f7SRuslan Bukin 	if ((pp = malloc(sizeof(*pp))) == NULL)
247d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR: Cannot allocate pid descriptor");
248d27927f7SRuslan Bukin 
249d27927f7SRuslan Bukin 	pp->pp_pid = pid;
250d27927f7SRuslan Bukin 	pp->pp_isactive = 1;
251d27927f7SRuslan Bukin 
252d27927f7SRuslan Bukin 	TAILQ_INIT(&pp->pp_map);
253d27927f7SRuslan Bukin 
254d27927f7SRuslan Bukin 	LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next);
255d27927f7SRuslan Bukin 	return (pp);
256d27927f7SRuslan Bukin }
257d27927f7SRuslan Bukin 
258d27927f7SRuslan Bukin void
pmcstat_create_process(int * pmcstat_sockpair,struct pmcstat_args * args,int pmcstat_kq)259d27927f7SRuslan Bukin pmcstat_create_process(int *pmcstat_sockpair, struct pmcstat_args *args,
260d27927f7SRuslan Bukin     int pmcstat_kq)
261d27927f7SRuslan Bukin {
262d27927f7SRuslan Bukin 	char token;
263d27927f7SRuslan Bukin 	pid_t pid;
264d27927f7SRuslan Bukin 	struct kevent kev;
265d27927f7SRuslan Bukin 	struct pmcstat_target *pt;
266d27927f7SRuslan Bukin 
267d27927f7SRuslan Bukin 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pmcstat_sockpair) < 0)
268d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR: cannot create socket pair");
269d27927f7SRuslan Bukin 
270d27927f7SRuslan Bukin 	switch (pid = fork()) {
271d27927f7SRuslan Bukin 	case -1:
272d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR: cannot fork");
273d27927f7SRuslan Bukin 		/*NOTREACHED*/
274d27927f7SRuslan Bukin 
275d27927f7SRuslan Bukin 	case 0:		/* child */
276d27927f7SRuslan Bukin 		(void) close(pmcstat_sockpair[PARENTSOCKET]);
277d27927f7SRuslan Bukin 
278d27927f7SRuslan Bukin 		/* Write a token to tell our parent we've started executing. */
279d27927f7SRuslan Bukin 		if (write(pmcstat_sockpair[CHILDSOCKET], "+", 1) != 1)
280d27927f7SRuslan Bukin 			err(EX_OSERR, "ERROR (child): cannot write token");
281d27927f7SRuslan Bukin 
282d27927f7SRuslan Bukin 		/* Wait for our parent to signal us to start. */
283d27927f7SRuslan Bukin 		if (read(pmcstat_sockpair[CHILDSOCKET], &token, 1) < 0)
284d27927f7SRuslan Bukin 			err(EX_OSERR, "ERROR (child): cannot read token");
285d27927f7SRuslan Bukin 		(void) close(pmcstat_sockpair[CHILDSOCKET]);
286d27927f7SRuslan Bukin 
287d27927f7SRuslan Bukin 		/* exec() the program requested */
288d27927f7SRuslan Bukin 		execvp(*args->pa_argv, args->pa_argv);
289d27927f7SRuslan Bukin 		/* and if that fails, notify the parent */
290d27927f7SRuslan Bukin 		kill(getppid(), SIGCHLD);
291d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR: execvp \"%s\" failed", *args->pa_argv);
292d27927f7SRuslan Bukin 		/*NOTREACHED*/
293d27927f7SRuslan Bukin 
294d27927f7SRuslan Bukin 	default:	/* parent */
295d27927f7SRuslan Bukin 		(void) close(pmcstat_sockpair[CHILDSOCKET]);
296d27927f7SRuslan Bukin 		break;
297d27927f7SRuslan Bukin 	}
298d27927f7SRuslan Bukin 
299d27927f7SRuslan Bukin 	/* Ask to be notified via a kevent when the target process exits. */
300d27927f7SRuslan Bukin 	EV_SET(&kev, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0,
301d27927f7SRuslan Bukin 	    NULL);
302d27927f7SRuslan Bukin 	if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
303d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR: cannot monitor child process %d", pid);
304d27927f7SRuslan Bukin 
305d27927f7SRuslan Bukin 	if ((pt = malloc(sizeof(*pt))) == NULL)
306d27927f7SRuslan Bukin 		errx(EX_SOFTWARE, "ERROR: Out of memory.");
307d27927f7SRuslan Bukin 
308d27927f7SRuslan Bukin 	pt->pt_pid = pid;
309d27927f7SRuslan Bukin 	SLIST_INSERT_HEAD(&args->pa_targets, pt, pt_next);
310d27927f7SRuslan Bukin 
311d27927f7SRuslan Bukin 	/* Wait for the child to signal that its ready to go. */
312d27927f7SRuslan Bukin 	if (read(pmcstat_sockpair[PARENTSOCKET], &token, 1) < 0)
313d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR (parent): cannot read token");
314d27927f7SRuslan Bukin 
315d27927f7SRuslan Bukin 	return;
316d27927f7SRuslan Bukin }
317d27927f7SRuslan Bukin 
318d27927f7SRuslan Bukin /*
319d27927f7SRuslan Bukin  * Do process profiling
320d27927f7SRuslan Bukin  *
321d27927f7SRuslan Bukin  * If a pid was specified, attach each allocated PMC to the target
322d27927f7SRuslan Bukin  * process.  Otherwise, fork a child and attach the PMCs to the child,
323d27927f7SRuslan Bukin  * and have the child exec() the target program.
324d27927f7SRuslan Bukin  */
325d27927f7SRuslan Bukin 
326d27927f7SRuslan Bukin void
pmcstat_start_process(int * pmcstat_sockpair)327d27927f7SRuslan Bukin pmcstat_start_process(int *pmcstat_sockpair)
328d27927f7SRuslan Bukin {
329d27927f7SRuslan Bukin 	/* Signal the child to proceed. */
330d27927f7SRuslan Bukin 	if (write(pmcstat_sockpair[PARENTSOCKET], "!", 1) != 1)
331d27927f7SRuslan Bukin 		err(EX_OSERR, "ERROR (parent): write of token failed");
332d27927f7SRuslan Bukin 
333d27927f7SRuslan Bukin 	(void) close(pmcstat_sockpair[PARENTSOCKET]);
334d27927f7SRuslan Bukin }
335d27927f7SRuslan Bukin 
336d27927f7SRuslan Bukin void
pmcstat_attach_pmcs(struct pmcstat_args * args)337d27927f7SRuslan Bukin pmcstat_attach_pmcs(struct pmcstat_args *args)
338d27927f7SRuslan Bukin {
339d27927f7SRuslan Bukin 	struct pmcstat_ev *ev;
340d27927f7SRuslan Bukin 	struct pmcstat_target *pt;
341d27927f7SRuslan Bukin 	int count;
342d27927f7SRuslan Bukin 
343d27927f7SRuslan Bukin 	/* Attach all process PMCs to target processes. */
344d27927f7SRuslan Bukin 	count = 0;
345d27927f7SRuslan Bukin 	STAILQ_FOREACH(ev, &args->pa_events, ev_next) {
346d27927f7SRuslan Bukin 		if (PMC_IS_SYSTEM_MODE(ev->ev_mode))
347d27927f7SRuslan Bukin 			continue;
348d27927f7SRuslan Bukin 		SLIST_FOREACH(pt, &args->pa_targets, pt_next) {
349d27927f7SRuslan Bukin 			if (pmc_attach(ev->ev_pmcid, pt->pt_pid) == 0)
350d27927f7SRuslan Bukin 				count++;
351d27927f7SRuslan Bukin 			else if (errno != ESRCH)
352d27927f7SRuslan Bukin 				err(EX_OSERR,
353d27927f7SRuslan Bukin "ERROR: cannot attach pmc \"%s\" to process %d",
354d27927f7SRuslan Bukin 				    ev->ev_name, (int)pt->pt_pid);
355d27927f7SRuslan Bukin 		}
356d27927f7SRuslan Bukin 	}
357d27927f7SRuslan Bukin 
358d27927f7SRuslan Bukin 	if (count == 0)
359d27927f7SRuslan Bukin 		errx(EX_DATAERR, "ERROR: No processes were attached to.");
360d27927f7SRuslan Bukin }
361