class Metasm::PPC

Public Class Methods

new() click to toggle source
Calls superclass method
# File metasm/cpu/ppc/main.rb, line 111
def initialize
        super()
        @endianness = :big
        @size = 32
end

Public Instance Methods

addop(name, bin, *argprops) click to toggle source
# File metasm/cpu/ppc/opcodes.rb, line 11
def addop(name, bin, *argprops)
        o = Opcode.new name, bin
        argprops.each { |a|
                o.args << a if @valid_args[a]
                o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a]
                o.props[a] = true if @valid_props[a]
        }
        @opcode_list << o
end
addop_(base, bin, *argprops) click to toggle source

adds op and 'op.' with last bit of bin set

# File metasm/cpu/ppc/opcodes.rb, line 86
def addop_(base, bin, *argprops)
        addop(base, bin, *argprops)
        addop(base+'.', bin|1, *argprops)
end
addop_branch(nbase, bin, *argprops) click to toggle source

generate l/a variations, add :setip/:saveip, include lr/ctr in opname

# File metasm/cpu/ppc/opcodes.rb, line 22
def addop_branch(nbase, bin, *argprops)
        nbase += 'ctr' if argprops.delete :ctr
        nbase += 'lr'  if argprops.delete :lr
        addop(nbase,      bin,   :setip, *argprops)
        addop(nbase+'l',  bin|1, :setip, :saveip, *argprops)
        return if nbase[-2, 2] == 'lr' or nbase[-3, 3] == 'ctr'

        addop(nbase+'a',  bin|2, :setip, *argprops)
        addop(nbase+'la', bin|3, :setip, :saveip, *argprops)
end
addop_branchcond(nbase, bin, *argprops) click to toggle source

generate condition variations, passes to #addop_branch

# File metasm/cpu/ppc/opcodes.rb, line 34
def addop_branchcond(nbase, bin, *argprops)
        # :bi & 0b11100 is the condition register to use, shift&mask == :bfa. Defaults to cr0
        # bo values
        # no cc (10000 != 0)
        addop_branch(nbase,       bin|(0b10100<<21), :ign_bo_zzz, :stopexec, *argprops)
        addop_branch(nbase+'dz',  bin|(0b10010<<21), :ign_bo_at2, :stopexec, *argprops) if not argprops.include? :ctr
        addop_branch(nbase+'dnz', bin|(0b10000<<21), :ign_bo_at2, :stopexec, *argprops) if not argprops.include? :ctr

        # conditionnal
        %w[lt gt eq so].each_with_index { |cd, i|
                ncd = {'lt' => 'gte', 'gt' => 'lte', 'eq' => 'ne', 'so' => 'nso'}[cd]
                addop_branch(nbase+cd, bin|(0b1100<<21)|(i<<16), :ign_bo_at, *argprops)
                addop_branch(nbase+cd, bin|(0b1100<<21)|(i<<16), :ign_bo_at, :bfa, *argprops)
                addop_branch(nbase+ncd, bin|(0b100<<21)|(i<<16), :ign_bo_at, *argprops)
                addop_branch(nbase+ncd, bin|(0b100<<21)|(i<<16), :ign_bo_at, :bfa, *argprops)
                next if argprops.include? :ctr

                addop_branch(nbase+'dz'+cd,  bin|(0b1010<<21)|(i<<16), :ign_bo_z, *argprops)
                addop_branch(nbase+'dz'+cd,  bin|(0b1010<<21)|(i<<16), :ign_bo_z, :bfa, *argprops)
                addop_branch(nbase+'dnz'+cd, bin|(0b1000<<21)|(i<<16), :ign_bo_z, *argprops)
                addop_branch(nbase+'dnz'+cd, bin|(0b1000<<21)|(i<<16), :ign_bo_z, :bfa, *argprops)
                addop_branch(nbase+'dz'+ncd,  bin|(0b010<<21)|(i<<16), :ign_bo_z, *argprops)
                addop_branch(nbase+'dz'+ncd,  bin|(0b010<<21)|(i<<16), :ign_bo_z, :bfa, *argprops)
                addop_branch(nbase+'dnz'+ncd, bin|(0b000<<21)|(i<<16), :ign_bo_z, *argprops)
                addop_branch(nbase+'dnz'+ncd, bin|(0b000<<21)|(i<<16), :ign_bo_z, :bfa, *argprops)
        }
end
addop_cmp(nbase, bin, *argprops) click to toggle source

generate cmp variations (default cr0, w/d)

# File metasm/cpu/ppc/opcodes.rb, line 78
def addop_cmp(nbase, bin, *argprops)
        addop nbase.sub(/(cmpl?)/, '\1w'), bin, *(argprops-[:bf])
        addop nbase.sub(/(cmpl?)/, '\1w'), bin, *argprops
        addop nbase.sub(/(cmpl?)/, '\1d'), bin|(1<<@fields_shift[:l]), *(argprops-[:bf])
        addop nbase.sub(/(cmpl?)/, '\1d'), bin|(1<<@fields_shift[:l]), *argprops
end
addop_o(base, bin, *argprops) click to toggle source

adds op and 'opo'

# File metasm/cpu/ppc/opcodes.rb, line 92
def addop_o(base, bin, *argprops)
        addop(base, bin, *argprops)
        addop(base+'o', bin|0x400, *argprops)
end
addop_trap(nbase, bin, *argprops) click to toggle source
# File metasm/cpu/ppc/opcodes.rb, line 62
def addop_trap(nbase, bin, *argprops)
        addop nbase+'trap', bin|(0b11111<<21), *argprops
        addop nbase+'lt', bin|(0b10000<<21), *argprops
        addop nbase+'le', bin|(0b10100<<21), *argprops
        addop nbase+'eq', bin|(0b00100<<21), *argprops
        addop nbase+'ge', bin|(0b01100<<21), *argprops
        addop nbase+'gt', bin|(0b01000<<21), *argprops
        addop nbase+'ne', bin|(0b11000<<21), *argprops
        addop nbase+'llt', bin|(0b00010<<21), *argprops
        addop nbase+'lle', bin|(0b00110<<21), *argprops
        addop nbase+'lge', bin|(0b00101<<21), *argprops
        addop nbase+'lgt', bin|(0b00001<<21), *argprops
end
backtrace_binding() click to toggle source

hash opname => lambda { |di, *sym_args| binding }

# File metasm/cpu/ppc/decode.rb, line 180
def backtrace_binding
        @backtrace_binding ||= init_backtrace_binding
end
backtrace_binding=(b) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 183
def backtrace_binding=(b) @backtrace_binding = b end
backtrace_is_function_return(expr, di=nil) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 144
def backtrace_is_function_return(expr, di=nil)
        expr.reduce_rec == :lr
end
backtrace_is_stack_address(expr) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 148
def backtrace_is_stack_address(expr)
        Expression[expr].expr_externals.include? :sp
end
backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs) click to toggle source

