mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-02 13:00:26 +02:00
2012-12-02 Paulo Andrade <pcpa@gnu.org> * tests/Makefile.am, tests/3to2.c, tests/3to2.ok, tests/add.c, tests/add.ok, tests/allocai.c, tests/allocai.ok, tests/bp.c, tests/bp.ok, tests/divi.c, tests/divi.ok, tests/fib.c, tests/fib.ok, tests/fibdelay.c, tests/fibdelay.ok, tests/fibit.c, tests/fibit.ok, tests/funcfp.c, tests/funcfp.ok, tests/incr.c, tests/incr.ok, tests/ldst.c, tests/ldst.ok, tests/ldxi.c, tests/ldxi.ok, tests/modi.c, tests/modi.ok, tests/movi.c, tests/movi.ok, tests/printf.c, tests/printf.ok, tests/printf2.c, tests/printf2.ok, tests/ret.c, tests/ret.ok, tests/rpn.c, tests/rpn.ok, tests/rpnfp.c, tests/rpnfp.ok, tests/sete.c, tests/sete.ok, tests/testfp.c, tests/testfp.ok, tests-run-test: Removed previous test suite, in favor of a newer one in the check subdirectory. * check/3to2.ok, check/3to2.tst, check/add.ok, check/add.tst, check/allocai.ok, check/allocai.tst, check/bp.ok, check/bp.tst, check/divi.ok, check/divi.tst, check/fib.ok, check/fib.tst: New sample input for the new test program, loosely matching several of the previous test cases. * check/Makefile.am: New test suite makefile. * check/check.sh, check/run-test: New wrapper files for the new test suite. * check/lightning.c: New file. The main driver of the new test suite, that compiles to a parser of a very simple assembly like language, generates jit and executes it. * check/all.tst: New file. A generic debug and sample test file with a directive to prevent it from being executed, and useful to read disassembly of all possible instructions, using a fixed set of registers. * include/Makefile.am, include/lightning.h, include/lightning/Makefile.am, include/lightning/jit_arm.h, include/lightning/jit_mips.h, include/lightning/jit_ppc.h, include/lightning/jit_private.h, include/lightning/jit_x86.h, lib/Makefile.am, lib/jit_disasm.c, lib/jit_print.c, lib/jit_x86-cpu.c, lib/jit_x86-sse.c, lib/jit_x86-x87.c, lib/jit_x86.c, lib/lightning.c: New files. These files are written from scratch, only by <pcpa@gnu.org>, and have now copyright assignment to the FSF. This is the core of the new lightning rework. Previously it was integrated in code with a garbage collector and several custom types like vectors and hash tables, so this first code merge with lightning converts that code into a library extracting only the jit bits, and at first only for x86_64 GNU/Linux. * lightning.h, m4/lightning.m4: Removed. These are no longer required in the new lightning code. .gitignore, Makefile.am, configure.ac: Update for the new lightning code.
297 lines
7.6 KiB
C
297 lines
7.6 KiB
C
/*
|
|
* Copyright (C) 2012 Free Software Foundation, Inc.
|
|
*
|
|
* This is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* Authors:
|
|
* Paulo Cesar Pereira de Andrade
|
|
*/
|
|
|
|
#include <lightning.h>
|
|
#include <lightning/jit_private.h>
|
|
#include <dis-asm.h>
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
#if DISASSEMBLER
|
|
static int
|
|
disasm_compare_symbols(const void *ap, const void *bp);
|
|
|
|
static void
|
|
disasm_print_address(bfd_vma addr, struct disassemble_info *info);
|
|
|
|
static void
|
|
disassemble(jit_pointer_t code, jit_int32_t length);
|
|
#endif
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
#if DISASSEMBLER
|
|
static bfd *disasm_bfd;
|
|
static disassemble_info disasm_info;
|
|
static disassembler_ftype disasm_print;
|
|
static asymbol **disasm_symbols;
|
|
static asymbol *disasm_synthetic;
|
|
static long disasm_num_symbols;
|
|
static long disasm_num_synthetic;
|
|
#define disasm_stream stdout
|
|
#endif
|
|
|
|
/*
|
|
* Implementation
|
|
*/
|
|
void
|
|
jit_init_debug(void)
|
|
{
|
|
#if DISASSEMBLER
|
|
bfd_init();
|
|
|
|
/* FIXME */
|
|
disasm_bfd = bfd_openr("/proc/self/exe", NULL);
|
|
|
|
assert(disasm_bfd);
|
|
bfd_check_format(disasm_bfd, bfd_object);
|
|
bfd_check_format(disasm_bfd, bfd_archive);
|
|
disasm_print = disassembler(disasm_bfd);
|
|
assert(disasm_print);
|
|
INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf);
|
|
# if defined(__i386__) || defined(__x86_64__)
|
|
disasm_info.arch = bfd_arch_i386;
|
|
# if defined(__x86_64__)
|
|
disasm_info.mach = bfd_mach_x86_64;
|
|
# else
|
|
disasm_info.mach = bfd_mach_i386_i386;
|
|
# endif
|
|
# endif
|
|
# if defined(__arm__)
|
|
/* FIXME add mapping for prolog switching to arm and possible jump
|
|
* before first prolog also in arm mode */
|
|
if (jit_cpu.thumb)
|
|
disasm_info.disassembler_options = "force-thumb";
|
|
# endif
|
|
disasm_info.print_address_func = disasm_print_address;
|
|
|
|
if (bfd_get_file_flags(disasm_bfd) & HAS_SYMS) {
|
|
asymbol **in;
|
|
asymbol **out;
|
|
asymbol *symbol;
|
|
long offset;
|
|
long sym_count;
|
|
long dyn_count;
|
|
long sym_storage;
|
|
long dyn_storage;
|
|
|
|
sym_storage = bfd_get_symtab_upper_bound(disasm_bfd);
|
|
assert(sym_storage >= 0);
|
|
|
|
if (bfd_get_file_flags(disasm_bfd) & DYNAMIC) {
|
|
dyn_storage = bfd_get_dynamic_symtab_upper_bound(disasm_bfd);
|
|
assert(dyn_storage >= 0);
|
|
}
|
|
else
|
|
dyn_storage = 0;
|
|
|
|
disasm_symbols = malloc(sym_storage + dyn_storage);
|
|
sym_count = bfd_canonicalize_symtab(disasm_bfd, disasm_symbols);
|
|
assert(sym_count >= 0);
|
|
if (dyn_storage) {
|
|
dyn_count = bfd_canonicalize_dynamic_symtab(disasm_bfd,
|
|
disasm_symbols +
|
|
sym_count);
|
|
assert(dyn_count >= 0);
|
|
}
|
|
else
|
|
dyn_count = 0;
|
|
disasm_num_symbols = sym_count + dyn_count;
|
|
|
|
disasm_num_synthetic = bfd_get_synthetic_symtab(disasm_bfd,
|
|
sym_count,
|
|
disasm_symbols,
|
|
dyn_count,
|
|
disasm_symbols +
|
|
sym_count,
|
|
&disasm_synthetic);
|
|
if (disasm_num_synthetic > 0) {
|
|
disasm_symbols = realloc(disasm_symbols,
|
|
sym_storage + dyn_storage +
|
|
disasm_num_synthetic * sizeof(asymbol *));
|
|
for (offset = 0; offset < disasm_num_synthetic; offset++)
|
|
disasm_symbols[disasm_num_symbols++] =
|
|
disasm_synthetic + offset;
|
|
}
|
|
|
|
/* remove symbols not useful for disassemble */
|
|
in = out = disasm_symbols;
|
|
for (offset = 0; offset < disasm_num_symbols; offset++) {
|
|
symbol = *in++;
|
|
if (symbol->name &&
|
|
symbol->name[0] != '\0' &&
|
|
!(symbol->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) &&
|
|
!bfd_is_und_section(symbol->section) &&
|
|
!bfd_is_com_section(symbol->section))
|
|
*out++ = symbol;
|
|
}
|
|
disasm_num_symbols = out - disasm_symbols;
|
|
qsort(disasm_symbols, disasm_num_symbols,
|
|
sizeof(asymbol *), disasm_compare_symbols);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
jit_finish_debug(void)
|
|
{
|
|
#if DISASSEMBLER
|
|
if (disasm_synthetic)
|
|
free(disasm_synthetic);
|
|
if (disasm_symbols)
|
|
free(disasm_symbols);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
_jit_disassemble(jit_state_t *_jit)
|
|
{
|
|
#if DISASSEMBLER
|
|
disassemble(_jit->code.ptr, _jit->pc.uc - _jit->code.ptr);
|
|
#endif
|
|
}
|
|
|
|
#if DISASSEMBLER
|
|
/* Based on objdump source */
|
|
static int
|
|
disasm_compare_symbols(const void *ap, const void *bp)
|
|
{
|
|
const asymbol *a = *(const asymbol **)ap;
|
|
const asymbol *b = *(const asymbol **)bp;
|
|
|
|
if (bfd_asymbol_value(a) > bfd_asymbol_value(b))
|
|
return (1);
|
|
if (bfd_asymbol_value(a) < bfd_asymbol_value(b))
|
|
return (-1);
|
|
return (0);
|
|
}
|
|
|
|
#if __WORDSIZE == 32
|
|
# define address_buffer_length 16
|
|
# define address_buffer_format "%llx"
|
|
#else
|
|
# define address_buffer_length 32
|
|
# define address_buffer_format "%lx"
|
|
#endif
|
|
static void
|
|
disasm_print_address(bfd_vma addr, struct disassemble_info *info)
|
|
{
|
|
char buffer[address_buffer_length];
|
|
|
|
sprintf(buffer, address_buffer_format, (jit_word_t)addr);
|
|
(*info->fprintf_func)(info->stream, "0x%s", buffer);
|
|
|
|
if (disasm_num_symbols) {
|
|
long low;
|
|
long high;
|
|
long offset;
|
|
asymbol *symbol;
|
|
|
|
low = 0;
|
|
high = disasm_num_symbols;
|
|
do {
|
|
offset = (low + high) >> 1;
|
|
symbol = disasm_symbols[offset];
|
|
if (bfd_asymbol_value(symbol) > addr)
|
|
high = offset - 1;
|
|
else if (bfd_asymbol_value(symbol) < addr)
|
|
low = offset + 1;
|
|
else
|
|
break;
|
|
} while (low < high);
|
|
|
|
if (offset >= 0 && offset < disasm_num_symbols) {
|
|
if (bfd_asymbol_value(symbol) < addr) {
|
|
while (++offset < disasm_num_symbols) {
|
|
symbol = disasm_symbols[offset];
|
|
if (bfd_asymbol_value(symbol) >= addr)
|
|
break;
|
|
}
|
|
}
|
|
else if (bfd_asymbol_value(symbol) > addr) {
|
|
while (offset--) {
|
|
if (bfd_asymbol_value(disasm_symbols[offset]) < addr)
|
|
break;
|
|
symbol = disasm_symbols[offset];
|
|
}
|
|
}
|
|
if (bfd_asymbol_value(symbol) == addr)
|
|
(*info->fprintf_func)(info->stream, " # %s", symbol->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
disassemble(jit_pointer_t code, jit_int32_t length)
|
|
{
|
|
int bytes;
|
|
#if __arm__
|
|
jit_data_info_t *data_info;
|
|
jit_int32_t data_offset;
|
|
#endif
|
|
bfd_vma pc = (jit_uword_t)code;
|
|
bfd_vma end = (jit_uword_t)code + length;
|
|
char buffer[address_buffer_length];
|
|
|
|
#if __arm__
|
|
data_info = _jit->data_info;
|
|
data_offset = 0;
|
|
#endif
|
|
disasm_info.buffer = code;
|
|
disasm_info.buffer_vma = (jit_uword_t)code;
|
|
disasm_info.buffer_length = length;
|
|
while (pc < end) {
|
|
#if __arm__
|
|
again:
|
|
if (data_info) {
|
|
while (data_info.ptr[data_offset].code < pc) {
|
|
data_offset += 2;
|
|
if (data_offset >= data_info.length) {
|
|
data_info = NULL;
|
|
goto again;
|
|
}
|
|
}
|
|
if (pc == data_info.ptr[data_offset].code) {
|
|
line = data_info.ptr[data_offset].length;
|
|
for (; line >= 4; line -= 4, pc += 4) {
|
|
bytes = sprintf(buffer, address_buffer_format, pc);
|
|
(*disasm_info.fprintf_func)(disasm_stream,
|
|
"%*c0x%s\t.data\t0x%08x\n",
|
|
16 - bytes, ' ', buffer,
|
|
*(jit_uint32_t *)
|
|
(jit_uint32_t)pc);
|
|
}
|
|
/* reset disassemble information instead of attempting
|
|
* to hack the arm specific backend data structures to
|
|
* tell it to forward the required number of bytes. */
|
|
disasm_info.buffer = (jit_pointer_t)(jit_uint32_t)pc;
|
|
disasm_info.buffer_vma = (jit_uword_t)pc;
|
|
if ((disasm_info.buffer_length = end - pc) <= 0)
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
bytes = sprintf(buffer, address_buffer_format, (jit_word_t)pc);
|
|
(*disasm_info.fprintf_func)(disasm_stream, "%*c0x%s\t",
|
|
16 - bytes, ' ', buffer);
|
|
pc += (*disasm_print)(pc, &disasm_info);
|
|
putc('\n', disasm_stream);
|
|
}
|
|
}
|
|
#endif
|