x86_64 support for host_dasm
[libpicofe.git] / linux / host_dasm.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2009-2010
3  *
4  * This work is licensed under the terms of any of these licenses
5  * (at your option):
6  *  - GNU GPL, version 2 or later.
7  *  - GNU LGPL, version 2.1 or later.
8  *  - MAME license.
9  * See the COPYING file in the top-level directory.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdarg.h>
16 #include <bfd.h>
17 #include <dis-asm.h>
18
19 #include "host_dasm.h"
20
21 extern char **g_argv;
22
23 static struct disassemble_info di;
24
25 #ifdef __arm__
26 #define print_insn_func print_insn_little_arm
27 #define BFD_ARCH bfd_arch_arm
28 #define BFD_MACH bfd_mach_arm_unknown
29 #define DASM_OPTS "reg-names-std"
30 #elif defined(__x86_64__) || defined(__i386__)
31 #define print_insn_func print_insn_i386_intel
32 #define BFD_ARCH bfd_arch_i386
33 #ifdef __x86_64__
34 #define BFD_MACH bfd_mach_x86_64_intel_syntax
35 #else
36 #define BFD_MACH bfd_mach_i386_i386_intel_syntax
37 #endif
38 #define DASM_OPTS NULL
39 #else
40 #error "missing arch support"
41 #endif
42
43 /* symbols */
44 static asymbol **symbols;
45 static long symcount, symstorage;
46 static int init_done;
47
48 /* Filter out (in place) symbols that are useless for disassembly.
49    COUNT is the number of elements in SYMBOLS.
50    Return the number of useful symbols.  */
51 static long
52 remove_useless_symbols (asymbol **symbols, long count)
53 {
54   asymbol **in_ptr = symbols, **out_ptr = symbols;
55
56   while (--count >= 0)
57     {
58       asymbol *sym = *in_ptr++;
59
60       if (sym->name == NULL || sym->name[0] == '\0' || sym->name[0] == '$')
61         continue;
62       if (sym->flags & (BSF_DEBUGGING | BSF_SECTION_SYM))
63         continue;
64       if (bfd_is_und_section (sym->section)
65           || bfd_is_com_section (sym->section))
66         continue;
67       if (sym->value + sym->section->vma == 0)
68         continue;
69 /*
70       printf("sym: %08lx %04x %08x v %08x \"%s\"\n",
71         (unsigned int)sym->value, (unsigned int)sym->flags, (unsigned int)sym->udata.i,
72         (unsigned int)sym->section->vma, sym->name);
73 */
74       *out_ptr++ = sym;
75     }
76
77   return out_ptr - symbols;
78 }
79
80 static void slurp_symtab(const char *filename)
81 {
82   bfd *abfd;
83
84   symcount = 0;
85
86   abfd = bfd_openr(filename, NULL);
87   if (abfd == NULL) {
88     fprintf(stderr, "failed to open: %s\n", filename);
89     goto no_symbols;
90   }
91
92   if (!bfd_check_format(abfd, bfd_object))
93     goto no_symbols;
94
95   if (!(bfd_get_file_flags(abfd) & HAS_SYMS))
96     goto no_symbols;
97
98   symstorage = bfd_get_symtab_upper_bound(abfd);
99   if (symstorage <= 0)
100     goto no_symbols;
101
102   symbols = malloc(symstorage);
103   if (symbols == NULL)
104     goto no_symbols;
105
106   symcount = bfd_canonicalize_symtab(abfd, symbols);
107   if (symcount < 0)
108     goto no_symbols;
109
110   symcount = remove_useless_symbols(symbols, symcount);
111 //  bfd_close(abfd);
112   return;
113
114 no_symbols:
115   fprintf(stderr, "no symbols in %s\n", bfd_get_filename(abfd));
116   if (symbols != NULL)
117     free(symbols);
118   symbols = NULL;
119   if (abfd != NULL)
120     bfd_close(abfd);
121 }
122
123 static const char *lookup_name(bfd_vma addr)
124 {
125   asymbol **sptr = symbols;
126   int i;
127
128   for (i = 0; i < symcount; i++) {
129     asymbol *sym = *sptr++;
130
131     if (addr == sym->value + sym->section->vma)
132       return sym->name;
133   }
134
135   return NULL;
136 }
137
138 /* Like target_read_memory, but slightly different parameters.  */
139 static int
140 dis_asm_read_memory(bfd_vma memaddr, bfd_byte *myaddr, unsigned int len,
141                      struct disassemble_info *info)
142 {
143   memcpy(myaddr, (void *)(long)memaddr, len);
144   return 0;
145 }
146
147 static void
148 dis_asm_memory_error(int status, bfd_vma memaddr,
149                       struct disassemble_info *info)
150 {
151   fprintf(stderr, "memory_error %p\n", (void *)(long)memaddr);
152 }
153
154 static void
155 dis_asm_print_address(bfd_vma addr, struct disassemble_info *info)
156 {
157   const char *name;
158
159   printf("%08x", (int)addr);
160
161   name = lookup_name(addr);
162   if (name != NULL)
163     printf(" <%s>", name);
164 }
165
166 static int insn_printf(void *f, const char *format, ...)
167 {
168   va_list args;
169   size_t n;
170
171   va_start(args, format);
172   n = vprintf(format, args);
173   va_end(args);
174
175   return n;
176 }
177
178 static void host_dasm_init(void)
179 {
180   bfd_init();
181   slurp_symtab(g_argv[0]);
182
183   init_disassemble_info(&di, NULL, insn_printf);
184   di.flavour = bfd_target_unknown_flavour;
185   di.memory_error_func = dis_asm_memory_error; 
186   di.print_address_func = dis_asm_print_address;
187 //  di.symbol_at_address_func = dis_asm_symbol_at_address;
188   di.read_memory_func = dis_asm_read_memory;
189   di.arch = BFD_ARCH;
190   di.mach = BFD_MACH;
191   di.endian = BFD_ENDIAN_LITTLE;
192   di.disassembler_options = DASM_OPTS;
193   disassemble_init_for_target(&di);
194   init_done = 1;
195 }
196
197 void host_dasm(void *addr, int len)
198 {
199   bfd_vma vma_end, vma = (bfd_vma)(long)addr;
200   const char *name;
201
202   if (!init_done)
203     host_dasm_init();
204
205   vma_end = vma + len;
206   while (vma < vma_end) {
207     name = lookup_name(vma);
208     if (name != NULL)
209       printf("%s:\n", name);
210
211     printf("   %08lx ", (long)vma);
212     vma += print_insn_func(vma, &di);
213     printf("\n");
214   }
215 }
216
217 void host_dasm_new_symbol_(void *addr, const char *name)
218 {
219   bfd_vma vma = (bfd_vma)(long)addr;
220   asymbol *sym, **tmp;
221
222   if (!init_done)
223     host_dasm_init();
224   if (symbols == NULL)
225     return;
226   if (symstorage <= symcount * sizeof(symbols[0])) {
227     tmp = realloc(symbols, symstorage * 2);
228     if (tmp == NULL)
229       return;
230     symstorage *= 2;
231     symbols = tmp;
232   }
233
234   symbols[symcount] = calloc(sizeof(*symbols[0]), 1);
235   if (symbols[symcount] == NULL)
236     return;
237
238   // a HACK (should use correct section), but ohwell
239   sym = symbols[symcount];
240   sym->section = symbols[0]->section;
241   sym->value = vma - sym->section->vma;
242   sym->name = name;
243   symcount++;
244 }
245