Merge pull request #663 from bslenul/rumble-fix
[pcsx_rearmed.git] / deps / lightning / lib / jit_disasm.c
CommitLineData
4a71579b
PC
1/*
2 * Copyright (C) 2012-2019 Free Software Foundation, Inc.
3 *
4 * This file is part of GNU lightning.
5 *
6 * GNU lightning is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
10 *
11 * GNU lightning is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 * License for more details.
15 *
16 * Authors:
17 * Paulo Cesar Pereira de Andrade
18 */
19
20#include <lightning.h>
21#include <lightning/jit_private.h>
22#if DISASSEMBLER
23# include <dis-asm.h>
24#endif
25
26/*
27 * Prototypes
28 */
29#if DISASSEMBLER
30static int
31disasm_compare_symbols(const void *ap, const void *bp);
32
33static void
34disasm_print_address(bfd_vma addr, struct disassemble_info *info);
35
36#define disassemble(u, v) _disassemble(_jit, u, v)
37static void
38_disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length);
39#endif
40
41/*
42 * Initialization
43 */
44#if DISASSEMBLER
45static bfd *disasm_bfd;
46static disassemble_info disasm_info;
47static disassembler_ftype disasm_print;
48static asymbol **disasm_symbols;
49static asymbol *disasm_synthetic;
50static long disasm_num_symbols;
51static long disasm_num_synthetic;
52static jit_state_t *disasm_jit;
519a9ea1 53static FILE *disasm_stream;
4a71579b
PC
54#endif
55
56/*
57 * Implementation
58 */
59void
60jit_init_debug(const char *progname)
61{
40a44dcb 62 jit_init_print();
4a71579b
PC
63#if DISASSEMBLER
64 bfd_init();
65
66 if (progname)
67 disasm_bfd = bfd_openr(progname, NULL);
68 if (disasm_bfd == NULL) {
69#if defined(__linux__)
70 disasm_bfd = bfd_openr("/proc/self/exe", NULL);
71 if (disasm_bfd == NULL)
72#endif
73 return;
74 }
75 bfd_check_format(disasm_bfd, bfd_object);
76 bfd_check_format(disasm_bfd, bfd_archive);
519a9ea1 77 if (!disasm_stream)
40a44dcb
PC
78 disasm_stream = stdout;
79
4a71579b 80 INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf);
40a44dcb
PC
81 disasm_info.arch = bfd_get_arch(disasm_bfd);
82 disasm_info.mach = bfd_get_mach(disasm_bfd);
83
84# if HAVE_DISASSEMBLE_INIT_FOR_TARGET
4a71579b 85 disassemble_init_for_target(&disasm_info);
40a44dcb
PC
86# endif
87
88# if defined(__powerpc64__)
4a71579b 89 disasm_info.disassembler_options = "64";
4a71579b 90# endif
40a44dcb 91# if defined(__sparc__) || defined(__s390__) || defined(__s390x__)
4a71579b
PC
92 disasm_info.endian = disasm_info.display_endian = BFD_ENDIAN_BIG;
93# endif
94# if defined(__s390__) || defined(__s390x__)
4a71579b 95 disasm_info.disassembler_options = "zarch";
4a71579b
PC
96# endif
97 disasm_info.print_address_func = disasm_print_address;
98
99# if BINUTILS_2_29
100 disasm_print = disassembler(disasm_info.arch, __BYTE_ORDER == __BIG_ENDIAN,
101 disasm_info.mach, disasm_bfd);
102# else
103 disasm_print = disassembler(disasm_bfd);
104# endif
105 assert(disasm_print);
106
107 if (bfd_get_file_flags(disasm_bfd) & HAS_SYMS) {
108 asymbol **in;
109 asymbol **out;
110 asymbol *symbol;
111 long offset;
112 long sym_count;
113 long dyn_count;
114 long sym_storage;
115 long dyn_storage;
116
117 if ((sym_storage = bfd_get_symtab_upper_bound(disasm_bfd)) >= 0) {
118
119 if (bfd_get_file_flags(disasm_bfd) & DYNAMIC) {
120 dyn_storage = bfd_get_dynamic_symtab_upper_bound(disasm_bfd);
121# if defined(__alpha__)
122 /* XXX */
123 if (dyn_storage < 0)
124 dyn_storage = 0;
125# else
126 assert(dyn_storage >= 0);
127# endif
128 }
129 else
130 dyn_storage = 0;
131
132 jit_alloc((jit_pointer_t *)&disasm_symbols,
133 (sym_storage + dyn_storage) * sizeof(asymbol *));
134 sym_count = bfd_canonicalize_symtab(disasm_bfd, disasm_symbols);
135 assert(sym_count >= 0);
136 if (dyn_storage) {
137 dyn_count = bfd_canonicalize_dynamic_symtab(disasm_bfd,
138 disasm_symbols +
139 sym_count);
140 assert(dyn_count >= 0);
141 }
142 else
143 dyn_count = 0;
144 disasm_num_symbols = sym_count + dyn_count;
145
146 disasm_num_synthetic = bfd_get_synthetic_symtab(disasm_bfd,
147 sym_count,
148 disasm_symbols,
149 dyn_count,
150 disasm_symbols +
151 sym_count,
152 &disasm_synthetic);
153 if (disasm_num_synthetic > 0) {
154 jit_realloc((jit_pointer_t *)&disasm_symbols,
155 (sym_storage + dyn_storage) * sizeof(asymbol *),
156 (sym_storage + dyn_storage + disasm_num_synthetic) *
157 sizeof(asymbol *));
158 for (offset = 0; offset < disasm_num_synthetic; offset++)
159 disasm_symbols[disasm_num_symbols++] =
160 disasm_synthetic + offset;
161 }
162
163 /* remove symbols not useful for disassemble */
164 in = out = disasm_symbols;
165 for (offset = 0; offset < disasm_num_symbols; offset++) {
166 symbol = *in++;
167 if (symbol->name &&
168 symbol->name[0] != '\0' &&
169 !(symbol->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) &&
170 !bfd_is_und_section(symbol->section) &&
171 !bfd_is_com_section(symbol->section))
172 *out++ = symbol;
173 }
174 disasm_num_symbols = out - disasm_symbols;
175 qsort(disasm_symbols, disasm_num_symbols,
176 sizeof(asymbol *), disasm_compare_symbols);
177 }
178 }
179#endif
180}
181
182void
183jit_finish_debug(void)
184{
185#if DISASSEMBLER
186 if (disasm_synthetic)
187 jit_free((jit_pointer_t *)&disasm_synthetic);
188 if (disasm_symbols)
189 jit_free((jit_pointer_t *)&disasm_symbols);
190 if (disasm_bfd)
191 bfd_close (disasm_bfd);
192#endif
193}
194
195void
196_jit_disassemble(jit_state_t *_jit)
197{
198#if DISASSEMBLER
199 if (disasm_bfd) {
200# if defined(__arm__)
201 /* FIXME add mapping for prolog switching to arm and possible jump
202 * before first prolog also in arm mode */
203 disasm_info.disassembler_options = jit_cpu.thumb ? "force-thumb" : "";
204# endif
205
206 disassemble(_jit->code.ptr, _jit->pc.uc - _jit->code.ptr);
207 }
208#endif
209}
210
211#if DISASSEMBLER
212/* Based on objdump source */
213static int
214disasm_compare_symbols(const void *ap, const void *bp)
215{
216 const asymbol *a = *(const asymbol **)ap;
217 const asymbol *b = *(const asymbol **)bp;
218
219 if (bfd_asymbol_value(a) > bfd_asymbol_value(b))
220 return (1);
221 if (bfd_asymbol_value(a) < bfd_asymbol_value(b))
222 return (-1);
223 return (0);
224}
225
226#if __WORDSIZE == 32
227# define address_buffer_length 16
228# define address_buffer_format "%llx"
229#else
230# define address_buffer_length 32
231# define address_buffer_format "%lx"
232#endif
233static void
234disasm_print_address(bfd_vma addr, struct disassemble_info *info)
235{
236 char *name;
237 char *file;
238 int line;
239 char buffer[address_buffer_length];
240
241 sprintf(buffer, address_buffer_format, (long long)addr);
242 (*info->fprintf_func)(info->stream, "0x%s", buffer);
243
244# define _jit disasm_jit
245# undef jit_pointer_p
246# define jit_pointer_p(u) \
247 ((u) >= _jit->code.ptr && (u) < _jit->pc.uc)
248 if (jit_pointer_p((jit_uint8_t *)(jit_word_t)addr)) {
249 if (jit_get_note((jit_uint8_t *)(jit_word_t)addr, &name, &file, &line))
250 (*info->fprintf_func)(info->stream, " %s:%s:%d",
251 name ? name : "",
252 file ? file : "",
253 line);
254 }
255# undef jit_pointer_p
256# undef _jit
257 else if (disasm_num_symbols) {
258 long low;
259 long high;
260 long offset;
261 asymbol *symbol;
262
263 low = 0;
264 high = disasm_num_symbols;
265 do {
266 offset = (low + high) >> 1;
267 symbol = disasm_symbols[offset];
268 if (bfd_asymbol_value(symbol) > addr)
269 high = offset - 1;
270 else if (bfd_asymbol_value(symbol) < addr)
271 low = offset + 1;
272 else
273 break;
274 } while (low < high);
275
276 if (offset >= 0 && offset < disasm_num_symbols) {
277 if (bfd_asymbol_value(symbol) < addr) {
278 while (++offset < disasm_num_symbols) {
279 symbol = disasm_symbols[offset];
280 if (bfd_asymbol_value(symbol) >= addr)
281 break;
282 }
283 }
284 else if (bfd_asymbol_value(symbol) > addr) {
285 while (offset--) {
286 if (bfd_asymbol_value(disasm_symbols[offset]) < addr)
287 break;
288 symbol = disasm_symbols[offset];
289 }
290 }
291 if (bfd_asymbol_value(symbol) == addr)
292 (*info->fprintf_func)(info->stream, " # %s", symbol->name);
293 }
294 }
295}
296
297static void
298_disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length)
299{
300 int bytes;
301 char *name, *old_name;
302 char *file, *old_file;
303 int line, old_line;
304#if __arm__
305 jit_int32_t offset;
306 jit_bool_t data_info;
307 jit_int32_t data_offset;
308#endif
309 bfd_vma pc = (jit_uword_t)code;
310 bfd_vma end = (jit_uword_t)code + length;
311 char buffer[address_buffer_length];
312#if DEVEL_DISASSEMBLER
313 jit_node_t *node;
314 jit_uword_t prevw;
315#endif
316
317#if __arm__
318 data_info = _jitc && _jitc->data_info.ptr;
319 data_offset = 0;
320#endif
321 disasm_info.buffer = code;
322 disasm_info.buffer_vma = (jit_uword_t)code;
323 disasm_info.buffer_length = length;
324 old_file = old_name = NULL;
325 old_line = 0;
326 disasm_jit = _jit;
327#if DEVEL_DISASSEMBLER
328 node = _jitc->head;
329 prevw = pc;
330#endif
331 while (pc < end) {
332#if DEVEL_DISASSEMBLER
333 while (node && (jit_uword_t)(prevw + node->offset) < (jit_uword_t)pc) {
334 prevw += node->offset;
335 node = node->next;
336 }
337 while (node && (jit_uword_t)(prevw + node->offset) == (jit_uword_t)pc) {
338 jit_print_node(node);
339 fputc('\n', stdout);
340 prevw += node->offset;
341 node = node->next;
342 }
343#endif
344#if __arm__
345 again:
346 if (data_info) {
347 while (_jitc->data_info.ptr[data_offset].code < pc) {
348 if (++data_offset >= _jitc->data_info.length) {
349 data_info = 0;
350 goto again;
351 }
352 }
353 if (pc == _jitc->data_info.ptr[data_offset].code) {
354 offset = _jitc->data_info.ptr[data_offset].length;
355 for (; offset >= 4; offset -= 4, pc += 4) {
356 bytes = sprintf(buffer, address_buffer_format, pc);
357 (*disasm_info.fprintf_func)(disasm_stream,
358 "%*c0x%s\t.data\t0x%08x\n",
359 16 - bytes, ' ', buffer,
360 *(jit_uint32_t *)
361 (jit_uint32_t)pc);
362 }
363 /* reset disassemble information instead of attempting
364 * to hack the arm specific backend data structures to
365 * tell it to forward the required number of bytes. */
366 disasm_info.buffer = (jit_pointer_t)(jit_uint32_t)pc;
367 disasm_info.buffer_vma = (jit_uword_t)pc;
368 if ((disasm_info.buffer_length = end - pc) <= 0)
369 break;
370 }
371 }
372#endif
373 if (jit_get_note((jit_uint8_t *)(jit_word_t)pc, &name, &file, &line) &&
374 (name != old_name || file != old_file || line != old_line)) {
375 (*disasm_info.fprintf_func)(disasm_stream, "# %s:%s:%d\n",
376 name ? name : "",
377 file ? file : "",
378 line);
379 old_name = name;
380 old_file = file;
381 old_line = line;
382 }
383
384 bytes = sprintf(buffer, address_buffer_format, (long long)pc);
385 (*disasm_info.fprintf_func)(disasm_stream, "%*c0x%s\t",
386 16 - bytes, ' ', buffer);
387 pc += (*disasm_print)(pc, &disasm_info);
388 putc('\n', disasm_stream);
389 }
390}
391#endif