Print this page
libconv
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/prof/common/prof.c
+++ new/usr/src/cmd/sgs/prof/common/prof.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 + * Copyright 2018 Jason King
25 26 */
26 27
27 28 /* Copyright (c) 1988 AT&T */
28 29 /* All Rights Reserved */
29 30
30 31 /*
31 32 * Program profiling report generator.
32 33 *
33 34 * Usage:
34 35 *
35 36 * prof [-ChsVz] [-a | c | n | t] [-o | x] [-g | l]
36 37 * [-m mdata] [prog]
37 38 *
38 39 * Where "prog" is the program that was profiled; "a.out" by default.
39 40 * Options are:
40 41 *
41 42 * -n Sort by symbol name.
42 43 * -t Sort by decreasing time.
43 44 * -c Sort by decreasing number of calls.
44 45 * -a Sort by increasing symbol address.
45 46 *
46 47 * The options that determine the type of sorting are mutually exclusive.
47 48 * Additional options are:
48 49 *
49 50 * -o Include symbol addresses in output (in octal).
50 51 * -x Include symbol addresses in output (in hexadecimal).
51 52 * -g Include non-global T-type symbols in output.
52 53 * -l Do NOT include local T-type symbols in output (default).
53 54 * -z Include all symbols in profiling range, even if zero
54 55 * number of calls or time.
55 56 * -h Suppress table header.
56 57 * -s Follow report with additional statistical information.
57 58 * -m mdata Use file "mdata" instead of MON_OUT for profiling data.
58 59 * -V print version information for prof (and exit, if only V spec'd)
59 60 * -C call C++ demangle routine to demangle names before printing.
60 61 */
61 62
62 63 #include <stdio.h>
63 64 #include <string.h>
64 65 #include <errno.h>
65 66 #include <dlfcn.h>
66 67 #include <ctype.h>
67 68 #include "conv.h"
68 69 #include "symint.h"
69 70 #include "sys/param.h" /* for HZ */
70 71 #include "mon.h"
71 72 #include "sys/stat.h"
72 73 #include "debug.h"
73 74
74 75 #define OLD_DEBUG(x)
75 76
76 77 #define Print (void) printf
77 78 #define Fprint (void) fprintf
78 79
79 80 #if vax
80 81 /* Max positive difference between a fnpc and sl_addr for match */
81 82 #define CCADIFF 22
82 83 /* Type if n_type field in file symbol table entry. */
83 84 #endif
84 85
85 86 #if (u3b || u3b15 || u3b2 || i386)
86 87 /* Max positive difference between a fnpc and sl_addr for match */
87 88 #define CCADIFF 20 /* ?? (16 would probably do) */
88 89 /* For u3b, the "type" is storage class + section number (no type_t) */
89 90 #endif
90 91
91 92 #if (sparc)
92 93 #define CCADIFF 24 /* PIC prologue length=20 + 4 */
93 94 #endif
94 95
95 96
96 97 #define PROFSEC(ticks) ((double)(ticks)/HZ) /* Convert clock ticks to seconds */
97 98
98 99 /* Title fragment used if symbol addresses in output ("-o" or "-x"). */
99 100 char *atitle = " Address ";
100 101 /* Format for addresses in output */
101 102 char *aformat = "%8o ";
102 103
103 104 #if !(vax || u3b || u3b15 || u3b2 || i386 || sparc)
104 105 /* Make sure something we are set up for. Else lay egg. */
105 106 #include "### No code for processor type ###"
106 107 #endif
107 108
108 109
109 110 /* Shorthand to gimme the Precise #of addresses per cells */
110 111 #define DBL_ADDRPERCELL (((double)bias)/sf)
111 112
112 113
113 114 /* Used for unsigned fixed-point fraction with binary scale at */
114 115 /* the left of 15'th bit (0 as least significant bit) . */
115 116 #define BIAS ((long)0200000L)
116 117
117 118 /*
118 119 * TS1 insures that the symbols section is executable.
119 120 */
120 121 #define TS1(s) (((s) > 0) && (scnhdrp[(s)-1].sh_flags & SHF_EXECINSTR))
121 122 /*
122 123 * TS2 insures that the symbol should be reported. We want
123 124 * to report only those symbols that are functions (STT_FUNC)
124 125 * or "notype" (STT_NOTYPE... "printf", for example). Also,
125 126 * unless the gflag is set, the symbol must be global.
126 127 */
127 128
128 129 #define TS2(i) \
129 130 (((ELF32_ST_TYPE(i) == STT_FUNC) || \
130 131 (ELF32_ST_TYPE(i) == STT_NOTYPE)) && \
131 132 ((ELF32_ST_BIND(i) == STB_GLOBAL) || \
132 133 (gflag && (ELF32_ST_BIND(i) == STB_LOCAL))))
133 134
134 135 #define TXTSYM(s, i) (TS1(s) && TS2(i))
135 136
136 137 int gflag = 0; /* replaces gmatch and gmask */
137 138 int Cflag = 0;
138 139
139 140 PROF_FILE *ldptr; /* For program ("a.out") file. */
140 141
141 142 FILE *mon_iop; /* For profile (MON_OUT) file. */
142 143 char *sym_fn = "a.out"; /* Default program file name. */
143 144 char *mon_fn = MON_OUT; /* Default profile file name. */
144 145 /* May be changed by "-m file". */
145 146
146 147 long bias; /* adjusted bias */
147 148 long temp; /* for bias adjust */
148 149
149 150 extern void profver(void);
150 151
151 152 /* For symbol table entries read from program file. */
152 153 PROF_SYMBOL nl;
153 154
154 155 /* Compare routines called from qsort() */
155 156
156 157 int c_ccaddr(const void *arg1, const void *arg2);
157 158 int c_sladdr(const void *arg1, const void *arg2);
158 159 int c_time(const void *arg1, const void *arg2);
159 160 int c_ncalls(const void *arg1, const void *arg2);
160 161 int c_name(const void *arg1, const void *arg2);
161 162
162 163 /* Other stuff. */
163 164
164 165 /* Return size of open file (arg is file descriptor) */
165 166 static off_t fsize(int fd);
166 167
167 168 static void snh(void);
168 169 static void Perror(char *s);
169 170 static void eofon(FILE *iop, char *fn);
170 171 static void usage(void);
171 172 static char *getname(PROF_FILE *ldpter, PROF_SYMBOL symbol);
172 173
173 174 /* Memory allocation. Like malloc(), but no return if error. */
174 175 static void *_prof_Malloc(int item_count, int item_size);
175 176
176 177 /* Scan past path part (if any) in the ... */
177 178 static char *basename(char *s);
178 179
179 180 /* command name, for error messages. */
180 181 char *cmdname;
181 182 /* Structure of subroutine call counters (cnt) is defined in mon.h. */
182 183
183 184 /* Structure for header of mon.out (hdr) is defined in mon.h. */
184 185
185 186 /* Local representation of symbols and call/time information. */
186 187 struct slist {
187 188 char *sl_name; /* Symbol name. */
188 189 char *sl_addr; /* Address. */
189 190 long sl_size; /* size of symbol */
190 191 long sl_count; /* Count of subroutine calls */
191 192 float sl_time; /* Count of clock ticks in this routine, */
192 193 /* converted to secs. */
193 194 };
194 195
195 196 /* local structure for tracking synonyms in our symbol list */
196 197 struct snymEntry {
197 198 char *sym_addr; /* address which has a synonym */
198 199 int howMany; /* # of synonyms for this symbol */
199 200 int snymReported; /* 'was printed in a report line already' */
200 201 /* flag, */
201 202 /* > 0 report line printed for these syns. */
202 203 /* == 0 not printed yet. */
203 204 long tot_sl_count; /* total subr calls for these snyms */
204 205 float tot_sl_time; /* total clock ticks (a la sl_time) */
205 206 };
206 207
207 208
208 209 #define AOUTHSZ (filhdr.f_opthdr)
209 210 PROF_FILE filhdr; /* profile file descriptor */
210 211 Elf32_Shdr *scnhdrp; /* pointer to first section header */
211 212 /* (space by _prof_Malloc) */
212 213
213 214 struct hdr head; /* Profile file (MON_OUT) header. */
214 215
215 216 int (*sort)() = NULL; /* Compare routine for sorting output */
216 217 /* symbols. Set by "-[acnt]". */
217 218
218 219 int flags; /* Various flag bits. */
219 220
220 221 char *pc_l; /* From head.lpc. */
221 222
222 223 char *pc_h; /* " head.hpc. */
223 224
224 225 short VwasSpecified = 0; /* 1 if -V was specified */
225 226
226 227 /*
227 228 * Bit macro and flag bit definitions. These need to be identical to the
228 229 * set in profv.h. Any change here should be reflected in profv.c also.
229 230 */
230 231 #define FBIT(pos) (01 << (pos)) /* Returns value with bit pos set. */
231 232 #define F_SORT FBIT(0) /* Set if "-[acnt]" seen. */
232 233 #define F_VERBOSE FBIT(1) /* Set if "-s" seen. */
233 234 #define F_ZSYMS FBIT(2) /* Set if "-z" seen. */
234 235 #define F_PADDR FBIT(3) /* Set if "-o" or "-x" seen. */
235 236 #define F_NHEAD FBIT(4) /* Set if "-h" seen. */
236 237
237 238
238 239 struct snymEntry *snymList; /* Pointer to allocated list of */
239 240 /* synonym entries. */
240 241 struct snymEntry *snymp;
241 242 /* for scanning entries. */
242 243
243 244 int snymCapacity; /* #slots in snymList */
244 245 int n_snyms; /* #used slots in snymList */
245 246
246 247 static int readnl(int symindex);
247 248 static int fprecision(long count);
248 249
249 250 /*
250 251 * Sort flags. Mutually exclusive. These need to be identical to the ones
251 252 * defined in profv.h
252 253 */
253 254 #define BY_ADDRESS 0x1
254 255 #define BY_NCALLS 0x2
255 256 #define BY_NAME 0x4
256 257 #define BY_TIME 0x8
257 258
258 259 extern unsigned char sort_flag; /* what type of sort ? */
259 260
260 261 /*
261 262 * printSnymNames - print a comma-seperated list of snym names.
262 263 * This routine hunts down all the synonyms for the given
263 264 * symbol, and prints them as a comma-seperated list.
264 265 * NB we assume that all the synonyms _Follow_ this one,
265 266 * since they are only printed when the First one
266 267 * is seen.
267 268 */
268 269 void
269 270 printSnymNames(struct slist *slp, struct snymEntry *snymp)
270 271 {
271 272 /* how many snyms for this addr, total, and their shared address */
272 273 int i = snymp->howMany;
273 274 char *sharedaddr = snymp->sym_addr;
274 275
275 276 /* put out first name - it counts as one, so decr count */
276 277 (void) fputs(slp->sl_name, stdout);
277 278 i--;
278 279
279 280 /* for the others: find each, print each. */
280 281 while (--i >= 0) {
281 282 while ((++slp)->sl_addr != sharedaddr)
282 283 ;
283 284 Print(", %s", slp->sl_name);
284 285 }
285 286 /* finally.. the trailing newline */
286 287 (void) putchar('\n');
287 288 }
288 289
289 290
290 291 /*
291 292 * getSnymEntry - see if addr was noted as a aliased address
292 293 * (i.e. a synonym symbol) and return the address of the
293 294 * snym entry if it was.
294 295 */
295 296 struct snymEntry *
296 297 getSnymEntry(char *sl_addr)
297 298 {
298 299 struct snymEntry *p;
299 300 int i;
300 301
301 302 for (p = snymList, i = n_snyms; --i >= 0; p++)
302 303 if (sl_addr == p->sym_addr)
303 304 return (p);
304 305
305 306 return ((struct snymEntry *)0);
306 307 }
307 308
308 309
309 310 int
310 311 main(int argc, char **argv)
311 312 {
312 313 char buffer[BUFSIZ]; /* buffer for printf */
313 314
314 315 WORD *pcounts; /* Pointer to allocated area for */
315 316 /* pcounts: PC clock hit counts */
316 317
317 318 WORD *pcp; /* For scanning pcounts. */
318 319
319 320 struct cnt *ccounts; /* Pointer to allocated area for cnt */
320 321 /* structures: subr PC-call counts. */
321 322
322 323 struct cnt *ccp; /* For scanning ccounts. */
323 324
324 325 struct slist *slist; /* Pointer to allocated slist structures: */
325 326 /* symbol name/address/time/call counts */
326 327
327 328 struct slist *slp; /* For scanning slist */
328 329
329 330 int vn_cc, n_cc; /* Number of cnt structures in profile data */
330 331 /* file (later # ones used). */
331 332
332 333 int n_pc; /* Number of pcounts in profile data file. */
333 334
334 335 int n_syms; /* Number of text symbols (of proper type) */
335 336 /* that fill in range of profiling. */
336 337
337 338 int n_nonzero; /* Number of (above symbols) actually printed */
338 339 /* because nonzero time or # calls. */
339 340
340 341 int symttl; /* Total # symbols in program file sym-table */
341 342
342 343 int i;
343 344
344 345 int fdigits = 0; /* # of digits of precision for print msecs/call */
345 346
346 347 int n, symct;
347 348
348 349 long sf; /* Scale for index into pcounts: */
349 350 /* i(pc) = ((pc - pc_l) * sf)/bias. */
350 351
351 352 unsigned pc_m; /* Range of PCs profiled: pc_m = pc_h - pc_l */
352 353
353 354 float t, t0;
354 355 float t_tot; /* Total time: PROFSEC(sum of all pcounts[i]) */
355 356 int callTotal = 0;
356 357
357 358 DEBUG_LOC("main: top");
358 359 setbuf(stdout, buffer);
359 360 cmdname = basename(*argv); /* command name. */
360 361
361 362 while ((n = getopt(argc, argv, "canthsglzoxT:m:VC")) != EOF) {
362 363 switch (n) {
363 364 int (*fcn)(); /* For function to sort results. */
364 365
365 366 case 'm': /* Specify data file: -m file */
366 367 mon_fn = optarg;
367 368 break;
368 369
369 370 #ifdef ddt
370 371 case 'T': /* Set trace flags: -T(octnum) */
371 372 debug_value = (int)strtol(optarg, 0, 8);
372 373 break;
373 374 #endif
374 375
375 376 case 'n': /* Sort by symbol name. */
376 377 fcn = c_name;
377 378 sort_flag |= BY_NAME;
378 379 goto check;
379 380
380 381 case 't': /* Sort by decreasing time. */
381 382 fcn = c_time;
382 383 sort_flag |= BY_TIME;
383 384 goto check;
384 385
385 386 case 'c': /* Sort by decreasing # calls. */
386 387 fcn = c_ncalls;
387 388 sort_flag |= BY_NCALLS;
388 389 goto check;
389 390
390 391 case 'a': /* Sort by increasing symbol address */
391 392 /* (don't have to -- it will be) */
392 393 fcn = NULL;
393 394 sort_flag |= BY_ADDRESS;
394 395 check: /* Here to check sort option conflicts. */
395 396 if (sort != NULL && sort != fcn) {
396 397 Fprint(stderr, "%s: Warning: %c overrides"
397 398 " previous specification\n", cmdname, n);
398 399 }
399 400 sort = fcn; /* Store sort routine */
400 401 flags |= F_SORT; /* Note have done so */
401 402 break;
402 403
403 404 case 'o': /* Include symbol addresses in output. */
404 405 case 'x': /* Include symbol addresses in output. */
405 406 aformat[2] = n; /* 'o' or 'x' in format */
406 407 flags |= F_PADDR; /* Set flag. */
407 408 break;
408 409
409 410 case 'g': /* Include local T symbols as well as global */
410 411 gflag = 1;
411 412 break;
412 413
413 414 case 'l': /* Do NOT include local T symbols */
414 415 gflag = 0;
415 416 break;
416 417
417 418 case 'z': /* Print all symbols in profiling range, */
418 419 /* even if no time or # calls. */
419 420 flags |= F_ZSYMS; /* Set flag. */
420 421 break;
421 422
422 423 case 'h': /* Suppress table header. */
423 424 flags |= F_NHEAD;
424 425 break;
425 426
426 427 case 's': /* Follow normal output with extra summary. */
427 428 flags |= F_VERBOSE; /* Set flag (...) */
428 429 break;
429 430
430 431 case 'V':
431 432 (void) fprintf(stderr, "prof: %s %s\n",
432 433 (const char *)SGU_PKG, (const char *)SGU_REL);
433 434 VwasSpecified = 1;
434 435 break;
435 436
436 437 case 'C': /* demangle C++ names before printing. */
437 438 Cflag = 1;
438 439 break;
439 440
440 441 case '?': /* But no good. */
441 442 usage();
442 443 } /* End switch (n) */
443 444 } /* End while (getopt) */
444 445
445 446 DEBUG_LOC("main: following getopt");
446 447
447 448 /* if -V the only argument, just exit. */
448 449 if (VwasSpecified && argc == 2 && !flags)
449 450 exit(0);
450 451
451 452 if (optind < argc)
452 453 sym_fn = argv[optind]; /* name other than `a.out' */
453 454
454 455 if (sort == NULL && !(flags & F_SORT))
455 456 /* If have not specified sort mode ... */
456 457 sort = c_time; /* then sort by decreasing time. */
457 458
458 459 /*
459 460 * profver() checks to see if the mon.out was "versioned" and if
460 461 * yes, processes it and exits; otherwise, we have an *old-style*
461 462 * mon.out and we process it the old way.
462 463 */
463 464 profver();
464 465
465 466 /* Open monitor data file (has counts). */
466 467 if ((mon_iop = fopen(mon_fn, "r")) == NULL)
467 468 Perror(mon_fn);
468 469
469 470 DEBUG_LOC("main: before _symintOpen");
470 471 if ((ldptr = _symintOpen(sym_fn)) == NULL) {
471 472 Perror("_symintOpen failed");
472 473 }
473 474 DEBUG_LOC("main: after _symintOpen");
474 475 filhdr = *ldptr;
475 476
476 477 scnhdrp = ldptr->pf_shdarr_p;
477 478
478 479 {
479 480 Elf_Kind k = elf_kind(filhdr.pf_elf_p);
480 481
481 482 DEBUG_EXP(printf("elf_kind = %d\n", k));
482 483 DEBUG_EXP(printf("elf_type = %d\n", filhdr.pf_elfhd_p->e_type));
483 484 if ((k != ELF_K_ELF) || (filhdr.pf_elfhd_p->e_type != ET_EXEC)) {
484 485 Fprint(stderr, "%s: %s: improper format\n", cmdname, sym_fn);
485 486 exit(1);
486 487 }
487 488 }
488 489
489 490 /* Compute the file address of symbol table. Machine-dependent. */
490 491
491 492 DEBUG_EXP(printf("number of symbols (pf_nsyms) = %d\n",
492 493 filhdr.pf_nsyms));
493 494
494 495 /* Number of symbols in file symbol table. */
495 496 symttl = filhdr.pf_nsyms;
496 497 if (symttl == 0) { /* This is possible. */
497 498 Fprint(stderr, "%s: %s: no symbols\n", cmdname, sym_fn);
498 499 exit(0); /* Note zero exit code. */
499 500 }
500 501 /* Get size of file containing profiling data. Read header part. */
501 502 n = fsize(fileno(mon_iop));
502 503 if (fread((char *)&head, sizeof (struct hdr), 1, mon_iop) != 1)
503 504 eofon(mon_iop, mon_fn); /* Probably junk file. */
504 505
505 506 /* Get # cnt structures (they follow header), */
506 507 /* and allocate space for them. */
507 508
508 509 n_cc = head.nfns;
509 510 ccounts = _prof_Malloc(n_cc, sizeof (struct cnt));
510 511
511 512 /* Read the call addr-count pairs. */
512 513 if (fread((char *)ccounts, sizeof (struct cnt), n_cc, mon_iop) != n_cc)
513 514 eofon(mon_iop, mon_fn);
514 515
515 516 /*
516 517 * Compute # PC counters (pcounts), which occupy whatever is left
517 518 * of the file after the header and call counts.
518 519 */
519 520
520 521 n_pc = (n - sizeof (head) - n_cc * sizeof (struct cnt))/sizeof (WORD);
521 522 ccp = &ccounts[n_cc]; /* Point to last (+1) of call counters ... */
522 523 do { /* and scan backward until find highest one used. */
523 524 if ((--ccp)->mcnt)
524 525 break; /* Stop when find nonzero count. */
525 526 } while (--n_cc > 0); /* Or all are zero. */
526 527
527 528 if (n_cc > 0) {
528 529
529 530 /* If less than all cnt entries are used, return unused space. */
530 531 if (n_cc < head.nfns) {
531 532 if ((ccounts = (struct cnt *)realloc((char *)ccounts,
532 533 (unsigned)n_cc * sizeof (struct cnt))) == NULL)
533 534 snh(); /* Should not fail when reducing size. */
534 535 }
535 536
536 537 /* If more than 250 cnt entries used set verbose for warning */
537 538 if (n_cc > (MPROGS0 * 5)/6)
538 539 flags |= F_VERBOSE;
539 540
540 541 /* Space for PC counts. */
541 542 pcounts = (WORD *)_prof_Malloc(n_pc, sizeof (WORD));
542 543 /* Read the PC counts from rest of MON_OUT file. */
543 544 if (fread((char *)pcounts, sizeof (WORD), n_pc, mon_iop) != n_pc)
544 545 eofon(mon_iop, mon_fn);
545 546 /*
546 547 *
547 548 * Having gotten preliminaries out of the way, get down to business.
548 549 * The range pc_m of addresses over which profiling was done is
549 550 * computed from the low (pc_l) and high (pc_h) addresses, gotten
550 551 * from the MON_OUT header. From this and the number of clock
551 552 * tick counters, n_pc, is computed the so-called "scale", sf, used
552 553 * in the mapping of addresses to indices, as follows:
553 554 *
554 555 * (pc - pc_l) * sf
555 556 * i(pc) = ----------------
556 557 * 0200000
557 558 *
558 559 * Also, the N-to-one value, s_inv, such that
559 560 *
560 561 * i(pc_l + K * s_inv + d) = K, for 0 <= d < s_inv
561 562 *
562 563 * Following this, the symbol table is scanned, and those symbols
563 564 * that qualify are counted. These are T-type symbols, excluding
564 565 * local (nonglobal) unless the "-g" option was given. Having thus
565 566 * determined the space requirements, space for symbols/times etc.
566 567 * is allocated, and the symbol table re-read, this time keeping
567 568 * qualified symbols.
568 569 *
569 570 * NB s_inv, as actually computed, is not sufficiently accurate
570 571 * (since it is truncated) for many calculations. Since it is
571 572 * logically equivalent to 1/(sf/bias), and the latter is much
572 573 * more accurate, therefore the latter will often appear in
573 574 * the code when 's_inv' is mentioned. dween
574 575 *
575 576 */
576 577
577 578
578 579 pc_l = head.lpc; /* Low PC of range that was profiled. */
579 580 pc_h = head.hpc; /* First address past range of profiling. */
580 581 pc_m = pc_h - pc_l; /* Range of profiled addresses. */
581 582
582 583 /* BEGIN CSTYLED */
583 584 OLD_DEBUG(if (debug_value) Fprint(stderr,
584 585 "low pc = %#o, high pc = %#o, range = %#o = %u\n\
585 586 call counts: %u, %u used; pc counters: %u\n",
586 587 pc_l, pc_h, pc_m, pc_m, head.nfns, n_cc, n_pc));
587 588 /* END CSTYLED */
588 589
589 590 /*LINTED: E_ASSIGMENT_CAUSE_LOSS_PREC*/
590 591 sf = (BIAS * (double)n_pc)/pc_m;
591 592 /*
592 593 * Now adjust bias and sf so that there is no overflow
593 594 * when calculating indices.
594 595 */
595 596 bias = BIAS;
596 597 temp = pc_m;
597 598 while ((temp >>= 1) > 0x7fff) {
598 599 sf >>= 1;
599 600 bias >>= 1;
600 601 }
601 602
602 603 /* BEGIN CSTYLED */
603 604 OLD_DEBUG(
604 605 if (debug_value) {
605 606
606 607 Fprint(stderr, "sf = %d, s_inv = %d bias = %d\n",
607 608 (long)sf, pc_m / n_pc, bias);
608 609 }
609 610 );
610 611 /* END CSTYLED */
611 612
612 613 /* Prepare to read symbols from "a.out" (or whatever). */
613 614 n_syms = 0; /* Init count of qualified symbols. */
614 615 n = symttl; /* Total symbols. */
615 616 while (--n >= 0) /* Scan symbol table. */
616 617 if (readnl(n)) /* Read and examine symbol, count qualifiers */
617 618 n_syms++;
618 619
619 620 /* BEGIN CSTYLED */
620 621 OLD_DEBUG(
621 622 if (debug_value) {
622 623 Fprint(stderr, "%u symbols, %u qualify\n", symttl, n_syms);
623 624 }
624 625 );
625 626 /* END CSTYLED */
626 627
627 628 /* Allocate space for qualified symbols. */
628 629
629 630 slist = slp = _prof_Malloc(n_syms, sizeof (struct slist));
630 631
631 632 /*
632 633 * Allocate space for synonym symbols
633 634 * (i.e. symbols that refer to the same address).
634 635 * NB there can be no more than n_syms/2 addresses
635 636 * with symbols, That Have Aliases, that refer to them!
636 637 */
637 638
638 639 snymCapacity = n_syms/2;
639 640 snymList = snymp =
640 641 _prof_Malloc(snymCapacity, sizeof (struct snymEntry));
641 642 n_snyms = 0;
642 643
643 644 /* OLD_DEBUG(debug_value &= ~020); */
644 645
645 646 /* Loop on number of qualified symbols. */
646 647 for (n = n_syms, symct = 0; n > 0; symct++) {
647 648 if (readnl(symct)) { /* Get one. Check again. */
648 649 /* Is qualified. Move name ... */
649 650 slp->sl_name = getname(ldptr, nl);
650 651
651 652 /* and address into slist structure. */
652 653 slp->sl_addr = (char *)nl.ps_sym.st_value;
653 654 slp->sl_size = nl.ps_sym.st_size;
654 655
655 656 /* set other slist fields to zero. */
656 657 slp->sl_time = 0.0;
657 658 slp->sl_count = 0;
658 659 /* BEGIN CSTYLED */
659 660 OLD_DEBUG(
660 661 if (debug_value & 02)
661 662 Fprint(stderr, "%-8.8s: %#8o\n", slp->sl_name, slp->sl_addr)
662 663 );
663 664 /* END CSTYLED */
664 665
665 666 slp++;
666 667 --n;
667 668 }
668 669 }
669 670 /*
670 671 *
671 672 * Now attempt to match call counts with symbols. To do this, it
672 673 * helps to first sort both the symbols and the call address/count
673 674 * pairs by ascending address, since they are generally not, to
674 675 * begin with. The addresses associated with the counts are not,
675 676 * of course, the subroutine addresses associated with the symbols,
676 677 * but some address slightly past these. Therefore a given count
677 678 * address (in the fnpc field) is matched with the closest symbol
678 679 * address (sl_addr) that is:
679 680 * (1) less than the fnpc value but,
680 681 * (2) not more than the length of the function
681 682 * In other words, unreasonable matchups are avoided.
682 683 * Situations such as this could arise when static procedures are
683 684 * counted but the "-g" option was not given to this program,
684 685 * causing the symbol to fail to qualify. Without this limitation,
685 686 * unmatched counts could be erroneously charged.
686 687 *
687 688 */
688 689
689 690
690 691 ccp = ccounts; /* Point to first call counter. */
691 692 slp = slist; /* " " " symbol. */
692 693 /* Sort call counters and ... */
693 694 qsort((char *)ccp, (unsigned)n_cc, sizeof (struct cnt), c_ccaddr);
694 695 /* symbols by increasing address. */
695 696 qsort((char *)slp, (unsigned)n_syms, sizeof (struct slist), c_sladdr);
696 697 vn_cc = n_cc; /* save this for verbose option */
697 698
698 699
699 700 /* Loop to match up call counts & symbols. */
700 701 for (n = n_syms; n > 0 && vn_cc > 0; ) {
701 702 int sz = slp->sl_size;
702 703
703 704 if (sz == 0)
704 705 sz = slp[ 1 ].sl_addr - slp->sl_addr;
705 706 if (slp->sl_addr < ccp->fnpc &&
706 707 ccp->fnpc <= slp->sl_addr + sz) {
707 708 /* got a candidate: find Closest. */
708 709 struct slist *closest_symp;
709 710 do {
710 711 closest_symp = slp;
711 712 slp++;
712 713 --n;
713 714 } while (n > 0 && slp->sl_addr < ccp->fnpc);
714 715
715 716 /* BEGIN CSTYLED */
716 717 OLD_DEBUG(
717 718 if (debug_value & 04) {
718 719 Fprint(stderr,
719 720 "Routine %-8.8s @ %#8x+%-2d matches count address %#8x\n",
720 721 closest_symp->sl_name,
721 722 closest_symp->sl_addr,
722 723 ccp->fnpc-slp->sl_addr,
723 724 ccp->fnpc);
724 725 }
725 726 );
726 727 /* END CSTYLED */
727 728 closest_symp->sl_count = ccp->mcnt; /* Copy count. */
728 729 ++ccp;
729 730 --vn_cc;
730 731 } else if (ccp->fnpc < slp->sl_addr) {
731 732 ++ccp;
732 733 --vn_cc;
733 734 } else {
734 735 ++slp;
735 736 --n;
736 737 }
737 738 }
738 739
739 740 /*
740 741 *
741 742 * The distribution of times to addresses is done on a proportional
742 743 * basis as follows: The t counts in pcounts[i] correspond to clock
743 744 * ticks for values of pc in the range pc, pc+1, ..., pc+s_inv-1
744 745 * (odd addresses excluded for PDP11s). Without more detailed info,
745 746 * it must be assumed that there is no greater probability
746 747 * of the clock ticking for any particular pc in this range than for
747 748 * any other. Thus the t counts are considered to be equally
748 749 * distributed over the addresses in the range, and that the time for
749 750 * any given address in the range is pcounts[i]/s_inv.
750 751 *
751 752 * The values of the symbols that qualify, bounded below and above
752 753 * by pc_l and pc_h, respectively, partition the profiling range into
753 754 * regions to which are assigned the total times associated with the
754 755 * addresses they contain in the following way:
755 756 *
756 757 * The sum of all pcounts[i] for which the corresponding addresses are
757 758 * wholly within the partition are charged to the partition (the
758 759 * subroutine whose address is the lower bound of the partition).
759 760 *
760 761 * If the range of addresses corresponding to a given t = pcounts[i]
761 762 * lies astraddle the boundary of a partition, e.g., for some k such
762 763 * that 0 < k < s_inv-1, the addresses pc, pc+1, ..., pc+k-1 are in
763 764 * the lower partition, and the addresses pc+k, pc+k+1, ..., pc+s_inv-1
764 765 * are in the next partition, then k*pcounts[i]/s_inv time is charged
765 766 * to the lower partition, and (s_inv-k) * pcounts[i]/s_inv time to the
766 767 * upper. It is conceivable, in cases of large granularity or small
767 768 * subroutines, for a range corresponding to a given pcounts[i] to
768 769 * overlap three regions, completely containing the (small) middle one.
769 770 * The algorithm is adjusted appropriately in this case.
770 771 *
771 772 */
772 773
773 774
774 775 pcp = pcounts; /* Reset to base. */
775 776 slp = slist; /* Ditto. */
776 777 t0 = 0.0; /* Time accumulator. */
777 778 for (n = 0; n < n_syms; n++) { /* Loop on symbols. */
778 779 /* Start addr of region, low addr of overlap. */
779 780 char *pc0, *pc00;
780 781 /* Start addr of next region, low addr of overlap. */
781 782 char *pc1, *pc10;
782 783 /* First index into pcounts for this region and next region. */
783 784 int i0, i1;
784 785 long ticks;
785 786
786 787 /* Address of symbol (subroutine). */
787 788 pc0 = slp[n].sl_addr;
788 789
789 790 /* Address of next symbol, if any or top */
790 791 /* of profile range, if not */
791 792 pc1 = (n < n_syms - 1) ? slp[n+1].sl_addr : pc_h;
792 793
793 794 /* Lower bound of indices into pcounts for this range */
794 795
795 796 i0 = (((unsigned)pc0 - (unsigned)pc_l) * sf)/bias;
796 797
797 798 /* Upper bound (least or least + 1) of indices. */
798 799 i1 = (((unsigned)pc1 - (unsigned)pc_l) * sf)/bias;
799 800
800 801 if (i1 >= n_pc) /* If past top, */
801 802 i1 = n_pc - 1; /* adjust. */
802 803
803 804 /* Lowest addr for which count maps to pcounts[i0]; */
804 805 pc00 = pc_l + (unsigned long)((bias * i0)/sf);
805 806
806 807 /* Lowest addr for which count maps to pcounts[i1]. */
807 808 pc10 = pc_l + (unsigned long)((bias * i1)/sf);
808 809
809 810 /* BEGIN CSTYLED */
810 811 OLD_DEBUG(if (debug_value & 010) Fprint(stderr,
811 812 "%-8.8s\ti0 = %4d, pc00 = %#6o, pc0 = %#6o\n\
812 813 \t\ti1 = %4d, pc10 = %#6o, pc1 = %#6o\n\t\t",
813 814 slp[n].sl_name, i0, pc00, pc0, i1, pc10, pc1));
814 815 /* END CSTYLED */
815 816 t = 0; /* Init time for this symbol. */
816 817 if (i0 == i1) {
817 818 /* Counter overlaps two areas? (unlikely */
818 819 /* unless large granularity). */
819 820 ticks = pcp[i0]; /* # Times (clock ticks). */
820 821 OLD_DEBUG(if (debug_value & 010) fprintf(stderr, "ticks = %d\n", ticks));
821 822
822 823 /* Time less that which overlaps adjacent areas */
823 824 t += PROFSEC(ticks * ((double)(pc1 - pc0) * sf)/bias);
824 825
825 826 /* BEGIN CSTYLED */
826 827 OLD_DEBUG(if (debug_value & 010)
827 828 Fprint(stderr, "%ld/(%.1f)", (pc1 - pc0) * ticks, DBL_ADDRPERCELL)
828 829 );
829 830 /* END CSTYLED */
830 831 } else {
831 832 /* Overlap with previous region? */
832 833 if (pc00 < pc0) {
833 834 ticks = pcp[i0];
834 835 /* BEGIN CSTYLED */
835 836 OLD_DEBUG(if (debug_value & 010)
836 837 fprintf(stderr, "pc00 < pc0 ticks = %d\n", ticks));
837 838
838 839 /* Get time of overlapping area and */
839 840 /* subtract proportion for lower region. */
840 841 t += PROFSEC(
841 842 ticks*(1-((double)(pc0-pc00) *sf)/bias));
842 843
843 844 /* Do not count this time when summing times */
844 845 /* wholly within the region. */
845 846 i0++;
846 847 /* BEGIN CSTYLED */
847 848 OLD_DEBUG(if (debug_value & 010)
848 849 Fprint(stderr, "%ld/(%.1f) + ", (pc0 - pc00) * ticks,
849 850 DBL_ADDRPERCELL));
850 851 /* END CSTYLED */
851 852 }
852 853
853 854 /* Init sum of counts for PCs not shared w/other */
854 855 /* routines. */
855 856 ticks = 0;
856 857
857 858 /* Stop at first count that overlaps following */
858 859 /* routine. */
859 860 for (i = i0; i < i1; i++)
860 861 ticks += pcp[i];
861 862
862 863 t += PROFSEC(ticks); /* Convert to secs, add to total */
863 864 OLD_DEBUG(if (debug_value & 010) Fprint(stderr, "%ld", ticks));
864 865 /* Some overlap with low addresses of next routine? */
865 866 if (pc10 < pc1) {
866 867 /* Yes. Get total count ... */
867 868 ticks = pcp[i1];
868 869
869 870 /* and accumulate proportion for addresses in */
870 871 /* range of this routine */
871 872 t += PROFSEC(((double)ticks *
872 873 (pc1 - pc10)*sf)/bias);
873 874 /* BEGIN CSTYLED */
874 875 OLD_DEBUG(if (debug_value & 010) fprintf(stderr, "ticks = %d\n", ticks));
875 876 OLD_DEBUG(if (debug_value & 010)
876 877 Fprint(stderr, " + %ld/(%.1f)", (pc1 - pc10) * ticks, DBL_ADDRPERCELL)
877 878 );
878 879 /* END CSTYLED */
879 880 }
880 881 } /* End if (i0 == i1) ... else ... */
881 882
882 883 slp[n].sl_time = t; /* Store time for this routine. */
883 884 t0 += t; /* Accumulate total time. */
884 885 OLD_DEBUG(if (debug_value & 010) Fprint(stderr, " ticks = %.2f msec\n", t));
885 886 } /* End for (n = 0; n < n_syms; n++) */
886 887
887 888 /* Final pass to total up time. */
888 889 /* Sum ticks, then convert to seconds. */
889 890
890 891 for (n = n_pc, temp = 0; --n >= 0; temp += *(pcp++))
891 892 ;
892 893
893 894 t_tot = PROFSEC(temp);
894 895
895 896 /*
896 897 * Now, whilst we still have the symbols sorted
897 898 * in address order..
898 899 * Loop to record duplicates, so we can display
899 900 * synonym symbols correctly.
900 901 * Synonym symbols, or symbols with the same address,
901 902 * are to be displayed by prof on the same line, with
902 903 * one statistics line, as below:
903 904 * ... 255 ldaopen, ldaopen
904 905 * The way this will be implemented, is as follows:
905 906 *
906 907 * Pass 1 - while the symbols are in address order, we
907 908 * do a pre-pass through them, to determine for which
908 909 * addresses there are more than one symbol (i.e. synonyms).
909 910 * During this prepass we collect summary statistics in
910 911 * the synonym entry, for all the synonyms.
911 912 *
912 913 * 'Pass' 2 - while printing a report, for each report line,
913 914 * if the current symbol is a synonym symbol (i.e. in the
914 915 * snymList) then we scan forward and pick up all the names
915 916 * which map to this address, and print them too.
916 917 * If the address' synonyms have already been printed, then
917 918 * we just skip this symbol and go on to process the next.
918 919 *
919 920 */
920 921
921 922 {
922 923 /* pass 1 */
923 924 char *thisaddr;
924 925 char *lastaddr = slist->sl_addr; /* use 1st sym as */
925 926 /* 'last/prior symbol' */
926 927 int lastWasSnym = 0; /* 1st can't be snym yet-no aliases seen! */
927 928 int thisIsSnym;
928 929
929 930 /* BEGIN CSTYLED */
930 931 OLD_DEBUG(
931 932 int totsnyms = 0; int totseries = 0; struct slist *lastslp = slist;
932 933 );
933 934 /* END CSTYLED */
934 935
935 936 /* NB loop starts with 2nd symbol, loops over n_syms-1 symbols! */
936 937 for (n = n_syms-1, slp = slist+1; --n >= 0; slp++) {
937 938 thisaddr = slp->sl_addr;
938 939 thisIsSnym = (thisaddr == lastaddr);
939 940
940 941 if (thisIsSnym) {
941 942 /* gotta synonym */
942 943 if (!lastWasSnym) {
943 944 /* BEGIN CSTYLED */
944 945 OLD_DEBUG(
945 946 if (debug_value) {
946 947 Fprint(stderr,
947 948 "Synonym series:\n1st->\t%s at address %x, ct=%ld, time=%f\n",
948 949 lastslp->sl_name, lastaddr, lastslp->sl_count,
949 950 lastslp->sl_time);
950 951 totseries++;
951 952 totsnyms++;
952 953 }
953 954 );
954 955 /* END CSTYLED */
955 956 /* this is the Second! of a series */
956 957 snymp = (n_snyms++ == 0 ? snymList : snymp+1);
957 958 snymp->howMany = 1; /* gotta count 1st one!! */
958 959 snymp->sym_addr = slp->sl_addr;
959 960 /* zero summary statistics */
960 961 snymp->tot_sl_count = 0;
961 962 snymp->tot_sl_time = 0.0;
962 963 /* Offen the Reported flag */
963 964 snymp->snymReported = 0;
964 965 }
965 966 /* BEGIN CSTYLED */
966 967 OLD_DEBUG(
967 968 if (debug_value) {
968 969 Fprint(stderr,
969 970 "\t%s at address %x, ct=%ld, time=%f\n",
970 971 slp->sl_name,
971 972 thisaddr,
972 973 slp->sl_count,
973 974 slp->sl_time);
974 975 totsnyms++;
975 976 }
976 977 );
977 978 /* END CSTYLED */
978 979 /* ok - bump count for snym, and note its Finding */
979 980 snymp->howMany++;
980 981 /* and update the summary statistics */
981 982 snymp->tot_sl_count += slp->sl_count;
982 983 snymp->tot_sl_time += slp->sl_time;
983 984 }
984 985 callTotal += slp->sl_count;
985 986 lastaddr = thisaddr;
986 987 lastWasSnym = thisIsSnym;
987 988 /* BEGIN CSTYLED */
988 989 OLD_DEBUG(
989 990 if (debug_value) lastslp = slp;
990 991 );
991 992 /* END CSTYLED */
992 993
993 994 }
994 995 /* BEGIN CSTYLED */
995 996 OLD_DEBUG(
996 997 if (debug_value) {
997 998 Fprint(stderr, "Total #series %d, #synonyms %d\n", totseries, totsnyms);
998 999 }
999 1000 );
1000 1001 /* END CSTYLED */
1001 1002 }
1002 1003 /*
1003 1004 * Most of the heavy work is done now. Only minor stuff remains.
1004 1005 * The symbols are currently in address order and must be re-sorted
1005 1006 * if desired in a different order. Report generating options
1006 1007 * include "-o" or "-x": Include symbol address, which causes
1007 1008 * another column
1008 1009 * in the output; and "-z": Include symbols in report even if zero
1009 1010 * time and call count. Symbols not in profiling range are excluded
1010 1011 * in any case. Following the main body of the report, the "-s"
1011 1012 * option causes certain additional information to be printed.
1012 1013 */
1013 1014
1014 1015 OLD_DEBUG(if (debug_value) Fprint(stderr,
1015 1016 "Time unaccounted for: %.7G\n", t_tot - t0));
1016 1017
1017 1018 if (sort) /* If comparison routine given then use it. */
1018 1019 qsort((char *)slist, (unsigned)n_syms,
1019 1020 sizeof (struct slist), sort);
1020 1021
1021 1022 if (!(flags & F_NHEAD)) {
1022 1023 if (flags & F_PADDR)
1023 1024 Print("%s", atitle); /* Title for addresses. */
1024 1025 (void) puts(" %Time Seconds Cumsecs #Calls msec/call Name");
1025 1026 }
1026 1027 t = 0.0; /* Init cumulative time. */
1027 1028 if (t_tot != 0.0) /* Convert to percent. */
1028 1029 t_tot = 100.0/t_tot; /* Prevent divide-by-zero fault */
1029 1030 n_nonzero = 0; /* Number of symbols with nonzero time or # calls. */
1030 1031 for (n = n_syms, slp = slist; --n >= 0; slp++) {
1031 1032 long count; /* # Calls. */
1032 1033 /* t0, time in seconds. */
1033 1034
1034 1035 /* if a snym symbol, use summarized stats, else use indiv. */
1035 1036 if ((snymp = getSnymEntry(slp->sl_addr)) != 0) {
1036 1037 count = snymp->tot_sl_count;
1037 1038 t0 = snymp->tot_sl_time;
1038 1039
1039 1040 } else {
1040 1041 count = slp->sl_count;
1041 1042 t0 = slp->sl_time;
1042 1043 }
1043 1044
1044 1045 /* if a snym and already reported, skip this entry */
1045 1046 if (snymp && snymp->snymReported)
1046 1047 continue;
1047 1048 /* Don't do entries with no action. */
1048 1049 if (t0 == 0.0 && count == 0 && !(flags & F_ZSYMS))
1049 1050 continue;
1050 1051 if ((strcmp(slp->sl_name, "_mcount") == 0) ||
1051 1052 (strcmp(slp->sl_name, "mcount") == 0)) {
1052 1053 count = callTotal;
1053 1054 }
1054 1055
1055 1056 /* count number of entries (i.e. symbols) printed */
1056 1057 if (snymp)
1057 1058 n_nonzero += snymp->howMany; /* add for each snym */
1058 1059 else
1059 1060 n_nonzero++;
1060 1061
1061 1062 if (flags & F_PADDR) { /* Printing address of symbol? */
1062 1063 /* LINTED: variable format */
1063 1064 Print(aformat, slp->sl_addr);
1064 1065 }
1065 1066 t += t0; /* move here; compiler bug !! */
1066 1067 Print("%6.1f%8.2f%8.2f", t0 * t_tot, t0, t);
1067 1068 fdigits = 0;
1068 1069 if (count) { /* Any calls recorded? */
1069 1070 /* Get reasonable number of fractional digits to print. */
1070 1071 fdigits = fprecision(count);
1071 1072 Print("%8ld%#*.*f", count, fdigits+8, fdigits,
1072 1073 1000.0*t0/count);
1073 1074 Print("%*s", 6-fdigits, " ");
1074 1075 } else {
1075 1076 Print("%22s", " ");
1076 1077 }
1077 1078 /*
1078 1079 * now print the name (or comma-seperate list of names,
1079 1080 * for synonym symbols).
1080 1081 */
1081 1082 if (snymp) {
1082 1083 printSnymNames(slp, snymp); /* print it, then */
1083 1084 snymp->snymReported = 1; /* mark it Done */
1084 1085 }
1085 1086 else
1086 1087 (void) puts(slp->sl_name); /* print the one name */
1087 1088 }
1088 1089 if (flags & F_VERBOSE) { /* Extra info? */
1089 1090 Fprint(stderr, "%5d/%d call counts used\n", n_cc, head.nfns);
1090 1091 Fprint(stderr, "%5d/%d symbols qualified", n_syms, symttl);
1091 1092 if (n_nonzero < n_syms)
1092 1093 Fprint(stderr,
1093 1094 ", %d had zero time and zero call-counts\n",
1094 1095 n_syms - n_nonzero);
1095 1096 else
1096 1097 (void) putc('\n', stderr);
1097 1098 Fprint(stderr, "%#lx scale factor\n", (long)sf);
1098 1099 }
1099 1100
1100 1101 _symintClose(ldptr);
1101 1102 } else {
1102 1103 Fprint(stderr, "prof: no call counts captured\n");
1103 1104 }
1104 1105 return (0);
1105 1106 }
1106 1107 /* Return size of file associated with file descriptor fd. */
1107 1108
1108 1109 static off_t
1109 1110 fsize(int fd)
1110 1111 {
1111 1112 struct stat sbuf;
1112 1113
1113 1114 if (fstat(fd, &sbuf) < 0) /* Status of open file. */
1114 1115 Perror("stat");
1115 1116 return (sbuf.st_size); /* This is a long. */
1116 1117 }
1117 1118
1118 1119 /* Read symbol entry. Return TRUE if satisfies conditions. */
1119 1120
1120 1121 static int
1121 1122 readnl(int symindex)
1122 1123 {
1123 1124 nl = ldptr->pf_symarr_p[symindex];
1124 1125
1125 1126 /* BEGIN CSTYLED */
1126 1127 OLD_DEBUG(
1127 1128 if (debug_value & 020) {
1128 1129 Fprint(stderr,
1129 1130 "`%-8.8s'\tst_info=%#4o, value=%#8.6o\n",
1130 1131 ldptr->pf_symstr_p[nl.ps_sym.st_name],
1131 1132 (unsigned char) nl.ps_sym.st_info,
1132 1133 nl.ps_sym.st_value);
1133 1134 }
1134 1135 );
1135 1136 /* END CSTYLED */
1136 1137
1137 1138 /*
1138 1139 * TXTSYM accepts global (and local, if "-g" given) T-type symbols.
1139 1140 * Only those in the profiling range are useful.
1140 1141 */
1141 1142 return (nl.ps_sym.st_shndx < SHN_LORESERVE &&
1142 1143 TXTSYM(nl.ps_sym.st_shndx, nl.ps_sym.st_info) &&
1143 1144 (pc_l <= (char *)nl.ps_sym.st_value) &&
1144 1145 ((char *)nl.ps_sym.st_value < pc_h));
1145 1146 }
1146 1147 /*
1147 1148 * Error-checking memory allocators -
1148 1149 * Guarantees good return (else none at all).
1149 1150 */
1150 1151
1151 1152 static void *
1152 1153 _prof_Malloc(int item_count, int item_size)
1153 1154 {
1154 1155 void *p;
1155 1156
1156 1157 if ((p = malloc((unsigned)item_count * (unsigned)item_size)) == NULL) {
1157 1158 (void) fprintf(stderr, "%s: Out of space\n", cmdname);
1158 1159 exit(1);
1159 1160 }
1160 1161 return (p);
1161 1162 }
1162 1163
1163 1164
1164 1165
1165 1166 /*
1166 1167 * Given the quotient Q = N/D, where entier(N) == N and D > 0, an
1167 1168 * approximation of the "best" number of fractional digits to use
1168 1169 * in printing Q is f = entier(log10(D)), which is crudely produced
1169 1170 * by the following routine.
1170 1171 */
1171 1172
1172 1173 static int
1173 1174 fprecision(long count)
1174 1175 {
1175 1176 return (count < 10 ? 0 : count < 100 ? 1 : count < 1000 ? 2 :
1176 1177 count < 10000 ? 3 : 4);
1177 1178 }
1178 1179
1179 1180 /*
1180 1181 * Return pointer to base name(name less path) of string s.
1181 1182 * Handles case of superfluous trailing '/'s, and unlikely
1182 1183 * case of s == "/".
1183 1184 */
1184 1185
1185 1186 static char *
1186 1187 basename(char *s)
1187 1188 {
1188 1189 char *p;
1189 1190
1190 1191 p = &s[strlen(s)]; /* End (+1) of string. */
1191 1192 while (p > s && *--p == '/') /* Trim trailing '/'s. */
1192 1193 *p = '\0';
1193 1194 p++; /* New end (+1) of string. */
1194 1195 while (p > s && *--p != '/') /* Break backward on '/'. */
1195 1196 ;
1196 1197 if (*p == '/') /* If found '/', point to 1st following. */
1197 1198 p++;
1198 1199 if (*p == '\0')
1199 1200 p = "/"; /* If NULL, must be "/". (?) */
1200 1201 return (p);
1201 1202 }
1202 1203 /* Here if unexpected read problem. */
1203 1204
1204 1205 static void
1205 1206 eofon(FILE *iop, char *fn)
1206 1207 {
1207 1208 if (ferror(iop)) /* Real error? */
1208 1209 Perror(fn); /* Yes. */
1209 1210 Fprint(stderr, "%s: %s: Premature EOF\n", cmdname, fn);
1210 1211 exit(1);
1211 1212 }
1212 1213
1213 1214 /*
1214 1215 * Version of perror() that prints cmdname first.
1215 1216 * Print system error message & exit.
1216 1217 */
1217 1218
1218 1219 static void
1219 1220 Perror(char *s)
1220 1221 {
1221 1222 int err = errno; /* Save current errno in case */
1222 1223
1223 1224 Fprint(stderr, "%s: ", cmdname);
1224 1225 errno = err; /* Put real error back. */
1225 1226 perror(s); /* Print message. */
1226 1227 _symintClose(ldptr); /* cleanup symbol information */
1227 1228 exit(1); /* Exit w/nonzero status. */
1228 1229 }
1229 1230
1230 1231 /* Here for things that "Should Never Happen". */
1231 1232
1232 1233 static void
1233 1234 snh(void)
1234 1235 {
1235 1236 Fprint(stderr, "%s: Internal error\n", cmdname);
1236 1237 (void) abort();
1237 1238 }
1238 1239
1239 1240 /*
1240 1241 * Various comparison routines for qsort. Uses:
1241 1242 *
1242 1243 * c_ccaddr - Compare fnpc fields of cnt structs to put
1243 1244 * call counters in increasing address order.
1244 1245 * c_sladdr - Sort slist structures on increasing address.
1245 1246 * c_time - " " " " decreasing time.
1246 1247 * c_ncalls - " " " " decreasing # calls.
1247 1248 * c_name - " " " " increasing symbol name
1248 1249 */
1249 1250
1250 1251 #define CMP2(v1, v2) ((v1) < (v2) ? -1 : (v1) == (v2) ? 0 : 1)
1251 1252 #define CMP1(v) CMP2(v, 0)
1252 1253
1253 1254 int
1254 1255 c_ccaddr(const void *arg1, const void *arg2)
1255 1256 {
1256 1257 struct cnt *p1 = (struct cnt *)arg1;
1257 1258 struct cnt *p2 = (struct cnt *)arg2;
1258 1259
1259 1260 return (CMP2(p1->fnpc, p2->fnpc));
1260 1261 }
1261 1262
1262 1263 int
1263 1264 c_sladdr(const void *arg1, const void *arg2)
1264 1265 {
1265 1266 struct slist *p1 = (struct slist *)arg1;
1266 1267 struct slist *p2 = (struct slist *)arg2;
1267 1268
1268 1269 return (CMP2(p1->sl_addr, p2->sl_addr));
1269 1270 }
1270 1271
1271 1272 int
1272 1273 c_time(const void *arg1, const void *arg2)
1273 1274 {
1274 1275 struct slist *p1 = (struct slist *)arg1;
1275 1276 struct slist *p2 = (struct slist *)arg2;
1276 1277 float dtime = p2->sl_time - p1->sl_time; /* Decreasing time. */
1277 1278
1278 1279 return (CMP1(dtime));
1279 1280 }
1280 1281
1281 1282 int
1282 1283 c_ncalls(const void *arg1, const void *arg2)
1283 1284 {
1284 1285 struct slist *p1 = (struct slist *)arg1;
1285 1286 struct slist *p2 = (struct slist *)arg2;
1286 1287 int diff = p2->sl_count - p1->sl_count;
1287 1288 /* Decreasing # calls. */
1288 1289 return (CMP1(diff));
1289 1290 }
1290 1291
1291 1292 int
1292 1293 c_name(const void *arg1, const void *arg2)
1293 1294 {
1294 1295 struct slist *p1 = (struct slist *)arg1;
1295 1296 struct slist *p2 = (struct slist *)arg2;
1296 1297 int diff;
1297 1298
1298 1299 /* flex names has variable length strings for names */
1299 1300 diff = strcmp(p1->sl_name, p2->sl_name);
1300 1301 return (CMP1(diff));
1301 1302 }
1302 1303
1303 1304 #define STRSPACE 2400 /* guess at amount of string space */
↓ open down ↓ |
1269 lines elided |
↑ open up ↑ |
1304 1305
1305 1306 char *format_buf;
1306 1307 #define FORMAT_BUF "%s\n\t\t\t\t\t [%s]"
1307 1308
1308 1309 static char *
1309 1310 demangled_name(char *s)
1310 1311 {
1311 1312 const char *name;
1312 1313 size_t len;
1313 1314
1314 - name = conv_demangle_name(s);
1315 -
1316 - if (strcmp(name, s) == 0)
1315 + if ((name = conv_demangle_name(s)) == s)
1317 1316 return (s);
1318 1317
1319 1318 if (format_buf != NULL)
1320 1319 free(format_buf);
1321 1320
1322 1321 len = strlen(name) + strlen(FORMAT_BUF) + strlen(s) + 1;
1323 1322 format_buf = malloc(len);
1324 1323 if (format_buf == NULL)
1325 1324 return (s);
1326 1325 (void) snprintf(format_buf, len, FORMAT_BUF, name, s);
1326 + free((void *)name);
1327 1327 return (format_buf);
1328 1328 }
1329 1329
1330 1330 /* getname - get the name of a symbol in a permanent fashion */
1331 1331 static char *
1332 1332 getname(PROF_FILE *ldpter, PROF_SYMBOL symbol)
1333 1333 {
1334 1334 static char *strtable = NULL; /* space for names */
1335 1335 static int sp_used = 0; /* space used so far */
1336 1336 static int size = 0; /* size of string table */
1337 1337 char *name; /* name to store */
1338 1338 int lth; /* space needed for name */
1339 1339 int get; /* amount of space to get */
1340 1340
1341 1341 name = elf_strptr(ldpter->pf_elf_p, ldpter->pf_symstr_ndx,
1342 1342 symbol.ps_sym.st_name);
1343 1343 if (name == NULL)
1344 1344 return ("<<bad symbol name>>");
1345 1345
1346 1346 if (Cflag)
1347 1347 name = demangled_name(name);
1348 1348
1349 1349 lth = strlen(name) + 1;
1350 1350 if ((sp_used + lth) > size) { /* if need more space */
1351 1351 /* just in case very long name */
1352 1352 get = lth > STRSPACE ? lth : STRSPACE;
1353 1353 strtable = _prof_Malloc(1, get);
1354 1354 size = get;
1355 1355 sp_used = 0;
1356 1356 }
1357 1357 (void) strcpy(&(strtable[sp_used]), name);
1358 1358 name = &(strtable[sp_used]);
1359 1359 sp_used += lth;
1360 1360 return (name);
1361 1361 }
1362 1362
1363 1363 static void
1364 1364 usage(void)
1365 1365 {
1366 1366 (void) fprintf(stderr,
1367 1367 "usage: %s [-ChsVz] [-a | c | n | t] [-o | x] [-g | l]\n"
1368 1368 "\t[-m mdata] [prog]\n",
1369 1369 cmdname);
1370 1370 exit(1);
1371 1371 }
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX