Print this page
Cstyle cleanup
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/prof/common/profv.c
+++ new/usr/src/cmd/sgs/prof/common/profv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 + *
26 + * Copyright 2018, Joyent, Inc.
25 27 */
26 28
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 29 /*
30 30 * All routines in this file are for processing new-style, *versioned*
31 31 * mon.out format. Together with rdelf.c, lookup.c and profv.h, these
32 32 * form the complete set of files to profile new-style mon.out files.
33 33 */
34 34
35 35 #include <stdlib.h>
36 36 #include <string.h>
37 37 #include "conv.h"
38 38 #include "profv.h"
39 39
40 40 bool time_in_ticks = FALSE;
41 41 size_t n_pcsamples, n_accounted_ticks, n_zeros, total_funcs;
42 42 unsigned char sort_flag;
43 43
44 44 mod_info_t modules;
45 45 size_t n_modules = 1; /* always include the aout object */
46 46
47 47 struct stat aout_stat, monout_stat;
48 48 profrec_t *profsym;
49 49
50 50 int
51 51 cmp_by_name(const void *arg1, const void *arg2)
52 52 {
53 53 profrec_t *a = (profrec_t *)arg1;
54 54 profrec_t *b = (profrec_t *)arg2;
55 55
56 56 return (strcmp(a->demangled_name, b->demangled_name));
57 57 }
58 58
59 59 static void
60 60 setup_demangled_names(void)
61 61 {
62 62 const char *p;
63 63 char *nbp, *nbe, *namebuf;
64 64 size_t cur_len = 0, namebuf_sz = BUCKET_SZ;
65 65 size_t i, namelen;
66 66
67 67 if ((namebuf = malloc(namebuf_sz)) == NULL) {
68 68 (void) fprintf(stderr, "%s: can't allocate %d bytes\n",
69 69 cmdname, namebuf_sz);
70 70 exit(ERR_MEMORY);
71 71 }
72 72
73 73 nbp = namebuf;
74 74 nbe = namebuf + namebuf_sz;
75 75
76 76 for (i = 0; i < total_funcs; i++) {
77 77 p = conv_demangle_name(profsym[i].name);
78 78 if (p == profsym[i].name)
79 79 continue;
80 80
81 81 namelen = strlen(p);
82 82 if ((nbp + namelen + 1) > nbe) {
83 83 namebuf_sz += BUCKET_SZ;
84 84 namebuf = realloc(namebuf, namebuf_sz);
85 85 if (namebuf == NULL) {
86 86 (void) fprintf(stderr,
87 87 "%s: can't alloc %d bytes\n",
88 88 cmdname, BUCKET_SZ);
89 89 exit(ERR_MEMORY);
90 90 }
91 91
92 92 nbp = namebuf + cur_len;
93 93 nbe = namebuf + namebuf_sz;
94 94 }
95 95
96 96 (void) strcpy(nbp, p);
97 97 profsym[i].demangled_name = nbp;
98 98
99 99 nbp += namelen + 1;
100 100 cur_len += namelen + 1;
101 101 free((void *)p);
102 102 }
103 103 }
104 104
105 105 int
106 106 cmp_by_time(const void *arg1, const void *arg2)
107 107 {
108 108 profrec_t *a = (profrec_t *)arg1;
109 109 profrec_t *b = (profrec_t *)arg2;
110 110
111 111 if (a->percent_time > b->percent_time)
112 112 return (-1);
113 113 else if (a->percent_time < b->percent_time)
114 114 return (1);
115 115 else
116 116 return (0);
117 117 }
118 118
119 119 int
120 120 cmp_by_ncalls(const void *arg1, const void *arg2)
121 121 {
122 122 profrec_t *a = (profrec_t *)arg1;
123 123 profrec_t *b = (profrec_t *)arg2;
124 124
125 125 if (a->ncalls > b->ncalls)
126 126 return (-1);
127 127 else if (a->ncalls < b->ncalls)
128 128 return (1);
129 129 else
130 130 return (0);
131 131
132 132 }
133 133
134 134 static void
135 135 print_profile_data(void)
136 136 {
137 137 int i;
138 138 int (*sort_func)(const void *, const void *);
139 139 mod_info_t *mi;
140 140 double cumsecs = 0;
141 141 char filler[20];
142 142
143 143 /*
144 144 * Sort the compiled data; the sort flags are mutually exclusive.
145 145 */
146 146 switch (sort_flag) {
147 147 case BY_NCALLS:
148 148 sort_func = cmp_by_ncalls;
149 149 break;
150 150
151 151 case BY_NAME:
152 152 if (Cflag)
153 153 setup_demangled_names();
154 154 sort_func = cmp_by_name;
155 155 break;
156 156
157 157 case BY_ADDRESS:
158 158 sort_flag |= BY_ADDRESS;
159 159 sort_func = NULL; /* already sorted by addr */
160 160 break;
161 161
162 162 case BY_TIME: /* default is to sort by time */
163 163 default:
164 164 sort_func = cmp_by_time;
165 165 }
166 166
167 167
168 168 if (sort_func) {
169 169 qsort(profsym, total_funcs, sizeof (profrec_t), sort_func);
170 170 }
171 171
172 172 /*
173 173 * If we're sorting by name, and if it is a verbose print, we wouldn't
174 174 * have set up the print_mid fields yet.
175 175 */
176 176 if ((flags & F_VERBOSE) && (sort_flag == BY_NAME)) {
177 177 for (i = 0; i < total_funcs; i++) {
178 178 /*
179 179 * same as previous or next (if there's one) ?
180 180 */
181 181 if (i && (strcmp(profsym[i].demangled_name,
182 182 profsym[i-1].demangled_name) == 0)) {
183 183 profsym[i].print_mid = TRUE;
184 184 } else if ((i < (total_funcs - 1)) &&
185 185 (strcmp(profsym[i].demangled_name,
186 186 profsym[i+1].demangled_name) == 0)) {
187 187 profsym[i].print_mid = TRUE;
188 188 }
189 189 }
190 190 }
191 191
192 192 /*
193 193 * The actual printing part.
194 194 */
195 195 if (!(flags & F_NHEAD)) {
196 196 if (flags & F_PADDR)
197 197 (void) printf(" %s", atitle);
198 198
199 199 if (time_in_ticks)
200 200 (void) puts(
201 201 " %Time Tiks Cumtiks #Calls tiks/call Name");
202 202 else
203 203 (void) puts(
204 204 " %Time Seconds Cumsecs #Calls msec/call Name");
205 205 }
206 206
207 207 mi = NULL;
208 208 for (i = 0; i < total_funcs; i++) {
209 209 /*
210 210 * Since the same value may denote different symbols in
211 211 * different shared objects, it is debatable if it is
212 212 * meaningful to print addresses at all. Especially so
213 213 * if we were asked to sort by symbol addresses.
214 214 *
215 215 * If we've to sort by address, I think it is better to sort
216 216 * it on a per-module basis and if verbose mode is on too,
217 217 * print a newline to separate out modules.
218 218 */
219 219 if ((flags & F_VERBOSE) && (sort_flag == BY_ADDRESS)) {
220 220 if (mi != profsym[i].module) {
221 221 (void) printf("\n");
222 222 mi = profsym[i].module;
223 223 }
224 224 }
225 225
226 226 if (flags & F_PADDR) {
227 227 if (aformat[2] == 'x')
228 228 (void) printf("%16llx ", profsym[i].addr);
229 229 else
230 230 (void) printf("%16llo ", profsym[i].addr);
231 231 }
232 232
233 233 cumsecs += profsym[i].seconds;
234 234 (void) printf("%6.1f%8.2f%8.2f", profsym[i].percent_time,
235 235 profsym[i].seconds, cumsecs);
236 236
237 237 (void) printf("%8d%12.4f ",
238 238 profsym[i].ncalls, profsym[i].msecs_per_call);
239 239
240 240 if (profsym[i].print_mid)
241 241 (void) printf("%d:", (profsym[i].module)->id);
242 242
243 243 (void) printf("%s\n", profsym[i].demangled_name);
244 244 }
245 245
246 246 if (flags & F_PADDR)
247 247 (void) sprintf(filler, "%16s", "");
248 248 else
249 249 filler[0] = 0;
250 250
251 251 if (flags & F_VERBOSE) {
252 252 (void) puts("\n");
253 253 (void) printf("%s Total Object Modules %7d\n",
254 254 filler, n_modules);
255 255 (void) printf("%s Qualified Symbols %7d\n",
256 256 filler, total_funcs);
257 257 (void) printf("%s Symbols with zero usage %7d\n",
258 258 filler, n_zeros);
259 259 (void) printf("%s Total pc-hits %7d\n",
260 260 filler, n_pcsamples);
261 261 (void) printf("%s Accounted pc-hits %7d\n",
262 262 filler, n_accounted_ticks);
263 263 if ((!gflag) && (n_pcsamples - n_accounted_ticks)) {
264 264 (void) printf("%s Missed pc-hits (try -g) %7d\n\n",
265 265 filler, n_pcsamples - n_accounted_ticks);
266 266 } else {
267 267 (void) printf("%s Missed pc-hits %7d\n\n",
268 268 filler, n_pcsamples - n_accounted_ticks);
269 269 }
270 270 (void) printf("%s Module info\n", filler);
271 271 for (mi = &modules; mi; mi = mi->next)
272 272 (void) printf("%s %d: `%s'\n", filler,
273 273 mi->id, mi->path);
274 274 }
275 275 }
276 276
277 277 int
278 278 name_cmp(const void *arg1, const void *arg2)
279 279 {
280 280 profnames_t *a = (profnames_t *)arg1;
281 281 profnames_t *b = (profnames_t *)arg2;
282 282
283 283 return (strcmp(a->name, b->name));
284 284 }
285 285
286 286 static void
287 287 check_dupnames(void)
288 288 {
289 289 int i;
290 290 profnames_t *pn;
291 291
292 292 pn = calloc(total_funcs, sizeof (profnames_t));
293 293 if (pn == NULL) {
294 294 (void) fprintf(stderr, "%s: no room for %d bytes\n",
295 295 cmdname, total_funcs * sizeof (profnames_t));
296 296 exit(ERR_MEMORY);
297 297 }
298 298
299 299 for (i = 0; i < total_funcs; i++) {
300 300 pn[i].name = profsym[i].demangled_name;
301 301 pn[i].pfrec = &profsym[i];
302 302 }
303 303
304 304 qsort(pn, total_funcs, sizeof (profnames_t), name_cmp);
305 305
306 306 for (i = 0; i < total_funcs; i++) {
307 307 /*
308 308 * same as previous or next (if there's one) ?
309 309 */
310 310 if (i && (strcmp(pn[i].name, pn[i-1].name) == 0))
311 311 (pn[i].pfrec)->print_mid = TRUE;
312 312 else if ((i < (total_funcs - 1)) &&
313 313 (strcmp(pn[i].name, pn[i+1].name) == 0)) {
314 314 (pn[i].pfrec)->print_mid = TRUE;
315 315 }
316 316 }
317 317
318 318 free(pn);
319 319 }
320 320
321 321 static void
322 322 compute_times(nltype *nl, profrec_t *psym)
323 323 {
324 324 static int first_time = TRUE;
325 325 static long hz;
326 326
327 327 if (first_time) {
328 328 if ((hz = sysconf(_SC_CLK_TCK)) == -1)
329 329 time_in_ticks = TRUE;
330 330 first_time = FALSE;
331 331 }
332 332
333 333 if (time_in_ticks) {
334 334 psym->seconds = (double)nl->nticks;
335 335 if (nl->ncalls) {
336 336 psym->msecs_per_call = (double)nl->nticks /
337 337 (double)nl->ncalls;
338 338 } else
339 339 psym->msecs_per_call = (double)0.0;
340 340 } else {
341 341 psym->seconds = (double)nl->nticks / (double)hz;
342 342 if (nl->ncalls) {
343 343 psym->msecs_per_call =
344 344 ((double)psym->seconds * 1000.0) /
345 345 (double)nl->ncalls;
346 346 } else
347 347 psym->msecs_per_call = (double)0.0;
348 348 }
349 349
350 350 if (n_pcsamples) {
351 351 psym->percent_time =
352 352 ((double)nl->nticks / (double)n_pcsamples) * 100;
353 353 }
354 354 }
355 355
356 356 static void
357 357 collect_profsyms(void)
358 358 {
359 359 mod_info_t *mi;
360 360 nltype *nl;
361 361 size_t i, ndx;
362 362
363 363
364 364 for (mi = &modules; mi; mi = mi->next)
365 365 total_funcs += mi->nfuncs;
366 366
367 367 profsym = calloc(total_funcs, sizeof (profrec_t));
368 368 if (profsym == NULL) {
369 369 (void) fprintf(stderr, "%s: no room for %d bytes\n",
370 370 cmdname, total_funcs * sizeof (profrec_t));
371 371 exit(ERR_MEMORY);
372 372 }
373 373
374 374 ndx = 0;
375 375 for (mi = &modules; mi; mi = mi->next) {
376 376 nl = mi->nl;
377 377 for (i = 0; i < mi->nfuncs; i++) {
378 378 /*
379 379 * I think F_ZSYMS doesn't make sense for the new
380 380 * mon.out format, since we don't have a profiling
381 381 * *range*, per se. But the man page demands it,
382 382 * so...
383 383 */
384 384 if ((nl[i].ncalls == 0) && (nl[i].nticks == 0)) {
385 385 n_zeros++;
386 386 if (!(flags & F_ZSYMS))
387 387 continue;
388 388 }
389 389
390 390 /*
391 391 * Initially, we set demangled_name to be
392 392 * the same as name. If Cflag is set, we later
393 393 * change this to be the demangled name ptr.
394 394 */
395 395 profsym[ndx].addr = nl[i].value;
396 396 profsym[ndx].ncalls = nl[i].ncalls;
397 397 profsym[ndx].name = nl[i].name;
398 398 profsym[ndx].demangled_name = nl[i].name;
399 399 profsym[ndx].module = mi;
400 400 profsym[ndx].print_mid = FALSE;
401 401 compute_times(&nl[i], &profsym[ndx]);
402 402 ndx++;
403 403 }
404 404 }
405 405
406 406 /*
407 407 * Adjust total_funcs to actual printable funcs
408 408 */
409 409 total_funcs = ndx;
410 410 }
411 411
412 412 static void
413 413 assign_pcsamples(mod_info_t *module, Address *pcsmpl,
414 414 size_t n_samples)
415 415 {
416 416 Address *pcptr, *pcse = pcsmpl + n_samples;
417 417 Address nxt_func;
418 418 nltype *nl;
419 419 size_t nticks;
420 420
421 421 /* Locate the first pc-hit for this module */
422 422 if ((pcptr = locate(pcsmpl, n_samples, module->load_base)) == NULL)
423 423 return; /* no pc-hits in this module */
424 424
425 425 /* Assign all pc-hits in this module to appropriate functions */
426 426 while ((pcptr < pcse) && (*pcptr < module->load_end)) {
427 427
428 428 /* Update the corresponding function's time */
429 429 if (nl = nllookup(module, *pcptr, &nxt_func)) {
430 430 /*
431 431 * Collect all pc-hits in this function. Each
432 432 * pc-hit counts as 1 tick.
433 433 */
434 434 nticks = 0;
435 435 while ((pcptr < pcse) && (*pcptr < nxt_func)) {
436 436 nticks++;
437 437 pcptr++;
438 438 }
439 439
440 440 nl->nticks += nticks;
441 441 n_accounted_ticks += nticks;
442 442 } else {
443 443 /*
444 444 * pc sample could not be assigned to function;
445 445 * probably in a PLT
446 446 */
447 447 pcptr++;
448 448 }
449 449 }
450 450 }
451 451
452 452 static int
453 453 pc_cmp(const void *arg1, const void *arg2)
454 454 {
455 455 Address *pc1 = (Address *)arg1;
456 456 Address *pc2 = (Address *)arg2;
457 457
458 458 if (*pc1 > *pc2)
459 459 return (1);
460 460
461 461 if (*pc1 < *pc2)
462 462 return (-1);
463 463
464 464 return (0);
465 465 }
466 466
467 467 static void
468 468 process_pcsamples(ProfBuffer *bufp)
469 469 {
470 470 Address *pc_samples;
471 471 mod_info_t *mi;
472 472 size_t nelem = bufp->bufsize;
473 473
474 474 /* buffer with no pc samples ? */
475 475 if (nelem == 0)
476 476 return;
477 477
478 478 /* Allocate for the pcsample chunk */
479 479 pc_samples = (Address *) calloc(nelem, sizeof (Address));
480 480 if (pc_samples == NULL) {
481 481 (void) fprintf(stderr, "%s: no room for %d sample pc's\n",
482 482 cmdname, nelem);
483 483 exit(ERR_MEMORY);
484 484 }
485 485
486 486 (void) memcpy(pc_samples, (caddr_t)bufp + bufp->buffer,
487 487 nelem * sizeof (Address));
488 488
489 489 /* Sort the pc samples */
490 490 qsort(pc_samples, nelem, sizeof (Address), pc_cmp);
491 491
492 492 /*
493 493 * Assign pcsamples to functions in the currently active
494 494 * module list
495 495 */
496 496 for (mi = &modules; mi; mi = mi->next) {
497 497 if (mi->active == FALSE)
498 498 continue;
499 499 assign_pcsamples(mi, pc_samples, nelem);
500 500 }
501 501
502 502 free(pc_samples);
503 503
504 504 /* Update total number of pcsamples read so far */
505 505 n_pcsamples += nelem;
506 506 }
507 507
508 508 static void
509 509 process_cgraph(ProfCallGraph *cgp)
510 510 {
511 511 mod_info_t *mi;
512 512 Address f_end;
513 513 Index callee_off;
514 514 ProfFunction *calleep;
515 515 nltype *nl;
516 516
517 517 for (callee_off = cgp->functions; callee_off;
518 518 callee_off = calleep->next_to) {
519 519
520 520 /* LINTED: pointer cast */
521 521 calleep = (ProfFunction *)((char *)cgp + callee_off);
522 522 if (calleep->count == 0)
523 523 continue;
524 524
525 525 /*
526 526 * If we cannot identify a callee with a module, we
527 527 * cannot get to its namelist, just skip it.
528 528 */
529 529 for (mi = &modules; mi; mi = mi->next) {
530 530 if (mi->active == FALSE)
531 531 continue;
532 532
533 533 if (calleep->topc >= mi->load_base &&
534 534 calleep->topc < mi->load_end) {
535 535 /*
536 536 * nllookup() returns the next lower entry
537 537 * point on a miss. So just make sure the
538 538 * callee's pc is not outside this function
539 539 */
540 540 if (nl = nllookup(mi, calleep->topc, 0)) {
541 541 f_end = mi->load_base + (nl->value -
542 542 mi->txt_origin) + nl->size;
543 543 if (calleep->topc < f_end)
544 544 nl->ncalls += calleep->count;
545 545 }
546 546 }
547 547 }
548 548 }
549 549 }
550 550
551 551 static mod_info_t *
552 552 get_shobj_syms(char *pathname, GElf_Addr ld_base, GElf_Addr ld_end)
553 553 {
554 554 mod_info_t *mi;
555 555
556 556 /* Create a new module element */
557 557 if ((mi = malloc(sizeof (mod_info_t))) == NULL) {
558 558 (void) fprintf(stderr, "%s: no room for %d bytes\n",
559 559 cmdname, sizeof (mod_info_t));
560 560 exit(ERR_MEMORY);
561 561 }
562 562
563 563 mi->path = malloc(strlen(pathname) + 1);
564 564 if (mi->path == NULL) {
565 565 (void) fprintf(stderr, "%s: can't allocate %d bytes\n",
566 566 cmdname, strlen(pathname) + 1);
567 567 exit(ERR_MEMORY);
568 568 }
569 569 (void) strcpy(mi->path, pathname);
570 570 mi->next = NULL;
571 571
572 572 get_syms(pathname, mi);
573 573
574 574 /* and fill in info... */
575 575 mi->id = n_modules + 1;
576 576 mi->load_base = ld_base;
577 577 mi->load_end = ld_end;
578 578 mi->active = TRUE;
579 579
580 580 n_modules++;
581 581
582 582 return (mi);
583 583 }
584 584
585 585 /*
586 586 * Two modules overlap each other if they don't lie completely *outside*
587 587 * each other.
588 588 */
589 589 static bool
590 590 does_overlap(ProfModule *new, mod_info_t *old)
591 591 {
592 592 /* case 1: new module lies completely *before* the old one */
593 593 if (new->startaddr < old->load_base && new->endaddr <= old->load_base)
594 594 return (FALSE);
595 595
596 596 /* case 2: new module lies completely *after* the old one */
597 597 if (new->startaddr >= old->load_end && new->endaddr >= old->load_end)
598 598 return (FALSE);
599 599
600 600 /* probably a dlopen: the modules overlap each other */
601 601 return (TRUE);
602 602 }
603 603
604 604 static bool
605 605 is_same_as_aout(char *modpath, struct stat *buf)
606 606 {
607 607 if (stat(modpath, buf) == -1) {
608 608 perror(modpath);
609 609 exit(ERR_SYSCALL);
610 610 }
611 611
612 612 if ((buf->st_dev == aout_stat.st_dev) &&
613 613 (buf->st_ino == aout_stat.st_ino)) {
614 614 return (TRUE);
615 615 } else
616 616 return (FALSE);
617 617 }
618 618
619 619 static void
620 620 process_modules(ProfModuleList *modlp)
621 621 {
622 622 ProfModule *newmodp;
623 623 mod_info_t *mi, *last, *new_module;
624 624 char *so_path;
625 625 bool more_modules = TRUE;
626 626 struct stat so_statbuf;
627 627
628 628 /* Check version of module type object */
629 629 if (modlp->version > PROF_MODULES_VER) {
630 630 (void) fprintf(stderr,
631 631 "%s: unsupported version %d for modules\n",
632 632 cmdname, modlp->version);
633 633 exit(ERR_INPUT);
634 634 }
635 635
636 636
637 637 /*
638 638 * Scan the PROF_MODULES_T list and add modules to current list
639 639 * of modules, if they're not present already
640 640 */
641 641 /* LINTED: pointer cast */
642 642 newmodp = (ProfModule *)((caddr_t)modlp + modlp->modules);
643 643 do {
644 644 /*
645 645 * Since the aout could've been renamed after its run, we
646 646 * should see if current module overlaps aout. If it does, it
647 647 * is probably the renamed aout. We should also skip any other
648 648 * non-sharedobj's that we see (or should we report an error ?)
649 649 */
650 650 so_path = (caddr_t)modlp + newmodp->path;
651 651 if (does_overlap(newmodp, &modules) ||
652 652 is_same_as_aout(so_path, &so_statbuf) ||
653 653 (!is_shared_obj(so_path))) {
654 654 if (!newmodp->next)
655 655 more_modules = FALSE;
656 656
657 657 /* LINTED: pointer cast */
658 658 newmodp = (ProfModule *)
659 659 ((caddr_t)modlp + newmodp->next);
660 660 continue;
661 661 }
662 662
663 663 /*
664 664 * Check all modules (leave the first one, 'cos that
665 665 * is the program executable info). If this module is already
666 666 * there in the list, skip it.
667 667 */
668 668 last = &modules;
669 669 while ((mi = last->next) != NULL) {
670 670 /*
671 671 * We expect the full pathname for all shared objects
672 672 * needed by the program executable. In this case, we
673 673 * simply need to compare the paths to see if they are
674 674 * the same file.
675 675 */
676 676 if (strcmp(mi->path, so_path) == 0)
677 677 break;
678 678
679 679 /*
680 680 * Check if this new shared object will overlap any
681 681 * existing module. If yes, deactivate the old one.
682 682 */
683 683 if (does_overlap(newmodp, mi))
684 684 mi->active = FALSE;
685 685
686 686 last = mi;
687 687 }
688 688
689 689 /* Module already there, skip it */
690 690 if (mi != NULL) {
691 691 mi->load_base = newmodp->startaddr;
692 692 mi->load_end = newmodp->endaddr;
693 693 mi->active = TRUE;
694 694 if (!newmodp->next)
695 695 more_modules = FALSE;
696 696
697 697 /* LINTED: pointer cast */
698 698 newmodp = (ProfModule *)
699 699 ((caddr_t)modlp + newmodp->next);
700 700 continue;
701 701 }
702 702
703 703 /*
704 704 * Check if mon.out is outdated with respect to the new
705 705 * module we want to add
706 706 */
707 707 if (monout_stat.st_mtime < so_statbuf.st_mtime) {
708 708 (void) fprintf(stderr,
709 709 "%s: newer shared obj %s outdates profile info\n",
710 710 cmdname, so_path);
711 711 exit(ERR_INPUT);
712 712 }
713 713
714 714 /* Create this module's nameslist */
715 715 new_module = get_shobj_syms(so_path,
716 716 newmodp->startaddr, newmodp->endaddr);
717 717
718 718 /* Add it to the tail of active module list */
719 719 last->next = new_module;
720 720
721 721 /*
722 722 * Move to the next module in the PROF_MODULES_T list
723 723 * (if present)
724 724 */
725 725 if (!newmodp->next)
726 726 more_modules = FALSE;
727 727
728 728 /* LINTED: pointer cast */
729 729 newmodp = (ProfModule *)((caddr_t)modlp + newmodp->next);
730 730
731 731 } while (more_modules);
732 732 }
733 733
734 734 static void
735 735 process_mon_out(caddr_t memp, size_t fsz)
736 736 {
737 737 ProfObject *objp;
738 738 caddr_t file_end;
739 739 bool found_pcsamples = FALSE, found_cgraph = FALSE;
740 740
741 741 /*
742 742 * Save file end pointer and start after header
743 743 */
744 744 file_end = memp + fsz;
745 745 /* LINTED: pointer cast */
746 746 objp = (ProfObject *)(memp + ((ProfHeader *)memp)->size);
747 747 while ((caddr_t)objp < file_end) {
748 748 switch (objp->type) {
749 749 case PROF_MODULES_T :
750 750 process_modules((ProfModuleList *)objp);
751 751 break;
752 752
753 753 case PROF_CALLGRAPH_T :
754 754 process_cgraph((ProfCallGraph *)objp);
755 755 found_cgraph = TRUE;
756 756 break;
757 757
758 758 case PROF_BUFFER_T :
759 759 process_pcsamples((ProfBuffer *)objp);
760 760 found_pcsamples = TRUE;
761 761 break;
762 762
763 763 default :
764 764 (void) fprintf(stderr,
765 765 "%s: unknown prof object type=%d\n",
766 766 cmdname, objp->type);
767 767 exit(ERR_INPUT);
768 768 }
769 769 /* LINTED: pointer cast */
770 770 objp = (ProfObject *)((caddr_t)objp + objp->size);
771 771 }
772 772
773 773 if (!found_cgraph || !found_pcsamples) {
774 774 (void) fprintf(stderr,
775 775 "%s: missing callgraph/pcsamples in `%s'\n",
776 776 cmdname, mon_fn);
777 777 exit(ERR_INPUT);
778 778 }
779 779
780 780 if ((caddr_t)objp > file_end) {
781 781 (void) fprintf(stderr, "%s: malformed file `%s'\n",
782 782 cmdname, mon_fn);
783 783 exit(ERR_INPUT);
784 784 }
785 785 }
786 786
787 787 static void
788 788 get_aout_syms(char *pathname, mod_info_t *mi)
789 789 {
790 790 mi->path = malloc(strlen(pathname) + 1);
791 791 if (mi->path == NULL) {
792 792 (void) fprintf(stderr, "%s: can't allocate %d bytes\n",
793 793 cmdname, strlen(pathname) + 1);
794 794 exit(ERR_MEMORY);
795 795 }
796 796
797 797 (void) strcpy(mi->path, pathname);
798 798 mi->next = NULL;
799 799
800 800 get_syms(pathname, mi);
801 801
802 802 mi->id = 1;
803 803 mi->load_base = mi->txt_origin;
804 804 mi->load_end = mi->data_end;
805 805 mi->active = TRUE;
806 806 }
807 807
808 808 void
809 809 profver(void)
810 810 {
811 811 int fd;
812 812 unsigned int magic_num;
813 813 bool invalid_version;
814 814 caddr_t fmem;
815 815 ProfHeader prof_hdr;
816 816
817 817 /*
818 818 * Check the magic and see if this is versioned or *old-style*
819 819 * mon.out.
820 820 */
821 821 if ((fd = open(mon_fn, O_RDONLY)) == -1) {
822 822 perror(mon_fn);
823 823 exit(ERR_SYSCALL);
824 824 }
825 825 if (read(fd, (char *)&magic_num, sizeof (unsigned int)) == -1) {
826 826 perror("read");
827 827 exit(ERR_SYSCALL);
828 828 }
829 829 if (magic_num != (unsigned int) PROF_MAGIC) {
830 830 (void) close(fd);
831 831 return;
832 832 }
833 833
834 834
835 835
836 836 /*
837 837 * Check versioning info. For now, let's say we provide
838 838 * backward compatibility, so we accept all older versions.
839 839 */
840 840 (void) lseek(fd, 0L, SEEK_SET);
841 841 if (read(fd, (char *)&prof_hdr, sizeof (ProfHeader)) == -1) {
842 842 perror("read");
843 843 exit(ERR_SYSCALL);
844 844 }
845 845 invalid_version = FALSE;
846 846 if (prof_hdr.h_major_ver > PROF_MAJOR_VERSION)
847 847 invalid_version = TRUE;
848 848 else if (prof_hdr.h_major_ver == PROF_MAJOR_VERSION) {
849 849 if (prof_hdr.h_minor_ver > PROF_MINOR_VERSION)
850 850 invalid_version = FALSE;
851 851 }
852 852 if (invalid_version) {
853 853 (void) fprintf(stderr,
854 854 "%s: mon.out version %d.%d not supported\n",
855 855 cmdname, prof_hdr.h_major_ver, prof_hdr.h_minor_ver);
856 856 exit(ERR_INPUT);
857 857 }
858 858
859 859
860 860
861 861 /*
862 862 * Map mon.out onto memory.
863 863 */
864 864 if (stat(mon_fn, &monout_stat) == -1) {
865 865 perror(mon_fn);
866 866 exit(ERR_SYSCALL);
867 867 }
868 868 if ((fmem = mmap(0, monout_stat.st_size,
869 869 PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
870 870 perror("mmap");
871 871 exit(ERR_SYSCALL);
872 872 }
873 873 (void) close(fd);
874 874
875 875
876 876 /*
877 877 * Now, read program executable's symbol table. Also save it's
878 878 * stat in aout_stat for use while processing mon.out
879 879 */
880 880 if (stat(sym_fn, &aout_stat) == -1) {
881 881 perror(sym_fn);
882 882 exit(ERR_SYSCALL);
883 883 }
884 884 get_aout_syms(sym_fn, &modules);
885 885
886 886 /*
887 887 * Process the mon.out, all shared objects it references
888 888 * and collect statistics on ticks spent in each function,
889 889 * number of calls, etc.
890 890 */
891 891 process_mon_out(fmem, monout_stat.st_size);
892 892
893 893 /*
894 894 * Based on the flags and the statistics we've got, create
895 895 * a list of relevant symbols whose profiling details should
896 896 * be printed
897 897 */
898 898 collect_profsyms();
899 899
900 900 /*
901 901 * Check for duplicate names in output. We need to print the
902 902 * module id's if verbose. Also, if we are sorting by name anyway,
903 903 * we don't need to check for duplicates here. We'll do that later.
904 904 */
905 905 if ((flags & F_VERBOSE) && (sort_flag != BY_NAME))
906 906 check_dupnames();
907 907
908 908 /*
909 909 * Print output
910 910 */
911 911 print_profile_data();
912 912
913 913
914 914 (void) munmap(fmem, monout_stat.st_size);
915 915 exit(0);
916 916 }
↓ open down ↓ |
878 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX