|
|
1.1 root 1: /*
2: * cdmp.c
3: * 3/24/93
4: * Requires libmisc functions: cc cdmp.c -lmisc
5: * Read and print COFF files.
6: * Usage: cdmp [ -adlrsx ] filename ...
7: * Options:
8: * -a supress symbol aux entries
9: * -d supress data dumps
10: * -l supress line numbers
11: * -r supress relocation entries
12: * -s supress symbol entries
13: * -V print version number
14: * -x dump aux entries in hex
15: * -? print usage info and exit
16: * Does not know all there is to know about aux entry structure yet.
17: */
18:
19: #include <misc.h> /* misc useful stuff */
20: #include <coff.h>
21: #include <errno.h>
22:
23: #define VERSION "V2.2"
24: #define VHSZ 48 /* line size in vertical hex dump */
25: typedef char SECNAME[9]; /* NUL-terminated 8 character section name */
26:
27: /* Some shortcut display stuff. */
28: #define showFlag(flag, msg) if (fh.f_flags & flag) printf("\t" msg "\n");
29: #define showCase(x) showDesc(x, #x)
30: #define showDesc(x, d) case x: printf(d); break;
31: #define showVal(x) case x: printf(#x "\tvalue=%ld ", se->n_value); break;
32: #define showHexVal(x) case x: printf(#x "\tvalue=0x%lX ", se->n_value); break;
33:
34: /* Externals. */
35: extern long ftell();
36: extern char *optarg;
37:
38: /* Forward. */
39: void fatal();
40: char *checkStr();
41: void optHeader();
42: void readHeaders();
43: void shrLib();
44: void readSection();
45: void readStrings();
46: void readSymbols();
47: void print_aux();
48: void print_sym();
49: void dump();
50: int clean();
51: void outc();
52: int hex();
53:
54: /* Globals. */
55: char aswitch; /* Suppress aux entry dumps */
56: char buf[VHSZ]; /* Buffer for hex dump */
57: char dswitch; /* Suppress data dumps */
58: FILE *fp; /* COFF file pointer */
59: char lswitch; /* Suppress line number dumps */
60: long num_sections; /* Number of sections */
61: long num_symbols; /* Number of symbols */
62: char rswitch; /* Suppress reloc dumps */
63: SECNAME *sec_name; /* Section names */
64: long section_seek; /* Seek to seek start of section */
65: char sswitch; /* Suppress symbol dumps */
66: char *str_tab; /* String char array */
67: long symptr; /* File pointer to symbol table entries */
68: char xswitch; /* Dump aux entries in hex */
69:
70: /*
71: * Print fatal error message and die.
72: */
73: /* VARARGS */
74: void
75: fatal(s) char *s;
76: {
77: register int save;
78:
79: save = errno;
80: fprintf(stderr, "cdmp: %r\n", &s);
81: if (0 != (errno = save))
82: perror("errno reports");
83: exit(1);
84: }
85:
86: /*
87: * Return a printable version of string s,
88: * massaging nonprintable characters if necessary.
89: */
90: char *
91: checkStr(s) unsigned char *s;
92: {
93: register unsigned char *p, c;
94: register int ct, badct;
95: static char *work = NULL;
96:
97: for (badct = 0, ct = 1, p = s; c = *p++; ct++)
98: if ((c <= ' ') || (c > '~'))
99: badct += 2; /* not printable as is */
100:
101: if (!badct)
102: return s; /* ok as is */
103:
104: if (NULL != work)
105: free(work); /* free previous */
106:
107: work = alloc(badct + ct);
108: for (p = work; c = *s++;) {
109: if (c > '~') {
110: *p++ = '~';
111: c &= 0x7f;
112: }
113: if (c <= ' ') {
114: *p++ = '^';
115: c |= '@';
116: }
117: *p++ = c;
118: }
119: return work;
120: }
121:
122: /*
123: * Process optional file header.
124: */
125: void
126: optHeader(size) unsigned int size;
127: {
128: register AOUTHDR *ohp;
129: register unsigned int tail;
130:
131: if ((tail = size - sizeof(*ohp)) < 0)
132: fatal("optional header too small -- %d bytes", size);
133: ohp = alloc(size);
134:
135: if (1 != fread(ohp, size, 1, fp))
136: fatal("error reading optional header");
137:
138: printf("\nOPTIONAL HEADER VALUES\n");
139: printf("magic = 0x%X\n", ohp->magic);
140: printf("version stamp = %d\n", ohp->vstamp);
141: printf("text size = 0x%lX\n", ohp->tsize);
142: printf("init data size = 0x%lX\n", ohp->dsize);
143: printf("uninit data size = 0x%lX\n", ohp->bsize);
144: printf("entry point = 0x%lX\n", ohp->entry);
145: printf("text start = 0x%lX\n", ohp->text_start);
146: printf("data start = 0x%lX\n", ohp->data_start);
147:
148: /* Print extra info, if any. */
149: if (tail) {
150: printf("\n EXTRA OPTIONAL HEADER INFO\n");
151: dump(ohp + 1, tail);
152: }
153: free(ohp);
154: }
155:
156: /*
157: * Process file header.
158: */
159: void
160: readHeaders(fn) char *fn;
161: {
162: FILEHDR fh;
163:
164: fp = xopen(fn, "rb");
165:
166: if (1 != fread(&fh, sizeof(fh), 1, fp))
167: fatal("error reading COFF header");
168:
169: printf("FILE %s HEADER VALUES\n", fn);
170: printf("magic number = 0x%X\n", fh.f_magic);
171: printf("sections = %ld\n", num_sections = fh.f_nscns);
172: printf("file date = %s", ctime(&fh.f_timdat));
173: printf("symbol ptr = 0x%lX\n", symptr = fh.f_symptr);
174: printf("symbols = %ld\n", num_symbols = fh.f_nsyms);
175: printf("sizeof(opthdr) = %d\n", fh.f_opthdr);
176: printf("flags = 0x%X\n", fh.f_flags);
177:
178: showFlag(F_RELFLG, "Relocation info stripped from file");
179: showFlag(F_EXEC, "File is executable");
180: showFlag(F_LNNO, "Line numbers stripped from file");
181: showFlag(F_LSYMS, "Local symbols stripped from file");
182: showFlag(F_MINMAL, "Minimal object file");
183:
184: /*
185: * Allocate section name array.
186: */
187: if (num_sections != 0)
188: sec_name = (SECNAME *)alloc(((int)num_sections) * (sizeof(SECNAME)));
189:
190: if (fh.f_opthdr)
191: optHeader(fh.f_opthdr); /* optional header */
192: section_seek = sizeof(FILEHDR) + fh.f_opthdr;
193: }
194:
195: /*
196: * Process shared library.
197: */
198: void
199: shrLib()
200: {
201: SHRLIB shr;
202: register long i;
203: register char *pathn;
204:
205: if (1 != fread(&shr, sizeof(shr), 1, fp))
206: fatal("error reading library section");
207:
208: if (shr.pathndx -= 2) {
209: long j;
210: printf("\nExtra Library info:\n");
211:
212: for (j = shr.pathndx * 4;
213: j && (i = fread(buf, 1, ((j > VHSZ) ? VHSZ : (int)j), fp));
214: j -= i) {
215: if (!i)
216: fatal("unexpected EOF in .lib data");
217: dump(buf, (int)i);
218: }
219: }
220:
221: pathn = alloc(i = (shr.entsz - 2) * 4);
222: if (1 != fread(pathn, i, 1, fp))
223: fatal("error reading library name");
224: printf("\nReferences %s\n", pathn);
225: free(pathn);
226: }
227:
228: /*
229: * Process sections.
230: */
231: void
232: readSection(n) register int n;
233: {
234: SCNHDR sh;
235: register long i;
236:
237: fseek(fp, section_seek, 0);
238: if (1 != fread(&sh, sizeof(SCNHDR), 1, fp))
239: fatal("error reading section header");
240:
241: section_seek += sizeof(SCNHDR);
242: fseek(fp, sh.s_scnptr, 0);
243:
244: strncpy(sec_name[n], checkStr(sh.s_name), sizeof(SECNAME) - 1);
245: printf("\n%s - SECTION HEADER -\n", sec_name[n]);
246: printf("physical address = 0x%lX\n", sh.s_paddr);
247: printf("virtual address = 0x%lX\n", sh.s_vaddr);
248: printf("section size = 0x%lX\n", sh.s_size);
249: printf("file ptr to data = 0x%lX\n", sh.s_scnptr);
250: printf("file ptr to relocs = 0x%lX\n", sh.s_relptr);
251: printf("file ptr to lines = 0x%lX\n", sh.s_lnnoptr);
252: printf("relocation entries = %u\n", sh.s_nreloc);
253: printf("line number entries = %u\n", sh.s_nlnno);
254: printf("flags = 0x%lX\t", sh.s_flags);
255: switch((int)sh.s_flags) {
256:
257: showDesc(STYP_GROUP, "grouped section")
258: showDesc(STYP_PAD, "padding section")
259: showDesc(STYP_COPY, "copy section")
260: showDesc(STYP_INFO, "comment section")
261: showDesc(STYP_OVER, "overlay section")
262: showDesc(STYP_TEXT, "text only")
263: showDesc(STYP_DATA, "data only")
264: showDesc(STYP_BSS, "bss only")
265:
266: case STYP_LIB:
267: printf(".lib section\n");
268: shrLib();
269: return;
270:
271: default:
272: printf("unrecognized section");
273: break;
274: }
275: putchar('\n');
276:
277: /* Print raw data. */
278: if (!dswitch && strcmp(sh.s_name, ".bss")) { /* don't output bss */
279: register long j;
280:
281: fseek(fp, sh.s_scnptr, 0);
282: printf("\nRAW DATA\n");
283:
284: for (j = sh.s_size;
285: j && (i = fread(buf, 1, ((j > VHSZ) ? VHSZ : (int)j), fp));
286: j -= i) {
287: if (!i)
288: fatal("unexpected EOF in %.8s data",
289: checkStr(sh.s_name));
290: dump(buf, (int)i);
291: }
292: }
293:
294: /* Print relocs. */
295: if (!rswitch && sh.s_nreloc) {
296: fseek(fp, sh.s_relptr, 0);
297: printf("\nRELOCATION ENTRIES\n");
298: for (i = 0; i < sh.s_nreloc; i++) {
299: RELOC re; /* Relocation entry structure */
300:
301: if (1 != fread(&re, RELSZ, 1, fp))
302: fatal("error reading relocation entry");
303:
304: printf("address=0x%lX\tindex=%ld \ttype=",
305: re.r_vaddr, re.r_symndx);
306: switch(re.r_type) {
307: showCase(R_DIR8)
308: showCase(R_DIR16)
309: showCase(R_DIR32)
310: showCase(R_RELBYTE)
311: showCase(R_RELWORD)
312: showCase(R_RELLONG)
313: showCase(R_PCRBYTE)
314: showCase(R_PCRWORD)
315: showCase(R_PCRLONG)
316: showCase(R_NONREL)
317: default:
318: fatal("unexpected relocation type 0x%X",
319: re.r_type);
320: break;
321: }
322: putchar('\n');
323: }
324: }
325:
326: /* Print line numbers. */
327: if (!lswitch && sh.s_nlnno) {
328: fseek(fp, sh.s_lnnoptr, 0);
329: printf("\nLINE NUMBER ENTRIES\n");
330:
331: for (i = 0; i < sh.s_nlnno; i++) {
332: LINENO le; /* Line number entry structure */
333:
334: if (1 != fread(&le, LINESZ, 1, fp))
335: fatal("error reading line number entry");
336:
337: if (le.l_lnno)
338: printf("address=0x%lX\tline=%d\n",
339: le.l_addr.l_paddr, le.l_lnno);
340: else
341: printf("function=%d\n", le.l_addr.l_symndx);
342: }
343: }
344: }
345:
346: /*
347: * Read the string table into memory.
348: * This allows readSymbols() to work.
349: */
350: void
351: readStrings()
352: {
353: register unsigned char *str_ptr, c;
354: long str_seek;
355: unsigned long str_length;
356: unsigned len;
357:
358: str_seek = symptr + (SYMESZ * num_symbols);
359: fseek(fp, str_seek, 0);
360:
361: if (1 != fread(&str_length, sizeof(str_length), 1, fp))
362: str_length = 0;
363:
364: if (str_length == 0) {
365: printf("\nNO STRING TABLE\n");
366: return;
367: }
368: printf("\nSTRING TABLE DUMP\n");
369: len = str_length -= 4;
370: if (len != str_length)
371: fatal("bad string table length %ld", str_length);
372: str_tab = alloc(len);
373: if (1 != fread(str_tab, len, 1, fp))
374: fatal("error reading string table %lX %d", ftell(fp), len);
375:
376: for (str_ptr = str_tab; str_ptr < str_tab + str_length; ) {
377: putchar('\t');
378: while (c = *str_ptr++) {
379: if (c > '~') {
380: c &= 0x7f;
381: putchar('~');
382: }
383: if (c < ' ') {
384: c |= '@';
385: putchar('^');
386: }
387: putchar(c);
388: }
389: putchar('\n');
390: }
391: }
392:
393: /*
394: * Process symbol table.
395: */
396: void
397: readSymbols()
398: {
399: SYMENT se;
400: register long i, j, naux;
401:
402: if (sswitch)
403: return;
404: fseek(fp, symptr, 0);
405: printf("\nSYMBOL TABLE ENTRIES\n");
406: for (i = 0; i < num_symbols; i++) {
407: if (1 != fread(&se, SYMESZ, 1, fp))
408: fatal("error reading symbol entry");
409: print_sym(&se, i);
410: naux = se.n_numaux;
411: for (j = 0; j < naux; j++)
412: print_aux(i+j+1, &se);
413: i += naux;
414: if (i >= num_symbols)
415: fatal("inconsistant sym table");
416: }
417: }
418:
419: #define showNe(x, d) if(l = ae.x) printf("\t" d "=%ld", l)
420: /*
421: * Process a symbol aux entry.
422: * This is still pretty ad hoc, it may not do all entries correctly yet.
423: * Does not print 0-valued fields.
424: */
425: void
426: print_aux(n, sep) int n; register SYMENT *sep;
427: {
428: AUXENT ae;
429: register int type, class;
430: register long l;
431: int has_fsize, has_fcn;
432: unsigned short *sp;
433: char fname[FILNMLEN + 1];
434:
435: if (1 != fread(&ae, AUXESZ, 1, fp))
436: fatal("error reading symbol aux entry");
437: if (aswitch)
438: return; /* suppressed */
439: printf("%4ld\t", n); /* symbol number */
440: if (xswitch) { /* dump in hex */
441: printf("\tAUX ENTRY DUMP\n");
442: dump(&ae, sizeof(ae));
443: return;
444: }
445:
446: class = sep->n_sclass;
447: type = sep->n_type;
448:
449: if (class == C_FILE) { /* .file */
450: strncpy(fname, ae.ae_fname, FILNMLEN);
451: fname[FILNMLEN] = '\0';
452: printf("\tfilename=%s\n", checkStr(fname));
453: return;
454: } else if (class == C_STAT && type == T_NULL) { /* section name */
455: printf("\tlength=%lX\trelocs=%d\tlinenos=%d\n",
456: ae.ae_scnlen,
457: ae.ae_nreloc,
458: ae.ae_nlinno);
459: return;
460: }
461:
462: /*
463: * In cases not handled above,
464: * the AUXENT is an x_sym which must be decyphered.
465: * Flags tell which members of unions to dump.
466: * The flag setting might not be quite right yet.
467: */
468: has_fsize = has_fcn = 0;
469: if (class == C_STRTAG || class == C_UNTAG || class == C_ENTAG
470: || class == C_BLOCK) /* tag definitions or .bb or .eb */
471: ++has_fcn;
472: if (ISFCN(type)) {
473: ++has_fsize;
474: ++has_fcn;
475: }
476:
477: /* Print tag index. */
478: showNe(ae_tagndx, "tag");
479:
480: /* Print fsize or lnsz info. */
481: if (has_fsize) {
482: showNe(ae_fsize, "fsize");
483: } else {
484: showNe(ae_lnno, "lnno");
485: showNe(ae_size, "size");
486: }
487:
488: /* Print fcn or ary info. */
489: if (has_fcn) {
490: if (l = ae.ae_lnnoptr)
491: printf("\tlnnoptr=0x%lX", l);
492: showNe(ae_endndx, "end");
493: } else {
494: sp = ae.ae_dimen;
495: if (*sp != 0) {
496: printf("\tdims=< ");
497: while (sp < &ae.ae_dimen[DIMNUM] && *sp)
498: printf("%d ", *sp++);
499: putchar('>');
500: }
501: }
502:
503: /* Print tv index. */
504: showNe(ae_tvndx, "tv");
505: putchar('\n');
506: }
507: #undef showNe
508:
509: /*
510: * Process symbol table entry.
511: */
512: void
513: print_sym(se, n) register SYMENT *se; register long n;
514: {
515: register int i, c, flag, derived;
516:
517: if (se->n_sclass == C_FILE && n > 0)
518: putchar('\n'); /* for readability */
519: printf("%4ld\t", n); /* index number */
520: if (se->n_zeroes != 0) { /* name in place */
521: for (flag = i = 0; i < SYMNMLEN; i++) {
522: if (flag)
523: ;
524: else if ((' ' < (c = se->n_name[i])) && ('~' >= c))
525: putchar(c);
526: else
527: flag = c ? 1 : -1;
528: }
529: putchar('\t');
530: } else /* name in string table */
531: printf("%s ", checkStr(str_tab + se->n_offset - 4));
532:
533: /* Print section. */
534: i = se->n_scnum;
535: printf("section=");
536: if (i >= 1 && i <= num_sections)
537: printf("%s", sec_name[i-1]);
538: else
539: switch(i) {
540: showCase(N_UNDEF)
541: showCase(N_ABS)
542: showCase(N_DEBUG)
543: default:
544: printf("%d?", i);
545: break;
546: }
547:
548: /* Print the type. */
549: printf("\ttype=");
550:
551: /* Print derived types. */
552: derived = 0;
553: for (i = se->n_type; i & N_TMASK; i >>= N_TSHIFT) {
554: if (derived++ == 0)
555: putchar('<');
556: switch((i & N_TMASK) >> N_BTSHFT) {
557: showCase(DT_PTR)
558: showCase(DT_FCN)
559: showCase(DT_ARY)
560: case DT_NON:
561: default:
562: fatal("unexpected derived type 0x%X", i & N_TMASK);
563: }
564: putchar(' ');
565: }
566:
567: switch (c = (se->n_type & N_BTMASK)) { /* base type */
568: showDesc(T_NULL, "none")
569: showCase(T_CHAR)
570: showCase(T_SHORT)
571: showCase(T_INT)
572: showCase(T_LONG)
573: showCase(T_FLOAT)
574: showCase(T_DOUBLE)
575: showCase(T_STRUCT)
576: showCase(T_UNION)
577: showCase(T_ENUM)
578: showCase(T_MOE)
579: showCase(T_UCHAR)
580: showCase(T_USHORT)
581: showCase(T_UINT)
582: showCase(T_ULONG)
583:
584: case T_ARG: /* What has base type (not storage class) ARG? */
585: default:
586: fatal("unexpected base type 0x%X", c);
587:
588: }
589: if (derived)
590: putchar('>');
591:
592: /* Print the storage class. */
593: printf("\tclass=");
594: switch (i = se->n_sclass) {
595:
596: showVal(C_EFCN)
597: showVal(C_NULL)
598: showVal(C_AUTO)
599: showHexVal(C_STAT)
600: showVal(C_REG)
601: showVal(C_EXTDEF)
602: showVal(C_LABEL)
603: showVal(C_ULABEL)
604: showVal(C_MOS)
605: showVal(C_ARG)
606: showVal(C_STRTAG)
607: showVal(C_MOU)
608: showVal(C_UNTAG)
609: showVal(C_TPDEF)
610: showVal(C_ENTAG)
611: showVal(C_MOE)
612: showVal(C_REGPARM)
613: showVal(C_FIELD)
614: showVal(C_BLOCK)
615: showVal(C_FCN)
616: showVal(C_EOS)
617: showVal(C_FILE)
618:
619: case C_EXT:
620: if (se->n_scnum != N_UNDEF)
621: printf("C_EXT\tvalue=0x%lX", se->n_value);
622: else if (se->n_value != 0)
623: printf("Common\tlength=%ld", se->n_value);
624: else
625: printf("External");
626: break;
627:
628: case C_USTATIC: /* What is an undefined static? */
629: fatal("unexpected storage class 0x%X", i);
630:
631: default:
632: printf("0x%X", i);
633:
634: }
635:
636: #if 0
637: if (se->n_numaux)
638: printf("\tnaux=%d", se->n_numaux);
639: #endif
640: putchar('\n');
641:
642: if (1 == flag) {
643: printf("*** Bad data in name **\n");
644: dump(se, SYMESZ);
645: }
646: }
647:
648: /*
649: * Vertical hex dump of p bytes from buffer buf.
650: */
651: void
652: dump(buf, p) register char *buf; register int p;
653: {
654: register int i;
655:
656: /* Offset. */
657: printf ("\n%6lX\t", ftell(fp) - p);
658:
659: /* Printable version of character. */
660: for (i = 0; i < p; i++ )
661: outc(clean(buf[i]), i, ' ');
662: printf("\n\t");
663:
664: /* High hex digit. */
665: for (i = 0; i < p; i++)
666: outc(hex((buf[i] >> 4) & 0x0f), i, '.');
667: printf("\n\t");
668:
669: /* Low hex digit. */
670: for (i = 0; i < p; i++)
671: outc(hex(buf[i]& 0x0f), i, '.');
672: putchar('\n');
673: }
674:
675: /*
676: * Return c if printable, '.' if not.
677: */
678: int
679: clean(c) register int c;
680: {
681: return (c >= ' ' && c <= '~' ) ? c : '.';
682: }
683:
684: /*
685: * Print c, preceded by s every 4 times.
686: */
687: void
688: outc(c, i, s) register int i, c, s;
689: {
690: if ((i&3) == 0 && i != 0 )
691: putchar(s);
692: putchar(c);
693: }
694:
695: /*
696: * Convert hex digit c to corresponding ASCII character.
697: */
698: int
699: hex(c) register int c;
700: {
701: return ( c <= 9 ) ? c + '0' : c + 'A' - 10;
702: }
703:
704: /*
705: * Mainline.
706: */
707: main(argc, argv) int argc; char *argv[];
708: {
709: register int i, c;
710:
711: while (EOF != (c = getargs(argc, argv, "adlrsxV?"))) {
712: switch (c) {
713:
714: case 0:
715: /* Process a COFF file. */
716: readHeaders(optarg);
717: for (i = 0; i < num_sections; i++)
718: readSection(i);
719: if (num_symbols) {
720: readStrings();
721: readSymbols();
722: }
723: /* Cleanup. */
724: if (sec_name != NULL) {
725: free(sec_name);
726: sec_name = NULL;
727: }
728: if (str_tab != NULL) {
729: free(str_tab);
730: str_tab = NULL;
731: }
732: fclose(fp);
733: break;
734:
735: case 'a': aswitch++; break;
736: case 'd': dswitch++; break;
737: case 'l': lswitch++; break;
738: case 'r': rswitch++; break;
739: case 's': sswitch++; break;
740: case 'x': xswitch++; break;
741:
742: case 'V':
743: fprintf(stderr, "cdmp: %s\n", VERSION);
744: break;
745:
746: case '?':
747: default:
748: fprintf(stderr,
749: "Usage: cdmp [ -adlrsx ] filename ...\n"
750: "Options:\n"
751: "\t-a\tsupress symbol aux entries\n"
752: "\t-d\tsupress data dumps\n"
753: "\t-l\tsupress line numbers\n"
754: "\t-r\tsupress relocation entries\n"
755: "\t-s\tsupress symbol entries\n"
756: "\t-x\tdump aux entries in hex\n");
757: exit(1);
758: break;
759: }
760: }
761: exit(0);
762: }
763:
764: /* end of cdmp.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.