class Metasm::OpenRisc

github.com/s-macke/jor1k/blob/master/js/worker/or1k/safecpu.js

Public Class Methods

new(family = :latest, endianness = :big, delay_slot = 1) click to toggle source
Calls superclass method
# File metasm/cpu/openrisc/main.rb, line 52
def initialize(family = :latest, endianness = :big, delay_slot = 1)
        super()
        @endianness = endianness
        @size = 32
        @family = family
        @delay_slot = delay_slot
end

Public Instance Methods

abi_funcall() click to toggle source

returns a hash { :retval => r, :changed => [] }

# File metasm/cpu/openrisc/decompile.rb, line 31
def abi_funcall
        { :retval => :r11, :changed => [3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].map { |n| "r#{n}".to_sym }, :args => [:r3, :r4, :r5, :r6, :r7, :r8] }
end
addop(name, bin, *args) click to toggle source
# File metasm/cpu/openrisc/opcodes.rb, line 12
def addop(name, bin, *args)
        o = Opcode.new name, bin
        args.each { |a|
                o.bin_mask = a if a.kind_of?(Integer)
                o.args << a if @valid_args[a]
                o.props.update a if a.kind_of?(::Hash)
        }
        @opcode_list << o
end
backtrace_is_function_return(expr, di=nil) click to toggle source
# File metasm/cpu/openrisc/decode.rb, line 174
def backtrace_is_function_return(expr, di=nil)
        Expression[expr].reduce_rec == :r9
end
backtrace_is_stack_address(expr) click to toggle source
# File metasm/cpu/openrisc/decode.rb, line 178
def backtrace_is_stack_address(expr)
        Expression[expr].expr_externals.include? :r1
end
build_bin_lookaside() click to toggle source
# File metasm/cpu/openrisc/decode.rb, line 12
def build_bin_lookaside
        bl = Array.new(255) { [] }
        opcode_list.each { |op|
                ((op.bin >> 24) .. ((op.bin | op.bin_mask) >> 24)).each { |b|
                        if (b | (op.bin_mask >> 24)) == ((op.bin | op.bin_mask) >> 24)
                                bl[b] << op
                        end
                }
        }
        bl
end
dbg_disable_bp(dbg, bp) click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 94
def dbg_disable_bp(dbg, bp)
end
dbg_enable_bp(dbg, bp) click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 91
def dbg_enable_bp(dbg, bp)
end
dbg_flag_list() click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 22
def dbg_flag_list
        @dbg_flag_list ||= []
end
dbg_need_stepover(dbg, addr, di) click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 97
def dbg_need_stepover(dbg, addr, di)
        if @delay_slot == 0
                di.opcode.props[:saveip]
        else
                ddi = dbg.disassembler.di_at(addr-4)
                ddi and ddi.opcode.props[:saveip]
        end
end
dbg_register_list() click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 18
def dbg_register_list
        @dbg_register_list ||= (1..31).to_a.map { |i| "r#{i}".to_sym } + [:pc, :nextpc, :flag]
end
dbg_register_pc() click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 11
def dbg_register_pc
        @dbg_register_pc ||= :pc
end
dbg_register_size() click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 26
def dbg_register_size
        @dbg_register_size ||= Hash.new(32)
end
dbg_register_sp() click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 14
def dbg_register_sp
        @dbg_register_sp ||= :r1
end
dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx) click to toggle source
Calls superclass method
# File metasm/cpu/openrisc/debug.rb, line 64
def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
        a = di.instruction.args.map { |aa| symbolic(aa) }

        cond = case di.opcode.name
        when 'bf'; dbg_ctx.get_reg_value(:flag) != 0
        when 'bnf'; dbg_ctx.get_reg_value(:flag) == 0
        else return super(di, fbd, pc_reg, dbg_ctx)
        end

        if cond
                n_a = a.last
        else
                if @delay_slot == 0
                        n_a = di.next_addr + 4
                else
                        n_a = Expression[:nextpc, :+, 4]
                end
        end

        if @delay_slot == 0
                fbd[pc_reg] = n_a
        else
                fbd[pc_reg] = Expression[:nextpc]
                fbd[:nextpc] = n_a
        end
end
decode_c_function_prototype(cp, sym, orig=nil) click to toggle source

returns a DecodedFunction from a parsed C function prototype