TODO

# File metasm/cpu/ppc/decode.rb, line 126
def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
        retaddrlist.to_a.map! { |retaddr| dasm.decoded[retaddr] ? dasm.decoded[retaddr].block.list.last.address : retaddr }
        b = f.backtrace_binding

        bt_val = lambda { |r|
                bt = []
                retaddrlist.to_a.each { |retaddr|
                        bt |= dasm.backtrace(Expression[r], retaddr,
                                :include_start => true, :snapshot_addr => faddr, :origin => retaddr)
                }
                b[r] = ((bt.length == 1) ? bt.first : Expression::Unknown)
        }
        wantregs = GPR::Sym if wantregs.empty?
        wantregs.map { |r| r.to_sym }.each(&bt_val)

        #puts "update_func_bind: #{Expression[faddr]} has sp -> #{b[:$sp]}" if not Expression[b[:$sp], :-, :$sp].reduce.kind_of?(::Integer) if $VERBOSE
end
build_bin_lookaside() click to toggle source
# File metasm/cpu/ppc/decode.rb, line 22
def build_bin_lookaside
        lookaside = Array.new(256) { [] }
        opcode_list.each { |op|
                next if not op.bin.kind_of? Integer
                build_opcode_bin_mask op

                b   = op.bin >> 24
                msk = op.bin_mask >> 24

                for i in b..(b | (255^msk))
                        next if i & msk != b & msk
                        lookaside[i] << op
                end
        }
        lookaside
end
build_opcode_bin_mask(op) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 12
def build_opcode_bin_mask(op)
        # bit = 0 if can be mutated by an field value, 1 if fixed by opcode
        return if not op.bin.kind_of? Integer
        op.bin_mask = 0
        op.fields.each { |k, (m, s)|
                op.bin_mask |= m << s
        }
        op.bin_mask = 0xffff_ffff ^ op.bin_mask
end
decode_aliases(i) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 89
def decode_aliases(i)
        case i.opname
        when /^n?or\.?$/
                if i.args[1] == i.args[2]
                        i.args.pop
                        i.opname = {'or' => 'mr', 'or.' => 'mr.', 'nor' => 'not', 'nor.' => 'not.'}[i.opname]
                end
        when /^addi/
                if a = i.args[2].reduce and a.kind_of? Integer and a < 0
                        i.args[2] = Expression[-a]
                        i.opname = i.opname.sub('addi', 'subi')
                end
        end

        case i.opname
        when /^(add|sub|xor|and|or|div|mul|nand)/
                if i.args.length == 3 and i.args[0] == i.args[1]
                        i.args.shift
                end
        end

end
decode_findopcode(edata) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 39
def decode_findopcode(edata)
        return if edata.ptr+4 > edata.length
        di = DecodedInstruction.new(self)
        val = edata.decode_imm(:u32, @endianness)
        edata.ptr -= 4
        di if di.opcode = @bin_lookaside[val >> 24].find { |op|
                (op.bin & op.bin_mask) == (val & op.bin_mask)
        }
end
decode_instr_interpret(di, addr) click to toggle source

