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