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 }