2 * Copyright (c) 2003-2008 Joseph Koshy
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
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>
36 #include <sys/module.h>
56 #include "libpmcstat.h"
59 * Associate an AOUT image with a process.
63 pmcstat_process_aout_exec(struct pmcstat_process *pp,
64 struct pmcstat_image *image, uintfptr_t entryaddr)
69 /* TODO Implement a.out handling */
73 * Associate an ELF image with a process.
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)
83 struct pmcstat_image *rtldimage;
85 assert(image->pi_type == PMCSTAT_IMAGE_ELF32 ||
86 image->pi_type == PMCSTAT_IMAGE_ELF64);
88 /* Create a map entry for the base executable. */
89 pmcstat_image_link(pp, image, image->pi_vaddr);
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
99 if (image->pi_isdynamic) {
102 * The runtime loader gets loaded just after the maximum
103 * possible heap address. Like so:
105 * [ TEXT DATA BSS HEAP -->*RTLD SHLIBS <--STACK]
107 * 0 VM_MAXUSER_ADDRESS
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.
119 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath,
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++;
128 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN)
129 pmcstat_image_get_elf_params(rtldimage, args);
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));
138 libstart = entryaddr - rtldimage->pi_entry;
139 pmcstat_image_link(pp, rtldimage, libstart);
144 * Associate an image and a process.
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)
153 struct pmcstat_image *image;
155 if ((image = pmcstat_image_from_path(path, 0,
156 args, plugins)) == NULL) {
157 pmcstat_stats->ps_exec_errors++;
161 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
162 pmcstat_image_determine_type(image, args);
164 assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN);
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);
174 case PMCSTAT_IMAGE_AOUT:
175 pmcstat_stats->ps_exec_aout++;
176 pmcstat_process_aout_exec(pp, image, entryaddr);
179 case PMCSTAT_IMAGE_INDETERMINABLE:
180 pmcstat_stats->ps_exec_indeterminable++;
185 "ERROR: Unsupported executable type for \"%s\"",
186 pmcstat_string_unintern(path));
191 * Find the map entry associated with process 'p' at PC value 'pc'.
194 struct pmcstat_pcmap *
195 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc)
197 struct pmcstat_pcmap *ppm;
199 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) {
200 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc)
202 if (pc < ppm->ppm_lowpc)
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.
218 struct pmcstat_process *
219 pmcstat_process_lookup(pid_t pid, int allocate)
222 struct pmcstat_pcmap *ppm, *ppmtmp;
223 struct pmcstat_process *pp, *pptmp;
225 hash = (uint32_t) pid & PMCSTAT_HASH_MASK; /* simplicity wins */
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) {
232 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next,
234 TAILQ_REMOVE(&pp->pp_map, ppm,
238 /* remove process entry */
239 LIST_REMOVE(pp, pp_next);
249 if ((pp = malloc(sizeof(*pp))) == NULL)
250 err(EX_OSERR, "ERROR: Cannot allocate pid descriptor");
255 TAILQ_INIT(&pp->pp_map);
257 LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next);
262 pmcstat_create_process(int *pmcstat_sockpair, struct pmcstat_args *args,
268 struct pmcstat_target *pt;
270 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pmcstat_sockpair) < 0)
271 err(EX_OSERR, "ERROR: cannot create socket pair");
273 switch (pid = fork()) {
275 err(EX_OSERR, "ERROR: cannot fork");
279 (void) close(pmcstat_sockpair[PARENTSOCKET]);
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");
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]);
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);
297 default: /* parent */
298 (void) close(pmcstat_sockpair[CHILDSOCKET]);
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,
305 if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
306 err(EX_OSERR, "ERROR: cannot monitor child process %d", pid);
308 if ((pt = malloc(sizeof(*pt))) == NULL)
309 errx(EX_SOFTWARE, "ERROR: Out of memory.");
312 SLIST_INSERT_HEAD(&args->pa_targets, pt, pt_next);
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");
322 * Do process profiling
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.
330 pmcstat_start_process(int *pmcstat_sockpair)
332 /* Signal the child to proceed. */
333 if (write(pmcstat_sockpair[PARENTSOCKET], "!", 1) != 1)
334 err(EX_OSERR, "ERROR (parent): write of token failed");
336 (void) close(pmcstat_sockpair[PARENTSOCKET]);
340 pmcstat_attach_pmcs(struct pmcstat_args *args)
342 struct pmcstat_ev *ev;
343 struct pmcstat_target *pt;
346 /* Attach all process PMCs to target processes. */
348 STAILQ_FOREACH(ev, &args->pa_events, ev_next) {
349 if (PMC_IS_SYSTEM_MODE(ev->ev_mode))
351 SLIST_FOREACH(pt, &args->pa_targets, pt_next) {
352 if (pmc_attach(ev->ev_pmcid, pt->pt_pid) == 0)
354 else if (errno != ESRCH)
356 "ERROR: cannot attach pmc \"%s\" to process %d",
357 ev->ev_name, (int)pt->pt_pid);
362 errx(EX_DATAERR, "ERROR: No processes were attached to.");