Mercurial > hg-old > index.cgi
annotate lwlink/objdump.c @ 388:8991eb507d2d
Added missing arg-nonnull.h ??? file to repo
author | lost@l-w.ca |
---|---|
date | Wed, 14 Jul 2010 20:17:57 -0600 |
parents | a741d2e4869f |
children |
rev | line source |
---|---|
339 | 1 /* |
2 objdump.c | |
3 Copyright © 2009 William Astle | |
4 | |
5 This file is part of LWLINK | |
6 | |
7 LWLINK is free software: you can redistribute it and/or modify it under the | |
8 terms of the GNU General Public License as published by the Free Software | |
9 Foundation, either version 3 of the License, or (at your option) any later | |
10 version. | |
11 | |
12 This program is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 more details. | |
16 | |
17 You should have received a copy of the GNU General Public License along with | |
18 this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
21 A standalone program to dump an object file in a text form to stdout | |
22 | |
23 */ | |
24 #include <config.h> | |
25 #include <stdio.h> | |
26 #include <stdlib.h> | |
27 | |
28 #include "util.h" | |
29 | |
30 #ifdef HAVE_CONFIG_H | |
31 #include "config.h" | |
32 #endif | |
33 | |
34 void read_lwobj16v0(unsigned char *filedata, long filesize); | |
35 char *program_name; | |
36 | |
387
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
37 char *string_cleanup(char *sym) |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
38 { |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
39 static char symbuf[4096]; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
40 int optr = 0; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
41 while (*sym) |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
42 { |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
43 if (*sym < 33 || *sym > 126) |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
44 { |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
45 int c; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
46 symbuf[optr++] = '\\'; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
47 c = *sym >> 4; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
48 c+= 48; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
49 if (c > 57) |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
50 c += 7; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
51 symbuf[optr++] = c; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
52 c = *sym & 15; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
53 c += 48; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
54 if (c > 57) |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
55 c += 7; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
56 symbuf[optr++] = c; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
57 } |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
58 else if (*sym == '\\') |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
59 { |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
60 symbuf[optr++] = '\\'; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
61 symbuf[optr++] = '\\'; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
62 } |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
63 else |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
64 { |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
65 symbuf[optr++] = *sym; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
66 } |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
67 sym++; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
68 } |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
69 symbuf[optr] = '\0'; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
70 return symbuf; |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
71 } |
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
72 |
339 | 73 /* |
74 The logic of reading the entire file into memory is simple. All the symbol | |
75 names in the file are NUL terminated strings and can be used directly without | |
76 making additional copies. | |
77 */ | |
78 int main(int argc, char **argv) | |
79 { | |
80 int i; | |
81 long size; | |
82 FILE *f; | |
83 long bread; | |
84 unsigned char *filedata; | |
85 | |
86 program_name = argv[0]; | |
87 if (argc != 2) | |
88 { | |
89 fprintf(stderr, "Must specify exactly one input file.\n"); | |
90 exit(1); | |
91 } | |
92 | |
93 f = fopen(argv[1], "rb"); | |
94 if (!f) | |
95 { | |
96 fprintf(stderr, "Can't open file %s:", argv[1]); | |
97 perror(""); | |
98 exit(1); | |
99 } | |
100 fseek(f, 0, SEEK_END); | |
101 size = ftell(f); | |
102 rewind(f); | |
103 | |
104 filedata = lw_malloc(size); | |
105 | |
106 bread = fread(filedata, 1, size, f); | |
107 if (bread < size) | |
108 { | |
109 fprintf(stderr, "Short read on file %s (%ld/%ld):", argv[1], bread, size); | |
110 perror(""); | |
111 exit(1); | |
112 } | |
113 | |
114 fclose(f); | |
115 | |
116 if (!memcmp(filedata, "LWOBJ16", 8)) | |
117 { | |
118 // read v0 LWOBJ16 file | |
119 read_lwobj16v0(filedata, size); | |
120 } | |
121 else | |
122 { | |
123 fprintf(stderr, "%s: unknown file format\n", argv[1]); | |
124 exit(1); | |
125 } | |
126 exit(0); | |
127 } | |
128 | |
129 // this macro is used to bail out if we run off the end of the file data | |
130 // while parsing - it keeps the code below cleaner | |
131 #define NEXTBYTE() do { cc++; if (cc > filesize) { fprintf(stderr, "***invalid file format\n"); exit(1); } } while (0) | |
132 // this macro is used to refer to the current byte in the stream | |
133 #define CURBYTE() (filedata[cc < filesize ? cc : filesize - 1]) | |
134 // this one will leave the input pointer past the trailing NUL | |
135 #define CURSTR() read_lwobj16v0_str(&cc, &filedata, filesize) | |
136 unsigned char *read_lwobj16v0_str(long *cc1, unsigned char **filedata1, long filesize) | |
137 { | |
138 int cc = *cc1; | |
139 unsigned char *filedata = *filedata1; | |
140 unsigned char *fp; | |
141 fp = &CURBYTE(); | |
142 while (CURBYTE()) | |
143 NEXTBYTE(); | |
144 NEXTBYTE(); | |
145 *cc1 = cc; | |
146 *filedata1 = filedata; | |
147 return fp; | |
148 } | |
149 // the function below can be switched to dealing with data coming from a | |
150 // source other than an in-memory byte pool by adjusting the input data | |
151 // in "fn" and the above two macros | |
152 void read_lwobj16v0(unsigned char *filedata, long filesize) | |
153 { | |
154 unsigned char *fp; | |
155 long cc; | |
156 int val; | |
157 int bss; | |
158 | |
159 static char *opernames[] = { | |
160 "?", | |
161 "PLUS", | |
162 "MINUS", | |
163 "TIMES", | |
164 "DIVIDE", | |
165 "MOD", | |
166 "INTDIV", | |
167 "BWAND", | |
168 "BWOR", | |
169 "BWXOR", | |
170 "AND", | |
171 "OR", | |
172 "NEG", | |
173 "COM" | |
174 }; | |
175 static const int numopers = 13; | |
176 | |
177 // start reading *after* the magic number | |
178 cc = 8; | |
179 | |
180 while (1) | |
181 { | |
182 bss = 0; | |
183 | |
184 // bail out if no more sections | |
185 if (!(CURBYTE())) | |
186 break; | |
187 | |
188 fp = CURSTR(); | |
189 | |
190 printf("SECTION %s\n", fp); | |
191 | |
192 // read flags | |
193 while (CURBYTE()) | |
194 { | |
195 switch (CURBYTE()) | |
196 { | |
197 case 0x01: | |
198 printf(" FLAG: BSS\n"); | |
199 bss = 1; | |
200 break; | |
201 | |
202 default: | |
203 printf(" FLAG: %02X (unknown)\n", CURBYTE()); | |
204 break; | |
205 } | |
206 NEXTBYTE(); | |
207 } | |
208 // skip NUL terminating flags | |
209 NEXTBYTE(); | |
210 | |
211 printf(" Local symbols:\n"); | |
212 // now parse the local symbol table | |
213 while (CURBYTE()) | |
214 { | |
215 fp = CURSTR(); | |
216 | |
217 // fp is the symbol name | |
218 val = (CURBYTE()) << 8; | |
219 NEXTBYTE(); | |
220 val |= (CURBYTE()); | |
221 NEXTBYTE(); | |
222 // val is now the symbol value | |
223 | |
387
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
224 printf(" %s=%04X\n", string_cleanup(fp), val); |
339 | 225 |
226 } | |
227 // skip terminating NUL | |
228 NEXTBYTE(); | |
229 | |
230 printf(" Exported symbols\n"); | |
231 | |
232 // now parse the exported symbol table | |
233 while (CURBYTE()) | |
234 { | |
235 fp = CURSTR(); | |
236 | |
237 // fp is the symbol name | |
238 val = (CURBYTE()) << 8; | |
239 NEXTBYTE(); | |
240 val |= (CURBYTE()); | |
241 NEXTBYTE(); | |
242 // val is now the symbol value | |
243 | |
387
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
244 printf(" %s=%04X\n", string_cleanup(fp), val); |
339 | 245 } |
246 // skip terminating NUL | |
247 NEXTBYTE(); | |
248 | |
249 // now parse the incomplete references and make a list of | |
250 // external references that need resolution | |
251 printf(" Incomplete references\n"); | |
252 while (CURBYTE()) | |
253 { | |
254 printf(" ("); | |
255 // parse the expression | |
256 while (CURBYTE()) | |
257 { | |
258 int tt = CURBYTE(); | |
259 NEXTBYTE(); | |
260 switch (tt) | |
261 { | |
262 case 0x01: | |
263 // 16 bit integer | |
264 tt = CURBYTE() << 8; | |
265 NEXTBYTE(); | |
266 tt |= CURBYTE(); | |
267 NEXTBYTE(); | |
268 // normalize for negatives... | |
269 if (tt > 0x7fff) | |
270 tt -= 0x10000; | |
271 printf(" I16=%d", tt); | |
272 break; | |
273 | |
274 case 0x02: | |
275 // external symbol reference | |
387
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
276 printf(" ES=%s", string_cleanup(CURSTR())); |
339 | 277 break; |
278 | |
279 case 0x03: | |
280 // internal symbol reference | |
387
a741d2e4869f
Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
lost@l-w.ca
parents:
378
diff
changeset
|
281 printf(" IS=%s", string_cleanup(CURSTR())); |
339 | 282 break; |
283 | |
284 case 0x04: | |
285 // operator | |
286 if (CURBYTE() > 0 && CURBYTE() <= numopers) | |
287 printf(" OP=%s", opernames[CURBYTE()]); | |
288 else | |
289 printf(" OP=?"); | |
290 NEXTBYTE(); | |
291 break; | |
292 | |
293 case 0x05: | |
294 // section base reference (NULL internal reference is | |
295 // the section base address | |
296 printf(" SB"); | |
297 break; | |
298 | |
299 case 0xFF: | |
300 // section flags | |
301 printf(" FLAGS=%02X", CURBYTE()); | |
302 NEXTBYTE(); | |
303 break; | |
304 | |
305 default: | |
306 printf(" ERR"); | |
307 } | |
308 } | |
309 // skip the NUL | |
310 NEXTBYTE(); | |
311 | |
312 // fetch the offset | |
313 val = CURBYTE() << 8; | |
314 NEXTBYTE(); | |
315 val |= CURBYTE() & 0xff; | |
316 NEXTBYTE(); | |
317 printf(" ) @ %04X\n", val); | |
318 } | |
319 // skip the NUL terminating the relocations | |
320 NEXTBYTE(); | |
321 | |
322 // now set code location and size and verify that the file | |
323 // contains data going to the end of the code (if !SECTION_BSS) | |
324 val = CURBYTE() << 8; | |
325 NEXTBYTE(); | |
326 val |= CURBYTE(); | |
327 NEXTBYTE(); | |
328 | |
329 printf(" CODE %04X bytes", val); | |
330 | |
331 // skip the code if we're not in a BSS section | |
332 if (!bss) | |
333 { | |
334 int i; | |
335 for (i = 0; i < val; i++) | |
336 { | |
337 if (! (i % 16)) | |
338 { | |
339 printf("\n %04X ", i); | |
340 } | |
341 printf("%02X", CURBYTE()); | |
342 NEXTBYTE(); | |
343 } | |
344 } | |
345 printf("\n"); | |
346 } | |
347 } |