Implement --mjit-dump-disasm
This commit is contained in:
parent
fd04e1b4db
commit
3fa4d41460
@ -3855,6 +3855,12 @@ AS_CASE(["${YJIT_SUPPORT}"],
|
|||||||
AC_DEFINE(USE_YJIT, 1)
|
AC_DEFINE(USE_YJIT, 1)
|
||||||
], [AC_DEFINE(USE_YJIT, 0)])
|
], [AC_DEFINE(USE_YJIT, 0)])
|
||||||
|
|
||||||
|
# If YJIT links capstone, libcapstone stops working on the C side.
|
||||||
|
# capstone should be linked for MJIT only when YJIT doesn't.
|
||||||
|
AS_IF([test x"$MJIT_SUPPORT" = "xyes" -a -z "$CARGO_BUILD_ARGS" ], [
|
||||||
|
AC_CHECK_LIB([capstone], [cs_disasm])
|
||||||
|
])
|
||||||
|
|
||||||
dnl These variables end up in ::RbConfig::CONFIG
|
dnl These variables end up in ::RbConfig::CONFIG
|
||||||
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
|
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
|
||||||
AC_SUBST(RUSTC)dnl Rust compiler command
|
AC_SUBST(RUSTC)dnl Rust compiler command
|
||||||
|
@ -6,12 +6,14 @@ class RubyVM::MJIT::Assembler
|
|||||||
end
|
end
|
||||||
|
|
||||||
def compile(compiler)
|
def compile(compiler)
|
||||||
RubyVM::MJIT::C.mjit_mark_writable
|
with_dump_disasm(compiler) do
|
||||||
write_bytes(compiler.write_addr, @bytes)
|
RubyVM::MJIT::C.mjit_mark_writable
|
||||||
RubyVM::MJIT::C.mjit_mark_executable
|
write_bytes(compiler.write_addr, @bytes)
|
||||||
|
RubyVM::MJIT::C.mjit_mark_executable
|
||||||
|
|
||||||
compiler.write_pos += @bytes.size
|
compiler.write_pos += @bytes.size
|
||||||
@bytes.clear
|
@bytes.clear
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mov(_reg, val)
|
def mov(_reg, val)
|
||||||
@ -24,6 +26,17 @@ class RubyVM::MJIT::Assembler
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def with_dump_disasm(compiler)
|
||||||
|
from = compiler.write_addr
|
||||||
|
yield
|
||||||
|
to = compiler.write_addr
|
||||||
|
if RubyVM::MJIT::C.mjit_opts.dump_disasm && from < to
|
||||||
|
RubyVM::MJIT::C.dump_disasm(from, to).each do |address, mnemonic, op_str|
|
||||||
|
puts " 0x#{"%p" % address}: #{mnemonic} #{op_str}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def write_bytes(addr, bytes)
|
def write_bytes(addr, bytes)
|
||||||
writer = ByteWriter.new(addr)
|
writer = ByteWriter.new(addr)
|
||||||
# If you pack bytes containing \x00, Ruby fails to recognize bytes after \x00.
|
# If you pack bytes containing \x00, Ruby fails to recognize bytes after \x00.
|
||||||
|
7
mjit.c
7
mjit.c
@ -304,6 +304,9 @@ mjit_setup_options(const char *s, struct mjit_options *mjit_opt)
|
|||||||
else if (opt_match_noarg(s, l, "pause")) {
|
else if (opt_match_noarg(s, l, "pause")) {
|
||||||
mjit_opt->pause = true;
|
mjit_opt->pause = true;
|
||||||
}
|
}
|
||||||
|
else if (opt_match_noarg(s, l, "dump-disasm")) {
|
||||||
|
mjit_opt->dump_disasm = true;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
rb_raise(rb_eRuntimeError,
|
rb_raise(rb_eRuntimeError,
|
||||||
"invalid MJIT option `%s' (--help will show valid MJIT options)", s);
|
"invalid MJIT option `%s' (--help will show valid MJIT options)", s);
|
||||||
@ -412,6 +415,10 @@ mjit_init(const struct mjit_options *opts)
|
|||||||
// Normalize options
|
// Normalize options
|
||||||
if (mjit_opts.call_threshold == 0)
|
if (mjit_opts.call_threshold == 0)
|
||||||
mjit_opts.call_threshold = DEFAULT_CALL_THRESHOLD;
|
mjit_opts.call_threshold = DEFAULT_CALL_THRESHOLD;
|
||||||
|
#ifndef HAVE_LIBCAPSTONE
|
||||||
|
if (mjit_opts.dump_disasm)
|
||||||
|
verbose(1, "libcapstone has not been linked. Ignoring --mjit-dump-disasm.");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
2
mjit.h
2
mjit.h
@ -63,6 +63,8 @@ struct mjit_options {
|
|||||||
bool pause;
|
bool pause;
|
||||||
// [experimental] Call custom RubyVM::MJIT.compile instead of MJIT.
|
// [experimental] Call custom RubyVM::MJIT.compile instead of MJIT.
|
||||||
bool custom;
|
bool custom;
|
||||||
|
// Enable disasm of all JIT code
|
||||||
|
bool dump_disasm;
|
||||||
};
|
};
|
||||||
|
|
||||||
// State of optimization switches
|
// State of optimization switches
|
||||||
|
43
mjit_c.c
43
mjit_c.c
@ -38,6 +38,49 @@
|
|||||||
#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
|
#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
|
||||||
#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
|
#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
|
||||||
|
|
||||||
|
// macOS: brew install capstone
|
||||||
|
// Ubuntu/Debian: apt-get install libcapstone-dev
|
||||||
|
// Fedora: dnf -y install capstone-devel
|
||||||
|
//#ifdef HAVE_LIBCAPSTONE
|
||||||
|
#if 1
|
||||||
|
#include <capstone/capstone.h>
|
||||||
|
|
||||||
|
#define CODE "\x55\x48\x8b\x05\xb8\x13\x00\x00"
|
||||||
|
|
||||||
|
// Return an array of [address, mnemonic, op_str]
|
||||||
|
static VALUE
|
||||||
|
dump_disasm(rb_execution_context_t *ec, VALUE self, VALUE from, VALUE to)
|
||||||
|
{
|
||||||
|
// Prepare for calling cs_disasm
|
||||||
|
static csh handle;
|
||||||
|
if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {
|
||||||
|
rb_raise(rb_eRuntimeError, "failed to make Capstone handle");
|
||||||
|
}
|
||||||
|
size_t from_addr = NUM2SIZET(from);
|
||||||
|
size_t to_addr = NUM2SIZET(to);
|
||||||
|
|
||||||
|
// Call cs_disasm and convert results to a Ruby array
|
||||||
|
cs_insn *insns;
|
||||||
|
size_t count = cs_disasm(handle, (const uint8_t *)from_addr, to_addr - from_addr, from_addr, 0, &insns);
|
||||||
|
VALUE result = rb_ary_new_capa(count);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
VALUE vals = rb_ary_new_from_args(3, LONG2NUM(insns[i].address), rb_str_new2(insns[i].mnemonic), rb_str_new2(insns[i].op_str));
|
||||||
|
rb_ary_push(result, vals);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free memory used by capstone
|
||||||
|
cs_free(insns, count);
|
||||||
|
cs_close(&handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static VALUE
|
||||||
|
mjit_disasm(VALUE self, VALUE from, VALUE to)
|
||||||
|
{
|
||||||
|
return rb_ary_new();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "mjit_c.rbinc"
|
#include "mjit_c.rbinc"
|
||||||
|
|
||||||
#endif // USE_MJIT
|
#endif // USE_MJIT
|
||||||
|
@ -25,6 +25,12 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @param from [Integer] - From address
|
||||||
|
# @param to [Integer] - To address
|
||||||
|
def dump_disasm(from, to)
|
||||||
|
Primitive.dump_disasm(from, to)
|
||||||
|
end
|
||||||
|
|
||||||
#========================================================================================
|
#========================================================================================
|
||||||
#
|
#
|
||||||
# Old stuff
|
# Old stuff
|
||||||
@ -372,6 +378,7 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
max_cache_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), max_cache_size)")],
|
max_cache_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), max_cache_size)")],
|
||||||
pause: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), pause)")],
|
pause: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), pause)")],
|
||||||
custom: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), custom)")],
|
custom: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), custom)")],
|
||||||
|
dump_disasm: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), dump_disasm)")],
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user