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 }