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