|
|
1.1 root 1: /*
2: * profil.c
3: * 2/8/85
4: * Usage: profil [ -alnz ] [ infile [ profile [ outfile ] ] ]
5: *
6: * Reads Intel 8086 OMF SMALL model executable infile and profile, then
7: * writes profile information on outfile; defaults are stdin, PFILE, stdout.
8: * The profile information is normally a list of nonzero counts and names
9: * (sorted by count), followed by a list of unmatched profile counts.
10: * Options: -a print addresses in addition to counts and names
11: * -l sort by location; implies -a
12: * -n sort by name
13: * -z include symbols with zero counts
14: *
15: * Reference: "8086 Relocatable Object Module Formats,"
16: * Intel 121748-001 (c) 1981 Intel Corp.
17: */
18:
19: #define VERSION "1.0" /* version number */
20: #ifdef UDI
21: #define VFLAG 'v' /* flags must be l.c. for UDI */
22: #else
23: #define VFLAG 'V'
24: #endif
25:
26: #define NERRMSG 80 /* error message buffer length */
27: #define NAMELEN 41 /* max length of an lname + NUL */
28:
29: #include <stdio.h>
30: #include <prof.h>
31:
32: extern char *malloc();
33: extern addrcomp();
34: extern countcomp();
35: extern long getlong();
36: extern namecomp();
37:
38: /*
39: * OMF types.
40: */
41: #define RHEADR 0x6E /* R-module header */
42: #define BLKDEF 0x7A /* Block definition */
43: #define BLKEND 0x7C /* Block end */
44: #define THEADR 0x80 /* T-module header */
45: #define LHEADR 0x82 /* L-module header */
46: #define MODEND 0x8A /* Module end */
47: #define PUBDEF 0x90 /* Public definition */
48: #define LNAMES 0x96 /* list of names */
49: #define SEGDEF 0x98 /* Segment definition */
50: #define GRPDEF 0x9A /* Group definition */
51:
52: /*
53: * Symbols.
54: */
55: struct sym {
56: struct sym *s_link; /* link */
57: char *s_addr; /* address */
58: long s_count; /* count */
59: char s_name[]; /* name */
60: };
61:
62: /*
63: * Globals.
64: */
65: int aflag; /* print address info */
66: int lflag; /* sort by location */
67: int nflag; /* sort by name */
68: int zflag; /* print zero counts */
69: int lnamen; /* lname index */
70: int segn; /* segment index */
71: int groupn; /* group index */
72: int len; /* record length excluding checksum */
73: int csum; /* checksum */
74: int codelname; /* lname index of CODE */
75: int cseg; /* segment index of CODE */
76: int cgrouplname; /* lname index of CGROUP */
77: int cgroup; /* group index of CGROUP */
78: int nsyms; /* number of symbols */
79: int nnotfound; /* profile entries not found in symbols */
80: struct sym *symlist; /* linked list of symbols */
81: struct sym **sympp; /* sorted table of symbols */
82: char id[NAMELEN]; /* identifier */
83: char *filename; /* file name */
84:
85: main(argc, argv)
86: int argc;
87: char **argv;
88: {
89: register int c;
90: ++argv;
91: if ((argc > 1) && (**argv == '-')) {
92: while (c = *++*argv) {
93: switch (c) {
94: case 'a': ++aflag;
95: break;
96: case 'l': ++lflag;
97: ++aflag;
98: break;
99: case 'n': ++nflag;
100: break;
101: case 'z': ++zflag;
102: break;
103: case VFLAG: fprintf(stderr, "profil: V%s\n", VERSION);
104: break;
105: default: usage();
106: break;
107: }
108: }
109: ++argv;
110: --argc;
111: }
112: if (argc > 4)
113: usage();
114: if (argc >=2) {
115: filename = *argv++;
116: if (freopen(filename, "rb", stdin) == NULL)
117: fatalf("cannot open executable %s for input");
118: }
119: else
120: filename = "stdin"; /* For error messages... */
121: readsyms(); /* Read symbols from the executable. */
122: addrsort(); /* Sort the symbols by address. */
123: filename = (argc >= 3) ? *argv++ : PFILE;
124: if (freopen(filename, "rb", stdin) == NULL)
125: fatalf("cannot open profile %s for input");
126: readprof(); /* Read the profile information. */
127: if (argc == 4) {
128: filename = *argv;
129: if (freopen(filename, "w", stdout) == NULL)
130: fatalf("cannot open %s for output");
131: }
132: dumpprof(); /* Dump the profile. */
133: exit(0);
134: }
135:
136: /*
137: * Compare the addresses of two symbols for qsort.
138: */
139: addrcomp(p1, p2)
140: struct sym **p1, **p2;
141: {
142: register char *a1, *a2;
143: a1 = (*p1)->s_addr;
144: a2 = (*p2)->s_addr;
145: return((a1 < a2) ? -1 : ((a1 == a2) ? 0 : 1));
146: }
147:
148: /*
149: * Sort the symbols by address.
150: */
151: addrsort()
152: {
153: register struct sym **spp;
154: /* Allocate a table for the sym pointers. */
155: if ((sympp = (struct sym **)malloc((nsyms+1)*sizeof(struct sym *))) == NULL)
156: fatal("out of memory for symbol sorting");
157: /* Copy the sym pointers from the linked list into the table. */
158: spp = sympp;
159: while (symlist) {
160: *spp++ = symlist;
161: symlist = symlist->s_link;
162: }
163: *spp = NULL; /* Null terminate the table. */
164: qsort(sympp, nsyms, sizeof(struct sym *), addrcomp); /* Sort it. */
165: }
166:
167: /*
168: * Add a new symbol with name id to the symbol list.
169: */
170: addsym(offset)
171: unsigned offset;
172: {
173: register struct sym *sp;
174: if ((sp = (struct sym *) malloc(sizeof(struct sym) + strlen(id) + 1)) == NULL)
175: fatal("out of memory for symbols");
176: sp->s_link = symlist;
177: sp->s_addr = offset;
178: sp->s_count = 0L;
179: strcpy(sp->s_name, id);
180: symlist = sp;
181: }
182:
183: /*
184: * Compare the counts of two symbols for qsort.
185: */
186: countcomp(p1, p2)
187: struct sym **p1, **p2;
188: {
189: register long l1, l2;
190: l1 = (*p1)->s_count;
191: l2 = (*p2)->s_count;
192: return((l1 < l2) ? -1 : ((l1 == l2) ? 0 : 1));
193: }
194:
195: /*
196: * Dump the profile information.
197: */
198: dumpprof()
199: {
200: /* Sort symbol table (now sorted by address) by desired method. */
201: if (nflag)
202: qsort(sympp, nsyms, sizeof(struct sym *), namecomp);
203: else if (!lflag)
204: qsort(sympp, nsyms, sizeof(struct sym *), countcomp);
205: dumpsyms(); /* Dump the sorted list. */
206: if (nnotfound == 0)
207: return; /* No unmatched symbols. */
208: printf("Not found:\n");
209: nsyms = nnotfound;
210: addrsort(); /* Sort the not found list. */
211: if (!lflag)
212: qsort(sympp, nsyms, sizeof(struct sym *), countcomp);
213: aflag = 1; /* Force address printing. */
214: dumpsyms(); /* Dump the not found list. */
215: }
216:
217: /*
218: * Dump the sorted symbol table.
219: * Free the symbols and the table.
220: */
221: dumpsyms()
222: {
223: register struct sym **spp;
224: register struct sym *sp;
225: for (spp = sympp; *spp; spp++) {
226: sp = *spp;
227: if (!zflag && (sp->s_count == 0L))
228: continue;
229: printf("%8ld ", sp->s_count);
230: if (aflag)
231: printf("0x%04x ", sp->s_addr);
232: printf("%s\n", sp->s_name);
233: free(sp);
234: }
235: free(sympp);
236: }
237:
238: /*
239: * Print error message and exit.
240: */
241: fatal(s)
242: register char *s;
243: {
244: fprintf(stderr, "profil: %s\n", s);
245: exit(1);
246: }
247:
248: /*
249: * Print error message with current filename and exit.
250: */
251: fatalf(s)
252: register char *s;
253: {
254: char errmsg[NERRMSG];
255: sprintf(errmsg, s, filename);
256: fatal(errmsg);
257: }
258:
259: /*
260: * Read a byte from standard input, update checksum and len.
261: */
262: getb()
263: {
264: register int i;
265: if ((i = getchar()) == EOF)
266: fatalf("premature EOF on %s");
267: csum += i;
268: --len;
269: return(i);
270: }
271:
272: /*
273: * Get BLKDEF procedure name info.
274: * This is not done for nested BLKDEFs.
275: */
276: getblkdef()
277: {
278: if (getgsf()) {
279: ++nsyms;
280: getname();
281: addsym(geti());
282: }
283: }
284:
285: /*
286: * Get GRPDEF info.
287: * Set cgroup if the LNAME is "CGROUP".
288: */
289: getgrpdef()
290: {
291: ++groupn; /* Bump group index. */
292: if (getindex() == cgrouplname)
293: cgroup = groupn;
294: }
295:
296: /*
297: * Get group, segment and optional frame number.
298: * Returns TRUE if group is CGROUP and segment is CODE.
299: */
300: getgsf()
301: {
302: register int group, segm;
303: group = getindex();
304: segm = getindex();
305: if ((group == 0) && (segm == 0))
306: return(0);
307: return((group==cgroup) && (segm==cseg));
308: }
309:
310: /*
311: * Read a word and return it.
312: */
313: geti()
314: {
315: register int i = getb();
316: return(i | (getb() << 8));
317: }
318:
319: /*
320: * Read an index and return it.
321: */
322: getindex()
323: {
324: register int i = getb();
325: if ((i&0x80) == 0)
326: return(i);
327: return(((i&0x7F)<<8) | getb());
328: }
329:
330: /*
331: * Get an LNAME record.
332: * Set codelname if the LNAME is "CODE".
333: * Set cgrouplname if the LNAME is "CGROUP".
334: */
335: getlnames()
336: {
337: while (len) {
338: ++lnamen; /* Bump LNAME index. */
339: getname();
340: if (strcmp(id, "CODE") == 0)
341: codelname = lnamen;
342: else if (strcmp(id, "CGROUP") == 0)
343: cgrouplname = lnamen;
344: }
345: }
346:
347: /*
348: * Read a long and return it.
349: */
350: long
351: getlong()
352: {
353: register long l = geti();
354: return(l | (geti() << 16));
355: }
356:
357: /*
358: * Read a name into id.
359: */
360: getname()
361: {
362: register int len = getb();
363: register char *cp = &id[0];
364: while (len--)
365: *cp++ = getb();
366: *cp = '\0';
367: }
368:
369: /*
370: * Get PUBDEF info.
371: * Add it to symbols if in CGROUP and CODE segment.
372: */
373: getpubdef()
374: {
375: if (getgsf()) {
376: while (len) {
377: ++nsyms;
378: getname();
379: addsym(geti());
380: getindex();
381: }
382: }
383: }
384:
385: /*
386: * Get SEGDEF info.
387: * Set cseg if the LNAME is "CODE".
388: */
389: getsegdef()
390: {
391: register int a;
392: ++segn; /* Bump segment index. */
393: a = (getb()&0xE0) >> 5;
394: if (a == 5)
395: return;
396: else if (a == 0) {
397: geti();
398: getb();
399: }
400: else if (a == 6) {
401: getb();
402: geti();
403: geti();
404: }
405: geti(); /* Length. */
406: if (getindex() == codelname)
407: cseg = segn; /* Set code segment index. */
408: }
409:
410: /*
411: * Ignore len bytes.
412: */
413: ignore()
414: {
415: while (len)
416: getb();
417: }
418:
419: /*
420: * Compare the names of two symbols for qsort.
421: */
422: namecomp(p1, p2)
423: struct sym **p1, **p2;
424: {
425: return(strcmp((*p1)->s_name, (*p2)->s_name));
426: }
427:
428: /*
429: * Print warning message.
430: */
431: nonfatal(s)
432: register char *s;
433: {
434: fprintf(stderr, "profil: warning: %s\n", s);
435: }
436:
437: /*
438: * Read the profile file.
439: */
440: readprof()
441: {
442: register struct sym **spp;
443: register unsigned int addr;
444: register int i;
445: register long count;
446: if (geti() != PSMALL)
447: fatalf("%s is not a profile file");
448: id[0] = '\0'; /* Nil id for nonfounds. */
449: while ((i=getchar()) != EOF) { /* Look ahead for EOF. */
450: ungetc(i, stdin); /* Put it back. */
451: count = getlong(); /* Get count. */
452: geti(); /* Ignore link. */
453: addr = geti() - PSBACK; /* Get loc and adjust. */
454: for (spp = sympp; *spp ; spp++) {
455: if ((*spp)->s_addr == addr) { /* Matched. */
456: (*spp)->s_count = count;
457: break;
458: }
459: else if ((*spp)->s_addr > addr) {
460: ++nnotfound; /* Not found. */
461: addsym(addr); /* Add to not found list. */
462: symlist->s_count = count;
463: break;
464: }
465: }
466: }
467: }
468:
469: /*
470: * Read symbols from the OMF executable file and build symbol table.
471: */
472: readsyms()
473: {
474: register int type, blevel, xflag;
475: type = getb();
476: if ((type != THEADR) && (type != LHEADR) && (type != RHEADR))
477: fatalf("%s is not an object file");
478: ungetc(type, stdin);
479: csum = blevel = xflag = 0;
480: while (!xflag) {
481: type = getb(); /* Record type. */
482: len = geti() - 1; /* Record length without csum. */
483: switch (type) {
484: case BLKDEF:
485: if (blevel++ == 0)
486: getblkdef();
487: break;
488: case BLKEND:
489: --blevel;
490: break;
491: case GRPDEF:
492: getgrpdef();
493: break;
494: case LNAMES:
495: getlnames();
496: break;
497: case MODEND:
498: xflag = 1;
499: break;
500: case PUBDEF:
501: getpubdef();
502: break;
503: case SEGDEF:
504: getsegdef();
505: break;
506: default:
507: break;
508: }
509: ignore(); /* Skip to csum. */
510: getb(); /* Read the csum. */
511: if ((csum&0xFF) != 0)
512: fatalf("checksum error on executable %s");
513: }
514: if (getchar() != EOF)
515: fatalf("data after MODEND on executable %s");
516: if (cseg == 0)
517: nonfatal("cannot find CODE segment");
518: if (cgroup == 0)
519: nonfatal("cannot find CGROUP");
520: }
521:
522: /*
523: * Print usage message and exit.
524: */
525: usage()
526: {
527: fatal("Usage: profil [ -alnz ] [ infile [ profile [ outfile ] ] ]");
528: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.