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