2 * Copyright (C) 2012-2023 Free Software Foundation, Inc.
4 * This file is part of GNU lightning.
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)
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.
17 * Paulo Cesar Pereira de Andrade
20 #include <lightning.h>
21 #include <lightning/jit_private.h>
31 disasm_compare_symbols(const void *ap, const void *bp);
34 disasm_print_address(bfd_vma addr, struct disassemble_info *info);
36 #define disassemble(u, v) _disassemble(_jit, u, v)
38 _disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length);
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;
57 static int fprintf_styled(void * stream, enum disassembler_style style, const char* fmt, ...)
63 r = vfprintf(disasm_stream, fmt, args);
74 jit_init_debug(const char *progname)
81 disasm_bfd = bfd_openr(progname, NULL);
82 if (disasm_bfd == NULL) {
83 #if defined(__linux__)
84 disasm_bfd = bfd_openr("/proc/self/exe", NULL);
85 if (disasm_bfd == NULL)
89 bfd_check_format(disasm_bfd, bfd_object);
90 bfd_check_format(disasm_bfd, bfd_archive);
92 disasm_stream = stdout;
95 INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf, fprintf_styled);
97 INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf);
99 disasm_info.arch = bfd_get_arch(disasm_bfd);
100 disasm_info.mach = bfd_get_mach(disasm_bfd);
102 # if HAVE_DISASSEMBLE_INIT_FOR_TARGET
103 disassemble_init_for_target(&disasm_info);
106 # if defined(__powerpc64__)
107 disasm_info.disassembler_options = "64";
109 # if defined(__sparc__) || defined(__s390__) || defined(__s390x__)
110 disasm_info.endian = disasm_info.display_endian = BFD_ENDIAN_BIG;
112 # if defined(__s390__) || defined(__s390x__)
113 disasm_info.disassembler_options = "zarch";
115 disasm_info.print_address_func = disasm_print_address;
118 disasm_print = disassembler(disasm_info.arch, __BYTE_ORDER == __BIG_ENDIAN,
119 disasm_info.mach, disasm_bfd);
121 disasm_print = disassembler(disasm_bfd);
123 assert(disasm_print);
125 if (bfd_get_file_flags(disasm_bfd) & HAS_SYMS) {
135 if ((sym_storage = bfd_get_symtab_upper_bound(disasm_bfd)) >= 0) {
137 if (bfd_get_file_flags(disasm_bfd) & DYNAMIC) {
138 dyn_storage = bfd_get_dynamic_symtab_upper_bound(disasm_bfd);
139 # if defined(__alpha__)
144 assert(dyn_storage >= 0);
150 jit_alloc((jit_pointer_t *)&disasm_symbols,
151 (sym_storage + dyn_storage) * sizeof(asymbol *));
152 sym_count = bfd_canonicalize_symtab(disasm_bfd, disasm_symbols);
153 assert(sym_count >= 0);
155 dyn_count = bfd_canonicalize_dynamic_symtab(disasm_bfd,
158 assert(dyn_count >= 0);
162 disasm_num_symbols = sym_count + dyn_count;
164 disasm_num_synthetic = bfd_get_synthetic_symtab(disasm_bfd,
171 if (disasm_num_synthetic > 0) {
172 jit_realloc((jit_pointer_t *)&disasm_symbols,
173 (sym_storage + dyn_storage) * sizeof(asymbol *),
174 (sym_storage + dyn_storage + disasm_num_synthetic) *
176 for (offset = 0; offset < disasm_num_synthetic; offset++)
177 disasm_symbols[disasm_num_symbols++] =
178 disasm_synthetic + offset;
181 /* remove symbols not useful for disassemble */
182 in = out = disasm_symbols;
183 for (offset = 0; offset < disasm_num_symbols; offset++) {
186 symbol->name[0] != '\0' &&
187 !(symbol->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) &&
188 !bfd_is_und_section(symbol->section) &&
189 !bfd_is_com_section(symbol->section))
192 disasm_num_symbols = out - disasm_symbols;
193 qsort(disasm_symbols, disasm_num_symbols,
194 sizeof(asymbol *), disasm_compare_symbols);
201 jit_finish_debug(void)
204 if (disasm_synthetic)
205 jit_free((jit_pointer_t *)&disasm_synthetic);
207 jit_free((jit_pointer_t *)&disasm_symbols);
209 bfd_close (disasm_bfd);
214 _jit_disassemble(jit_state_t *_jit)
218 # if defined(__arm__)
219 /* FIXME add mapping for prolog switching to arm and possible jump
220 * before first prolog also in arm mode */
221 disasm_info.disassembler_options = jit_cpu.thumb ? "force-thumb" : "";
224 disassemble(_jit->code.ptr, _jit->pc.uc - _jit->code.ptr);
230 /* Based on objdump source */
232 disasm_compare_symbols(const void *ap, const void *bp)
234 const asymbol *a = *(const asymbol **)ap;
235 const asymbol *b = *(const asymbol **)bp;
237 if (bfd_asymbol_value(a) > bfd_asymbol_value(b))
239 if (bfd_asymbol_value(a) < bfd_asymbol_value(b))
245 # define address_buffer_length 16
246 # define address_buffer_format "%llx"
248 # define address_buffer_length 32
249 # define address_buffer_format "%lx"
252 disasm_print_address(bfd_vma addr, struct disassemble_info *info)
257 char buffer[address_buffer_length];
259 sprintf(buffer, address_buffer_format, addr);
260 (*info->fprintf_func)(info->stream, "0x%s", buffer);
262 # define _jit disasm_jit
263 # undef jit_pointer_p
264 # define jit_pointer_p(u) \
265 ((u) >= _jit->code.ptr && (u) < _jit->pc.uc)
266 if (jit_pointer_p((jit_uint8_t *)(jit_word_t)addr)) {
267 if (jit_get_note((jit_uint8_t *)(jit_word_t)addr, &name, &file, &line))
268 (*info->fprintf_func)(info->stream, " %s:%s:%d",
273 # undef jit_pointer_p
275 else if (disasm_num_symbols) {
282 high = disasm_num_symbols;
284 offset = (low + high) >> 1;
285 symbol = disasm_symbols[offset];
286 if (bfd_asymbol_value(symbol) > addr)
288 else if (bfd_asymbol_value(symbol) < addr)
292 } while (low < high);
294 if (offset >= 0 && offset < disasm_num_symbols) {
295 if (bfd_asymbol_value(symbol) < addr) {
296 while (++offset < disasm_num_symbols) {
297 symbol = disasm_symbols[offset];
298 if (bfd_asymbol_value(symbol) >= addr)
302 else if (bfd_asymbol_value(symbol) > addr) {
304 if (bfd_asymbol_value(disasm_symbols[offset]) < addr)
306 symbol = disasm_symbols[offset];
309 if (bfd_asymbol_value(symbol) == addr)
310 (*info->fprintf_func)(info->stream, " # %s", symbol->name);
316 _disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length)
319 char *name, *old_name;
320 char *file, *old_file;
322 #if __riscv && __WORDSIZE == 64
327 jit_bool_t data_info;
328 jit_int32_t data_offset;
330 bfd_vma pc = (jit_uword_t)code;
331 bfd_vma end = (jit_uword_t)code + length;
332 char buffer[address_buffer_length];
333 #if DEVEL_DISASSEMBLER
338 #if __riscv && __WORDSIZE == 64
339 end -= _jitc->consts.hash.count * 8;
343 data_info = _jitc && _jitc->data_info.ptr;
346 disasm_info.buffer = code;
347 disasm_info.buffer_vma = (jit_uword_t)code;
348 disasm_info.buffer_length = length;
349 old_file = old_name = NULL;
352 #if DEVEL_DISASSEMBLER
357 #if DEVEL_DISASSEMBLER
358 while (node && (jit_uword_t)(prevw + node->offset) < (jit_uword_t)pc) {
359 prevw += node->offset;
362 while (node && (jit_uword_t)(prevw + node->offset) == (jit_uword_t)pc) {
363 jit_print_node(node);
364 fputc('\n', disasm_stream);
365 prevw += node->offset;
372 while (_jitc->data_info.ptr[data_offset].code < pc) {
373 if (++data_offset >= _jitc->data_info.length) {
378 if (pc == _jitc->data_info.ptr[data_offset].code) {
379 offset = _jitc->data_info.ptr[data_offset].length;
380 for (; offset >= 4; offset -= 4, pc += 4) {
381 bytes = sprintf(buffer, address_buffer_format, pc);
382 (*disasm_info.fprintf_func)(disasm_stream,
383 "%*c0x%s\t.data\t0x%08x\n",
384 16 - bytes, ' ', buffer,
388 /* reset disassemble information instead of attempting
389 * to hack the arm specific backend data structures to
390 * tell it to forward the required number of bytes. */
391 disasm_info.buffer = (jit_pointer_t)(jit_uint32_t)pc;
392 disasm_info.buffer_vma = (jit_uword_t)pc;
393 if ((disasm_info.buffer_length = end - pc) <= 0)
398 if (jit_get_note((jit_uint8_t *)(jit_word_t)pc, &name, &file, &line) &&
399 (name != old_name || file != old_file || line != old_line)) {
400 (*disasm_info.fprintf_func)(disasm_stream, "# %s:%s:%d\n",
409 bytes = sprintf(buffer, address_buffer_format, pc);
410 (*disasm_info.fprintf_func)(disasm_stream, "%*c0x%s\t",
411 16 - bytes, ' ', buffer);
412 pc += (*disasm_print)(pc, &disasm_info);
413 putc('\n', disasm_stream);
415 #if __riscv && __WORDSIZE == 64
416 for (vector = (jit_word_t *)end, offset = 0;
417 offset < _jitc->consts.hash.count; offset++) {
418 bytes = sprintf(buffer, address_buffer_format,
419 (long long)end + offset * sizeof(jit_word_t));
420 (*disasm_info.fprintf_func)(disasm_stream,
421 "%*c0x%s\t.quad\t0x%016lx\t# (%ld)\n",
422 16 - bytes, ' ', buffer,
423 vector[offset], vector[offset]);