From 54780cac3f03df28d51cfd4a2c59e0dc5369d391 Mon Sep 17 00:00:00 2001 From: jj Date: Fri, 31 Aug 2012 15:51:22 +0200 Subject: [PATCH] ruby: allow vmethod call with 6 args, use direct fptr --- plugins/ruby/README | 2 +- plugins/ruby/ruby-autogen-defs.rb | 12 ++++++++---- plugins/ruby/ruby.cpp | 32 +++++++++++++++---------------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/plugins/ruby/README b/plugins/ruby/README index c9a84fb37..9246fec88 100644 --- a/plugins/ruby/README +++ b/plugins/ruby/README @@ -177,7 +177,7 @@ Symbol. This works for array indexes too. ex: df.unit_find(:selected).status.labors[:HAUL_FOOD] = true df.map_tile_at(df.cursor).designation.liquid_type = :Water -Virtual method calls are supported for C++ objects, with a maximum of 4 +Virtual method calls are supported for C++ objects, with a maximum of 6 arguments. Arguments / return value are interpreted as Compound/Enums as specified in the vmethod definition in the xmls. diff --git a/plugins/ruby/ruby-autogen-defs.rb b/plugins/ruby/ruby-autogen-defs.rb index 0cee6426f..874746798 100644 --- a/plugins/ruby/ruby-autogen-defs.rb +++ b/plugins/ruby/ruby-autogen-defs.rb @@ -698,8 +698,8 @@ module DFHack return if not addr @_tg._at(addr)._get end - alias next= _next= - alias prev= _prev= + alias next= _next= + alias prev= _prev= include Enumerable def each @@ -795,8 +795,12 @@ module DFHack v if v != 0 end - def self.vmethod_call(obj, voff, a0=0, a1=0, a2=0, a3=0, a4=0) - vmethod_do_call(obj._memaddr, voff, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), vmethod_arg(a3)) + def self.vmethod_call(obj, voff, a0=0, a1=0, a2=0, a3=0, a4=0, a5=0) + this = obj._memaddr + vt = df.get_vtable_ptr(this) + fptr = df.memory_read_int32(vt + voff) & 0xffffffff + vmethod_do_call(this, fptr, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), + vmethod_arg(a3), vmethod_arg(a4), vmethod_arg(a5)) end def self.vmethod_arg(arg) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 482714d2a..d3b269ffe 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -632,7 +632,7 @@ static VALUE rb_dfmemory_patch(VALUE self, VALUE addr, VALUE raw) bool ret; ret = Core::getInstance().p->patchMemory((void*)rb_num2ulong(addr), - rb_string_value_ptr(&raw), strlen); + rb_string_value_ptr(&raw), strlen); return ret ? Qtrue : Qfalse; } @@ -838,8 +838,8 @@ static VALUE rb_dfmemory_bitarray_set(VALUE self, VALUE addr, VALUE idx, VALUE v /* call an arbitrary object virtual method */ #ifdef WIN32 -__declspec(naked) static int raw_vcall(char **that, unsigned long voff, unsigned long a0, - unsigned long a1, unsigned long a2, unsigned long a3) +__declspec(naked) static int raw_vcall(void *that, void *fptr, unsigned long a0, + unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) { // __thiscall requires that the callee cleans up the stack // here we dont know how many arguments it will take, so @@ -848,6 +848,8 @@ __declspec(naked) static int raw_vcall(char **that, unsigned long voff, unsigned push ebp mov ebp, esp + push a5 + push a4 push a3 push a2 push a1 @@ -855,9 +857,7 @@ __declspec(naked) static int raw_vcall(char **that, unsigned long voff, unsigned mov ecx, that - mov eax, [ecx] - add eax, voff - call [eax] + call fptr mov esp, ebp pop ebp @@ -865,25 +865,25 @@ __declspec(naked) static int raw_vcall(char **that, unsigned long voff, unsigned } } #else -static int raw_vcall(char **that, unsigned long voff, unsigned long a0, - unsigned long a1, unsigned long a2, unsigned long a3) +static int raw_vcall(void *that, void *fptr, unsigned long a0, + unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) { - int (*fptr)(char **me, int, int, int, int); - fptr = (decltype(fptr))*(void**)(*that + voff); - return fptr(that, a0, a1, a2, a3); + int (*t_fptr)(void *me, int, int, int, int, int, int); + t_fptr = (decltype(t_fptr))fptr; + return t_fptr(that, a0, a1, a2, a3, a4, a5); } #endif // call an arbitrary vmethod, convert args/ret to native values for raw_vcall -static VALUE rb_dfvcall(VALUE self, VALUE cppobj, VALUE cppvoff, VALUE a0, VALUE a1, VALUE a2, VALUE a3) +static VALUE rb_dfvcall(VALUE self, VALUE cppobj, VALUE fptr, VALUE a0, VALUE a1, VALUE a2, VALUE a3, VALUE a4, VALUE a5) { - return rb_int2inum(raw_vcall((char**)rb_num2ulong(cppobj), rb_num2ulong(cppvoff), + return rb_int2inum(raw_vcall((void*)rb_num2ulong(cppobj), (void*)rb_num2ulong(fptr), rb_num2ulong(a0), rb_num2ulong(a1), - rb_num2ulong(a2), rb_num2ulong(a3))); + rb_num2ulong(a2), rb_num2ulong(a3), + rb_num2ulong(a4), rb_num2ulong(a5))); } - // define module DFHack and its methods static void ruby_bind_dfhack(void) { rb_cDFHack = rb_define_module("DFHack"); @@ -902,7 +902,7 @@ static void ruby_bind_dfhack(void) { rb_define_singleton_method(rb_cDFHack, "print_err", RUBY_METHOD_FUNC(rb_dfprint_err), 1); rb_define_singleton_method(rb_cDFHack, "malloc", RUBY_METHOD_FUNC(rb_dfmalloc), 1); rb_define_singleton_method(rb_cDFHack, "free", RUBY_METHOD_FUNC(rb_dffree), 1); - rb_define_singleton_method(rb_cDFHack, "vmethod_do_call", RUBY_METHOD_FUNC(rb_dfvcall), 6); + rb_define_singleton_method(rb_cDFHack, "vmethod_do_call", RUBY_METHOD_FUNC(rb_dfvcall), 8); rb_define_singleton_method(rb_cDFHack, "memory_read", RUBY_METHOD_FUNC(rb_dfmemory_read), 2); rb_define_singleton_method(rb_cDFHack, "memory_read_int8", RUBY_METHOD_FUNC(rb_dfmemory_read_int8), 1);