# File metasm/cpu/openrisc/decode.rb, line 123
def decode_c_function_prototype(cp, sym, orig=nil)
        sym = cp.toplevel.symbol[sym] if sym.kind_of?(::String)
        df = DecodedFunction.new
        orig ||= Expression[sym.name]

        new_bt = lambda { |expr, rlen|
                df.backtracked_for << BacktraceTrace.new(expr, orig, expr, rlen ? :r : :x, rlen)
        }

        # return instr emulation
        if sym.has_attribute 'noreturn' or sym.has_attribute '__noreturn__'
                df.noreturn = true
        else
                new_bt[:r9, nil]
        end

        [3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].each { |r|
                # dirty regs according to ABI
                df.backtrace_binding.update "r#{r}".to_sym => Expression::Unknown
        }

        # scan args for function pointers
        reg_args = [:r3, :r4, :r5, :r6, :r7, :r8]
        sym.type.args.to_a.zip(reg_args).each { |a, ra|
                break if not a or not ra
                if a.type.untypedef.kind_of?(C::Pointer)
                        pt = a.type.untypedef.type.untypedef
                        if pt.kind_of?(C::Function)
                                new_bt[ra, nil]
                                df.backtracked_for.last.detached = true
                        elsif pt.kind_of?(C::Struct)
                                new_bt[ra, cp.typesize[:ptr]]
                        else
                                new_bt[ra, cp.sizeof(nil, pt)]
                        end
                end
        }

        df
end
decode_findopcode(edata) click to toggle source

tries to find the opcode encoded at edata.ptr

# File metasm/cpu/openrisc/decode.rb, line 25
def decode_findopcode(edata)
        return if edata.ptr > edata.data.length-4
        di = DecodedInstruction.new self
        val = edata.decode_imm(:u32, @endianness)
        di.misc = val
        return 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
# File metasm/cpu/openrisc/decode.rb, line 68
def decode_instr_interpret(di, addr)
        if di.opcode.props[:setip]
                case di.opcode.name
                when 'j', 'jal', 'bf', 'bnf'
                        # abs26 is not absolute, duh
                        arg = Expression[addr, :+, [di.instruction.args[-1], :<<, 2]].reduce
                        di.instruction.args[-1] = Expression[arg]
                end
        end

        di
end
decode_instr_op(edata, di) click to toggle source
# File metasm/cpu/openrisc/decode.rb, line 35
def decode_instr_op(edata, di)
        op = di.opcode
        di.instruction.opname = op.name
        di.bin_length = 4
        val = di.misc
        fld = lambda { |f|
                (val >> @fields_off[f]) & @fields_mask[f]
        }
        sign_fld = lambda { |f, sz|
                Expression.make_signed(Expression[fld[f]], sz).reduce
        }
        fld_smoo = lambda {
                Expression[Expression.make_signed((val & 0x7ff) | ((val >> 10) & 0xF800), 16)]
        }

        op.args.each { |a|
                di.instruction.args << case a
                when :rA, :rB, :rD; Reg.new(fld[a])
                when :fA; FpReg.new(fld[:rA])
                when :fB; FpReg.new(fld[:rB])
                when :fD; FpReg.new(fld[:rD])
                when :disp26; Expression[sign_fld[a, 26]]
                when :uimm5, :uimm16; Expression[fld[a]]
                when :simm16; Expression[sign_fld[a, 16]]
                when :rA_simm16; Memref.new(Reg.new(fld[:rA]), Expression[sign_fld[:simm16, 16]], di.opcode.props[:memsz])
                when :rA_smoo; Memref.new(Reg.new(fld[:rA]), fld_smoo[], di.opcode.props[:memsz])
                else raise "unhandled arg #{a}"
                end
        }

        di
