1 /*- 2 * Copyright (c) 2005, 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 /* 31 * Transform a hwpmc(4) log into human readable form and into gprof(1) 32 * compatible profiles. 33 * 34 * Each executable object encountered in the log gets one 'gmon.out' 35 * profile per PMC. We currently track: 36 * - program executables 37 * - shared libraries loaded by the runtime loader 38 * - the runtime loader itself 39 * - the kernel. 40 * We do not track shared objects mapped in by dlopen() yet (this 41 * needs additional support from hwpmc(4)). 42 * 43 * 'gmon.out' profiles generated for a given sampling PMC are 44 * aggregates of all the samples for that particular executable 45 * object. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/endian.h> 50 #include <sys/gmon.h> 51 #include <sys/imgact_aout.h> 52 #include <sys/imgact_elf.h> 53 #include <sys/mman.h> 54 #include <sys/pmc.h> 55 #include <sys/queue.h> 56 #include <sys/stat.h> 57 #include <sys/wait.h> 58 59 #include <netinet/in.h> 60 61 #include <assert.h> 62 #include <err.h> 63 #include <fcntl.h> 64 #include <libgen.h> 65 #include <limits.h> 66 #include <pmc.h> 67 #include <pmclog.h> 68 #include <sysexits.h> 69 #include <stdint.h> 70 #include <stdio.h> 71 #include <stdlib.h> 72 #include <string.h> 73 #include <unistd.h> 74 75 #include "pmcstat.h" 76 77 #define min(A,B) ((A) < (B) ? (A) : (B)) 78 #define max(A,B) ((A) > (B) ? (A) : (B)) 79 80 /* 81 * A simple implementation of interned strings. Each interned string 82 * is assigned a unique address, so that subsequent string compares 83 * can be done by a simple pointer comparision instead of with 84 * strcmp(). 85 */ 86 struct pmcstat_string { 87 LIST_ENTRY(pmcstat_string) ps_next; /* hash link */ 88 int ps_len; 89 int ps_hash; 90 const char *ps_string; 91 }; 92 93 static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; 94 95 /* 96 * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable 97 * names. 98 */ 99 100 struct pmcstat_pmcrecord { 101 LIST_ENTRY(pmcstat_pmcrecord) pr_next; 102 pmc_id_t pr_pmcid; 103 const char *pr_pmcname; 104 }; 105 106 static LIST_HEAD(,pmcstat_pmcrecord) pmcstat_pmcs = 107 LIST_HEAD_INITIALIZER(&pmcstat_pmcs); 108 109 110 /* 111 * struct pmcstat_gmonfile tracks a given 'gmon.out' file. These 112 * files are mmap()'ed in as needed. 113 */ 114 115 struct pmcstat_gmonfile { 116 LIST_ENTRY(pmcstat_gmonfile) pgf_next; /* list of entries */ 117 pmc_id_t pgf_pmcid; /* id of the associated pmc */ 118 size_t pgf_nbuckets; /* #buckets in this gmon.out */ 119 const char *pgf_name; /* pathname of gmon.out file */ 120 size_t pgf_ndatabytes; /* number of bytes mapped */ 121 void *pgf_gmondata; /* pointer to mmap'ed data */ 122 }; 123 124 static TAILQ_HEAD(,pmcstat_gmonfile) pmcstat_gmonfiles = 125 TAILQ_HEAD_INITIALIZER(pmcstat_gmonfiles); 126 127 /* 128 * A 'pmcstat_image' structure describes an executable program on 129 * disk. 'pi_internedpath' is a cookie representing the pathname of 130 * the executable. 'pi_start' and 'pi_end' are the least and greatest 131 * virtual addresses for the text segments in the executable. 132 * 'pi_gmonlist' contains a linked list of gmon.out files associated 133 * with this image. 134 */ 135 136 enum pmcstat_image_type { 137 PMCSTAT_IMAGE_UNKNOWN = 0, 138 PMCSTAT_IMAGE_ELF, 139 PMCSTAT_IMAGE_AOUT 140 }; 141 142 struct pmcstat_image { 143 LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ 144 TAILQ_ENTRY(pmcstat_image) pi_lru; /* LRU list */ 145 const char *pi_internedpath; /* cookie */ 146 const char *pi_samplename; /* sample path name */ 147 148 enum pmcstat_image_type pi_type; /* executable type */ 149 uintfptr_t pi_start; /* start address (inclusive) */ 150 uintfptr_t pi_end; /* end address (exclusive) */ 151 uintfptr_t pi_entry; /* entry address */ 152 int pi_isdynamic; /* whether a dynamic object */ 153 const char *pi_dynlinkerpath; /* path in .interp section */ 154 155 LIST_HEAD(,pmcstat_gmonfile) pi_gmlist; 156 }; 157 158 static LIST_HEAD(,pmcstat_image) pmcstat_image_hash[PMCSTAT_NHASH]; 159 static TAILQ_HEAD(,pmcstat_image) pmcstat_image_lru = 160 TAILQ_HEAD_INITIALIZER(pmcstat_image_lru); 161 162 struct pmcstat_pcmap { 163 TAILQ_ENTRY(pmcstat_pcmap) ppm_next; 164 uintfptr_t ppm_lowpc; 165 uintfptr_t ppm_highpc; 166 struct pmcstat_image *ppm_image; 167 }; 168 169 /* 170 * A 'pmcstat_process' structure tracks processes. 171 */ 172 173 struct pmcstat_process { 174 LIST_ENTRY(pmcstat_process) pp_next; /* hash-next */ 175 pid_t pp_pid; /* associated pid */ 176 int pp_isactive; /* whether active */ 177 uintfptr_t pp_entryaddr; /* entry address */ 178 TAILQ_HEAD(,pmcstat_pcmap) pp_map; /* address range map */ 179 }; 180 181 static LIST_HEAD(,pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH]; 182 183 static struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ 184 185 /* 186 * Prototypes 187 */ 188 189 static void pmcstat_gmon_create_file(struct pmcstat_gmonfile *_pgf, 190 struct pmcstat_image *_image); 191 static const char *pmcstat_gmon_create_name(const char *_sd, 192 struct pmcstat_image *_img, pmc_id_t _pmcid); 193 static void pmcstat_gmon_map_file(struct pmcstat_gmonfile *_pgf); 194 static void pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *_pgf); 195 196 static struct pmcstat_image *pmcstat_image_from_path(const char *_path); 197 static enum pmcstat_image_type pmcstat_image_get_type(const char *_p); 198 static void pmcstat_image_get_elf_params(struct pmcstat_image *_image); 199 static void pmcstat_image_increment_bucket(struct pmcstat_pcmap *_pcm, 200 uintfptr_t _pc, pmc_id_t _pmcid, struct pmcstat_args *_a); 201 static void pmcstat_image_link(struct pmcstat_process *_pp, 202 struct pmcstat_image *_i, uintfptr_t _lpc, uintfptr_t _hpc); 203 204 static void pmcstat_pmcid_add(pmc_id_t _pmcid, const char *_name, 205 struct pmcstat_args *_a); 206 static const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid); 207 208 static void pmcstat_process_add_elf_image(struct pmcstat_process *_pp, 209 const char *_path, uintfptr_t _entryaddr); 210 static void pmcstat_process_exec(struct pmcstat_process *_pp, 211 const char *_path, uintfptr_t _entryaddr); 212 static struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, int _allocate); 213 static struct pmcstat_pcmap *pmcstat_process_find_map( 214 struct pmcstat_process *_p, uintfptr_t _pc); 215 216 static int pmcstat_string_compute_hash(const char *_string); 217 static const char *pmcstat_string_intern(const char *_s); 218 static struct pmcstat_string *pmcstat_string_lookup(const char *_s); 219 220 221 /* 222 * Create a gmon.out file and size it. 223 */ 224 225 static void 226 pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf, 227 struct pmcstat_image *image) 228 { 229 int fd; 230 size_t count; 231 struct gmonhdr gm; 232 char buffer[DEFAULT_BUFFER_SIZE]; 233 234 if ((fd = open(pgf->pgf_name, O_RDWR|O_NOFOLLOW|O_CREAT, 235 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) 236 err(EX_OSERR, "ERROR: Cannot open \"%s\"", pgf->pgf_name); 237 238 gm.lpc = image->pi_start; 239 gm.hpc = image->pi_end; 240 gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) + 241 sizeof(struct gmonhdr); 242 gm.version = GMONVERSION; 243 gm.profrate = 0; /* use ticks */ 244 gm.histcounter_type = 0; /* compatibility with moncontrol() */ 245 gm.spare[0] = gm.spare[1] = 0; 246 247 /* Write out the gmon header */ 248 if (write(fd, &gm, sizeof(gm)) < 0) 249 goto error; 250 251 /* Zero fill the samples[] array */ 252 (void) memset(buffer, 0, sizeof(buffer)); 253 254 count = pgf->pgf_ndatabytes - sizeof(struct gmonhdr); 255 while (count > sizeof(buffer)) { 256 if (write(fd, &buffer, sizeof(buffer)) < 0) 257 goto error; 258 count -= sizeof(buffer); 259 } 260 261 if (write(fd, &buffer, count) < 0) 262 goto error; 263 264 (void) close(fd); 265 266 return; 267 268 error: 269 err(EX_OSERR, "ERROR: Cannot write \"%s\"", pgf->pgf_name); 270 } 271 272 const char * 273 pmcstat_gmon_create_name(const char *samplesdir, struct pmcstat_image *image, 274 pmc_id_t pmcid) 275 { 276 const char *pmcname; 277 char fullpath[PATH_MAX]; 278 279 pmcname = pmcstat_pmcid_to_name(pmcid); 280 281 (void) snprintf(fullpath, sizeof(fullpath), 282 "%s/%s/%s", samplesdir, pmcname, image->pi_samplename); 283 284 return pmcstat_string_intern(fullpath); 285 } 286 287 288 static void 289 pmcstat_gmon_map_file(struct pmcstat_gmonfile *pgf) 290 { 291 int fd; 292 293 /* the gmon.out file must already exist */ 294 if ((fd = open(pgf->pgf_name, O_RDWR | O_NOFOLLOW, 0)) < 0) 295 err(EX_OSERR, "ERROR: cannot open \"%s\"", 296 pgf->pgf_name); 297 298 pgf->pgf_gmondata = mmap(NULL, pgf->pgf_ndatabytes, 299 PROT_READ|PROT_WRITE, MAP_NOSYNC|MAP_SHARED, fd, 0); 300 301 if (pgf->pgf_gmondata == MAP_FAILED) 302 /* XXX unmap a few files and try again? */ 303 err(EX_OSERR, "ERROR: cannot map \"%s\"", pgf->pgf_name); 304 305 (void) close(fd); 306 } 307 308 /* 309 * Unmap the data mapped from a gmon.out file. 310 */ 311 312 static void 313 pmcstat_gmon_unmap_file(struct pmcstat_gmonfile *pgf) 314 { 315 (void) msync(pgf->pgf_gmondata, pgf->pgf_ndatabytes, 316 MS_SYNC); 317 (void) munmap(pgf->pgf_gmondata, pgf->pgf_ndatabytes); 318 pgf->pgf_gmondata = NULL; 319 } 320 321 static void 322 pmcstat_image_get_elf_params(struct pmcstat_image *image) 323 { 324 int fd, i; 325 struct stat st; 326 void *mapbase; 327 uintfptr_t minva, maxva; 328 const Elf_Ehdr *h; 329 const Elf_Phdr *ph; 330 const Elf_Shdr *sh; 331 #if defined(__amd64__) 332 const Elf32_Ehdr *h32; 333 const Elf32_Phdr *ph32; 334 const Elf32_Shdr *sh32; 335 #endif 336 const char *path; 337 338 assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN); 339 340 minva = ~(uintfptr_t) 0; 341 maxva = (uintfptr_t) 0; 342 path = image->pi_internedpath; 343 344 if ((fd = open(path, O_RDONLY, 0)) < 0) 345 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); 346 347 if (fstat(fd, &st) < 0) 348 err(EX_OSERR, "ERROR: Cannot stat \"%s\"", path); 349 350 if ((mapbase = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == 351 MAP_FAILED) 352 err(EX_OSERR, "ERROR: Cannot mmap \"%s\"", path); 353 354 (void) close(fd); 355 356 h = (const Elf_Ehdr *) mapbase; 357 if (!IS_ELF(*h)) 358 err(EX_SOFTWARE, "ERROR: \"%s\" not an ELF file", path); 359 360 /* we only handle executable objects */ 361 if (h->e_type != ET_EXEC && h->e_type != ET_DYN) 362 err(EX_DATAERR, "ERROR: Unknown file type for \"%s\"", 363 image->pi_internedpath); 364 365 #define GET_VA(H, SH, MINVA, MAXVA) do { \ 366 for (i = 0; i < (H)->e_shnum; i++) \ 367 if ((SH)[i].sh_flags & SHF_EXECINSTR) { \ 368 (MINVA) = min((MINVA),(SH)[i].sh_addr); \ 369 (MAXVA) = max((MAXVA),(SH)[i].sh_addr + \ 370 (SH)[i].sh_size); \ 371 } \ 372 } while (0) 373 374 375 #define GET_PHDR_INFO(H, PH, IMAGE) do { \ 376 for (i = 0; i < (H)->e_phnum; i++) { \ 377 switch ((PH)[i].p_type) { \ 378 case PT_DYNAMIC: \ 379 image->pi_isdynamic = 1; \ 380 break; \ 381 case PT_INTERP: \ 382 image->pi_dynlinkerpath = \ 383 pmcstat_string_intern( \ 384 (char *) mapbase + \ 385 (PH)[i].p_offset); \ 386 break; \ 387 } \ 388 } \ 389 } while (0) 390 391 image->pi_type = PMCSTAT_IMAGE_ELF; 392 image->pi_isdynamic = 0; 393 image->pi_dynlinkerpath = NULL; 394 395 switch (h->e_machine) { 396 case EM_386: 397 case EM_486: 398 #if defined(__amd64__) 399 /* a 32 bit executable */ 400 h32 = (const Elf32_Ehdr *) h; 401 sh32 = (const Elf32_Shdr *)((uintptr_t) mapbase + h32->e_shoff); 402 403 GET_VA(h32, sh32, minva, maxva); 404 405 image->pi_entry = h32->e_entry; 406 407 if (h32->e_type == ET_EXEC) { 408 ph32 = (const Elf32_Phdr *)((uintptr_t) mapbase + 409 h32->e_phoff); 410 GET_PHDR_INFO(h32, ph32, image); 411 } 412 break; 413 #endif 414 default: 415 sh = (const Elf_Shdr *)((uintptr_t) mapbase + h->e_shoff); 416 417 GET_VA(h, sh, minva, maxva); 418 419 image->pi_entry = h->e_entry; 420 421 if (h->e_type == ET_EXEC) { 422 ph = (const Elf_Phdr *)((uintptr_t) mapbase + 423 h->e_phoff); 424 GET_PHDR_INFO(h, ph, image); 425 } 426 break; 427 } 428 429 #undef GET_PHDR_INFO 430 #undef GET_VA 431 432 image->pi_start = minva; 433 image->pi_end = maxva; 434 435 if (munmap(mapbase, st.st_size) < 0) 436 err(EX_OSERR, "ERROR: Cannot unmap \"%s\"", path); 437 438 } 439 440 /* 441 * Locate an image descriptor given an interned path, adding a fresh 442 * descriptor to the cache if necessary. This function also finds a 443 * suitable name for this image's sample file. 444 */ 445 446 static struct pmcstat_image * 447 pmcstat_image_from_path(const char *internedpath) 448 { 449 int count, hash, nlen; 450 struct pmcstat_image *pi; 451 char *sn; 452 char name[NAME_MAX]; 453 454 hash = pmcstat_string_compute_hash(internedpath); 455 456 /* Look for an existing entry. */ 457 LIST_FOREACH(pi, &pmcstat_image_hash[hash], pi_next) 458 if (pi->pi_internedpath == internedpath) { 459 /* move descriptor to the head of the lru list */ 460 TAILQ_REMOVE(&pmcstat_image_lru, pi, pi_lru); 461 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 462 return pi; 463 } 464 465 /* 466 * Allocate a new entry and place at the head of the hash and 467 * LRU lists. 468 */ 469 pi = malloc(sizeof(*pi)); 470 if (pi == NULL) 471 return NULL; 472 473 pi->pi_type = PMCSTAT_IMAGE_UNKNOWN; 474 pi->pi_internedpath = internedpath; 475 pi->pi_start = ~0; 476 pi->pi_entry = ~0; 477 pi->pi_end = 0; 478 479 /* 480 * Look for a suitable name for the sample files associated 481 * with this image: if `basename(path)`+".gmon" is available, 482 * we use that, otherwise we try iterating through 483 * `basename(path)`+ "~" + NNN + ".gmon" till we get a free 484 * entry. 485 */ 486 if ((sn = basename(internedpath)) == NULL) 487 err(EX_OSERR, "ERROR: Cannot process \"%s\"", internedpath); 488 489 nlen = strlen(sn); 490 nlen = min(nlen, (int) sizeof(name) - 6); /* ".gmon\0" */ 491 492 snprintf(name, sizeof(name), "%.*s.gmon", nlen, sn); 493 494 if (pmcstat_string_lookup(name) == NULL) 495 pi->pi_samplename = pmcstat_string_intern(name); 496 else { 497 nlen = strlen(sn); 498 nlen = min(nlen, (int) sizeof(name)-10); /* "~ddd.gmon\0" */ 499 count = 0; 500 do { 501 count++; 502 snprintf(name, sizeof(name), "%.*s~%3.3d", 503 nlen, sn, count); 504 if (pmcstat_string_lookup(name) == NULL) { 505 pi->pi_samplename = pmcstat_string_intern(name); 506 count = 0; 507 } 508 } while (count > 0); 509 } 510 511 LIST_INIT(&pi->pi_gmlist); 512 513 LIST_INSERT_HEAD(&pmcstat_image_hash[hash], pi, pi_next); 514 TAILQ_INSERT_HEAD(&pmcstat_image_lru, pi, pi_lru); 515 516 return pi; 517 } 518 519 /* 520 * Given an open file, determine its file type. 521 */ 522 523 static enum pmcstat_image_type 524 pmcstat_image_get_type(const char *path) 525 { 526 int fd; 527 Elf_Ehdr eh; 528 struct exec ex; 529 ssize_t nbytes; 530 char buffer[DEFAULT_BUFFER_SIZE]; 531 532 if ((fd = open(path, O_RDONLY)) < 0) 533 err(EX_OSERR, "ERROR: Cannot open \"%s\"", path); 534 535 nbytes = max(sizeof(eh), sizeof(ex)); 536 if ((nbytes = pread(fd, buffer, nbytes, 0)) < 0) 537 err(EX_OSERR, "ERROR: Cannot read \"%s\"", path); 538 539 (void) close(fd); 540 541 /* check if its an ELF file */ 542 if ((unsigned) nbytes >= sizeof(Elf_Ehdr)) { 543 bcopy(buffer, &eh, sizeof(eh)); 544 if (IS_ELF(eh)) 545 return PMCSTAT_IMAGE_ELF; 546 } 547 548 /* Look for an A.OUT header */ 549 if ((unsigned) nbytes >= sizeof(struct exec)) { 550 bcopy(buffer, &ex, sizeof(ex)); 551 if (!N_BADMAG(ex)) 552 return PMCSTAT_IMAGE_AOUT; 553 } 554 555 return PMCSTAT_IMAGE_UNKNOWN; 556 } 557 558 /* 559 * Increment the bucket in the gmon.out file corresponding to 'pmcid' 560 * and 'pc'. 561 */ 562 563 static void 564 pmcstat_image_increment_bucket(struct pmcstat_pcmap *map, uintfptr_t pc, 565 pmc_id_t pmcid, struct pmcstat_args *a) 566 { 567 struct pmcstat_image *image; 568 struct pmcstat_gmonfile *pgf; 569 uintfptr_t bucket; 570 HISTCOUNTER *hc; 571 572 assert(pc >= map->ppm_lowpc && pc < map->ppm_highpc); 573 574 /* 575 * Find the gmon file corresponding to 'pmcid', creating it if 576 * needed. 577 */ 578 579 image = map->ppm_image; 580 581 LIST_FOREACH(pgf, &image->pi_gmlist, pgf_next) 582 if (pgf->pgf_pmcid == pmcid) 583 break; 584 585 /* If we don't have a gmon.out file for this PMCid, create one */ 586 if (pgf == NULL) { 587 if ((pgf = calloc(1, sizeof(*pgf))) == NULL) 588 err(EX_OSERR, "ERROR:"); 589 590 pgf->pgf_gmondata = NULL; /* mark as unmapped */ 591 pgf->pgf_name = pmcstat_gmon_create_name(a->pa_samplesdir, 592 image, pmcid); 593 pgf->pgf_pmcid = pmcid; 594 assert(image->pi_end > image->pi_start); 595 pgf->pgf_nbuckets = (image->pi_end - image->pi_start) / 596 FUNCTION_ALIGNMENT; /* see <machine/profile.h> */ 597 pgf->pgf_ndatabytes = sizeof(struct gmonhdr) + 598 pgf->pgf_nbuckets * sizeof(HISTCOUNTER); 599 600 pmcstat_gmon_create_file(pgf, image); 601 602 LIST_INSERT_HEAD(&image->pi_gmlist, pgf, pgf_next); 603 } 604 605 /* 606 * Map the gmon file in if needed. It may have been mapped 607 * out under memory pressure. 608 */ 609 if (pgf->pgf_gmondata == NULL) 610 pmcstat_gmon_map_file(pgf); 611 612 bucket = (pc - map->ppm_lowpc) / FUNCTION_ALIGNMENT; 613 614 assert(bucket < pgf->pgf_nbuckets); 615 616 hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata + 617 sizeof(struct gmonhdr)); 618 619 /* saturating add */ 620 if (hc[bucket] < 0xFFFF) 621 hc[bucket]++; 622 623 } 624 625 /* 626 * Record the fact that PC values from 'lowpc' to 'highpc' come from 627 * image 'image'. 628 */ 629 630 static void 631 pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image, 632 uintfptr_t lowpc, uintfptr_t highpc) 633 { 634 struct pmcstat_pcmap *pcm, *pcmnew; 635 636 if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) 637 err(EX_OSERR, "ERROR: "); 638 639 pcmnew->ppm_lowpc = lowpc; 640 pcmnew->ppm_highpc = highpc; 641 pcmnew->ppm_image = image; 642 643 TAILQ_FOREACH(pcm, &pp->pp_map, ppm_next) 644 if (pcm->ppm_lowpc < lowpc) 645 break; 646 647 if (pcm == NULL) 648 TAILQ_INSERT_TAIL(&pp->pp_map, pcmnew, ppm_next); 649 else 650 TAILQ_INSERT_BEFORE(pcm, pcmnew, ppm_next); 651 } 652 653 /* 654 * Add a {pmcid,name} mapping. 655 */ 656 657 static void 658 pmcstat_pmcid_add(pmc_id_t pmcid, const char *name, struct pmcstat_args *a) 659 { 660 struct pmcstat_pmcrecord *pr; 661 struct stat st; 662 char fullpath[PATH_MAX]; 663 664 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 665 if (pr->pr_pmcid == pmcid) { 666 pr->pr_pmcname = name; 667 return; 668 } 669 670 if ((pr = malloc(sizeof(*pr))) == NULL) 671 err(EX_OSERR, "ERROR: Cannot allocate pmc record"); 672 673 pr->pr_pmcid = pmcid; 674 pr->pr_pmcname = name; 675 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 676 677 (void) snprintf(fullpath, sizeof(fullpath), "%s/%s", a->pa_samplesdir, 678 name); 679 680 /* If the path name exists, it should be a directory */ 681 if (stat(fullpath, &st) == 0 && S_ISDIR(st.st_mode)) 682 return; 683 684 if (mkdir(fullpath, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) 685 err(EX_OSERR, "ERROR: Cannot create directory \"%s\"", 686 fullpath); 687 } 688 689 /* 690 * Given a pmcid in use, find its human-readable name, or a 691 */ 692 693 static const char * 694 pmcstat_pmcid_to_name(pmc_id_t pmcid) 695 { 696 struct pmcstat_pmcrecord *pr; 697 char fullpath[PATH_MAX]; 698 699 LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) 700 if (pr->pr_pmcid == pmcid) 701 return pr->pr_pmcname; 702 703 /* create a default name and add this entry */ 704 if ((pr = malloc(sizeof(*pr))) == NULL) 705 err(EX_OSERR, "ERROR: "); 706 pr->pr_pmcid = pmcid; 707 708 (void) snprintf(fullpath, sizeof(fullpath), "%X", (unsigned int) pmcid); 709 pr->pr_pmcname = pmcstat_string_intern(fullpath); 710 711 LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); 712 713 return pr->pr_pmcname; 714 } 715 716 /* 717 * Associate an ELF image with a process. Argument 'path' names the 718 * executable while 'fd' is an already open descriptor to it. 719 */ 720 721 static void 722 pmcstat_process_add_elf_image(struct pmcstat_process *pp, const char *path, 723 uintfptr_t entryaddr) 724 { 725 size_t linelen; 726 FILE *rf; 727 char *line; 728 uintmax_t libstart; 729 struct pmcstat_image *image, *rtldimage; 730 char libpath[PATH_MAX]; 731 char command[PATH_MAX + sizeof(PMCSTAT_LDD_COMMAND) + 1]; 732 733 /* Look up path in the cache. */ 734 if ((image = pmcstat_image_from_path(path)) == NULL) 735 return; 736 737 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 738 pmcstat_image_get_elf_params(image); 739 740 /* Create a map entry for the base executable. */ 741 pmcstat_image_link(pp, image, image->pi_start, image->pi_end); 742 743 /* 744 * For dynamically linked executables we need to: 745 * (a) find where the dynamic linker was mapped to for this 746 * process, 747 * (b) find all the executable objects that the dynamic linker 748 * brought in. 749 */ 750 if (image->pi_isdynamic) { 751 752 /* 753 * The runtime loader gets loaded just after the maximum 754 * possible heap address. Like so: 755 * 756 * [ TEXT DATA BSS HEAP -->*RTLD SHLIBS <--STACK] 757 * ^ ^ 758 * 0 VM_MAXUSER_ADDRESS 759 * 760 * The exact address where the loader gets mapped in 761 * will vary according to the size of the executable 762 * and the limits on the size of the process'es data 763 * segment at the time of exec(). The entry address 764 * recorded at process exec time corresponds to the 765 * 'start' address inside the dynamic linker. From 766 * this we can figure out the address where the 767 * runtime loader's file object had been mapped to. 768 */ 769 rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath); 770 if (rtldimage == NULL) 771 err(EX_OSERR, "ERROR: Cannot find image for " 772 "\"%s\"", image->pi_dynlinkerpath); 773 if (rtldimage->pi_type == PMCSTAT_IMAGE_UNKNOWN) 774 pmcstat_image_get_elf_params(rtldimage); 775 776 libstart = entryaddr - rtldimage->pi_entry; 777 pmcstat_image_link(pp, rtldimage, libstart, 778 libstart + rtldimage->pi_end - rtldimage->pi_start); 779 780 /* Process all other objects loaded by this executable. */ 781 (void) snprintf(command, sizeof(command), "%s %s", 782 PMCSTAT_LDD_COMMAND, path); 783 784 if ((rf = popen(command, "r")) == NULL) 785 err(EX_OSERR, "ERROR: Cannot create pipe"); 786 787 (void) fgetln(rf, &linelen); 788 789 while (!feof(rf) && !ferror(rf)) { 790 791 if ((line = fgetln(rf, &linelen)) == NULL) 792 continue; 793 line[linelen-1] = '\0'; 794 795 if (sscanf(line, "%s %jx", 796 libpath, &libstart) != 2) 797 continue; 798 799 image = pmcstat_image_from_path( 800 pmcstat_string_intern(libpath)); 801 if (image == NULL) 802 err(EX_OSERR, "ERROR: Cannot process " 803 "\"%s\"", libpath); 804 805 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 806 pmcstat_image_get_elf_params(image); 807 808 pmcstat_image_link(pp, image, libstart + image->pi_start, 809 libstart + image->pi_end); 810 } 811 812 (void) pclose(rf); 813 814 } 815 } 816 817 /* 818 * Find the process descriptor corresponding to a PID. If 'allocate' 819 * is zero, we return a NULL if a pid descriptor could not be found or 820 * a process descriptor process. If 'allocate' is non-zero, then we 821 * will attempt to allocate a fresh process descriptor. Zombie 822 * process descriptors are only removed if a fresh allocation for the 823 * same PID is requested. 824 */ 825 826 static struct pmcstat_process * 827 pmcstat_process_lookup(pid_t pid, int allocate) 828 { 829 uint32_t hash; 830 struct pmcstat_pcmap *ppm, *ppmtmp; 831 struct pmcstat_process *pp, *pptmp; 832 833 hash = (uint32_t) pid & PMCSTAT_HASH_MASK; /* simplicity wins */ 834 835 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[hash], pp_next, pptmp) 836 if (pp->pp_pid == pid) { 837 /* Found a descriptor, check and process zombies */ 838 if (allocate && !pp->pp_isactive) { 839 /* remove maps */ 840 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, 841 ppmtmp) { 842 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 843 free(ppm); 844 } 845 /* remove process entry */ 846 LIST_REMOVE(pp, pp_next); 847 free(pp); 848 break; 849 } 850 return pp; 851 } 852 853 if (!allocate) 854 return NULL; 855 856 if ((pp = malloc(sizeof(*pp))) == NULL) 857 err(EX_OSERR, "ERROR: Cannot allocate pid descriptor"); 858 859 pp->pp_pid = pid; 860 pp->pp_isactive = 1; 861 862 TAILQ_INIT(&pp->pp_map); 863 864 LIST_INSERT_HEAD(&pmcstat_process_hash[hash], pp, pp_next); 865 return pp; 866 } 867 868 /* 869 * Associate an image and a process. 870 */ 871 872 static void 873 pmcstat_process_exec(struct pmcstat_process *pp, const char *path, 874 uintfptr_t entryaddr) 875 { 876 enum pmcstat_image_type filetype; 877 struct pmcstat_image *image; 878 879 if ((image = pmcstat_image_from_path(path)) == NULL) 880 return; 881 882 if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) 883 filetype = pmcstat_image_get_type(path); 884 else 885 filetype = image->pi_type; 886 887 switch (filetype) { 888 case PMCSTAT_IMAGE_ELF: 889 pmcstat_process_add_elf_image(pp, path, entryaddr); 890 break; 891 892 case PMCSTAT_IMAGE_AOUT: 893 break; 894 895 default: 896 err(EX_SOFTWARE, "ERROR: Unsupported executable type for " 897 "\"%s\"", path); 898 } 899 } 900 901 902 /* 903 * Find the map entry associated with process 'p' at PC value 'pc'. 904 */ 905 906 static struct pmcstat_pcmap * 907 pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc) 908 { 909 struct pmcstat_pcmap *ppm; 910 911 TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) 912 if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc) 913 return ppm; 914 915 return NULL; 916 } 917 918 919 /* 920 * Compute a 'hash' value for a string. 921 */ 922 923 static int 924 pmcstat_string_compute_hash(const char *s) 925 { 926 int hash; 927 928 for (hash = 0; *s; s++) 929 hash ^= *s; 930 931 return hash & PMCSTAT_HASH_MASK; 932 } 933 934 /* 935 * Intern a copy of string 's', and return a pointer to it. 936 */ 937 938 static const char * 939 pmcstat_string_intern(const char *s) 940 { 941 struct pmcstat_string *ps; 942 int hash, len; 943 944 hash = pmcstat_string_compute_hash(s); 945 len = strlen(s); 946 947 if ((ps = pmcstat_string_lookup(s)) != NULL) 948 return ps->ps_string; 949 950 if ((ps = malloc(sizeof(*ps))) == NULL) 951 err(EX_OSERR, "ERROR: Could not intern string"); 952 ps->ps_len = len; 953 ps->ps_hash = hash; 954 ps->ps_string = strdup(s); 955 LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); 956 return ps->ps_string; 957 } 958 959 static struct pmcstat_string * 960 pmcstat_string_lookup(const char *s) 961 { 962 struct pmcstat_string *ps; 963 int hash, len; 964 965 hash = pmcstat_string_compute_hash(s); 966 len = strlen(s); 967 968 LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next) 969 if (ps->ps_len == len && ps->ps_hash == hash && 970 strcmp(ps->ps_string, s) == 0) 971 return ps; 972 return NULL; 973 } 974 975 /* 976 * Public Interfaces. 977 */ 978 979 /* 980 * Close a logfile, after first flushing all in-module queued data. 981 */ 982 983 int 984 pmcstat_close_log(struct pmcstat_args *a) 985 { 986 if (pmc_flush_logfile() < 0 || 987 pmc_configure_logfile(-1) < 0) 988 err(EX_OSERR, "ERROR: logging failed"); 989 a->pa_flags &= ~(FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE); 990 return a->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : 991 PMCSTAT_FINISHED; 992 } 993 994 995 int 996 pmcstat_convert_log(struct pmcstat_args *a) 997 { 998 uintfptr_t pc; 999 struct pmcstat_process *pp, *ppnew; 1000 struct pmcstat_pcmap *ppm, *ppmtmp; 1001 struct pmclog_ev ev; 1002 const char *image_path; 1003 1004 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1005 assert(ev.pl_state == PMCLOG_OK); 1006 1007 switch (ev.pl_type) { 1008 case PMCLOG_TYPE_MAPPINGCHANGE: 1009 /* 1010 * Introduce an address range mapping for a 1011 * process. 1012 */ 1013 break; 1014 1015 case PMCLOG_TYPE_PCSAMPLE: 1016 1017 /* 1018 * We bring in the gmon file for the image 1019 * currently associated with the PMC & pid 1020 * pair and increment the appropriate entry 1021 * bin inside this. 1022 */ 1023 pc = ev.pl_u.pl_s.pl_pc; 1024 pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, 1); 1025 if ((ppm = pmcstat_process_find_map(pp, pc)) == NULL && 1026 (ppm = pmcstat_process_find_map(pmcstat_kernproc, 1027 pc)) == NULL) 1028 break; /* unknown process,offset pair */ 1029 1030 pmcstat_image_increment_bucket(ppm, pc, 1031 ev.pl_u.pl_s.pl_pmcid, a); 1032 1033 break; 1034 1035 case PMCLOG_TYPE_PMCALLOCATE: 1036 /* 1037 * Record the association pmc id between this 1038 * PMC and its name. 1039 */ 1040 pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid, 1041 pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), a); 1042 break; 1043 1044 case PMCLOG_TYPE_PROCEXEC: 1045 1046 /* 1047 * Change the executable image associated with 1048 * a process. 1049 */ 1050 pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, 1); 1051 1052 /* delete the current process map */ 1053 TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { 1054 TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); 1055 free(ppm); 1056 } 1057 1058 /* locate the descriptor for the new 'base' image */ 1059 image_path = pmcstat_string_intern( 1060 ev.pl_u.pl_x.pl_pathname); 1061 1062 /* link to the new image */ 1063 pmcstat_process_exec(pp, image_path, 1064 ev.pl_u.pl_x.pl_entryaddr); 1065 break; 1066 1067 case PMCLOG_TYPE_PROCEXIT: 1068 1069 /* 1070 * Due to the way the log is generated, the 1071 * last few samples corresponding to a process 1072 * may appear in the log after the process 1073 * exit event is recorded. Thus we keep the 1074 * process' descriptor and associated data 1075 * structures around, but mark the process as 1076 * having exited. 1077 */ 1078 pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0); 1079 if (pp == NULL) 1080 break; 1081 pp->pp_isactive = 0; /* make a zombie */ 1082 break; 1083 1084 case PMCLOG_TYPE_SYSEXIT: 1085 pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0); 1086 if (pp == NULL) 1087 break; 1088 pp->pp_isactive = 0; /* make a zombie */ 1089 break; 1090 1091 case PMCLOG_TYPE_PROCFORK: 1092 1093 /* 1094 * If we had been tracking 'oldpid', then clone 1095 * its pid descriptor. 1096 */ 1097 pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0); 1098 if (pp == NULL) 1099 break; 1100 1101 ppnew = 1102 pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, 1); 1103 1104 /* copy the old process' address maps */ 1105 TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next) 1106 pmcstat_image_link(ppnew, ppm->ppm_image, 1107 ppm->ppm_lowpc, ppm->ppm_highpc); 1108 break; 1109 1110 default: /* other types of entries are not relevant */ 1111 break; 1112 } 1113 } 1114 1115 if (ev.pl_state == PMCLOG_EOF) 1116 return PMCSTAT_FINISHED; 1117 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1118 return PMCSTAT_RUNNING; 1119 1120 err(EX_DATAERR, "ERROR: event parsing failed (record %jd, " 1121 "offset 0x%jx)", (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1122 } 1123 1124 1125 /* 1126 * Open a log file, for reading or writing. 1127 * 1128 * The function returns the fd of a successfully opened log or -1 in 1129 * case of failure. 1130 */ 1131 1132 int 1133 pmcstat_open(const char *path, int mode) 1134 { 1135 int fd; 1136 1137 /* 1138 * If 'path' is "-" then open one of stdin or stdout depending 1139 * on the value of 'mode'. Otherwise, treat 'path' as a file 1140 * name and open that. 1141 */ 1142 if (path[0] == '-' && path[1] == '\0') 1143 fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; 1144 else 1145 fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? 1146 O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), 1147 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 1148 1149 return fd; 1150 } 1151 1152 /* 1153 * Print log entries as text. 1154 */ 1155 1156 int 1157 pmcstat_print_log(struct pmcstat_args *a) 1158 { 1159 struct pmclog_ev ev; 1160 1161 while (pmclog_read(a->pa_logparser, &ev) == 0) { 1162 assert(ev.pl_state == PMCLOG_OK); 1163 switch (ev.pl_type) { 1164 case PMCLOG_TYPE_CLOSELOG: 1165 PMCSTAT_PRINT_ENTRY(a,"closelog",); 1166 break; 1167 case PMCLOG_TYPE_DROPNOTIFY: 1168 PMCSTAT_PRINT_ENTRY(a,"drop",); 1169 break; 1170 case PMCLOG_TYPE_INITIALIZE: 1171 PMCSTAT_PRINT_ENTRY(a,"initlog","0x%x \"%s\"", 1172 ev.pl_u.pl_i.pl_version, 1173 pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); 1174 break; 1175 case PMCLOG_TYPE_MAPPINGCHANGE: 1176 PMCSTAT_PRINT_ENTRY(a,"mapping","%s %d %p %p \"%s\"", 1177 ev.pl_u.pl_m.pl_type == PMCLOG_MAPPING_INSERT ? 1178 "insert" : "delete", 1179 ev.pl_u.pl_m.pl_pid, 1180 (void *) ev.pl_u.pl_m.pl_start, 1181 (void *) ev.pl_u.pl_m.pl_end, 1182 ev.pl_u.pl_m.pl_pathname); 1183 break; 1184 case PMCLOG_TYPE_PCSAMPLE: 1185 PMCSTAT_PRINT_ENTRY(a,"sample","0x%x %d %p %c", 1186 ev.pl_u.pl_s.pl_pmcid, 1187 ev.pl_u.pl_s.pl_pid, 1188 (void *) ev.pl_u.pl_s.pl_pc, 1189 ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); 1190 break; 1191 case PMCLOG_TYPE_PMCALLOCATE: 1192 PMCSTAT_PRINT_ENTRY(a,"allocate","0x%x \"%s\" 0x%x", 1193 ev.pl_u.pl_a.pl_pmcid, 1194 ev.pl_u.pl_a.pl_evname, 1195 ev.pl_u.pl_a.pl_flags); 1196 break; 1197 case PMCLOG_TYPE_PMCATTACH: 1198 PMCSTAT_PRINT_ENTRY(a,"attach","0x%x %d \"%s\"", 1199 ev.pl_u.pl_t.pl_pmcid, 1200 ev.pl_u.pl_t.pl_pid, 1201 ev.pl_u.pl_t.pl_pathname); 1202 break; 1203 case PMCLOG_TYPE_PMCDETACH: 1204 PMCSTAT_PRINT_ENTRY(a,"detach","0x%x %d", 1205 ev.pl_u.pl_d.pl_pmcid, 1206 ev.pl_u.pl_d.pl_pid); 1207 break; 1208 case PMCLOG_TYPE_PROCCSW: 1209 PMCSTAT_PRINT_ENTRY(a,"cswval","0x%x %d %jd", 1210 ev.pl_u.pl_c.pl_pmcid, 1211 ev.pl_u.pl_c.pl_pid, 1212 ev.pl_u.pl_c.pl_value); 1213 break; 1214 case PMCLOG_TYPE_PROCEXEC: 1215 PMCSTAT_PRINT_ENTRY(a,"exec","0x%x %d %p \"%s\"", 1216 ev.pl_u.pl_x.pl_pmcid, 1217 ev.pl_u.pl_x.pl_pid, 1218 (void *) ev.pl_u.pl_x.pl_entryaddr, 1219 ev.pl_u.pl_x.pl_pathname); 1220 break; 1221 case PMCLOG_TYPE_PROCEXIT: 1222 PMCSTAT_PRINT_ENTRY(a,"exitval","0x%x %d %jd", 1223 ev.pl_u.pl_e.pl_pmcid, 1224 ev.pl_u.pl_e.pl_pid, 1225 ev.pl_u.pl_e.pl_value); 1226 break; 1227 case PMCLOG_TYPE_PROCFORK: 1228 PMCSTAT_PRINT_ENTRY(a,"fork","%d %d", 1229 ev.pl_u.pl_f.pl_oldpid, 1230 ev.pl_u.pl_f.pl_newpid); 1231 break; 1232 case PMCLOG_TYPE_USERDATA: 1233 PMCSTAT_PRINT_ENTRY(a,"userdata","0x%x", 1234 ev.pl_u.pl_u.pl_userdata); 1235 break; 1236 case PMCLOG_TYPE_SYSEXIT: 1237 PMCSTAT_PRINT_ENTRY(a,"exit","%d", 1238 ev.pl_u.pl_se.pl_pid); 1239 break; 1240 default: 1241 fprintf(a->pa_printfile, "unknown %d", 1242 ev.pl_type); 1243 } 1244 } 1245 1246 if (ev.pl_state == PMCLOG_EOF) 1247 return PMCSTAT_FINISHED; 1248 else if (ev.pl_state == PMCLOG_REQUIRE_DATA) 1249 return PMCSTAT_RUNNING; 1250 1251 err(EX_DATAERR, "ERROR: event parsing failed " 1252 "(record %jd, offset 0x%jx)", 1253 (uintmax_t) ev.pl_count + 1, ev.pl_offset); 1254 /*NOTREACHED*/ 1255 } 1256 1257 /* 1258 * Process a log file in offline analysis mode. 1259 */ 1260 1261 int 1262 pmcstat_process_log(struct pmcstat_args *a) 1263 { 1264 1265 /* 1266 * If gprof style profiles haven't been asked for, just print the 1267 * log to the current output file. 1268 */ 1269 if (a->pa_flags & FLAG_DO_PRINT) 1270 return pmcstat_print_log(a); 1271 else 1272 /* convert the log to gprof compatible profiles */ 1273 return pmcstat_convert_log(a); 1274 } 1275 1276 void 1277 pmcstat_initialize_logging(struct pmcstat_args *a) 1278 { 1279 int i; 1280 const char *kernpath; 1281 struct pmcstat_image *img; 1282 1283 /* use a convenient format for 'ldd' output */ 1284 if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%p %x\n",1) != 0) 1285 goto error; 1286 1287 /* Initialize hash tables */ 1288 for (i = 0; i < PMCSTAT_NHASH; i++) { 1289 LIST_INIT(&pmcstat_image_hash[i]); 1290 LIST_INIT(&pmcstat_process_hash[i]); 1291 LIST_INIT(&pmcstat_string_hash[i]); 1292 } 1293 1294 /* create a fake 'process' entry for the kernel with pid == -1 */ 1295 if ((pmcstat_kernproc = pmcstat_process_lookup((pid_t) -1, 1)) == NULL) 1296 goto error; 1297 1298 if ((kernpath = pmcstat_string_intern(a->pa_kernel)) == NULL) 1299 goto error; 1300 1301 img = pmcstat_image_from_path(kernpath); 1302 1303 pmcstat_image_get_elf_params(img); 1304 pmcstat_image_link(pmcstat_kernproc, img, img->pi_start, img->pi_end); 1305 1306 return; 1307 1308 error: 1309 err(EX_OSERR, "ERROR: Cannot initialize logging"); 1310 } 1311 1312 void 1313 pmcstat_shutdown_logging(void) 1314 { 1315 int i; 1316 struct pmcstat_gmonfile *pgf, *pgftmp; 1317 struct pmcstat_image *pi, *pitmp; 1318 struct pmcstat_process *pp, *pptmp; 1319 struct pmcstat_string *ps, *pstmp; 1320 1321 for (i = 0; i < PMCSTAT_NHASH; i++) { 1322 LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) { 1323 /* flush gmon.out data to disk */ 1324 LIST_FOREACH_SAFE(pgf, &pi->pi_gmlist, pgf_next, 1325 pgftmp) { 1326 pmcstat_gmon_unmap_file(pgf); 1327 LIST_REMOVE(pgf, pgf_next); 1328 free(pgf); 1329 } 1330 1331 LIST_REMOVE(pi, pi_next); 1332 free(pi); 1333 } 1334 LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, 1335 pptmp) { 1336 LIST_REMOVE(pp, pp_next); 1337 free(pp); 1338 } 1339 LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next, 1340 pstmp) { 1341 LIST_REMOVE(ps, ps_next); 1342 free(ps); 1343 } 1344 } 1345 } 1346