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/types.h>
28 #include <sys/cpuset.h>
29 #include <sys/event.h>
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/module.h>
34 #include <sys/pmc.h>
35
36 #include <assert.h>
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <netdb.h>
43 #include <pmc.h>
44 #include <pmclog.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <sysexits.h>
51 #include <unistd.h>
52
53 #include "libpmcstat.h"
54
55 /*
56 * Associate an AOUT image with a process.
57 */
58
59 void
pmcstat_process_aout_exec(struct pmcstat_process * pp,struct pmcstat_image * image,uintptr_t baseaddr)60 pmcstat_process_aout_exec(struct pmcstat_process *pp,
61 struct pmcstat_image *image, uintptr_t baseaddr)
62 {
63 (void) pp;
64 (void) image;
65 (void) baseaddr;
66 /* TODO Implement a.out handling */
67 }
68
69 /*
70 * Associate an ELF image with a process.
71 */
72
73 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)74 pmcstat_process_elf_exec(struct pmcstat_process *pp,
75 struct pmcstat_image *image, uintptr_t baseaddr, uintptr_t dynaddr,
76 struct pmcstat_args *args, struct pmc_plugins *plugins,
77 struct pmcstat_stats *pmcstat_stats)
78 {
79 struct pmcstat_image *rtldimage;
80
81 assert(image->pi_type == PMCSTAT_IMAGE_ELF32 ||
82 image->pi_type == PMCSTAT_IMAGE_ELF64);
83
84 /*
85 * The exact address where the executable gets mapped in will vary for
86 * PIEs. The dynamic address recorded at process exec time corresponds
87 * to the address where the executable's file object had been mapped to.
88 */
89 pmcstat_image_link(pp, image, image->pi_vaddr + dynaddr);
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 * The exact address where the loader gets mapped in
110 * will vary according to the size of the executable
111 * and the limits on the size of the process'es data
112 * segment at the time of exec(). The base address
113 * recorded at process exec time corresponds to the
114 * address where the runtime loader's file object had
115 * been mapped to.
116 */
117 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath,
118 0, args, plugins);
119 if (rtldimage == NULL) {
120 warnx("WARNING: Cannot find image for \"%s\".",
121 pmcstat_string_unintern(image->pi_dynlinkerpath));
122 pmcstat_stats->ps_exec_errors++;
123 return;
124 }
125
126 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN)
127 pmcstat_image_get_elf_params(rtldimage, args);
128
129 if (rtldimage->pi_type != PMCSTAT_IMAGE_ELF32 &&
130 rtldimage->pi_type != PMCSTAT_IMAGE_ELF64) {
131 warnx("WARNING: rtld not an ELF object \"%s\".",
132 pmcstat_string_unintern(image->pi_dynlinkerpath));
133 return;
134 }
135
136 pmcstat_image_link(pp, rtldimage, baseaddr);
137 }
138 }
139
140 /*
141 * Associate an image and a process.
142 */
143
144 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)145 pmcstat_process_exec(struct pmcstat_process *pp,
146 pmcstat_interned_string path, uintptr_t baseaddr, uintptr_t dynaddr,
147 struct pmcstat_args *args, struct pmc_plugins *plugins,
148 struct pmcstat_stats *pmcstat_stats)
149 {
150 struct pmcstat_image *image;
151
152 if ((image = pmcstat_image_from_path(path, 0,
153 args, plugins)) == NULL) {
154 pmcstat_stats->ps_exec_errors++;
155 return;
156 }
157
158 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
159 pmcstat_image_determine_type(image, args);
160
161 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN);
162
163 switch (image->pi_type) {
164 case PMCSTAT_IMAGE_ELF32:
165 case PMCSTAT_IMAGE_ELF64:
166 pmcstat_stats->ps_exec_elf++;
167 pmcstat_process_elf_exec(pp, image, baseaddr, dynaddr,
168 args, plugins, pmcstat_stats);
169 break;
170
171 case PMCSTAT_IMAGE_AOUT:
172 pmcstat_stats->ps_exec_aout++;
173 pmcstat_process_aout_exec(pp, image, baseaddr);
174 break;
175
176 case PMCSTAT_IMAGE_INDETERMINABLE:
177 pmcstat_stats->ps_exec_indeterminable++;
178 break;
179
180 default:
181 err(EX_SOFTWARE,
182 "ERROR: Unsupported executable type for \"%s\"",
183 pmcstat_string_unintern(path));
184 }
185 }
186
187 /*
188 * Find the map entry associated with process 'p' at PC value 'pc'.
189 */
190
191 struct pmcstat_pcmap *
pmcstat_process_find_map(struct pmcstat_process * p,uintfptr_t pc)192 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc)
193 {
194 struct pmcstat_pcmap *ppm;
195
196 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) {
197 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc)
198 return (ppm);
199 if (pc < ppm->ppm_lowpc)
200 return (NULL);
201 }
202
203 return (NULL);
204 }
205
206 /*
207 * Find the process descriptor corresponding to a PID. If 'allocate'
208 * is zero, we return a NULL if a pid descriptor could not be found or
209 * a process descriptor process. If 'allocate' is non-zero, then we
210 * will attempt to allocate a fresh process descriptor. Zombie
211 * process descriptors are only removed if a fresh allocation for the
212 * same PID is requested.
213 */
214
215 struct pmcstat_process *
pmcstat_process_lookup(pid_t pid,int allocate)216 pmcstat_process_lookup(pid_t pid, int allocate)
217 {
218 uint32_t hash;
219 struct pmcstat_pcmap *ppm, *ppmtmp;
220 struct pmcstat_process *pp, *pptmp;
221
222 hash = (uint32_t) pid & PMCSTAT_HASH_MASK; /* simplicity wins */
223
224 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp)
225 if (pp->pp_pid == pid) {
226 /* Found a descriptor, check and process zombies */
227 if (allocate && pp->pp_isactive == 0) {
228 /* remove maps */
229 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next,
230 ppmtmp) {
231 TAILQ_REMOVE(&pp->pp_map, ppm,
232 ppm_next);
233 free(ppm);
234 }
235 /* remove process entry */
236 LIST_REMOVE(pp, pp_next);
237 free(pp);
238 break;
239 }
240 return (pp);
241 }
242
243 if (!allocate)
244 return (NULL);
245
246 if ((pp = malloc(sizeof(*pp))) == NULL)
247 err(EX_OSERR, "ERROR: Cannot allocate pid descriptor");
248
249 pp->pp_pid = pid;
250 pp->pp_isactive = 1;
251
252 TAILQ_INIT(&pp->pp_map);
253
254 LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next);
255 return (pp);
256 }
257
258 void
pmcstat_create_process(int * pmcstat_sockpair,struct pmcstat_args * args,int pmcstat_kq)259 pmcstat_create_process(int *pmcstat_sockpair, struct pmcstat_args *args,
260 int pmcstat_kq)
261 {
262 char token;
263 pid_t pid;
264 struct kevent kev;
265 struct pmcstat_target *pt;
266
267 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pmcstat_sockpair) < 0)
268 err(EX_OSERR, "ERROR: cannot create socket pair");
269
270 switch (pid = fork()) {
271 case -1:
272 err(EX_OSERR, "ERROR: cannot fork");
273 /*NOTREACHED*/
274
275 case 0: /* child */
276 (void) close(pmcstat_sockpair[PARENTSOCKET]);
277
278 /* Write a token to tell our parent we've started executing. */
279 if (write(pmcstat_sockpair[CHILDSOCKET], "+", 1) != 1)
280 err(EX_OSERR, "ERROR (child): cannot write token");
281
282 /* Wait for our parent to signal us to start. */
283 if (read(pmcstat_sockpair[CHILDSOCKET], &token, 1) < 0)
284 err(EX_OSERR, "ERROR (child): cannot read token");
285 (void) close(pmcstat_sockpair[CHILDSOCKET]);
286
287 /* exec() the program requested */
288 execvp(*args->pa_argv, args->pa_argv);
289 /* and if that fails, notify the parent */
290 kill(getppid(), SIGCHLD);
291 err(EX_OSERR, "ERROR: execvp \"%s\" failed", *args->pa_argv);
292 /*NOTREACHED*/
293
294 default: /* parent */
295 (void) close(pmcstat_sockpair[CHILDSOCKET]);
296 break;
297 }
298
299 /* Ask to be notified via a kevent when the target process exits. */
300 EV_SET(&kev, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0,
301 NULL);
302 if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
303 err(EX_OSERR, "ERROR: cannot monitor child process %d", pid);
304
305 if ((pt = malloc(sizeof(*pt))) == NULL)
306 errx(EX_SOFTWARE, "ERROR: Out of memory.");
307
308 pt->pt_pid = pid;
309 SLIST_INSERT_HEAD(&args->pa_targets, pt, pt_next);
310
311 /* Wait for the child to signal that its ready to go. */
312 if (read(pmcstat_sockpair[PARENTSOCKET], &token, 1) < 0)
313 err(EX_OSERR, "ERROR (parent): cannot read token");
314
315 return;
316 }
317
318 /*
319 * Do process profiling
320 *
321 * If a pid was specified, attach each allocated PMC to the target
322 * process. Otherwise, fork a child and attach the PMCs to the child,
323 * and have the child exec() the target program.
324 */
325
326 void
pmcstat_start_process(int * pmcstat_sockpair)327 pmcstat_start_process(int *pmcstat_sockpair)
328 {
329 /* Signal the child to proceed. */
330 if (write(pmcstat_sockpair[PARENTSOCKET], "!", 1) != 1)
331 err(EX_OSERR, "ERROR (parent): write of token failed");
332
333 (void) close(pmcstat_sockpair[PARENTSOCKET]);
334 }
335
336 void
pmcstat_attach_pmcs(struct pmcstat_args * args)337 pmcstat_attach_pmcs(struct pmcstat_args *args)
338 {
339 struct pmcstat_ev *ev;
340 struct pmcstat_target *pt;
341 int count;
342
343 /* Attach all process PMCs to target processes. */
344 count = 0;
345 STAILQ_FOREACH(ev, &args->pa_events, ev_next) {
346 if (PMC_IS_SYSTEM_MODE(ev->ev_mode))
347 continue;
348 SLIST_FOREACH(pt, &args->pa_targets, pt_next) {
349 if (pmc_attach(ev->ev_pmcid, pt->pt_pid) == 0)
350 count++;
351 else if (errno != ESRCH)
352 err(EX_OSERR,
353 "ERROR: cannot attach pmc \"%s\" to process %d",
354 ev->ev_name, (int)pt->pt_pid);
355 }
356 }
357
358 if (count == 0)
359 errx(EX_DATAERR, "ERROR: No processes were attached to.");
360 }
361