end
decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil) click to toggle source
# File metasm/cpu/openrisc/decompile.rb, line 163
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
        blocks_toclean = myblocks.dup
        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
                        }
                }

                # returns an array to use as funcall arguments
                get_func_args = lambda { |di, f|
                        # XXX see remarks in #finddeps
                        args_todo = f.type.args.to_a.dup
                        args = []
                        args_abi = abi_funcall[:args].dup
                        args_todo.each { |a_|
                                if r = a_.has_attribute_var('register')
                                        args << Expression[r.to_sym]
                                        args_abi.delete r.to_sym
                                else
                                        args << Expression[args_abi.shift]
                                end
                        }

                        if f.type.varargs
                                nargs = 1
                                if f.type.args.last.type.pointer?
                                        # check if last arg is a fmtstring
                                        bt = dcmp.dasm.backtrace(args.last, di.block.list.last.address, :snapshot_addr => func_entry, :include_start => true)
                                        if bt.length == 1 and s = dcmp.dasm.get_section_at(bt.first)
                                                fmt = s[0].read(512)
                                                fmt = fmt.unpack('v*').pack('C*') if dcmp.sizeof(f.type.args.last.type.untypedef.type) == 2
                                                if fmt.index(?\0)
                                                        fmt = fmt[0...fmt.index(?\0)]
                                                        nargs = fmt.gsub('%%', '').count('%')   # XXX %.*s etc..
                                                end
                                        end
                                end
                                bt = dcmp.dasm.backtrace(:r1, di.block.list.last.address, :snapshot_addr => func_entry, :include_start => true)
                                stackoff = Expression[bt, :-, :r1].bind(:r1 => :frameptr).reduce rescue nil
                                if stackoff and nargs > 0
                                        nargs.times {
                                                args << Indirection[[:frameptr, :+, stackoff], @size/8]
                                                stackoff += @size/8
                                        }
                                end
                        end

                        args.map { |e| ceb[e] }
                }

                # go !
                di_list = dcmp.dasm.decoded[b].block.list.dup
                if di_list[-2] and di_list[-2].opcode.props[:setip] and @delay_slot > 0
                        di_list[-1], di_list[-2] = di_list[-2], di_list[-1]
                end
                di_list.each { |di|
                        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)
                                if di.opcode.name == /bfeq/
                                        cc = ceb[:flag]
                                else
                                        cc = ceb[:!, :flag]
                                end
                                # XXX switch/indirect/multiple jmp
                                stmts << C::If.new(C::CExpression[cc], C::Goto.new(n))
                                to.delete dcmp.dasm.normalize(n)
                                next
                        end

                        if di.instruction.to_s == 'jr r9'
                                commit[]
                                ret = C::CExpression[ceb[abi_funcall[:retval]]] unless func.type.type.kind_of?(C::BaseType) and func.type.type.name == :void
                                stmts << C::Return.new(ret)
                        elsif di.opcode.name == 'jal' or di.opcode.name == 'jalr'
                                n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
                                args = []
                                if f = dcmp.c_parser.toplevel.symbol[n] and f.type.kind_of?(C::Function) and f.type.args
                                        args = get_func_args[di, f]
                                end
                                commit[]
                                #next if not di.block.to_subfuncret

                                if not n.kind_of?(::String) or (f and not f.type.kind_of?(C::Function))
                                        # indirect funcall
                                        fptr = ceb[n]
                                        binding.delete n
                                        proto = C::Function.new(C::BaseType.new(:int))
                                        proto = f.type if f and f.type.kind_of?(C::Function)
                                        f = C::CExpression[[fptr], C::Pointer.new(proto)]
                                elsif not f
                                        # internal functions are predeclared, so this one is extern
                                        f = C::Variable.new
                                        f.name = n
                                        f.type = C::Function.new(C::BaseType.new(:int))
                                        if dcmp.recurse > 0
                                                dcmp.c_parser.toplevel.symbol[n] = f
                                                dcmp.c_parser.toplevel.statements << C::Declaration.new(f)
                                        end
                                end
                                commit[]
                                binding.delete abi_funcall[:retval]
                                e = C::CExpression[f, :funcall, args]
                                e = C::CExpression[ce[abi_funcall[:retval]], :'=', e, f.type.type] if deps[b].include?(abi_funcall[:retval]) and f.type.type != C::BaseType.new(:void)
                                stmts << e
                        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
                                        update = {}
                                        bd.each { |k, v|
                                                if k.kind_of?(::Symbol) and not deps[b].include?(k)
                                                        ops << [k, v]
                                                        update[k] = Expression[Expression[v].bind(binding).reduce]
                                                else
                                                        stmts << ceb[k, :'=', v]
                                                        stmts.pop if stmts.last.kind_of?(C::Variable)   # [:eflag_s, :=, :unknown].reduce
                                                end
                                        }
                                        binding.update update
                                end
                        end
                }
                commit[]

                case to.length
                when 0
                        if not myblocks.empty? and (dcmp.dasm.decoded[b].block.list[-1-@delay_slot].instruction.to_s != 'jr r9' rescue true)
                                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

        # cleanup di.bt_binding (we set :frameptr etc in those, this may confuse the dasm)
        blocks_toclean.each { |b_, to_|
                dcmp.dasm.decoded[b_].block.list.each { |di|
                        di.backtrace_binding = nil
                }
        }
