# This file is part of Metasm, the Ruby assembly manipulation suite # Copyright (C) 2006-2009 Yoann GUILLOT # # Licence is LGPL, see LICENCE in the top-level directory require 'metasm/main' module Metasm # a Renderable element has a method #render that returns an array of [String or Renderable] module Renderable def to_s render.join end # yields each Expr seen in #render (recursive) def each_expr r = proc { |e| case e when Expression yield e r[e.lexpr] ; r[e.rexpr] when Renderable e.render.each { |re| r[re] } end } r[self] end end class Instruction include Renderable def render @cpu.render_instruction(self) end end class Label include Renderable def render [@name + ':'] end end class CPU # renders an instruction # may use instruction-global properties to render an argument (eg specify pointer size if not implicit) def render_instruction(i) r = [] r << i.opname r << ' ' i.args.each { |a| r << a << ', ' } r.pop r end # ease debugging in irb def inspect "#<#{self.class}:#{'%x' % object_id} ... >" end end class Expression include Renderable attr_accessor :render_info # this is an accessor to @@render_int, the lambda used to render integers > 10 # usage: Expression.render_int = lambda { |e| '0x%x' % e } # or Expression.render_int { |e| '0x%x' % e } # XXX the returned string should be suitable for inclusion in a label name etc def self.render_int(&b) if b @@render_int = b else @@render_int end end def self.render_int=(p) @@render_int = p end @@render_int = nil def render_integer(e) if render_info and @render_info[:char] ee = e v = [] while ee > 0 v << (ee & 0xff) ee >>= 8 end v.reverse! if @render_info[:char] == :big if not v.empty? and v.all? { |c| c < 0x7f } # XXX endianness return "'" + v.pack('C*').inspect.gsub("'") { '\\\'' }[1...-1] + "'" end end if e < 0 neg = true e = -e end if e < 10; e = e.to_s elsif @@render_int e = @@render_int[e] else e = '%xh' % e e = '0' << e unless (?0..?9).include? e[0] end e = '-' << e if neg e end NOSQ1 = NOSQ2 = {:* => [:*], :+ => [:+, :-, :*], :- => [:+, :-, :*]} NOSQ2[:-] = [:*] def render l = @lexpr.kind_of?(Integer) ? render_integer(@lexpr) : @lexpr r = @rexpr.kind_of?(Integer) ? render_integer(@rexpr) : @rexpr l = ['(', l, ')'] if @lexpr.kind_of? Expression and (not oa = NOSQ1[@op] or not oa.include?(@lexpr.op)) r = ['(', r, ')'] if @rexpr.kind_of? Expression and (not oa = NOSQ2[@op] or not oa.include?(@rexpr.op)) op = @op if l or @op != :+ if op == :+ r0 = [r].flatten.first r0 = r0.render.flatten.first while r0.kind_of? Renderable op = nil if (r0.kind_of? Integer and r0 < 0) or (r0.kind_of? String and r0[0] == ?-) or r0 == :- end [l, op, r].compact end end end