converts relative branch offsets to absolute addresses else just add the offset off of the instruction + its length (off may be an Expression) assumes edata.ptr points just after the instruction (as #decode_instr_op left it) do not call twice on the same di !

# File metasm/cpu/ppc/decode.rb, line 116
def decode_instr_interpret(di, addr)
        if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.opcode.name[0] != ?t and di.opcode.name[-1] != ?a
                arg = Expression[addr, :+, di.instruction.args.last].reduce
                di.instruction.args[-1] = Expression[arg]
        end

        di
end
decode_instr_op(edata, di) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 49
def decode_instr_op(edata, di)
        before_ptr = edata.ptr
        op = di.opcode
        di.instruction.opname = op.name
        val = edata.decode_imm(:u32, @endianness)

        field_val = lambda { |f|
                r = (val >> @fields_shift[f]) & @fields_mask[f]
                case f
                when :bd, :d, :ds, :dq, :si, :ui; r = Expression.make_signed(r<<@fields_shift[f], 16)
                when :li; r = Expression.make_signed(r<<@fields_shift[f], 26)
                else r
                end
        }

        op.args.each { |a|
                di.instruction.args << case a
                when :ra, :rb, :rs, :rt; GPR.new field_val[a]
                when :fra, :frb, :frc, :frs, :frt; FPR.new field_val[a]
                when :ra_i16, :ra_i16s, :ra_i16q
                        i = field_val[{:ra_i16 => :d, :ra_i16s => :ds, :ra_i16q => :dq}[a]]
                        Memref.new GPR.new(field_val[:ra]), Expression[i]
                when :bd, :d, :ds, :dq, :si, :ui, :li, :sh, :mb, :me, :mb_, :me_, :u; Expression[field_val[a]]
                when :ba, :bf, :bfa, :bt; CR.new field_val[a]
                when :bb, :bh, :flm, :fxm, :l_, :l__, :lev, :nb, :sh_, :spr, :sr, :tbr, :th, :to
                        puts "PPC.decode: unsupported argument #{a.inspect}" if $VERBOSE    # TODO
                        Expression[field_val[a]]
                else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
                end
        }

        di.bin_length += edata.ptr - before_ptr

        return if edata.ptr > edata.length

        decode_aliases(di.instruction)

        di
end
decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil) click to toggle source
# File metasm/cpu/ppc/decompile.rb, line 97
def decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil)
        scope = func.initializer
        func.type.args.each { |a| scope.symbol[a.name] = a }
        stmts = scope.statements
        func_entry = myblocks.first[0]
        until myblocks.empty?
                b, to = myblocks.shift
                if l = dcmp.dasm.get_label_at(b)
                        stmts << C::Label.new(l)
                end

                # list of assignments [[dest reg, expr assigned]]
                ops = []
                # reg binding (reg => value, values.externals = regs at block start)
                binding = {}
                # Expr => CExpr
                ce  = lambda { |*e| dcmp.decompile_cexpr(Expression[Expression[*e].reduce], scope) }
                # Expr => Expr.bind(binding) => CExpr
                ceb = lambda { |*e| ce[Expression[*e].bind(binding)] }

                # dumps a CExprs that implements an assignment to a reg (uses ops[], patches op => [reg, nil])
                commit = lambda {
                        deps[b].map { |k|
                                [k, ops.rindex(ops.reverse.find { |r, v| r == k })]
                        }.sort_by { |k, i| i.to_i }.each { |k, i|
                                next if not i or not binding[k]
                                e = k
                                final = []
                                ops[0..i].reverse_each { |r, v|
                                        final << r if not v
                                        e = Expression[e].bind(r => v).reduce if not final.include? r
                                }
                                ops[i][1] = nil
                                binding.delete k
                                stmts << ce[k, :'=', e] if k != e
                        }
                }

                # go !
                dcmp.dasm.decoded[b].block.list.each_with_index { |di, didx|
                        a = di.instruction.args
                        if di.opcode.props[:setip] and not di.opcode.props[:stopexec]
                                # conditional jump
                                commit[]
                                n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
                                #cc = ceb[decode_cc_to_expr(di.opcode.name[1..-1])]
                                cc = ceb[:condjmp]
                                stmts << C::If.new(C::CExpression[cc], C::Goto.new(n))
                                to.delete dcmp.dasm.normalize(n)
                                next
                        end

                        case di.opcode.name
                        when 'blr'
                                commit[]
                                stmts << C::Return.new(nil)
                        when 'bl'   # :saveip
                                n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
                                args = []
                                if t = dcmp.c_parser.toplevel.symbol[n] and t.type.args
                                        stackoff = Expression[dcmp.dasm.backtrace(:sp, di.address, :snapshot_addr => func_entry), :-, :sp].bind(:sp => :frameptr).reduce rescue nil
                                        args_todo = t.type.args.dup
                                        args = []
                                        args_todo.each {
                                                if stackoff.kind_of? Integer
                                                        var = Indirection[[:frameptr, :+, stackoff], @size/8]
                                                        stackoff += @size/8
                                                else
                                                        var = 0
                                                end
                                                args << ceb[var]
                                                binding.delete var
                                        }
                                end
                                commit[]
                                #next if not di.block.to_subfuncret

                                if n.kind_of? ::String
                                        if not f = dcmp.c_parser.toplevel.symbol[n]
                                                # internal functions are predeclared, so this one is extern
                                                f = dcmp.c_parser.toplevel.symbol[n] = C::Variable.new
                                                f.name = n
                                                f.type = C::Function.new(C::BaseType.new(:int))
                                                dcmp.c_parser.toplevel.statements << C::Declaration.new(f)
                                        end
                                        commit[]
                                else
                                        # indirect funcall
                                        fptr = ceb[n]
                                        binding.delete n
                                        commit[]
                                        proto = C::Function.new(C::BaseType.new(:int))
                                        f = C::CExpression[[fptr], proto]
                                end
                                binding.delete :eax
                                e = C::CExpression[f, :funcall, args]
                                e = C::CExpression[ce[:eax], :'=', e, f.type.type] if deps[b].include? :eax and f.type.type != C::BaseType.new(:void)
                                stmts << e
                        when 'b'
                                a = di.instruction.args.first
                                if a.kind_of? Expression
                                else
                                        # indirect jmp, convert to return (*fptr)();
                                        n = di.instruction.args.first.symbolic
                                        fptr = ceb[n]
                                        binding.delete n
                                        commit[]
                                        proto = C::Function.new(C::BaseType.new(:void))
                                        ret = C::Return.new(C::CExpression[[[fptr], C::Pointer.new(proto)], :funcall, []])
                                        class << ret ; attr_accessor :from_instr end
                                        ret.from_instr = di
                                        stmts << ret
                                        to = []
                                end
                        else
                                bd = get_fwdemu_binding(di)
                                if di.backtrace_binding[:incomplete_binding]
                                        commit[]
                                        stmts << C::Asm.new(di.instruction.to_s, nil, nil, nil, nil, nil)
                                else
                                        bd.each { |k, v|
                                                if k.kind_of? ::Symbol
                                                        ops << [k, v]
                                                else     # memory
                                                        stmts << ceb[k, :'=', v]
                                                        binding.delete k
                                                end
                                        }
                                        update = {}
                                        bd.each { |k, v|
                                                next if not k.kind_of? ::Symbol
                                                update[k] = Expression[Expression[v].bind(binding).reduce]
                                        }
                                        binding.update update
                                end
                        end
                }
                commit[]

                case to.length
                when 0
                        if not myblocks.empty? and not %w[ret jmp].include? dcmp.dasm.decoded[b].block.list.last.instruction.opname
                                puts "  block #{Expression[b]} has no to and don't end in ret"
                        end
                when 1
                        if (myblocks.empty? ? nextaddr != to[0] : myblocks.first.first != to[0])
                                stmts << C::Goto.new(dcmp.dasm.auto_label_at(to[0], 'unknown_goto'))
                        end
                else
                        puts "  block #{Expression[b]} with multiple to"
                end
        end
end
decompile_func_finddeps(dcmp, blocks, func) click to toggle source

list variable dependency for each block, remove useless writes returns { blockaddr => [list of vars that are needed by a following block] }

# File metasm/cpu/ppc/decompile.rb, line 26
def decompile_func_finddeps(dcmp, blocks, func)
        deps_r = {} ; deps_w = {} ; deps_to = {}
        deps_subfunc = {}     # things read/written by subfuncs

        # find read/writes by each block
        blocks.each { |b, to|
                deps_r[b] = [] ; deps_w[b] = [] ; deps_to[b] = to
                deps_subfunc[b] = []

                blk = dcmp.dasm.decoded[b].block
                blk.list.each { |di|
                        a = di.backtrace_binding.values
                        w = []
                        di.backtrace_binding.keys.each { |k|
                                case k
                                when ::Symbol; w |= [k]
                                else a |= Expression[k].externals  # if dword [eax] <- 42, eax is read
                                end
                        }
                        #a << :eax if di.opcode.name == 'ret'               # standard ABI

                        deps_r[b] |= a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - deps_w[b]
                        deps_w[b] |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
                }
                stackoff = nil
                blk.each_to_normal { |t|
                        t = dcmp.backtrace_target(t, blk.list.last.address)
                        next if not t = dcmp.c_parser.toplevel.symbol[t]
                        t.type = C::Function.new(C::BaseType.new(:int)) if not t.type.kind_of? C::Function  # XXX this may seem a bit extreme, and yes, it is.
                        stackoff ||= Expression[dcmp.dasm.backtrace(:sp, blk.list.last.address, :snapshot_addr => blocks.first[0]).first, :-, :sp].reduce
                }
                if stackoff  # last block instr == subfunction call
                        deps_r[b] |= deps_subfunc[b] - deps_w[b]
                        #deps_w[b] |= [:eax, :ecx, :edx]                    # standard ABI
                end
        }



        # find regs read and never written (must have been set by caller and are part of the func ABI)
        uninitialized = lambda { |b, r, done|
                from = deps_to.keys.find_all { |f| deps_to[f].include? b } - done
                from.empty? or from.find { |f|
                        !deps_w[f].include?(r) and uninitialized[f, r, done + [b]]
                }
        }

        # remove writes from a block if no following block read the value
        dw = {}
        deps_w.each { |b, deps|
                dw[b] = deps.reject { |dep|
                        ret = true
                        done = []
                        todo = deps_to[b].dup
                        while a = todo.pop
                                next if done.include? a
                                done << a
                                if not deps_r[a] or deps_r[a].include? dep
                                        ret = false
                                        break
                                elsif not deps_w[a].include? dep
                                        todo.concat deps_to[a]
                                end
                        end
                        ret
                }
        }

        dw