end
decompile_check_abi(dcmp, entry, func) click to toggle source
# File metasm/cpu/openrisc/decompile.rb, line 344
def decompile_check_abi(dcmp, entry, func)
        a = func.type.args || []
        # TODO check abi_funcall[:args], dont delete r4 __unused if r5 is used
        a.delete_if { |arg| arg.has_attribute_var('register') and arg.has_attribute('unused') }
end
decompile_func_abi_fcallret(r, rdi, blk) click to toggle source

return true if r is the implicit register read made by the subfunction return instruction to symbolize the return value ABI

# File metasm/cpu/openrisc/decompile.rb, line 157
def decompile_func_abi_fcallret(r, rdi, blk)
        rdi ||= blk.list[-1-@delay_slot]
        return if not rdi
        r == abi_funcall[:retval] and rdi.instruction.to_s == 'jr r9'
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/openrisc/decompile.rb, line 37
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
                        }
                        decompile_func_finddeps_di(dcmp, func, di, a, w)

                        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]
                }
                subfunccall = false
                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.
                        subfunccall = true
                        t.type.args.to_a.each { |arg|
                                if reg = arg.has_attribute('register')
                                        deps_subfunc[b] |= [reg.to_sym]
                                end
                        }
                }
                if subfunccall       # last block instr == subfunction call
                        deps_r[b] |= deps_subfunc[b] - deps_w[b]
                        deps_w[b] |= abi_funcall[:changed]
                end
        }

        bt = blocks.transpose
        roots = bt[0] - bt[1].flatten # XXX jmp 1stblock ?

        # find regs read and never written (must have been set by caller and are part of the func ABI)
        uninitialized = lambda { |b, r, done|
                if not deps_r[b]
                elsif deps_r[b].include?(r)
                        blk = dcmp.dasm.decoded[b].block
                        bw = []
                        rdi = blk.list.find { |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
                                }
                                decompile_func_finddeps_di(dcmp, func, di, a, w)

                                next true if (a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - bw).include?(r)
                                bw |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
                                false
                        }
                        if decompile_func_abi_fcallret(r, rdi, blk)
                                func.type.type = C::BaseType.new(:void)
                                false
                        elsif rdi and rdi.backtrace_binding[r]
                                false      # mov al, 42 ; ret  -> don't regarg eax
                        else
                                true
                        end
                elsif deps_w[b].include?(r)
                else
                        done << b
                        (deps_to[b] - done).find { |tb| uninitialized[tb, r, done] }
                end
        }

        regargs = []
        register_symbols.each { |r|
                if roots.find { |root| uninitialized[root, r, []] }
                        regargs << r
                end
        }

        # TODO honor user-defined prototype if available (eg no, really, eax is not read in this function returning al)
        regargs.sort_by { |r| r.to_s }.each { |r|
                a = C::Variable.new(r.to_s, C::BaseType.new(:int, :unsigned))
                a.add_attribute("register(#{r})")
                func.type.args << a
        }

        # 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_func_finddeps_di(dcmp, func, di, a, w) click to toggle source

add di-specific registry written/accessed

# File metasm/cpu/openrisc/decompile.rb, line 21
def decompile_func_finddeps_di(dcmp, func, di, a, w)
        a << abi_funcall[:retval] if di.instruction.to_s == 'jr r9' and (not func.type.kind_of?(C::BaseType) or func.type.type.name != :void) # standard ABI
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/openrisc/decompile.rb, line 13
def decompile_makestackvars(dasm, funcstart, blocks)
        oldfuncbd = dasm.address_binding[funcstart]
        dasm.address_binding[funcstart] = { :r1 => :frameptr }
        blocks.each { |block| yield block }
        dasm.address_binding[funcstart] = oldfuncbd if oldfuncbd
end
delay_slot(di=nil) click to toggle source
# File metasm/cpu/openrisc/main.rb, line 65
def delay_slot(di=nil)
        @delay_slot
