git subrepo pull --force deps/lightning
[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{
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);
519a9ea1
PC
76 if (!disasm_stream)
77 disasm_stream = stderr;
4a71579b
PC
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
222void
223jit_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
235void
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 */
253static int
254disasm_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
273static void
274disasm_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
337static 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