comparison src/objdump.c @ 311:8272b46b5a34

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