7f9fe3b527
git-svn-id: file:///home/svn/framework3/trunk@10600 4d416f70-5f16-0410-b530-b9f4589650da
131 lines
2.8 KiB
Ruby
131 lines
2.8 KiB
Ruby
# 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
|