git subrepo pull --force deps/lightning
[pcsx_rearmed.git] / deps / lightning / lib / jit_disasm.c
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
30 static int
31 disasm_compare_symbols(const void *ap, const void *bp);
32
33 static void
34 disasm_print_address(bfd_vma addr, struct disassemble_info *info);
35
36 #define disassemble(u, v)       _disassemble(_jit, u, v)
37 static 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
45 static bfd                       *disasm_bfd;
46 static disassemble_info           disasm_info;
47 static disassembler_ftype         disasm_print;
48 static asymbol                  **disasm_symbols;
49 static asymbol                   *disasm_synthetic;
50 static long                       disasm_num_symbols;
51 static long                       disasm_num_synthetic;
52 static jit_state_t               *disasm_jit;
53 static FILE                      *disasm_stream;
54 #endif
55
56 /*
57  * Implementation
58  */
59 void
60 jit_init_debug(const char *progname)
61 {
62 #if DISASSEMBLER
63     bfd_init();
64
65     if (progname)
66         disasm_bfd = bfd_openr(progname, NULL);
67     if (disasm_bfd == NULL) {
68 #if defined(__linux__)
69         disasm_bfd = bfd_openr("/proc/self/exe", NULL);
70         if (disasm_bfd == NULL)
71 #endif
72             return;
73     }
74     bfd_check_format(disasm_bfd, bfd_object);
75     bfd_check_format(disasm_bfd, bfd_archive);
76     if (!disasm_stream)
77         disasm_stream = stderr;
78     INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf);
79 #  if defined(__i386__) || defined(__x86_64__)
80     disasm_info.arch = bfd_arch_i386;
81 #    if defined(__x86_64__)
82 #      if __WORDSIZE == 32
83     disasm_info.mach = bfd_mach_x64_32;
84 #      else
85     disasm_info.mach = bfd_mach_x86_64;
86 #      endif
87 #    else
88     disasm_info.mach = bfd_mach_i386_i386;
89 #    endif
90 #  endif
91 #  if defined(__powerpc__)
92     disasm_info.arch = bfd_arch_powerpc;
93     disasm_info.mach = bfd_mach_ppc64;
94 #    if HAVE_DISASSEMBLE_INIT_FOR_TARGET
95     disassemble_init_for_target(&disasm_info);
96 #    elif HAVE_DISASSEMBLE_INIT_POWERPC
97     disassemble_init_powerpc(&disasm_info);
98 #    endif
99 #    if defined(__powerpc64__)
100     disasm_info.disassembler_options = "64";
101 #    endif
102 #    if HAVE_DISASSEMBLE_INIT_FOR_TARGET
103     disassemble_init_for_target(&disasm_info);
104 #    elif HAVE_DISASSEMBLE_INIT_POWERPC
105     disassemble_init_powerpc(&disasm_info);
106 #    endif
107 #  endif
108 #  if defined(__sparc__)
109     disasm_info.endian = disasm_info.display_endian = BFD_ENDIAN_BIG;
110 #  endif
111 #  if defined(__s390__) || defined(__s390x__)
112     disasm_info.arch = bfd_arch_s390;
113 #    if __WORDSIZE == 32
114     disasm_info.mach = bfd_mach_s390_31;
115 #    else
116     disasm_info.mach = bfd_mach_s390_64;
117 #    endif
118     disasm_info.endian = disasm_info.display_endian = BFD_ENDIAN_BIG;
119     disasm_info.disassembler_options = "zarch";
120 #  endif
121 #  if defined(__alpha__)
122     disasm_info.arch = bfd_arch_alpha;
123     disasm_info.mach = bfd_mach_alpha_ev6;
124 #  endif
125 #  if defined(__hppa__)
126     disasm_info.arch = bfd_arch_hppa;
127     disasm_info.mach = bfd_mach_hppa10;
128 #  endif
129 #  if defined(__riscv)
130     disasm_info.arch = bfd_arch_riscv;
131 #  if __WORDSIZE == 32
132     disasm_info.mach = bfd_mach_riscv32;
133 #  else
134     disasm_info.mach = bfd_mach_riscv64;
135 #  endif
136 #  endif
137     disasm_info.print_address_func = disasm_print_address;
138
139 # if BINUTILS_2_29
140     disasm_print = disassembler(disasm_info.arch, __BYTE_ORDER == __BIG_ENDIAN,
141                                 disasm_info.mach, disasm_bfd);
142 #  else
143     disasm_print = disassembler(disasm_bfd);
144 #  endif
145     assert(disasm_print);
146
147     if (bfd_get_file_flags(disasm_bfd) & HAS_SYMS) {
148         asymbol         **in;
149         asymbol         **out;
150         asymbol          *symbol;
151         long              offset;
152         long              sym_count;
153         long              dyn_count;
154         long              sym_storage;
155         long              dyn_storage;
156
157         if ((sym_storage = bfd_get_symtab_upper_bound(disasm_bfd)) >= 0) {
158
159             if (bfd_get_file_flags(disasm_bfd) & DYNAMIC) {
160                 dyn_storage = bfd_get_dynamic_symtab_upper_bound(disasm_bfd);
161 #  if defined(__alpha__)
162                 /* XXX */
163                 if (dyn_storage < 0)
164                     dyn_storage = 0;
165 #  else
166                 assert(dyn_storage >= 0);
167 #  endif
168             }
169             else
170                 dyn_storage = 0;
171
172             jit_alloc((jit_pointer_t *)&disasm_symbols,
173                       (sym_storage + dyn_storage) * sizeof(asymbol *));
174             sym_count = bfd_canonicalize_symtab(disasm_bfd, disasm_symbols);
175             assert(sym_count >= 0);
176             if (dyn_storage) {
177                 dyn_count = bfd_canonicalize_dynamic_symtab(disasm_bfd,
178                                                             disasm_symbols +
179                                                             sym_count);
180                 assert(dyn_count >= 0);
181             }
182             else
183                 dyn_count = 0;
184             disasm_num_symbols = sym_count + dyn_count;
185
186             disasm_num_synthetic = bfd_get_synthetic_symtab(disasm_bfd,
187                                                             sym_count,
188                                                             disasm_symbols,
189                                                             dyn_count,
190                                                             disasm_symbols +
191                                                             sym_count,
192                                                             &disasm_synthetic);
193             if (disasm_num_synthetic > 0) {
194                 jit_realloc((jit_pointer_t *)&disasm_symbols,
195                             (sym_storage + dyn_storage) * sizeof(asymbol *),
196                             (sym_storage + dyn_storage + disasm_num_synthetic) *
197                             sizeof(asymbol *));
198                 for (offset = 0; offset < disasm_num_synthetic; offset++)
199                     disasm_symbols[disasm_num_symbols++] =
200                         disasm_synthetic + offset;
201             }
202
203             /* remove symbols not useful for disassemble */
204             in = out = disasm_symbols;
205             for (offset = 0; offset < disasm_num_symbols; offset++) {
206                 symbol = *in++;
207                 if (symbol->name &&
208                     symbol->name[0] != '\0' &&
209                     !(symbol->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) &&
210                     !bfd_is_und_section(symbol->section) &&
211                     !bfd_is_com_section(symbol->section))
212                     *out++ = symbol;
213             }
214             disasm_num_symbols = out - disasm_symbols;
215             qsort(disasm_symbols, disasm_num_symbols,
216                   sizeof(asymbol *), disasm_compare_symbols);
217         }
218     }
219 #endif
220 }
221
222 void
223 jit_finish_debug(void)
224 {
225 #if DISASSEMBLER
226     if (disasm_synthetic)
227         jit_free((jit_pointer_t *)&disasm_synthetic);
228     if (disasm_symbols)
229         jit_free((jit_pointer_t *)&disasm_symbols);
230     if (disasm_bfd)
231         bfd_close (disasm_bfd);
232 #endif
233 }
234
235 void
236 _jit_disassemble(jit_state_t *_jit)
237 {
238 #if DISASSEMBLER
239     if (disasm_bfd) {
240 #  if defined(__arm__)
241         /* FIXME add mapping for prolog switching to arm and possible jump
242          * before first prolog also in arm mode */
243         disasm_info.disassembler_options = jit_cpu.thumb ? "force-thumb" : "";
244 #  endif
245
246         disassemble(_jit->code.ptr, _jit->pc.uc - _jit->code.ptr);
247     }
248 #endif
249 }
250
251 #if DISASSEMBLER
252 /* Based on objdump source */
253 static int
254 disasm_compare_symbols(const void *ap, const void *bp)
255 {
256     const asymbol       *a = *(const asymbol **)ap;
257     const asymbol       *b = *(const asymbol **)bp;
258
259     if (bfd_asymbol_value(a) > bfd_asymbol_value(b))
260         return (1);
261     if (bfd_asymbol_value(a) < bfd_asymbol_value(b))
262         return (-1);
263     return (0);
264 }
265
266 #if __WORDSIZE == 32
267 #  define address_buffer_length         16
268 #  define address_buffer_format         "%llx"
269 #else
270 #  define address_buffer_length         32
271 #  define address_buffer_format         "%lx"
272 #endif
273 static void
274 disasm_print_address(bfd_vma addr, struct disassemble_info *info)
275 {
276     char                *name;
277     char                *file;
278     int                  line;
279     char                 buffer[address_buffer_length];
280
281     sprintf(buffer, address_buffer_format, (long long)addr);
282     (*info->fprintf_func)(info->stream, "0x%s", buffer);
283
284 #  define _jit                          disasm_jit
285 #  undef jit_pointer_p
286 #  define jit_pointer_p(u)                                      \
287         ((u) >= _jit->code.ptr && (u) < _jit->pc.uc)
288     if (jit_pointer_p((jit_uint8_t *)(jit_word_t)addr)) {
289         if (jit_get_note((jit_uint8_t *)(jit_word_t)addr, &name, &file, &line))
290             (*info->fprintf_func)(info->stream, " %s:%s:%d",
291                                   name ? name : "",
292                                   file ? file : "",
293                                   line);
294     }
295 #  undef jit_pointer_p
296 #  undef _jit
297     else if (disasm_num_symbols) {
298         long             low;
299         long             high;
300         long             offset;
301         asymbol         *symbol;
302
303         low = 0;
304         high = disasm_num_symbols;
305         do {
306             offset = (low + high) >> 1;
307             symbol = disasm_symbols[offset];
308             if (bfd_asymbol_value(symbol) > addr)
309                 high = offset - 1;
310             else if (bfd_asymbol_value(symbol) < addr)
311                 low = offset + 1;
312             else
313                 break;
314         } while (low < high);
315
316         if (offset >= 0 && offset < disasm_num_symbols) {
317             if (bfd_asymbol_value(symbol) < addr) {
318                 while (++offset < disasm_num_symbols) {
319                     symbol = disasm_symbols[offset];
320                     if (bfd_asymbol_value(symbol) >= addr)
321                         break;
322                 }
323             }
324             else if (bfd_asymbol_value(symbol) > addr) {
325                 while (offset--) {
326                     if (bfd_asymbol_value(disasm_symbols[offset]) < addr)
327                         break;
328                     symbol = disasm_symbols[offset];
329                 }
330             }
331             if (bfd_asymbol_value(symbol) == addr)
332                 (*info->fprintf_func)(info->stream, " # %s", symbol->name);
333         }
334     }
335 }
336
337 static void
338 _disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length)
339 {
340     int                  bytes;
341     char                *name, *old_name;
342     char                *file, *old_file;
343     int                  line,  old_line;
344 #if __arm__
345     jit_int32_t          offset;
346     jit_bool_t           data_info;
347     jit_int32_t          data_offset;
348 #endif
349     bfd_vma              pc = (jit_uword_t)code;
350     bfd_vma              end = (jit_uword_t)code + length;
351     char                 buffer[address_buffer_length];
352 #if DEVEL_DISASSEMBLER
353     jit_node_t          *node;
354     jit_uword_t          prevw;
355 #endif
356
357 #if __arm__
358     data_info = _jitc && _jitc->data_info.ptr;
359     data_offset = 0;
360 #endif
361     disasm_info.buffer = code;
362     disasm_info.buffer_vma = (jit_uword_t)code;
363     disasm_info.buffer_length = length;
364     old_file = old_name = NULL;
365     old_line = 0;
366     disasm_jit = _jit;
367 #if DEVEL_DISASSEMBLER
368     node = _jitc->head;
369     prevw = pc;
370 #endif
371     while (pc < end) {
372 #if DEVEL_DISASSEMBLER
373         while (node && (jit_uword_t)(prevw + node->offset) < (jit_uword_t)pc) {
374             prevw += node->offset;
375             node = node->next;
376         }
377         while (node && (jit_uword_t)(prevw + node->offset) == (jit_uword_t)pc) {
378             jit_print_node(node);
379             fputc('\n', stdout); 
380             prevw += node->offset;
381             node = node->next;
382         }
383 #endif
384 #if __arm__
385     again:
386         if (data_info) {
387             while (_jitc->data_info.ptr[data_offset].code < pc) {
388                 if (++data_offset >= _jitc->data_info.length) {
389                     data_info = 0;
390                     goto again;
391                 }
392             }
393             if (pc == _jitc->data_info.ptr[data_offset].code) {
394                 offset = _jitc->data_info.ptr[data_offset].length;
395                 for (; offset >= 4; offset -= 4, pc += 4) {
396                     bytes = sprintf(buffer, address_buffer_format, pc);
397                     (*disasm_info.fprintf_func)(disasm_stream,
398                                                 "%*c0x%s\t.data\t0x%08x\n",
399                                                 16 - bytes, ' ', buffer,
400                                                 *(jit_uint32_t *)
401                                                 (jit_uint32_t)pc);
402                 }
403                 /* reset disassemble information instead of attempting
404                  * to hack the arm specific backend data structures to
405                  * tell it to forward the required number of bytes. */
406                 disasm_info.buffer = (jit_pointer_t)(jit_uint32_t)pc;
407                 disasm_info.buffer_vma = (jit_uword_t)pc;
408                 if ((disasm_info.buffer_length = end - pc) <= 0)
409                     break;
410             }
411         }
412 #endif
413         if (jit_get_note((jit_uint8_t *)(jit_word_t)pc, &name, &file, &line) &&
414             (name != old_name || file != old_file || line != old_line)) {
415             (*disasm_info.fprintf_func)(disasm_stream, "# %s:%s:%d\n",
416                                         name ? name : "",
417                                         file ? file : "",
418                                         line);
419             old_name = name;
420             old_file = file;
421             old_line = line;
422         }
423
424         bytes = sprintf(buffer, address_buffer_format, (long long)pc);
425         (*disasm_info.fprintf_func)(disasm_stream, "%*c0x%s\t",
426                                     16 - bytes, ' ', buffer);
427         pc += (*disasm_print)(pc, &disasm_info);
428         putc('\n', disasm_stream);
429     }
430 }
431 #endif