end
disassembler_default_func() click to toggle source
# File metasm/cpu/openrisc/decode.rb, line 164
def disassembler_default_func
        df = DecodedFunction.new
        df.backtrace_binding = (1..32).inject({}) { |h, r| h.update "r#{r}".to_sym => Expression["r#{r}".to_sym] }
        [3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].each { |r|
                df.backtrace_binding["r#{r}".to_sym] = Expression::Unknown
        }
        df.backtracked_for = [BacktraceTrace.new(Expression[:r9], :default, Expression[:r9], :x)]
        df
end
get_fwdemu_binding(di, pc_reg=nil, dbg_ctx=nil) click to toggle source
# File metasm/cpu/openrisc/debug.rb, line 30
def get_fwdemu_binding(di, pc_reg=nil, dbg_ctx=nil)
        fbd = di.backtrace_binding ||= get_backtrace_binding(di)
        fbd = fix_fwdemu_binding(di, fbd)
        if pc_reg
                if @delay_slot == 0
                        n_a = Expression[pc_reg, :+, 4]
                else
                        n_a = Expression[:nextpc, :+, 4]
                end
                if di.opcode.props[:setip]
                        xr = get_xrefs_x(nil, di).to_a
                        xr |= [n_a] if not di.opcode.props[:stopexec]
                        if xr.length == 1
                                if @delay_slot == 0
                                        fbd[pc_reg] = xr[0]
                                else
                                        fbd[pc_reg] = Expression[:nextpc]
                                        fbd[:nextpc] = xr[0]
                                end
                        else
                                dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
                        end
                else
                        if @delay_slot == 0
                                fbd[pc_reg] = n_a
                        else
                                fbd[pc_reg] = Expression[:nextpc]
                                fbd[:nextpc] = n_a
                        end
                end
        end
        fbd
end
init_backtrace_binding() click to toggle source

populate the @backtrace_binding hash with default values

# File metasm/cpu/openrisc/decode.rb, line 82
def init_backtrace_binding
        @backtrace_binding ||= {}

        opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
                binding = case op
                when 'movhi'; lambda { |di, a0, a1| { a0 => Expression[a1, :<<, 16] } }
                when 'add'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :+, a2] } }
                when 'sub'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :-, a2] } }
                when 'mul'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :*, a2] } }
                when 'div'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :/, a2] } }
                when 'and'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :&, a2] } }
                when 'or';  lambda { |di, a0, a1, a2| { a0 => Expression[a1, :|, a2] } }
                when 'xor'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :^, a2] } }
                when 'shl'; lambda { |di, a0, a1, a2| { a0 => Expression[[a1, :<<, a2], :&, 0xffff_ffff] } }
                when 'shr'; lambda { |di, a0, a1, a2| { a0 => Expression[[a1, :>>, a2], :&, 0xffff_ffff] } }
                when 'sar'; lambda { |di, a0, a1, a2| { a0 => Expression[[[a1, :>>, a2], :|, [[0xffff_ffff, :<<, a2], :*, [a1, :>>, 31]]], :&, 0xffff_ffff] } }
                when 'ror'; lambda { |di, a0, a1, a2| { a0 => Expression[[[a1, :>>, a2], :|, [a1, :<<, [32, :-, a2]]], :&, 0xffff_ffff] } }
                when 'lwz', 'lbz', 'lhz'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'lbs'; lambda { |di, a0, a1| { a0 => Expression[Expression.make_signed(a1, 8)] } }
                when 'lhs'; lambda { |di, a0, a1| { a0 => Expression[Expression.make_signed(a1, 16)] } }
                when 'sw', 'sh', 'sb';  lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'jal', 'jalr'; lambda { |di, a0| { :r9 => Expression[di.next_addr + delay_slot(di)*4] } }
                when 'jr', 'j', 'bf', 'bnf', 'nop'; lambda { |di, *a| {} }
                when 'sfeq'; lambda { |di, a0, a1| { :flag => Expression[a0, :==, a1] } }
                when 'sfne'; lambda { |di, a0, a1| { :flag => Expression[a0, :!=, a1] } }
                when 'sfgtu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :>, [a1, :&, 0xffff_ffff]] } }
                when 'sfgeu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :>=, [a1, :&, 0xffff_ffff]] } }
                when 'sfltu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :<, [a1, :&, 0xffff_ffff]] } }
                when 'sfleu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :<=, [a1, :&, 0xffff_ffff]] } }
                when 'sfgts'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :>, Expression.make_signed(a1, 32)] } }
                when 'sfges'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :>=, Expression.make_signed(a1, 32)] } }
                when 'sflts'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :<, Expression.make_signed(a1, 32)] } }
                when 'sfles'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :<=, Expression.make_signed(a1, 32)] } }
                end
                @backtrace_binding[op] ||= binding if binding
        }

        @backtrace_binding
