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