end
decompile_makestackvars(dasm, funcstart, blocks) { |block| ... } click to toggle source

temporarily setup dasm.address_binding so that backtracking stack-related offsets resolve in :frameptr (relative to func start)

# File metasm/cpu/ppc/decompile.rb, line 13
def decompile_makestackvars(dasm, funcstart, blocks)
        oldfuncbd = dasm.address_binding[funcstart]
        dasm.address_binding[funcstart] = { :sp => :frameptr }        # this would suffice, the rest here is just optimisation

        blocks.each { |block|
                yield block
        }

        dasm.address_binding[funcstart] = oldfuncbd if oldfuncbd
end
disassembler_default_func() click to toggle source
# File metasm/cpu/ppc/decode.rb, line 164
def disassembler_default_func
        df = DecodedFunction.new
        df.backtrace_binding = (0..31).inject({}) { |h, r| r != 1 ? h.update("r#{r}".to_sym => Expression::Unknown) : h }
        df.backtracked_for = [BacktraceTrace.new(Expression[:lr], :default, Expression[:lr], :x)]
        df.btfor_callback = lambda { |dasm, btfor, funcaddr, calladdr|
                if funcaddr != :default
                        btfor
                elsif di = dasm.decoded[calladdr] and di.opcode.props[:saveip]
                        btfor
                else []
                end
        }
        df
end
get_backtrace_binding(di) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 234
def get_backtrace_binding(di)
        a = di.instruction.args.map { |arg|
                case arg
                when Memref; arg.symbolic(di.address)
                when Reg; arg.symbolic
                else arg
                end
        }

        binding = if binding = backtrace_binding[di.instruction.opname]
                binding[di, *a]
        else
                puts "unknown instruction to emu #{di}" if $VERBOSE
                {}
        end

        binding
end
get_xrefs_x(dasm, di) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 253
def get_xrefs_x(dasm, di)
        return [] if not di.opcode.props[:setip]

        arg = case di.instruction.opname
              when 'bctr', 'bctrl'; :ctr
              when 'blr', 'blrl'; :lr
              else di.instruction.args.last
              end

        [Expression[
        case arg
        when Memref; Indirection[[arg.base.to_s.to_sym, :+, arg.offset], @size/8, di.address]
        when Reg; arg.to_s.to_sym
        else arg
        end]]
end
init() click to toggle source
# File metasm/cpu/ppc/opcodes.rb, line 97
def init
        @opcode_list = []
        @fields_shift.update :aa => 1, :ba => 16, :bb => 11, :bd => 2, :bf => 23,
                :bfa => 18, :bh => 11, :bt => 21, :d => 0, :dq => 4,
                :ds => 2, :flm => 17, :fra => 16, :frb => 11, :frc => 6, :frs => 21,
                :frt => 21, :fxm => 12, :l => 21, :l_ => 21, :l__ => 16, :lev => 5,
                :li => 2, :lk => 0, :mb => 5, :mb_ => 6, :me => 5, :me_ => 1,
                :nb => 11, :oe => 10, :ra => 16, :rb => 11, :rc => 0, :rs => 21,
                :rt => 21, :sh => 11, :sh_ => 1, :si => 0, :spr => 11, :sr => 16,
                :tbr => 11, :th => 21, :to => 21, :u => 12, :ui => 0,
                :ign_bo_zzz => 16, :ign_bo_z => 21, :ign_bo_at => 21, :ign_bo_at2 => 16

        @fields_mask.update :aa => 1, :ba => 31, :bb => 31, :bd => 0x3FFF, :bf => 7,
                :bfa => 7, :bh => 3, :bt => 31, :d => 0xFFFF, :dq => 0xFFF,
                :ds => 0x3FFF, :flm => 255, :fra => 31, :frb => 31, :frc => 31, :frs => 31,
                :frt => 31, :fxm => 255, :l => 1, :l_ => 3, :l__ => 1, :lev => 127,
                :li => 0xFFFFFF, :lk => 1, :mb => 63, :mb_ => 31, :me => 63, :me_ => 31,
                :nb => 31, :oe => 1, :ra => 31, :rb => 31, :rc => 1, :rs => 31,
                :rt => 31, :sh => 31, :sh_ => 1, :si => 0xFFFF, :spr => 0x3FF, :sr => 15,
                :tbr => 0x3FF, :th => 15, :to => 31, :u => 15, :ui => 0xFFFF,
                :ign_bo_zzz => 0b101111111, :ign_bo_z => 1, :ign_bo_at => 3, :ign_bo_at2 => 0b100111111

        @valid_args = @fields_mask.dup
        [:ign_bo_zzz, :ign_bo_z, :ign_bo_at, :ign_bo_at2, :aa, :lk, :oe, :rc, :l].each { |k| @valid_args.delete k }

        @fields_shift[:ra_i16]  = @fields_shift[:ra_i16s] = @fields_shift[:ra_i16q] = 0
        @fields_mask[:ra_i16]  = (@fields_mask[:d]  << @fields_shift[:d]) | (@fields_mask[:ra] << @fields_shift[:ra])
        @fields_mask[:ra_i16s] = (@fields_mask[:ds] << @fields_shift[:d]) | (@fields_mask[:ra] << @fields_shift[:ra])
        @fields_mask[:ra_i16q] = (@fields_mask[:dq] << @fields_shift[:d]) | (@fields_mask[:ra] << @fields_shift[:ra])


        addop_branch 'b', 0x48000000, :li, :stopexec
        addop_branchcond 'b', 0x40000000, :bd
        addop_branchcond 'b', 0x4C000020, :lr
        addop_branchcond 'b', 0x4C000420, :ctr

        addop 'sc',     0x44000002, :lev
        addop 'crand',  0x4C000202, :bt, :ba, :bb
        addop 'crxor',  0x4C000182, :bt, :ba, :bb
#      alias crclr bx  ->  crxor bx, bx, bx
        addop 'cror',   0x4C000382, :bt, :ba, :bb
#      alias crmove bx, by  ->  cror bx, by, by
        addop 'crnand', 0x4C0001C2, :bt, :ba, :bb
        addop 'crnor',  0x4C000042, :bt, :ba, :bb
#      alias crnot bx, by  ->  crnor bx, by, by
        addop 'crandc', 0x4C000102, :bt, :ba, :bb
        addop 'creqv',  0x4C000242, :bt, :ba, :bb