end
init_latest()
Alias for: init_or1k
init_opcode_list() click to toggle source
# File metasm/cpu/openrisc/main.rb, line 60
def init_opcode_list
        send("init_#@family")
        @opcode_list
end
init_or1k() click to toggle source
# File metasm/cpu/openrisc/opcodes.rb, line 22
def init_or1k
        @opcode_list = []
        @valid_args = [ :rA, :rB, :rD, :fA, :fB, :fD, :disp26, :uimm16, :simm16, :uimm5, :rA_simm16, :rA_smoo ].inject({}) { |h, a| h.update a => true }
        @fields_off = { :rD => 21, :rA => 16, :rB => 11, :disp26 => 0, :uimm16 => 0, :simm16 => 0, :uimm5 => 0, :smoo => 0 }
        @fields_mask = { :rD => 0x1F, :rA => 0x1F, :rB => 0x1F, :disp26 => 0x3FFFFFF, :simm16 => 0xFFFF, :uimm16 => 0xFFFF, :uimm5 => 0x1F, :smoo => 0x3E007FF }

        addop 'j',     0x0000_0000, 0x03FF_FFFF, :disp26, :setip => true, :stopexec => true
        addop 'jal',   0x0400_0000, 0x03FF_FFFF, :disp26, :setip => true, :stopexec => true, :saveip => true
        addop 'bnf',   0x0C00_0000, 0x03FF_FFFF, :disp26, :setip => true      # branch if not flag
        addop 'bf',    0x1000_0000, 0x03FF_FFFF, :disp26, :setip => true
        addop 'nop',   0x1400_0000, 0x03FF_FFFF
        addop 'movhi', 0x1800_0000, 0x03FE_FFFF, :rD, :uimm16
        addop 'macrc', 0x1801_0000, 0x03FE_FFFF
        addop 'trap',  0x2100_0000, 0x0000_FFFF
        addop 'sys',   0x2000_0000, 0x03FF_FFFF               # args ?
        addop 'rfe',   0x2400_0000, 0x03FF_FFFF
        addop 'jr',    0x4400_0000, 0x03FF_FFFF, :rB, :setip => true, :stopexec => true
        addop 'jalr',  0x4800_0000, 0x03FF_FFFF, :rB, :setip => true, :stopexec => true, :saveip => true
        addop 'lwa',   0x6C00_0000, 0x03FF_FFFF, :rD, :rA_simm16
        addop 'lwz',   0x8400_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 4
        addop 'lbz',   0x8C00_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 1
        addop 'lbs',   0x9000_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 1 # lbz + sign-expand byte
        addop 'lhz',   0x9400_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 2
        addop 'lhs',   0x9800_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 2
        addop 'add',   0x9C00_0000, 0x03FF_FFFF, :rD, :rA, :simm16
        addop 'and',   0xA400_0000, 0x03FF_FFFF, :rD, :rA, :uimm16
        addop 'or',    0xA800_0000, 0x03FF_FFFF, :rD, :rA, :uimm16
        addop 'xor',   0xAC00_0000, 0x03FF_FFFF, :rD, :rA, :simm16
        addop 'mfspr', 0xB400_0000, 0x03FF_FFFF, :rD, :rA, :simm16
        addop 'shl',   0xB800_0000, 0x03FF_FF3F, :rD, :rA, :uimm5
        addop 'ror',   0xB800_0040, 0x03FF_FF3F, :rD, :rA, :uimm5
        addop 'sar',   0xB800_0080, 0x03FF_FF3F, :rD, :rA, :uimm5
        addop 'sfeq',  0xBC00_0000, 0x001F_FFFF, :rA, :simm16
        addop 'sfne',  0xBC20_0000, 0x001F_FFFF, :rA, :simm16
        addop 'sfgtu', 0xBC40_0000, 0x001F_FFFF, :rA, :uimm16
        addop 'sfgeu', 0xBC60_0000, 0x001F_FFFF, :rA, :uimm16
        addop 'sfltu', 0xBC80_0000, 0x001F_FFFF, :rA, :uimm16
        addop 'sfleu', 0xBCA0_0000, 0x001F_FFFF, :rA, :uimm16
        addop 'sfgts', 0xBD40_0000, 0x001F_FFFF, :rA, :simm16
        addop 'sfges', 0xBD60_0000, 0x001F_FFFF, :rA, :simm16
        addop 'sflts', 0xBD80_0000, 0x001F_FFFF, :rA, :simm16
        addop 'sfles', 0xBDA0_0000, 0x001F_FFFF, :rA, :simm16
        addop 'mtspr', 0xC000_0000, 0x03FF_FFFF, :rA_smoo, :rB                # smoo = (ins & 0x7ff) | ((ins >> 10) & 0xf800) ; setspr((rA|smoo), rB)
        addop 'add',   0xC800_0000, 0x03FF_FF00, :fD, :fA, :fB                # FPU
        addop 'sub',   0xC800_0001, 0x03FF_FF00, :fD, :fA, :fB
        addop 'mul',   0xC800_0002, 0x03FF_FF00, :fD, :fA, :fB
        addop 'div',   0xC800_0003, 0x03FF_FF00, :fD, :fA, :fB
        addop 'itof',  0xC800_0004, 0x03FF_FF00, :fD, :rA
        addop 'ftoi',  0xC800_0005, 0x03FF_FF00, :rD, :fA
        addop 'madd',  0xC800_0007, 0x03FF_FF00, :fD, :fA, :fB                # fD += fA*fB
        addop 'sfeq',  0xC800_0008, 0x03FF_FF00, :fA, :fB
        addop 'sfne',  0xC800_0009, 0x03FF_FF00, :fA, :fB
        addop 'sfgt',  0xC800_000A, 0x03FF_FF00, :fA, :fB
        addop 'sfge',  0xC800_000B, 0x03FF_FF00, :fA, :fB
        addop 'sflt',  0xC800_000C, 0x03FF_FF00, :fA, :fB
        addop 'sfle',  0xC800_000D, 0x03FF_FF00, :fA, :fB
        addop 'swa',   0xCC00_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 4   # sw + setf(ra_smoo == current_EA ?)
        addop 'sw',    0xD400_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 4
        addop 'sb',    0xD800_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 1
        addop 'sh',    0xDC00_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 2
        addop 'add',   0xE000_0000, 0x03FF_FC30, :rD, :rA, :rB
        addop 'sub',   0xE000_0002, 0x03FF_FC30, :rD, :rA, :rB
        addop 'and',   0xE000_0003, 0x03FF_FC30, :rD, :rA, :rB
        addop 'or',    0xE000_0004, 0x03FF_FC30, :rD, :rA, :rB
        addop 'xor',   0xE000_0005, 0x03FF_FC30, :rD, :rA, :rB
        addop 'shl',   0xE000_0008, 0x03FF_FC30, :rD, :rA, :rB
        addop 'ff1',   0xE000_000F, 0x03FF_FC30, :rD, :rA, :rB        # find first bit == 1
        addop 'shr',   0xE000_0048, 0x03FF_FC30, :rD, :rA, :rB
        addop 'sar',   0xE000_0088, 0x03FF_FC30, :rD, :rA, :rB
        addop 'fl1',   0xE000_010F, 0x03FF_FC30, :rD, :rA, :rB        # find last bit
        addop 'mul',   0xE000_0306, 0x03FF_FC30, :rD, :rA, :rB        # signed multiply ?
        addop 'div',   0xE000_0309, 0x03FF_FC30, :rD, :rA, :rB
        addop 'divu',  0xE000_030A, 0x03FF_FC30, :rD, :rA, :rB        # rD = rA&0xffffffff / rB&0xffffffff
        addop 'sfeq',  0xE400_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfne',  0xE420_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfgtu', 0xE440_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfgeu', 0xE460_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfltu', 0xE480_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfleu', 0xE4A0_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfgts', 0xE540_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfges', 0xE560_0000, 0x001F_FFFF, :rA, :rB
        addop 'sflts', 0xE580_0000, 0x001F_FFFF, :rA, :rB
        addop 'sfles', 0xE5A0_0000, 0x001F_FFFF, :rA, :rB
end
Also aliased as: init_latest
register_symbols() click to toggle source

list of register symbols

# File metasm/cpu/openrisc/decompile.rb, line 26
def register_symbols
        @dbg_register_list ||= (1..31).to_a.map { |i| "r#{i}".to_sym }
end