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