#      alias crset bx  ->  creqv bx, bx, bx
        addop 'crorc',  0x4C000342, :bt, :ba, :bb
        addop 'mcrf',   0x4C000000, :bf, :bfa
        addop 'lbz',    0x88000000, :rt, :ra_i16
        addop 'lbzu',   0x8C000000, :rt, :ra_i16
        addop 'lbzx',   0x7C0000AE, :rt, :ra, :rb
        addop 'lbzux',  0x7C0000EE, :rt, :ra, :rb
        addop 'lhz',    0xA0000000, :rt, :ra_i16
        addop 'lhzu',   0xA4000000, :rt, :ra_i16
        addop 'lhzx',   0x7C00022E, :rt, :ra, :rb
        addop 'lhzux',  0x7C00026E, :rt, :ra, :rb
        addop 'lha',    0xA8000000, :rt, :ra_i16
        addop 'lhau',   0xAC000000, :rt, :ra_i16
        addop 'lhax',   0x7C0002AE, :rt, :ra, :rb
        addop 'lhaux',  0x7C0002EE, :rt, :ra, :rb
        addop 'lwz',    0x80000000, :rt, :ra_i16
        addop 'lwzu',   0x84000000, :rt, :ra_i16
        addop 'lwzx',   0x7C00002E, :rt, :ra, :rb
        addop 'lwzux',  0x7C00006E, :rt, :ra, :rb
        addop 'lwa',    0xE8000002, :rt, :ra_i16s
        addop 'lwax',   0x7C0002AA, :rt, :ra, :rb
        addop 'lwaux',  0x7C0002EA, :rt, :ra, :rb
        addop 'ld',     0xE8000000, :rt, :ra_i16s
        addop 'ldu',    0xE8000001, :rt, :ra_i16s
        addop 'ldx',    0x7C00002A, :rt, :ra, :rb
        addop 'ldux',   0x7C00006A, :rt, :ra, :rb
        addop 'stb',    0x98000000, :rs, :ra_i16
        addop 'stbu',   0x9C000000, :rs, :ra_i16
        addop 'stbx',   0x7C0001AE, :rs, :ra, :rb
        addop 'stbux',  0x7C0001EE, :rs, :ra, :rb
        addop 'sth',    0xB0000000, :rs, :ra_i16
        addop 'sthu',   0xB4000000, :rs, :ra_i16
        addop 'sthx',   0x7C00032E, :rs, :ra, :rb
        addop 'sthux',  0x7C00036E, :rs, :ra, :rb
        addop 'stw',    0x90000000, :rs, :ra_i16
        addop 'stwu',   0x94000000, :rs, :ra_i16
        addop 'stwx',   0x7C00012E, :rs, :ra, :rb
        addop 'stwux',  0x7C00016E, :rs, :ra, :rb
        addop 'std',    0xF8000000, :rs, :ra_i16s
        addop 'stdu',   0xF8000001, :rs, :ra_i16s
        addop 'stdx',   0x7C00012A, :rs, :ra, :rb
        addop 'stdux',  0x7C00016A, :rs, :ra, :rb
        addop 'lhbrx',  0x7C00062C, :rt, :ra, :rb
        addop 'lwbrx',  0x7C00042C, :rt, :ra, :rb
        addop 'sthbrx', 0x7C00072C, :rs, :ra, :rb
        addop 'stwbrx', 0x7C00052C, :rs, :ra, :rb
        addop 'lmw',    0xB8000000, :rt, :ra_i16
        addop 'stmw',   0xBC000000, :rs, :ra_i16
        addop 'lswi',   0x7C0004AA, :rt, :ra, :nb
        addop 'lswx',   0x7C00042A, :rt, :ra, :rb
        addop 'stswi',  0x7C0005AA, :rs, :ra, :nb
        addop 'stswx',  0x7C00052A, :rs, :ra, :rb
        addop 'li',     0x38000000, :rt, :si                                  #    alias li rx, value  ->  addi rx, 0, value
        addop 'addi',   0x38000000, :rt, :ra, :si
        addop 'la',     0x38000000, :rt, :ra_i16                              # alias la rx, disp(ry)  ->  addi rx, ry, disp
        addop 'lis',    0x3C000000, :rt, :si                                  #    alias lis rx, value  ->  addis rx, 0, value
        addop 'addis',  0x3C000000, :rt, :ra, :si
        addop_o 'add',  0x7C000214, :rt, :ra, :rb
        addop 'addic',  0x30000000, :rt, :ra, :si
        addop_o 'sub',  0x7C000050, :rt, :rb, :ra                             #        alias sub rx, ry, rz  ->  subf rx, rz, ry
        addop_o 'subf', 0x7C000050, :rt, :ra, :rb
        addop 'addic.', 0x34000000, :rt, :ra, :si
        addop 'subfic', 0x20000000, :rt, :ra, :si
        addop_o 'addc', 0x7C000014, :rt, :ra, :rb
        addop_o 'subc', 0x7C000010, :rt, :rb, :ra                             #        alias subc rx, ry, rz  ->  subfc rx, rz, ry
        addop_o 'subfc',0x7C000010, :rt, :ra, :rb
        addop_o 'adde', 0x7C000114, :rt, :ra, :rb
        addop_o 'addme',0x7C0001D4, :rt, :ra
        addop_o 'subfe',0x7C000110, :rt, :ra, :rb
        addop_o 'subfme',0x7C0001D0,:rt, :ra
        addop_o 'addze',0x7C000194, :rt, :ra
        addop_o 'subfze',0x7C000190,:rt, :ra
        addop_o 'neg',  0x7C0000D0, :rt, :ra
        addop 'mulli',  0x1C000000, :rt, :ra, :si
        addop_o 'mulld',0x7C0001D2, :rt, :ra, :rb
        addop_o 'mullw',0x7C0001D6, :rt, :ra, :rb
        addop_ 'mulhd', 0x7C000092, :rt, :ra, :rb
        addop_ 'mulhdu',0x7C000012, :rt, :ra, :rb
        addop_ 'mulhw', 0x7C000096, :rt, :ra, :rb
        addop_ 'mulhwu',0x7C000016, :rt, :ra, :rb
        addop_o 'divd', 0x7C0003D2, :rt, :ra, :rb
        addop_o 'divw', 0x7C0003D6, :rt, :ra, :rb
        addop_o 'divdu',0x7C000392, :rt, :ra, :rb
        addop_o 'divwu',0x7C000396, :rt, :ra, :rb
        addop_cmp 'cmpi',  0x2C000000, :bf, :ra, :si
        addop_cmp 'cmp',   0x7C000000, :bf, :ra, :rb
        addop_cmp 'cmpli', 0x28000000, :bf, :ra, :ui
        addop_cmp 'cmpl',  0x7C000040, :bf, :ra, :rb
        addop 'andi.',  0x70000000, :ra, :rs, :ui
        addop 'andis.', 0x74000000, :ra, :rs, :ui
        addop 'nop',    0x60000000
        addop 'ori',    0x60000000, :ra, :rs, :ui
        addop 'oris',   0x64000000, :ra, :rs, :ui
        addop 'xori',   0x68000000, :ra, :rs, :ui
        addop 'xoris',  0x6C000000, :ra, :rs, :ui
        addop_ 'and',   0x7C000038, :ra, :rs, :rb
        addop_ 'xor',   0x7C000278, :ra, :rs, :rb
        addop_ 'or',    0x7C000378, :ra, :rs, :rb
