Beginnings of a crude utility to dump the contents of an OMF file
[platform/upstream/nasm.git] / misc / omfdump.c
1 /*
2  * omfdump.c
3  *
4  * Very simple program to dump the contents of an OMF (OBJ) file
5  *
6  * This assumes a littleendian, unaligned-load-capable host and a
7  * C compiler which handles basic C99.
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <inttypes.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #include <sys/stat.h>
18
19 const char *progname;
20
21 static const char *record_types[256] =
22 {
23     [0x80] = "THEADR",
24     [0x82] = "LHEADR",
25     [0x88] = "COMENT",
26     [0x8a] = "MODEND16",
27     [0x8b] = "MODEND32",
28     [0x8c] = "EXTDEF",
29     [0x90] = "PUBDEF16",
30     [0x91] = "PUBDEF32",
31     [0x94] = "LINNUM16",
32     [0x95] = "LINNUM32",
33     [0x96] = "LNAMES",
34     [0x98] = "SEGDEF16",
35     [0x99] = "SEGDEF32",
36     [0x9a] = "GRPDEF",
37     [0x9c] = "FIXUPP16",
38     [0x9d] = "FIXUPP32",
39     [0xa0] = "LEDATA16",
40     [0xa1] = "LEDATA32",
41     [0xa2] = "LIDATA16",
42     [0xa3] = "LIDATA32",
43     [0xb0] = "COMDEF",
44     [0xb2] = "BAKPAT16",
45     [0xb3] = "BAKPAT32",
46     [0xb4] = "LEXTDEF",
47     [0xb6] = "LPUBDEF16",
48     [0xb7] = "LPUBDEF32",
49     [0xb8] = "LCOMDEF",
50     [0xbc] = "CEXTDEF",
51     [0xc2] = "COMDAT16",
52     [0xc3] = "COMDAT32",
53     [0xc4] = "LINSYM16",
54     [0xc5] = "LINSYM32",
55     [0xc6] = "ALIAS",
56     [0xc8] = "NBKPAT16",
57     [0xc9] = "NBKPAT32",
58     [0xca] = "LLNAMES",
59     [0xcc] = "VERNUM",
60     [0xce] = "VENDEXT",
61     [0xf0] = "LIBHDR",
62     [0xf1] = "LIBEND",
63 };
64
65 typedef void (*dump_func)(uint8_t, const uint8_t *, size_t);
66
67 static void hexdump_data(unsigned int offset, const uint8_t *data, size_t n)
68 {
69     unsigned int i, j;
70
71     for (i = 0; i < n; i += 16) {
72         printf("  %04x: ", i+offset);
73         for (j = 0; j < 16; j++) {
74             if (i+j < n)
75                 printf("%02x%c", data[i+j], (j == 7) ? '-' : ' ');
76             else
77                 printf("   ");
78         }
79         printf(" :  ");
80         for (j = 0; j < 16; j++) {
81             if (i+j < n)
82                 putchar(isprint(data[i+j]) ? data[i+j] : '.');
83         }
84         putchar('\n');
85     }
86 }
87
88 static void dump_unknown(uint8_t type, const uint8_t *data, size_t n)
89 {
90     (void)type;
91     hexdump_data(0, data, n);
92 }
93
94 static void dump_coment(uint8_t type, const uint8_t *data, size_t n)
95 {
96     uint8_t class;
97     static const char *coment_class[256] = {
98         [0x00] = "Translator",
99         [0x01] = "Copyright",
100         [0x81] = "Library specifier",
101         [0x9c] = "MS-DOS version",
102         [0x9d] = "Memory model",
103         [0x9e] = "DOSSEG",
104         [0x9f] = "Library search",
105         [0xa0] = "OMF extensions",
106         [0xa1] = "New OMF extension",
107         [0xa2] = "Link pass separator",
108         [0xa3] = "LIBMOD",
109         [0xa4] = "EXESTR",
110         [0xa6] = "INCERR",
111         [0xa7] = "NOPAD",
112         [0xa8] = "WKEXT",
113         [0xa9] = "LZEXT",
114         [0xda] = "Comment",
115         [0xdb] = "Compiler",
116         [0xdc] = "Date",
117         [0xdd] = "Timestamp",
118         [0xdf] = "User",
119         [0xe9] = "Dependency file",
120         [0xff] = "Command line"
121     };
122
123     if (n < 2) {
124         dump_unknown(type, data, n);
125         return;
126     }
127
128     type  = data[0];
129     class = data[1];
130
131     printf("  [NP=%d NL=%d UD=%02X] %02X %s\n",
132            (type >> 7) & 1,
133            (type >> 6) & 1,
134            type & 0x3f,
135            class,
136            coment_class[class] ? coment_class[class] : "???");
137
138     hexdump_data(2, data+2, n-2);
139 }
140
141 static const dump_func dump_type[256] =
142 {
143     [0x88] = dump_coment,
144 };
145
146 int dump_omf(int fd)
147 {
148     struct stat st;
149     size_t len, n;
150     uint8_t type;
151     const uint8_t *p, *data;
152
153     if (fstat(fd, &st))
154         return -1;
155
156     len = st.st_size;
157
158     data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
159     if (data == MAP_FAILED)
160         return -1;
161
162     p = data;
163     while (len >= 3) {
164         uint8_t csum;
165         int i;
166
167         type = p[0];
168         n = *(uint16_t *)(p+1);
169
170         printf("%02x %-10s %4zd bytes",
171                type,
172                record_types[type] ? record_types[type] : "???",
173                n);
174
175         if (len < n+3) {
176             printf("\n  (truncated, only %zd bytes left)\n", len-3);
177             break;              /* Truncated */
178         }
179
180         p += 3;       /* Header doesn't count in the length */
181         n--;          /* Remove checksum byte */
182
183         csum = 0;
184         for (i = -3; i < (int)n; i++)
185             csum -= p[i];
186
187         printf(", checksum %02X", p[i]);
188         if (csum == p[i])
189             printf(" (valid)\n");
190         else
191             printf(" (actual = %02X)\n", csum);
192
193         if (dump_type[type])
194             dump_type[type](type, p, n);
195         else
196             dump_unknown(type, p, n);
197
198         p   += n+1;
199         len -= (n+4);
200     }
201
202     munmap((void *)data, st.st_size);
203     return 0;
204 }
205
206 int main(int argc, char *argv[])
207 {
208     int fd;
209     int i;
210
211     progname = argv[0];
212
213     for (i = 1; i < argc; i++) {
214         fd = open(argv[i], O_RDONLY);
215         if (fd < 0 || dump_omf(fd)) {
216             perror(argv[i]);
217             return 1;
218         }
219         close(fd);
220     }
221
222     return 0;
223 }