FreeCalypso > hg > freecalypso-reveng
comparison leo-obj/tool/disasm.c @ 130:87b82398a08b
leo-obj project subtree started, tiobjd tool moved into it
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 06 Apr 2014 22:14:39 +0000 |
parents | ticoff/disasm.c@03f8a618689e |
children | daeaa5950d10 |
comparison
equal
deleted
inserted
replaced
129:597143ba1c37 | 130:87b82398a08b |
---|---|
1 /* | |
2 * Putting it all together: section-, symbol- and reloc-aware disassembly | |
3 */ | |
4 | |
5 #include <sys/types.h> | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <strings.h> | |
10 #include "intstruct.h" | |
11 #include "coffconst.h" | |
12 #include "globals.h" | |
13 | |
14 extern unsigned get_u16(), get_u32(); | |
15 extern char *storage_class_to_string(); | |
16 | |
17 static int auto_xlat_section_relocs = 1; | |
18 | |
19 static void | |
20 find_better_symbol(sec, symp, addp) | |
21 struct internal_scnhdr *sec; | |
22 struct internal_syment **symp; | |
23 unsigned *addp; | |
24 { | |
25 unsigned addr, delta; | |
26 struct internal_syment *sym; | |
27 unsigned n; | |
28 | |
29 addr = *addp; | |
30 for (n = 0; n < sec->nsymbols; n++) { | |
31 sym = sec->sorted_symbols[n]; | |
32 if (sym->value > addr) | |
33 return; | |
34 if (sym->class != C_EXT && sym->class != C_STAT) | |
35 continue; | |
36 delta = addr - sym->value; | |
37 if (sym->name[0] == '_' && !delta || | |
38 sym->name[0] == '$' && delta <= 1) { | |
39 *symp = sym; | |
40 *addp = delta; | |
41 } | |
42 } | |
43 } | |
44 | |
45 void | |
46 disasm_reloc_target(sec, rel, addend) | |
47 struct internal_scnhdr *sec; | |
48 struct internal_reloc *rel; | |
49 unsigned addend; | |
50 { | |
51 struct internal_syment *sym = rel->sym; | |
52 | |
53 if (sym) | |
54 addend -= sym->value; | |
55 if (auto_xlat_section_relocs && | |
56 (!sym || sym->section && !strcmp(sym->name, sym->section->name))) | |
57 find_better_symbol(sym ? sym->section : sec, &sym, &addend); | |
58 if (sym) | |
59 fputs(sym->name, stdout); | |
60 else | |
61 fputs(sec->name, stdout); | |
62 if (addend >= 10) | |
63 printf("+0x%x", addend); | |
64 else if (addend) | |
65 printf("+%u", addend); | |
66 } | |
67 | |
68 void | |
69 disasm_word32_reloc(sec, rel) | |
70 struct internal_scnhdr *sec; | |
71 struct internal_reloc *rel; | |
72 { | |
73 unsigned word; | |
74 | |
75 word = get_u32(filemap + sec->data_offset + rel->location); | |
76 printf("%08x R\t.word\t", word); | |
77 disasm_reloc_target(sec, rel, word); | |
78 putchar('\n'); | |
79 } | |
80 | |
81 void | |
82 disasm_end_of_section(sec, symnum) | |
83 struct internal_scnhdr *sec; | |
84 unsigned symnum; | |
85 { | |
86 struct internal_syment *sym; | |
87 char *sym_comment; | |
88 | |
89 putchar('\n'); | |
90 while (symnum < sec->nsymbols) { | |
91 sym = sec->sorted_symbols[symnum]; | |
92 if (sym->value != sec->size) { | |
93 printf("error: expecting symbol at end of section\n"); | |
94 return; | |
95 } | |
96 switch (sym->class) { | |
97 case C_EXT: | |
98 sym_comment = "Global"; | |
99 break; | |
100 case C_STAT: | |
101 sym_comment = "static"; | |
102 break; | |
103 case C_LABEL: | |
104 sym_comment = "label"; | |
105 break; | |
106 default: | |
107 sym_comment = "unexpected class!"; | |
108 } | |
109 printf("%s:\t; %s\n", sym->name, sym_comment); | |
110 symnum++; | |
111 } | |
112 printf("%8x:\t<end of section>\n", sec->size); | |
113 } | |
114 | |
115 void | |
116 disasm_text_section(sec) | |
117 struct internal_scnhdr *sec; | |
118 { | |
119 unsigned symnum, relnum; | |
120 unsigned pos, incr, headroom; | |
121 int state = -1, linebrk = 0; | |
122 struct internal_syment *sym; | |
123 struct internal_reloc *rel; | |
124 char *sym_comment; | |
125 | |
126 printf("Disassembling code section:\n"); | |
127 if (sec->nsymbols) | |
128 sort_symbols_of_sec(sec); | |
129 if (sec->nreloc) | |
130 get_relocs_of_sec(sec); | |
131 symnum = relnum = 0; | |
132 for (pos = 0; pos < sec->size; pos += incr) { | |
133 headroom = sec->size - pos; | |
134 while (symnum < sec->nsymbols) { | |
135 sym = sec->sorted_symbols[symnum]; | |
136 if (sym->value > pos) { | |
137 if (sym->value - pos < headroom) | |
138 headroom = sym->value - pos; | |
139 break; | |
140 } | |
141 /* hit symbol */ | |
142 if (!linebrk) { | |
143 putchar('\n'); | |
144 linebrk = 1; | |
145 } | |
146 switch (sym->class) { | |
147 case C_EXT: | |
148 sym_comment = "Global"; | |
149 break; | |
150 case C_STAT: | |
151 sym_comment = "static"; | |
152 break; | |
153 case C_LABEL: | |
154 sym_comment = "label"; | |
155 if (!strcmp(sym->name, "$CODE16")) | |
156 state = 1; | |
157 else if (!strcmp(sym->name, "$CODE32")) | |
158 state = 0; | |
159 break; | |
160 default: | |
161 sym_comment = "unexpected class!"; | |
162 } | |
163 printf("%s:\t; %s\n", sym->name, sym_comment); | |
164 symnum++; | |
165 } | |
166 if (relnum < sec->nreloc) { | |
167 rel = sec->int_relocs + relnum; | |
168 if (rel->location == pos) | |
169 relnum++; /* it's ours */ | |
170 else { | |
171 if (rel->location - pos < headroom) | |
172 headroom = rel->location - pos; | |
173 rel = 0; /* no reloc for current pos */ | |
174 } | |
175 } else | |
176 rel = 0; | |
177 printf("%8x:\t", pos); | |
178 if (rel && rel->type == RTYPE_LONG) { | |
179 if (pos & 3) { | |
180 printf("MISALIGNED pos for word32 reloc, aborting\n"); | |
181 return; | |
182 } | |
183 disasm_word32_reloc(sec, rel); | |
184 incr = 4; | |
185 goto next; | |
186 } | |
187 if (pos & 1 || headroom < 2) { | |
188 if (rel) { | |
189 printf("error: reloc at byte pos, aborting\n"); | |
190 return; | |
191 } | |
192 printf("%02x\n", filemap[sec->data_offset + pos]); | |
193 incr = 1; | |
194 goto next; | |
195 } | |
196 switch (state) { | |
197 case 0: /* ARM */ | |
198 if (pos & 3) { | |
199 printf("MISALIGNED pos in CODE32 state, aborting\n"); | |
200 return; | |
201 } | |
202 if (rel) { | |
203 if (rel->type != RTYPE_ARM_B) { | |
204 printf("Wrong reloc type in CODE32 state, aborting\n"); | |
205 return; | |
206 } | |
207 arm_branch_reloc(sec, rel); | |
208 } else | |
209 arm_disasm_line(sec, pos); | |
210 incr = 4; | |
211 break; | |
212 case 1: /* Thumb */ | |
213 if (pos & 1) { | |
214 printf("MISALIGNED pos in CODE16 state, aborting\n"); | |
215 return; | |
216 } | |
217 if (rel) { | |
218 if (rel->type != RTYPE_THUMB_BL) { | |
219 printf("Wrong reloc type in CODE16 state, aborting\n"); | |
220 return; | |
221 } | |
222 thumb_bl_reloc(sec, rel); | |
223 incr = 4; | |
224 } else if (headroom >= 4 && thumb_check_bl(sec, pos)) | |
225 incr = 4; | |
226 else { | |
227 thumb_disasm_line(sec, pos); | |
228 incr = 2; | |
229 } | |
230 break; | |
231 default: | |
232 printf("UNKNOWN T state, aborting\n"); | |
233 return; | |
234 } | |
235 next: linebrk = 0; | |
236 if (incr > headroom) { | |
237 printf("error: increment %u > headroom %u, aborting\n", | |
238 incr, headroom); | |
239 return; | |
240 } | |
241 } | |
242 if (symnum < sec->nsymbols) | |
243 disasm_end_of_section(sec, symnum); | |
244 } | |
245 | |
246 void | |
247 disasm_data_section(sec) | |
248 struct internal_scnhdr *sec; | |
249 { | |
250 unsigned symnum, relnum; | |
251 unsigned pos, incr, headroom; | |
252 int linebrk = 0; | |
253 struct internal_syment *sym; | |
254 struct internal_reloc *rel; | |
255 char *sym_comment; | |
256 | |
257 printf("Disassembling data section:\n"); | |
258 if (sec->nsymbols) | |
259 sort_symbols_of_sec(sec); | |
260 if (sec->nreloc) | |
261 get_relocs_of_sec(sec); | |
262 symnum = relnum = 0; | |
263 for (pos = 0; pos < sec->size; pos += incr) { | |
264 headroom = sec->size - pos; | |
265 while (symnum < sec->nsymbols) { | |
266 sym = sec->sorted_symbols[symnum]; | |
267 if (sym->value > pos) { | |
268 if (sym->value - pos < headroom) | |
269 headroom = sym->value - pos; | |
270 break; | |
271 } | |
272 /* hit symbol */ | |
273 if (!linebrk) { | |
274 putchar('\n'); | |
275 linebrk = 1; | |
276 } | |
277 switch (sym->class) { | |
278 case C_EXT: | |
279 sym_comment = "Global"; | |
280 break; | |
281 case C_STAT: | |
282 sym_comment = "static"; | |
283 break; | |
284 case C_LABEL: | |
285 sym_comment = "label"; | |
286 break; | |
287 default: | |
288 sym_comment = "unexpected class!"; | |
289 } | |
290 printf("%s:\t; %s\n", sym->name, sym_comment); | |
291 symnum++; | |
292 } | |
293 if (relnum < sec->nreloc) { | |
294 rel = sec->int_relocs + relnum; | |
295 if (rel->location == pos) | |
296 relnum++; /* it's ours */ | |
297 else { | |
298 if (rel->location - pos < headroom) | |
299 headroom = rel->location - pos; | |
300 rel = 0; /* no reloc for current pos */ | |
301 } | |
302 } else | |
303 rel = 0; | |
304 printf("%8x:\t", pos); | |
305 if (rel) { | |
306 if (rel->type != RTYPE_LONG) { | |
307 printf("error: reloc other than word32 in data section\n"); | |
308 return; | |
309 } | |
310 if (pos & 3) { | |
311 printf("MISALIGNED pos for word32 reloc, aborting\n"); | |
312 return; | |
313 } | |
314 disasm_word32_reloc(sec, rel); | |
315 incr = 4; | |
316 } else if (pos & 1 || headroom < 2) { | |
317 printf("%02x\n", filemap[sec->data_offset + pos]); | |
318 incr = 1; | |
319 } else if (pos & 2 || headroom < 4) { | |
320 printf("%04x\n", | |
321 get_u16(filemap + sec->data_offset + pos)); | |
322 incr = 2; | |
323 } else { | |
324 printf("%08x\n", | |
325 get_u32(filemap + sec->data_offset + pos)); | |
326 incr = 4; | |
327 } | |
328 linebrk = 0; | |
329 if (incr > headroom) { | |
330 printf("error: increment %u > headroom %u, aborting\n", | |
331 incr, headroom); | |
332 return; | |
333 } | |
334 } | |
335 if (symnum < sec->nsymbols) | |
336 disasm_end_of_section(sec, symnum); | |
337 } | |
338 | |
339 void | |
340 disasm_bss(sec) | |
341 struct internal_scnhdr *sec; | |
342 { | |
343 unsigned m; | |
344 struct internal_syment *sym; | |
345 char classbuf[8]; | |
346 | |
347 putchar('\n'); | |
348 for (m = 0; m < sec->nsymbols; m++) { | |
349 sym = sec->sorted_symbols[m]; | |
350 printf("%08X %-7s %s\n", sym->value, | |
351 storage_class_to_string(sym->class, classbuf), | |
352 sym->name); | |
353 } | |
354 printf("%08X <end of section>\n", sec->size); | |
355 } | |
356 | |
357 void | |
358 disasm_sec_by_type(sec) | |
359 struct internal_scnhdr *sec; | |
360 { | |
361 switch (sec->disasm_mode) { | |
362 case DISASM_MODE_CODE: | |
363 disasm_text_section(sec); | |
364 return; | |
365 case DISASM_MODE_DATA: | |
366 disasm_data_section(sec); | |
367 return; | |
368 case DISASM_MODE_BSS: | |
369 disasm_bss(sec); | |
370 return; | |
371 default: | |
372 printf("Unrecognized section type, skipped\n"); | |
373 } | |
374 } | |
375 | |
376 cmd_disasm(argc, argv) | |
377 char **argv; | |
378 { | |
379 extern char *optarg; | |
380 char *hintsfile = 0; | |
381 struct internal_scnhdr *sec; | |
382 unsigned secnum; | |
383 int c; | |
384 | |
385 while ((c = getopt(argc, argv, "h:s")) != EOF) | |
386 switch (c) { | |
387 case 'h': | |
388 hintsfile = optarg; | |
389 continue; | |
390 case 's': | |
391 auto_xlat_section_relocs = 0; | |
392 continue; | |
393 default: | |
394 /* error msg already printed */ | |
395 exit(1); | |
396 } | |
397 | |
398 printf("%s:\n", objfilename); | |
399 dump_filehdr_info(); | |
400 putchar('\n'); | |
401 get_int_section_table(); | |
402 get_int_symbol_table(); | |
403 if (hintsfile) | |
404 read_hints_file(hintsfile); | |
405 extern_profile_report("Module"); | |
406 sort_symbols_of_all_sec(); | |
407 for (secnum = 0; secnum < nsections; secnum++) { | |
408 sec = sections + secnum; | |
409 printf("=== %s ===\n", sec->name); | |
410 disasm_sec_by_type(sec); | |
411 putchar('\n'); | |
412 } | |
413 exit(0); | |
414 } |