class Metasm::RubyHack

Constants

NODETYPE
RUBY_INTERN_NODE

basic C defs for ruby AST - ruby1.8 only !

Public Class Methods

get_method_node_ptr(klass, meth) click to toggle source
# File samples/dynamic_ruby.rb, line 61
def get_method_node_ptr(klass, meth)
        raise "#{klass.inspect} is not a class" if not klass.kind_of? Module
        rb_method_node(rb_obj_to_value(klass), meth.to_sym.to_i)
end
read_method_ast(klass, meth) click to toggle source
# File samples/dynamic_ruby.rb, line 92
def read_method_ast(klass, meth)
        read_node get_method_node_ptr(klass, meth)
end
read_node(ptr, cur=nil) click to toggle source
# File samples/dynamic_ruby.rb, line 101
def read_node(ptr, cur=nil)
        return if ptr == 0 or ptr == 4

        type = NODETYPE[(memory_read_int(ptr) >> 11) & 0xff]
        v1 = memory_read_int(ptr+8)
        v2 = memory_read_int(ptr+12)
        v3 = memory_read_int(ptr+16)

        case type
        when :block, :array, :hash
                cur = nil if cur and cur[0] != type
                cur ||= [type]
                cur << read_node(v1)
                n = read_node(v3, cur)
                raise "block->next = #{n.inspect}" if n and n[0] != type
                cur
        when :newline
                read_node(v3)        # debug/trace usage only
        when :if
                [type, read_node(v1), read_node(v2), read_node(v3)]
        when :cfunc
                v2 = {0xffffffff => -1, 0xfffffffe => -2, 0xffffffffffffffff => -1, 0xfffffffffffffffe => -2}[v2] || v2
                [type, {:fptr => v1, # c func pointer
                        :arity => v2}]
        when :scope
                [type, {:localnr => (v1 != 0 && v1 != 4 ? memory_read_int(v1) : 0),  # nr of local vars (+2 for $_/$~)
                        :cref => read_node(v2)[1..-1]},     # node, starting point for const/@@var resolution
                        read_node(v3)]
        when :cref
                cur = nil if cur and cur[0] != type
                cur ||= [type]
                cur << rb_value_to_obj(v1) if v1 != 0 and v1 != 4
                n = read_node(v3, cur)
                raise "block->next = #{n.inspect}" if n and n[0] != type
                cur
        when :call, :fcall, :vcall
                [type, read_node(v1), v2.id2name, read_node(v3)]
        when :dstr
                ret = [type, [:str, rb_value_to_obj(v1)]]
                if args = read_node(v3)
                        raise "#{ret.inspect} with args != array: #{args.inspect}" if args[0] != :array
                        ret.concat args[1..-1]
                end
                ret
        when :zarray
                [:array]
        when :lasgn
                [type, v3, read_node(v2)]
        when :iasgn, :dasgn, :dasgn_curr, :gasgn, :cvasgn
                [type, v1.id2name, read_node(v2)]
        when :masgn
                # multiple assignment: a, b = 42 / lambda { |x, y| }.call(1, 2)
                # v3 = remainder storage (a, b, *c = ary => v3=c)
                [type, read_node(v1), read_node(v2), read_node(v3)]
        when :attrasgn
                [type, ((v1 == 1) ? :self : read_node(v1)), v2.id2name, read_node(v3)]
        when :lvar
                [type, v3]
        when :ivar, :dvar, :gvar, :cvar, :const, :attrset
                [type, v1.id2name]
        when :str
                # cannot use _id2ref here, probably the parser does not use standard alloced objects
                s = memory_read(memory_read_int(v1+12), memory_read_int(v1+16))
                [type, s]
        when :lit
                [type, rb_value_to_obj(v1)]
        when :args    # specialcased by rb_call0, invalid in rb_eval
                cnt = v3     # nr of required args, copied directly to local_vars
                opt = read_node(v1)  # :block to execute for each missing arg / with N optargs specified, skip N 1st statements
                rest = read_node(v2) # catchall arg in def foo(rq1, rq2, *rest)
                [type, cnt, opt, rest]
        when :and, :or
                [type, read_node(v1), read_node(v2)] # shortcircuit
        when :not
                [type, read_node(v2)]
        when :nil, :true, :false, :self
                [type]
        when :redo, :retry
                [type]
        when :case
                #    [:case, var_test, [:when, cnd, action, [:when, cnd2, action2, else]]]
                # => [:case, var_test, [:when, cnd, action], [:when, cnd2, action], else]
                cs = [type, read_node(v1), read_node(v2)]
                cs << cs[-1].pop while cs[-1][0] == :when and cs[-1][3]
                cs
        when :when
                # [:when, [:array, [test]], then, else]
                [type, read_node(v1), read_node(v2), read_node(v3)]
        when :iter
                # save a block for the following funcall
                args = read_node(v1) # assignments with nil, not realized, just to store the arg list (multi args -> :masgn)
                body = read_node(v2) # the body statements (multi -> :block)
                subj = read_node(v3) # the stuff which is passed the block, probably a :call
                [type, args, body, subj]
        when :while, :until
                [type, read_node(v1), read_node(v2), v3]
        when :return, :break, :next, :defined
                [type, read_node(v1)]
        when :to_ary
                [type, read_node(v1)]
        when :colon2
                [type, read_node(v1), v2.id2name]
        when :colon3  # ::Stuff
                [type, v2.id2name]
        when :method
                [type, v1, read_node(v2), v3]
        when :alias
                [type, v1, v2, v3]   # ?
        when :evstr
                [type, read_node(v2)]
        when :dot2, :dot3
                [type, read_node(v1), read_node(v2)]
        when :splat
                [type, read_node(v1)]
        when :argscat
                [type, read_node(v1), read_node(v2), v3]
        when :block_pass
                # [args, block, receiver]: foo(bar, &baz) => [:bpass, [:array, bar], [:lvar, baz], [:call, 'foo', bar]]  (args in v1&v3!)
                [type, read_node(v1), read_node(v2), read_node(v3)]
        when :block_arg
                [type, v1.id2name, v2, v3]
        when :ensure
                [type, read_node(v1), v2, read_node(v3)]
        else
                puts "unhandled #{type.inspect}"
                [type, v1, v2, v3]
        end
