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