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