]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpmcstat/libpmcstat_process.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / lib / libpmcstat / libpmcstat_process.c
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
62 void
63 pmcstat_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
76 void
77 pmcstat_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
147 void
148 pmcstat_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
194 struct pmcstat_pcmap *
195 pmcstat_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
218 struct pmcstat_process *
219 pmcstat_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
261 void
262 pmcstat_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
329 void
330 pmcstat_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
339 void
340 pmcstat_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 }