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