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