|
|
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.