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_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