#      alias mr rx, ry  ->  or rx, ry, ry
        addop_ 'nand',  0x7C0003B8, :ra, :rs, :rb
        addop_ 'nor',   0x7C0000F8, :ra, :rs, :rb
#      alias not rx, ry  ->  nor rx, ry, ry
        addop_ 'andc',  0x7C000078, :ra, :rs, :rb
        addop_ 'eqv',   0x7C000238, :ra, :rs, :rb
        addop_ 'orc',   0x7C000338, :ra, :rs, :rb
        addop_ 'extsb', 0x7C000774, :ra, :rs
        addop_ 'extsw', 0x7C0007B4, :ra, :rs
        addop_ 'extsh', 0x7C000734, :ra, :rs
        addop_ 'cntlzd',0x7C000074, :ra, :rs
        addop_ 'cntlzw',0x7C000034, :ra, :rs
        addop 'popcntb',0x7C0000F4, :ra, :rs
        addop 'clrldi', 0x78000000, :ra, :rs, :mb                             #        alias clrldi rx, ry, n  ->  rldicl rx, ry, 0, n
        addop_ 'rldicl',0x78000000, :ra, :rs, :sh, :mb, :sh_
#      alias extrdi rx, ry, n, b  ->  rldicl rx, ry, b+n, 64 - n
#      alias srdi rx, ry, n  ->  rldicl rx, ry, 64 - n, n
        addop_ 'rldicr',0x78000004, :ra, :rs, :sh, :me, :sh_
#      alias extldi rx, ry, n, b  ->  rldicr rx, ry, b, n - 1
#      alias sldi rx, ry, n  ->  rldicr rx, ry, n, 63 - n
#      alias clrrdi rx, ry, n  ->  rldicr rx, ry, 0, 63 - n
        addop_ 'rldic', 0x78000008, :ra, :rs, :sh, :mb, :sh_
#      alias clrlsldi rx, ry, b, n  ->  rldic rx, ry, n, b - n
        addop_ 'rlwinm',0x54000000, :ra, :rs, :sh, :mb_, :me_
#      alias extlwi rx, ry, n, b  ->  rlwinm rx, ry, b, 0, n - 1
#      alias srwi rx, ry, n  ->  rlwinm rx, ry, 32 - n, n, 31
#      alias clrrwi rx, ry, n  ->  rlwinm rx, ry, 0, 0, 31 - n
        addop 'rotld',  0x78000010, :ra, :rs, :rb                             #        alias rotld rx, ry, rz  ->  rldcl rx, ry, rz, 0
        addop_ 'rldcl', 0x78000010, :ra, :rs, :rb, :mb
        addop_ 'rldcr', 0x78000012, :ra, :rs, :rb, :me
        addop 'rotlw',  0x5C000000|(31<<@fields_shift[:me_]), :ra, :rs, :rb   # alias rotlw rx, ry, rz  ->  rlwnm rx, ry, rz, 0, 31
        addop_ 'rlwnm', 0x5C000000, :ra, :rs, :rb, :mb_, :me_
        addop_ 'rldimi',0x7800000C, :ra, :rs, :sh, :mb, :sh_
#      alias insrdi rx, ry, n, b  ->  rldimi rx, ry, 64 - (b+n), b
        addop_ 'rlwimi',0x50000000, :ra, :rs, :sh, :mb_, :me_
#      alias inslwi rx, ry, n, b  ->  rlwimi rx, ry, 32-b, b, b+n - 1
        addop_ 'sld',   0x7C000036, :ra, :rs, :rb
        addop_ 'slw',   0x7C000030, :ra, :rs, :rb
        addop_ 'srd',   0x7C000436, :ra, :rs, :rb
        addop_ 'srw',   0x7C000430, :ra, :rs, :rb
        addop_ 'sradi', 0x7C000674, :ra, :rs, :sh, :sh_
        addop_ 'srawi', 0x7C000670, :ra, :rs, :sh
        addop_ 'srad',  0x7C000634, :ra, :rs, :rb
        addop_ 'sraw',  0x7C000630, :ra, :rs, :rb
        #addop 'mtspr', 0x7C0003A6, :spr, :rs
        addop 'mtxer',  0x7C0003A6|(1<<16), :rs
        addop 'mtlr',   0x7C0003A6|(8<<16), :rs
        addop 'mtctr',  0x7C0003A6|(9<<16), :rs
        #addop 'mfspr',  0x7C0002A6, :rt, :spr
        addop 'mfxer',  0x7C0002A6|(1<<16), :rt
        addop 'mflr',   0x7C0002A6|(8<<16), :rt
        addop 'mfctr',  0x7C0002A6|(9<<16), :rt
        addop 'mtcrf',  0x7C000120, :fxm, :rs