end
read_singleton_method_ast(klass, meth) click to toggle source
# File samples/dynamic_ruby.rb, line 96
def read_singleton_method_ast(klass, meth)
        klass = (class << klass ; self ; end)
        read_method_ast(klass, meth)
end
set_class_method_raw(klass, meth, code, nparams) click to toggle source
# File samples/dynamic_ruby.rb, line 56
def set_class_method_raw(klass, meth, code, nparams)
        memory_perm(str_ptr(code), code.length, 'rwx')
        rb_define_method(rb_obj_to_value(klass), meth, code, nparams)
end
set_method_binary(klass, methodname, raw, nargs=nil) click to toggle source

sets up rawopcodes as the method implementation for class klass rawopcodes must implement the expected ABI or things will break horribly this method is VERY UNSAFE, and breaks everything put in place by the ruby interpreter use with EXTREME CAUTION nargs arglist -2 self, arg_ary -1 argc, VALUE*argv, self >=0 self, arg0, arg1..

# File samples/dynamic_ruby.rb, line 74
def set_method_binary(klass, methodname, raw, nargs=nil)
        nargs ||= klass.instance_method(methodname).arity
        if raw.kind_of? EncodedData
                baseaddr = str_ptr(raw.data)
                bd = raw.binding(baseaddr)
                raw.reloc_externals.uniq.each { |ext| bd[ext] = sym_addr(0, ext) or raise "unknown symbol #{ext}" }
                raw.fixup(bd)
                raw = raw.data
        end
        (@@prevent_gc ||= {})[[klass, methodname]] = raw
        set_class_method_raw(klass, methodname.to_s, raw, nargs)
end
set_singleton_method_binary(obj, *a) click to toggle source

same as load_binary_method but with an object and not a class

# File samples/dynamic_ruby.rb, line 88
def set_singleton_method_binary(obj, *a)
        set_method_binary((class << obj ; self ; end), *a)
end