#      alias mtcr rx  ->  mtcrf 0xff, rx
        addop 'mfcr',   0x7C000026, :rt
        addop 'lfs',    0xC0000000, :frt, :ra_i16
        addop 'lfsu',   0xC4000000, :frt, :ra_i16
        addop 'lfsx',   0x7C00042E, :frt, :ra, :rb
        addop 'lfsux',  0x7C00046E, :frt, :ra, :rb
        addop 'lfd',    0xC8000000, :frt, :ra_i16
        addop 'lfdu',   0xCC000000, :frt, :ra_i16
        addop 'lfdx',   0x7C0004AE, :frt, :ra, :rb
        addop 'lfdux',  0x7C0004EE, :frt, :ra, :rb
        addop 'stfs',   0xD0000000, :frs, :ra_i16
        addop 'stfsu',  0xD4000000, :frs, :ra_i16
        addop 'stfsx',  0x7C00052E, :frs, :ra, :rb
        addop 'stfsux', 0x7C00056E, :frs, :ra, :rb
        addop 'stfd',   0xD8000000, :frs, :ra_i16
        addop 'stfdu',  0xDC000000, :frs, :ra_i16
        addop 'stfdx',  0x7C0005AE, :frs, :ra, :rb
        addop 'stfdux', 0x7C0005EE, :frs, :ra, :rb
        addop 'stfiwx', 0x7C0007AE, :frs, :ra, :rb
        addop_ 'fmr',   0xFC000090, :frt, :frb
        addop_ 'fabs',  0xFC000210, :frt, :frb
        addop_ 'fneg',  0xFC000050, :frt, :frb
        addop_ 'fnabs', 0xFC000110, :frt, :frb
        addop_ 'fadd',  0xFC00002A, :frt, :fra, :frb
        addop_ 'fadds', 0xEC00002A, :frt, :fra, :frb
        addop_ 'fsub',  0xFC000028, :frt, :fra, :frb
        addop_ 'fsubs', 0xEC000028, :frt, :fra, :frb
        addop_ 'fmul',  0xFC000032, :frt, :fra, :frc
        addop_ 'fmuls', 0xEC000032, :frt, :fra, :frc
        addop_ 'fdiv',  0xFC000024, :frt, :fra, :frb
        addop_ 'fdivs', 0xEC000024, :frt, :fra, :frb
        addop_ 'fmadd', 0xFC00003A, :frt, :fra, :frc, :frb
        addop_ 'fmadds',0xEC00003A, :frt, :fra, :frc, :frb
        addop_ 'fmsub', 0xFC000038, :frt, :fra, :frc, :frb
        addop_ 'fmsubs',0xEC000038, :frt, :fra, :frc, :frb
        addop_ 'fnmadd',0xFC00003E, :frt, :fra, :frc, :frb
        addop_ 'fnmadds',0xEC00003E,:frt, :fra, :frc, :frb
        addop_ 'fnmsub',0xFC00003C, :frt, :fra, :frc, :frb
        addop_ 'fnmsubs',0xEC00003C,:frt, :fra, :frc, :frb
        addop_ 'frsp',  0xFC000018, :frt, :frb
        addop_ 'fctid', 0xFC00065C, :frt, :frb
        addop_ 'fctidz',0xFC00065E, :frt, :frb
        addop_ 'fctiw', 0xFC00001C, :frt, :frb
        addop_ 'fctiwz',0xFC00001E, :frt, :frb
        addop_ 'fcfid', 0xFC00069C, :frt, :frb
        addop 'fcmpu',  0xFC000000, :bf, :fra, :frb
        addop 'fcmpo',  0xFC000040, :bf, :fra, :frb
        addop_ 'mffs',  0xFC00048E, :frt
        addop 'mcrfs',  0xFC000080, :bf, :bfa
        addop_ 'mtfsfi',0xFC00010C, :bf, :u
        addop_ 'mtfsf', 0xFC00058E, :flm, :frb
        addop_ 'mtfsb0',0xFC00008C, :bt
        addop_ 'mtfsb1',0xFC00004C, :bt
        addop 'mtocrf', 0x7C100120, :fxm, :rs
        addop_ 'fsqrt', 0xFC00002C, :frt, :frb
        addop_ 'fsqrts',0xEC00002C, :frt, :frb
        addop_ 'fre',   0xFC000030, :frt, :frb
        addop_ 'fres',  0xEC000030, :frt, :frb
        addop_ 'frsqrte',0xFC000034,:frt, :frb
        addop_ 'frsqrtes',0xEC000034, :frt, :frb
        addop_ 'fsel',  0xFC00002E, :frt, :fra, :frc, :frb
        addop 'mcrxr',  0x7C000400, :bf
        addop 'icbi',   0x7C0007AC, :ra, :rb
        addop 'dcbt',   0x7C00022C, :ra, :rb
        addop 'dcbtst', 0x7C0001EC, :ra, :rb
        addop 'dcbz',   0x7C0007EC, :ra, :rb
        addop 'dcbst',  0x7C00006C, :ra, :rb
        addop 'dcbf',   0x7C0000AC, :ra, :rb
        addop 'isync',  0x4C00012C
        addop 'lwarx',  0x7C000028, :rt, :ra, :rb
        addop 'ldarx',  0x7C0000A8, :rt, :ra, :rb
        addop 'stwcx.', 0x7C00012D, :rs, :ra, :rb
        addop 'stdcx.', 0x7C0001AD, :rs, :ra, :rb
        addop 'sync',   0x7C0004AC, :l_
        addop 'eieio',  0x7C0006AC
        addop 'mftb',   0x7C0002E6, :rt, :tbr
        addop 'eciwx',  0x7C00026C, :rt, :ra, :rb
        addop 'ecowx',  0x7C00036C, :rs, :ra, :rb
        addop 'dcbt',   0x7C00022C, :ra, :rb, :th
        addop 'dcbf',   0x7C0000AC, :ra, :rb
        addop 'dcbf',   0x7C0000AC, :ra, :rb, :l
        addop 'sc',     0x44000002, :lev
        addop 'rfid',   0x4C000024
        addop 'hrfid',  0x4C000224
        addop 'mtmsrd', 0x7C000164, :rs, :l__
        addop 'mfmsr',  0x7C0000A6, :rt
        addop 'slbie',  0x7C000364, :rb
        addop 'slbmte', 0x7C000324, :rs, :rb
        addop 'slbmfev',0x7C0006A6, :rt, :rb
        addop 'slbmfee',0x7C000726, :rt, :rb
        addop 'tlbie',  0x7C000264, :rb, :l
        addop 'tlbiel', 0x7C000224, :rb, :l
        addop 'tlbia',  0x7C0002E4
        addop 'tlbsync',0x7C00046C
        addop 'mtmsr',  0x7C000124, :rs, :l__
        addop 'lq',     0xE0000000, :rt, :ra_i16q
        addop 'stq',    0xF8000002, :rs, :ra_i16s
        addop 'mtsr',   0x7C0001A4, :sr, :rs
        addop 'mtsrin', 0x7C0001E4, :rs, :rb
        addop 'mfsr',   0x7C0004A6, :rt, :sr
        addop 'mfsrin', 0x7C000526, :rt, :rb

        addop_trap 'tw',  0x7C000008, :ra, :rb
        addop_trap 'twi',  0xC0000000, :ra, :si
        addop_trap 'td',  0x7C000088, :ra, :rb
        addop_trap 'tdi', 0x08000000, :ra, :si

        # pseudo-instructions
        addop 'mr', :pseudo, :ra, :rb
        addop 'not', :pseudo, :ra
        addop 'not', :pseudo, :ra, :rb
        @opcode_list.each { |op|
                if op.name =~ /^addi/
                        addop op.name.sub('add', 'sub'), :pseudo, *op.args
                end
                if op.name =~ /^(add|sub|xor|and|or|div|mul|nand)/ and op.args.length == 3
                        addop op.name, :pseudo, *op.args[1..-1]
                end
        }
end
init_backtrace_binding() click to toggle source
# File metasm/cpu/ppc/decode.rb, line 185
def init_backtrace_binding
        @backtrace_binding ||= {}
        opcode_list.map { |ol| ol.name }.uniq.each { |op|
                binding = case op
                when 'mr', 'li', 'la'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'lis'; lambda { |di, a0, a1| { a0 => Expression[a1, :<<, 16] } }
                when 'mtctr'; lambda { |di, a0| { :ctr => Expression[a0] } }
                when 'mfctr'; lambda { |di, a0| { a0 => Expression[:ctr] } }
                when 'mtlr'; lambda { |di, a0| { :lr => Expression[a0] } }
                when 'mflr'; lambda { |di, a0| { a0 => Expression[:lr] } }
                when 'lwzu'; lambda { |di, a0, m|
                        ret = { a0 => Expression[m] }
                        ptr = m.pointer.externals.grep(Symbol).first
                        ret[ptr] = m.pointer if ptr != a0
                        ret
                }
                when 'lwz'; lambda { |di, a0, m| { a0 => Expression[m] } }
                when 'stwu'; lambda { |di, a0, m|
                        { m => Expression[a0], m.pointer.externals.grep(Symbol).first => m.pointer }
                }
                when 'stw'; lambda { |di, a0, m| { m => Expression[a0] } }
                when 'rlwinm'; lambda { |di, a0, a1, sh, mb, me|
                        mb, me = mb.reduce, me.reduce
                        cpmsk = (1<<@size) - 1
                        a1 = Expression[a1, :&, cpmsk]
                        rol = Expression[[a1, :<<, sh], :|, [a1, :>>, [@size, :-, sh]]]
                        if mb == me+1
                                msk = cpmsk
                        elsif mb < me+1
                                msk = (((1 << ((me+1)-mb)) - 1) << (@size-(me+1)))
                        else
                                msk = (((1 << (mb-(me+1))) - 1) << (@size-mb)) ^ cpmsk
                        end
                        { a0 => Expression[Expression[rol, :&, msk].reduce] }
                }

                when 'add', 'addi', 'add.', 'addi.'; lambda { |di, *a| { a[0] => Expression[a[-2], :+, a[-1]] } }
                when 'addis', 'addis.'; lambda { |di, *a| { a[0] => Expression[a[-2], :+, [a[-1], :<<, 16]] } }
                when 'sub', 'subi', 'sub.', 'subi.'; lambda { |di, *a| { a[0] => Expression[a[-2], :-, a[-1]] } }
                when 'subis', 'subis.'; lambda { |di, *a| { a[0] => Expression[a[-2], :-, [a[-1], :<<, 16]] } }
                when /^b.*la?$/; lambda { |di, *a| { :lr => Expression[di.next_addr] } }
                when 'nop', /^cmp/, /^b/; lambda { |di, *a| {} }
                end

                @backtrace_binding[op] ||= binding if binding
        }
        @backtrace_binding
end
init_opcode_list() click to toggle source
# File metasm/cpu/ppc/main.rb, line 117
def init_opcode_list
        init
end
parse_arg_valid?(op, sym, arg) click to toggle source

TODO

# File metasm/cpu/ppc/parse.rb, line 13
def parse_arg_valid?(op, sym, arg)
        case sym
        when :ra, :rb, :rs, :rt; arg.kind_of?(GPR)
        when :fra, :frb, :frc, :frs, :frt; arg.kind_of?(FPR)
        when :ra_i16, :ra_i16s, :ra_i16q; arg.kind_of?(Memref)
        when :bd, :d, :ds, :dq, :si, :ui, :li, :sh, :mb, :me, :mb_, :me_, :u; arg.kind_of?(Expression)
        when :ba, :bf, :bfa, :bt; arg.kind_of?(CR)
        when :ign_bo_zzz, :ign_bo_z, :ign_bo_at, :ign_bo_at2, :aa, :lk, :oe, :rc, :l; # ?
        when :bb, :bh, :flm, :fxm, :l_, :l__, :lev, :nb, :sh_, :spr, :sr, :tbr, :th, :to
                # TODO
        else raise "internal error: mips arg #{sym.inspect}"
        end
end
parse_argument(pgm) click to toggle source
# File metasm/cpu/ppc/parse.rb, line 27
def parse_argument(pgm)
        pgm.skip_space
        return if not tok = pgm.readtok
        if tok.type == :string
                return GPR.new(GPR.s_to_i[tok.raw]) if GPR.s_to_i[tok.raw]
                return SPR.new(SPR.s_to_i[tok.raw]) if SPR.s_to_i[tok.raw]
                return FPR.new(FPR.s_to_i[tok.raw]) if FPR.s_to_i[tok.raw]
                return CR.new(CR.s_to_i[tok.raw]) if CR.s_to_i[tok.raw]
                return MSR.new if tok.raw == 'msr'
        end
        pgm.unreadtok tok
        arg = Expression.parse pgm
        pgm.skip_space
        # check memory indirection: 'off(base reg)'   # XXX scaled index ?
        if arg and pgm.nexttok and pgm.nexttok.type == :punct and pgm.nexttok.raw == '('
                pgm.readtok
                pgm.skip_space_eol
                ntok = pgm.readtok
                raise tok, "Invalid base #{ntok}" unless ntok and ntok.type == :string and GPR.s_to_i[ntok.raw]
                base = GPR.new GPR.s_to_i[ntok.raw]
                pgm.skip_space_eol
                ntok = pgm.readtok
                raise tok, "Invalid memory reference, ')' expected" if not ntok or ntok.type != :punct or ntok.raw != ')'
                arg = Memref.new base, arg
        end
        arg
end
render_instruction(i) click to toggle source
# File metasm/cpu/ppc/main.rb, line 121
def render_instruction(i)
        r = [i.opname]
        if not i.args.empty?
                r << ' '
                i.args.each { |a|
                        r << a << ', '
                }
                r.pop
        end
        r
end
replace_instr_arg_immediate(i, old, new) click to toggle source
# File metasm/cpu/ppc/decode.rb, line 152
def replace_instr_arg_immediate(i, old, new)
        i.args.map! { |a|
                case a
                when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
                when Memref
                        a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset.kind_of? Expression
                        a
                else a
                end
        }
end

Private Instance Methods

encode_instr_op(exe, instr, op) click to toggle source
# File metasm/cpu/ppc/encode.rb, line 13
        def encode_instr_op(exe, instr, op)
                base = op.bin
                set_field = lambda { |f, v|
                        base |= (v & @fields_mask[f]) << @fields_shift[f]
                }

                val, mask, shift = 0, 0, 0

# TODO
                # convert label name for jmp/call/loop to relative offset
                if op.props[:setip] and op.name[0] != ?t and instr.args.last.kind_of? Expression
                        postlabel = exe.new_label('jmp_offset')
                        instr = instr.dup
                        instr.args[-1] = Expression[[instr.args[-1], :-, postlabel], :>>, 2]
                        postdata = EncodedData.new '', :export => {postlabel => 0}
                else
                        postdata = ''
                end

                op.args.zip(instr.args).each { |sym, arg|
                        case sym
                        when :rs, :rt, :rd, :ba, :bf, :bfa, :bt
                                set_field[sym, arg.i]
                        when :ft
                                set_field[sym, arg.i]
                        when :rs_i16
                                set_field[:rs, arg.base.i]
                                val, mask, shift = arg.offset, @fields_mask[:i16], @fields_shift[:i16]
                        when :sa, :i16, :i20
                                val, mask, shift = arg, @fields_mask[sym], @fields_shift[sym]
                        when :i26
                                val, mask, shift = Expression[arg, :>>, 2], @fields_mask[sym], @fields_shift[sym]
                        end
                }

                Expression[base, :+, [[val, :&, mask], :<<, shift]].encode(:u32, @endianness) << postdata
        end