class Metasm::MIPS
This file is part of Metasm
, the Ruby assembly manipulation suite Copyright (C
) 2006-2009 Yoann GUILLOT
Licence is LGPL, see LICENCE in the top-level directory
Public Class Methods
new(endianness = :big, family = :latest)
click to toggle source
Calls superclass method
Metasm::CPU::new
# File metasm/cpu/mips/main.rb, line 59 def initialize(endianness = :big, family = :latest) super() @endianness = endianness @size = 32 @family = family end
Public Instance Methods
addop(name, bin, *args)
click to toggle source
# File metasm/cpu/mips/opcodes.rb, line 14 def addop(name, bin, *args) o = Opcode.new name, bin args.each { |a| o.args << a if @fields_mask[a] o.props[a] = true if @valid_props[a] } @opcode_list << o end
backtrace_found_result(dasm, di, expr, type, len)
click to toggle source
make the target of the call know the value of $t9 (specified by the ABI) XXX hackish
# File metasm/cpu/mips/decode.rb, line 245 def backtrace_found_result(dasm, di, expr, type, len) if di.opcode.name == 'jalr' and di.instruction.args == [:$t9] expr = dasm.normalize(expr) (dasm.address_binding[expr] ||= {})[:$t9] ||= expr end end
backtrace_is_function_return(expr, di=nil)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 223 def backtrace_is_function_return(expr, di=nil) expr.reduce_rec == :$ra end
backtrace_is_stack_address(expr)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 227 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
# File metasm/cpu/mips/decode.rb, line 203 def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs) retaddrlist.map! { |retaddr| dasm.decoded[retaddr] ? dasm.decoded[retaddr].block.list.last.address : retaddr } if retaddrlist b = f.backtrace_binding bt_val = lambda { |r| next if not retaddrlist bt = [] b[r] = Expression::Unknown # break recursive dep retaddrlist.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 = Reg.i_to_s.values 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/mips/decode.rb, line 21 def build_bin_lookaside lookaside = Array.new(256) { [] } opcode_list.each { |op| 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/mips/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 op.bin_mask = 0 op.args.each { |f| op.bin_mask |= @fields_mask[f] << @fields_shift[f] } op.bin_mask = 0xffffffff ^ op.bin_mask end
dbg_end_stepout(dbg, addr, di)
click to toggle source
# File metasm/cpu/mips/debug.rb, line 38 def dbg_end_stepout(dbg, addr, di) di and di.opcode.name == 'foobar' # TODO end
dbg_flag_list()
click to toggle source
# File metasm/cpu/mips/debug.rb, line 26 def dbg_flag_list @dbg_flag_list ||= [] end
dbg_need_stepover(dbg, addr, di)
click to toggle source
# File metasm/cpu/mips/debug.rb, line 34 def dbg_need_stepover(dbg, addr, di) di and di.opcode.props[:saveip] end
dbg_register_flags()
click to toggle source
# File metasm/cpu/mips/debug.rb, line 14 def dbg_register_flags @dbg_register_flags ||= :flags end
dbg_register_list()
click to toggle source
# File metasm/cpu/mips/debug.rb, line 18 def dbg_register_list @dbg_register_list ||= %w[z0 at v0 v1 a0 a1 a2 a3 t0 t1 t2 t3 t4 t5 t6 t7 s0 s1 s2 s3 s4 s5 s6 s7 t8 t9 k0 k1 gp sp fp ra sr mullo mulhi badva cause pc].map { |r| r.to_sym } end
dbg_register_pc()
click to toggle source
# File metasm/cpu/mips/debug.rb, line 11 def dbg_register_pc @dbg_register_pc ||= :pc end
dbg_register_size()
click to toggle source
# File metasm/cpu/mips/debug.rb, line 30 def dbg_register_size @dbg_register_size ||= Hash.new(@size) end
decode_findopcode(edata)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 37 def decode_findopcode(edata) di = DecodedInstruction.new(self) val = edata.decode_imm(:u32, @endianness) edata.ptr -= 4 if val.kind_of?(Expression) # relocations hval = Expression[val, :&, 0xff000000].reduce if hval.kind_of?(Expression) # reloc_i26 if hval.kind_of?(Expression) and pat = hval.match(Expression[['a', :&, 0x300_0000], :|, 'b'], 'a', 'b') hval = pat['b'] end end di if di.opcode = @bin_lookaside[hval >> 24].find { |op| (op.bin & op.bin_mask) == Expression[val, :&, op.bin_mask].reduce } else di if di.opcode = @bin_lookaside[val >> 24].find { |op| (op.bin & op.bin_mask) == (val & op.bin_mask) } end 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/mips/decode.rb, line 109 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 delta = Expression[di.instruction.args.last, :<<, 2].reduce if di.opcode.args.include? :i26 # absolute jump in the 0x3ff_ffff region surrounding next_pc if delta.kind_of? Expression and delta.op == :& and delta.rexpr == 0xfff_fffc # relocated arg: assume the linker mapped so that instr&target are in the same region arg = Expression[delta.lexpr].reduce else arg = Expression[[[addr, :+, di.bin_length], :&, 0xf000_0000], :+, delta].reduce end else arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce end di.instruction.args[-1] = Expression[arg] end di end
decode_instr_op(edata, di)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 60 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| if val.kind_of?(Expression) r = Expression[[val, :>>, @fields_shift[f]], :&, @fields_mask[f]].reduce else r = (val >> @fields_shift[f]) & @fields_mask[f] end next r if r.kind_of?(Expression) case f when :msbd; r += 1 when :i16; r = Expression.make_signed(r, 16) when :i20; r = Expression.make_signed(r, 20) else r end } op.args.each { |a| di.instruction.args << case a when :rs, :rt, :rd; Reg.new field_val[a] when :sa, :i16, :i20, :i26, :it, :msbd, :sel, :idb; Expression[field_val[a]] when :rs_i16 len = 32 len = 64 if op.props[:m64] len = 16 if op.props[:mi16] or op.props[:mu16] len = 8 if op.props[:mi8 ] or op.props[:mu8] Memref.new Reg.new(field_val[:rs]), Expression[field_val[:i16]], len when :ft; FpReg.new field_val[a] when :idm1; Expression['unsupported'] else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}" end } di.bin_length += edata.ptr - before_ptr return false if edata.ptr > edata.length di end
delay_slot(di=nil)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 252 def delay_slot(di=nil) # branch.*likely has no delay slot # bltzal/bgezal are 'link', not 'likely', hence the check for -2 (di and di.opcode.props[:setip] and (di.opcode.name[-1] != ?l or di.opcode.name[-2] == ?a)) ? 1 : 0 end
disassembler_default_func()
click to toggle source
# File metasm/cpu/mips/decode.rb, line 258 def disassembler_default_func df = DecodedFunction.new df.backtrace_binding = %w[v0 v1 a0 a1 a2 a3 t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 at k0 k1].inject({}) { |h, r| h.update "$#{r}".to_sym => Expression::Unknown } df.backtrace_binding.update %w[gp sp fp ra s0 s1 s2 s3 s4 s5 s6 s7].inject({}) { |h, r| h.update "$#{r}".to_sym => "$#{r}".to_sym } df.backtracked_for = [BacktraceTrace.new(Expression[:$ra], :default, Expression[:$ra], :x)] df.btfor_callback = lambda { |dasm, btfor, funcaddr, calladdr| if funcaddr != :default btfor elsif di = dasm.decoded[calladdr] and di.opcode.props[:saveip] and di.instruction.to_s != 'jr $ra' btfor else [] end } df end
get_backtrace_binding(di)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 172 def get_backtrace_binding(di) a = di.instruction.args.map { |arg| case arg when Memref; arg.symbolic(di) when Reg; arg.symbolic else arg end } if binding = backtrace_binding[di.instruction.opname] bd = binding[di, *a] bd.delete 0 # allow add $zero, 42 => nop bd else puts "unhandled instruction to backtrace: #{di}" if $VERBOSE {:incomplete_binding => Expression[1]} end end
get_xrefs_x(dasm, di)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 191 def get_xrefs_x(dasm, di) return [] if not di.opcode.props[:setip] arg = di.instruction.args.last [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_backtrace_binding()
click to toggle source
# File metasm/cpu/mips/decode.rb, line 129 def init_backtrace_binding @backtrace_binding ||= {} opcode_list.map { |ol| ol.name }.uniq.each { |op| binding = case op when 'break' when 'bltzal', 'bgezal'; lambda { |di, *a| # XXX $ra is set only if branch is taken... { :$ra => Expression[Expression[di.address, :+, 2*di.bin_length].reduce] } } when 'nop', 'j', 'jr', /^b/; lambda { |di, *a| {} } when 'lui'; lambda { |di, a0, a1| { a0 => Expression[[a1, :&, 0xffff], :<<, 16] } } when 'add', 'addu', 'addi', 'addiu'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :+, a2] } } # XXX addiu $sp, -40h should be addiu $sp, 0xffc0 from the books, but.. when 'sub', 'subu'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :-, a2] } } when 'slt', 'slti'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :<, a2] } } when 'and', 'andi'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :&, a2] } } when 'or', 'ori'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :|, a2] } } when 'nor'; lambda { |di, a0, a1, a2| { a0 => Expression[:~, [a1, :|, a2]] } } when 'not'; lambda { |di, a0, a1| { a0 => Expression[:~, a1] } } when 'xor'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :^, a2] } } when 'sll', 'sllv'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :>>, a2] } } when 'srl', 'srlv', 'sra', 'srav'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :<<, a2] } } # XXX sign-extend when 'lw', 'lwl', 'lwr'; lambda { |di, a0, a1| { a0 => Expression[a1] } } when 'sw', 'swl', 'swr'; lambda { |di, a0, a1| { a1 => Expression[a0] } } when 'lh', 'lhu'; lambda { |di, a0, a1| { a0 => Expression[a1] } } # XXX sign-extend when 'sh'; lambda { |di, a0, a1| { a1 => Expression[a0] } } when 'lb', 'lbu'; lambda { |di, a0, a1| { a0 => Expression[a1] } } when 'sb'; lambda { |di, a0, a1| { a1 => Expression[a0] } } when /^slti?u?/; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :<, a2] } } # XXX signedness when 'mfhi'; lambda { |di, a0| { a0 => Expression[:hi] } } when 'mflo'; lambda { |di, a0| { a0 => Expression[:lo] } } when 'mult', 'multu'; lambda { |di, a0, a1| { :hi => Expression[[a0, :*, a1], :>>, 32], :lo => Expression[[a0, :*, a1], :&, 0xffff_ffff] } } when 'div', 'divu'; lambda { |di, a0, a1| { :hi => Expression[a0, :%, a1], :lo => Expression[a0, :/, a1] } } when 'jal', 'jalr'; lambda { |di, a0| { :$ra => Expression[Expression[di.address, :+, 2*di.bin_length].reduce] } } when 'li', 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } } when 'syscall'; lambda { |di, *a| { :$v0 => Expression::Unknown } } when /^b/; lambda { |di, *a| {} } end @backtrace_binding[op] ||= binding if binding } @backtrace_binding end
init_mips32()
click to toggle source
# File metasm/cpu/mips/opcodes.rb, line 46 def init_mips32 @opcode_list = [] @fields_mask.update :rs => 0x1f, :rt => 0x1f, :rd => 0x1f, :sa => 0x1f, :i16 => 0xffff, :i26 => 0x3ffffff, :rs_i16 => 0x3e0ffff, :it => 0x1f, :ft => 0x1f, :idm1 => 0x1f, :idb => 0x1f, :sel => 7, :i20 => 0xfffff @fields_shift.update :rs => 21, :rt => 16, :rd => 11, :sa => 6, :i16 => 0, :i26 => 0, :rs_i16 => 0, :it => 16, :ft => 16, :idm1 => 11, :idb => 11, :sel => 0, :i20 => 6 @valid_props.update :mi8 => true, :mu8 => true, :mi16 => true, :mu16 => true init_mips32_obsolete init_mips32_reserved addop 'j', 0b000010 << 26, :i26, :setip, :stopexec # sets the program counter to (i26 << 2) | ((pc+4) & 0xfc000000) ie i26*4 in the 256M-aligned section containing the instruction in the delay slot addop 'jal', 0b000011 << 26, :i26, :setip, :stopexec, :saveip # same thing, saves return addr in r31 addop 'mov', 0b001000 << 26, :rt, :rs # rt <- rs+0 addop 'addi', 0b001000 << 26, :rt, :rs, :i16 # add rt <- rs+i addop 'li', 0b001001 << 26, :rt, :i16 # addiu rt <- zero+i addop 'addiu',0b001001 << 26, :rt, :rs, :i16 # add unsigned addop 'slti', 0b001010 << 26, :rt, :rs, :i16 # set on less than addop 'sltiu',0b001011 << 26, :rt, :rs, :i16 # set on less than unsigned addop 'andi', 0b001100 << 26, :rt, :rs, :i16 # and addop 'ori', 0b001101 << 26, :rt, :rs, :i16 # or addop 'xori', 0b001110 << 26, :rt, :rs, :i16 # xor addop 'lui', 0b001111 << 26, :rt, :i16 # load upper # addop 'li', (0b001111 << 26) << 32 | (0b001101 << 26), :rt_64, :i32 # lui + ori addop 'b', 0b000100 << 26, :i16, :setip, :stopexec # bz $zero addop 'bz', 0b000100 << 26, :rs, :i16, :setip # == 0 (beq $0) addop 'bz', 0b000100 << 26, :rt, :i16, :setip # == 0 addop 'bnz', 0b000101 << 26, :rs, :i16, :setip # != 0 addop 'bnz', 0b000101 << 26, :rt, :i16, :setip # != 0 addop 'beq', 0b000100 << 26, :rt, :rs, :i16, :setip # == addop 'bne', 0b000101 << 26, :rt, :rs, :i16, :setip # != addop 'blez', 0b000110 << 26, :rs, :i16, :setip # <= 0 addop 'bgtz', 0b000111 << 26, :rs, :i16, :setip # > 0 addop 'lb', 0b100000 << 26, :rt, :rs_i16, :mi8 # load byte rs <- [rt+i] addop 'lh', 0b100001 << 26, :rt, :rs_i16, :mi16 # load halfword addop 'lwl', 0b100010 << 26, :rt, :rs_i16 # load word left addop 'lw', 0b100011 << 26, :rt, :rs_i16 # load word addop 'lbu', 0b100100 << 26, :rt, :rs_i16, :mu8 # load byte unsigned addop 'lhu', 0b100101 << 26, :rt, :rs_i16, :mu16 # load halfword unsigned addop 'lwr', 0b100110 << 26, :rt, :rs_i16 # load word right addop 'sb', 0b101000 << 26, :rt, :rs_i16, :mi8 # store byte addop 'sh', 0b101001 << 26, :rt, :rs_i16, :mi16 # store halfword addop 'swl', 0b101010 << 26, :rt, :rs_i16 # store word left addop 'sw', 0b101011 << 26, :rt, :rs_i16 # store word addop 'swr', 0b101110 << 26, :rt, :rs_i16 # store word right addop 'll', 0b110000 << 26, :rt, :rs_i16 # load linked word (read for atomic r/modify/w, sc does the w) addop 'sc', 0b111000 << 26, :rt, :rs_i16 # store conditional word addop 'lwc1', 0b110001 << 26, :ft, :rs_i16 # load word in fpreg low addop 'swc1', 0b111001 << 26, :ft, :rs_i16 # store low fpreg word addop 'lwc2', 0b110010 << 26, :rt, :rs_i16 # load word to copro2 register low addop 'swc2', 0b111010 << 26, :rt, :rs_i16 # store low coproc2 register addop 'ldc1', 0b110101 << 26, :ft, :rs_i16 # load dword in fpreg low addop 'sdc1', 0b111101 << 26, :ft, :rs_i16 # store fpreg addop 'ldc2', 0b110110 << 26, :rt, :rs_i16 # load dword to copro2 register addop 'sdc2', 0b111110 << 26, :rt, :rs_i16 # store coproc2 register addop 'pref', 0b110011 << 26, :it, :rs_i16 # prefetch (it = %w[load store r2 r3 load_streamed store_streamed load_retained store_retained # r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 writeback_invalidate # id26 id27 id28 id29 prepare_for_store id31] addop 'cache',0b101111 << 26, :it, :rs_i16 # do things with the proc cache # special addop 'nop', 0 addop 'ssnop',1<<6 addop 'ehb', 3<<6 addop 'sll', 0b000000, :rd, :rt, :sa addop 'movf', 0b000001, :rd, :rs, :cc addop 'movt', 0b000001 | (1<<16), :rd, :rs, :cc addop 'srl', 0b000010, :rd, :rt, :sa addop 'sra', 0b000011, :rd, :rt, :sa addop 'sllv', 0b000100, :rd, :rt, :rs addop 'srlv', 0b000110, :rd, :rt, :rs addop 'srav', 0b000111, :rd, :rt, :rs addop 'jr', 0b001000, :rs, :setip, :stopexec # hint field ? addop 'jr.hb',0b001000 | (1<<10), :rs, :setip, :stopexec addop 'jalr', 0b001001 | (31<<11), :rs, :setip, :stopexec, :saveip # rd = r31 implicit addop 'jalr', 0b001001, :rd, :rs, :setip, :stopexec, :saveip addop 'jalr.hb', 0b001001 | (1<<10) | (31<<11), :rs, :setip, :stopexec, :saveip addop 'jalr.hb', 0b001001 | (1<<10), :rd, :rs, :setip, :stopexec, :saveip addop 'movz', 0b001010, :rd, :rs, :rt # rt == 0 ? rd <- rs addop 'movn', 0b001011, :rd, :rs, :rt addop 'syscall', 0b001100, :i20 addop 'break',0b001101, :i20, :stopexec addop 'sync', 0b001111 # type 0 implicit addop 'sync', 0b001111, :sa addop 'mfhi', 0b010000, :rd # copies special reg HI to reg addop 'mthi', 0b010001, :rs # copies reg to special reg HI addop 'mflo', 0b010010, :rd # copies special reg LO to reg addop 'mtlo', 0b010011, :rs # copies reg to special reg LO addop 'mult', 0b011000, :rs, :rt # multiplies the registers and store the result in HI:LO addop 'multu',0b011001, :rs, :rt addop 'div', 0b011010, :rs, :rt addop 'divu', 0b011011, :rs, :rt addop 'add', 0b100000, :rd, :rs, :rt addop 'addu', 0b100001, :rd, :rs, :rt addop 'sub', 0b100010, :rd, :rs, :rt addop 'subu', 0b100011, :rd, :rs, :rt addop 'and', 0b100100, :rd, :rs, :rt addop 'or', 0b100101, :rd, :rs, :rt addop 'xor', 0b100110, :rd, :rs, :rt addop 'not', 0b100111, :rd, :rt # nor $0 addop 'not', 0b100111, :rd, :rs addop 'nor', 0b100111, :rd, :rs, :rt addop 'slt', 0b101010, :rd, :rs, :rt # rs<rt ? rd<-1 : rd<-0 addop 'sltu', 0b101011, :rd, :rs, :rt addop 'tge', 0b110000, :rs, :rt # rs >= rt ? trap addop 'tgeu', 0b110001, :rs, :rt addop 'tlt', 0b110010, :rs, :rt addop 'tltu', 0b110011, :rs, :rt addop 'teq', 0b110100, :rs, :rt addop 'tne', 0b110110, :rs, :rt # regimm addop 'bltz', (1<<26) | (0b00000<<16), :rs, :i16, :setip addop 'bgez', (1<<26) | (0b00001<<16), :rs, :i16, :setip addop 'tgei', (1<<26) | (0b01000<<16), :rs, :i16, :setip addop 'tgfiu',(1<<26) | (0b01001<<16), :rs, :i16, :setip addop 'tlti', (1<<26) | (0b01010<<16), :rs, :i16, :setip addop 'tltiu',(1<<26) | (0b01011<<16), :rs, :i16, :setip addop 'teqi', (1<<26) | (0b01100<<16), :rs, :i16, :setip addop 'tnei', (1<<26) | (0b01110<<16), :rs, :i16, :setip addop 'bltzal', (1<<26) | (0b10000<<16), :rs, :i16, :setip, :saveip addop 'bgezal', (1<<26) | (0b10001<<16), :i16, :setip, :stopexec, :saveip # bgezal $zero => unconditional addop 'bgezal', (1<<26) | (0b10001<<16), :rs, :i16, :setip, :saveip # special2 addop 'madd', (0b011100<<26) | 0b000000, :rs, :rt addop 'maddu',(0b011100<<26) | 0b000001, :rs, :rt addop 'mul', (0b011100<<26) | 0b000010, :rd, :rs, :rt addop 'msub', (0b011100<<26) | 0b000100, :rs, :rt addop 'msubu',(0b011100<<26) | 0b000101, :rs, :rt addop 'clz', (0b011100<<26) | 0b100000, :rd, :rs, :rt # must have rs == rt addop 'clo', (0b011100<<26) | 0b100001, :rd, :rs, :rt # must have rs == rt addop 'sdbbp',(0b011100<<26) | 0b111111, :i20 # cp0 addop 'mfc0', (0b010000<<26) | (0b00000<<21), :rt, :idb addop 'mfc0', (0b010000<<26) | (0b00000<<21), :rt, :idb, :sel addop 'mtc0', (0b010000<<26) | (0b00100<<21), :rt, :idb addop 'mtc0', (0b010000<<26) | (0b00100<<21), :rt, :idb, :sel addop 'tlbr', (0b010000<<26) | (1<<25) | 0b000001 addop 'tlbwi',(0b010000<<26) | (1<<25) | 0b000010 addop 'tlbwr',(0b010000<<26) | (1<<25) | 0b000110 addop 'tlbp', (0b010000<<26) | (1<<25) | 0b001000 addop 'eret', (0b010000<<26) | (1<<25) | 0b011000 addop 'deret',(0b010000<<26) | (1<<25) | 0b011111 addop 'wait', (0b010000<<26) | (1<<25) | 0b100000 # mode field ? end
init_mips32_obsolete()
click to toggle source
# File metasm/cpu/mips/opcodes.rb, line 23 def init_mips32_obsolete addop 'beql', 0b010100 << 26, :rt, :rs, :i16, :setip # == , exec delay slot only if jump taken addop 'bnel', 0b010101 << 26, :rt, :rs, :i16, :setip # != addop 'blezl',0b010110 << 26, :rt_z, :rs, :i16, :setip # <= 0 addop 'bgtzl',0b010111 << 26, :rt_z, :rs, :i16, :setip # > 0 addop 'bltzl',1 << 26 | 0b00010 << 16, :rs, :i16, :setip addop 'bgezl',1 << 26 | 0b00011 << 16, :rs, :i16, :setip addop 'bltzall', 1 << 26 | 0b10010 << 16, :rs, :i16, :setip addop 'bgezall', 1 << 26 | 0b10011 << 16, :rs, :i16, :setip end
init_mips32_reserved()
click to toggle source
# File metasm/cpu/mips/opcodes.rb, line 34 def init_mips32_reserved addop 'future111011', 0b111011 << 26, :i26 %w[011000 011001 011010 011011 100111 101100 101101 110100 110111 111100 111111].each { |b| addop "reserved#{b}", b.to_i(2) << 26, :i26 } addop 'ase_jalx', 0b011101 << 26, :i26 addop 'ase011110', 0b011110 << 26, :i26 # TODO add all special/regimm/... end
init_mips32r2()
click to toggle source
# File metasm/cpu/mips/opcodes.rb, line 214 def init_mips32r2 init_mips32 addop 'rotr', 0b000010 | (1<<21), :rd, :rt, :sa addop 'rotrv',0b000110 | (1<<6), :rd, :rt, :rs addop 'synci',(1<<26) | (0b11111<<16), :rs_i16 # special3 addop 'ext', (0b011111<<26) | 0b000000, :rt, :rs, :sa, :idm1 addop 'ins', (0b011111<<26) | 0b000100, :rt, :rs, :sa, :idb addop 'rdhwr',(0b011111<<26)| 0b111011, :rt, :rd addop 'wsbh',(0b011111<<26) | (0b00010<<6) | 0b100000, :rd, :rt addop 'seb', (0b011111<<26) | (0b10000<<6) | 0b100000, :rd, :rt addop 'seh', (0b011111<<26) | (0b11000<<6) | 0b100000, :rd, :rt # cp0 addop 'rdpgpr', (0b010000<<26) | (0b01010<<21), :rd, :rt addop 'wrpgpr', (0b010000<<26) | (0b01110<<21), :rd, :rt addop 'di', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (0<<5) addop 'di', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (0<<5), :rt addop 'ei', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (1<<5) addop 'ei', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (1<<5), :rt end
Also aliased as: init_latest
init_opcode_list()
click to toggle source
# File metasm/cpu/mips/main.rb, line 66 def init_opcode_list send("init_#@family") @opcode_list end
parse_arg_valid?(op, sym, arg)
click to toggle source
# File metasm/cpu/mips/parse.rb, line 12 def parse_arg_valid?(op, sym, arg) # special case for lw reg, imm32(reg) ? (pseudo-instr, need to convert to 'lui t0, up imm32 ori t0 down imm32 add t0, reg lw reg, 0(t0) case sym when :rs, :rt, :rd; arg.kind_of? Reg when :sa, :i16, :i20, :i26; arg.kind_of? Expression when :rs_i16; arg.kind_of? Memref when :ft; arg.kind_of? FpReg else raise "internal error: mips arg #{sym.inspect}" end end
parse_argument(pgm)
click to toggle source
# File metasm/cpu/mips/parse.rb, line 23 def parse_argument(pgm) pgm.skip_space return if not tok = pgm.nexttok if tok.type == :string and Reg.s_to_i[tok.raw] pgm.readtok arg = Reg.new Reg.s_to_i[tok.raw] elsif tok.type == :string and FpReg.s_to_i[tok.raw] pgm.readtok arg = FpReg.new FpReg.s_to_i[tok.raw] else 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 Reg.s_to_i[ntok.raw] base = Reg.new Reg.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 end arg end
render_instruction(i)
click to toggle source
# File metasm/cpu/mips/render.rb, line 25 def render_instruction(i) r = [] r << i.opname if not i.args.empty? r << ' ' if (a = i.args.first).kind_of? Expression and a.op == :- and a.lexpr.kind_of? String and a.rexpr.kind_of? String and opcode_list_byname[i.opname].first.props[:setip] # jmp foo is stored as jmp foo - bar ; bar: r << a.lexpr else i.args.each { |a_| r << a_ << ', ' } r.pop end end r end
replace_instr_arg_immediate(i, old, new)
click to toggle source
# File metasm/cpu/mips/decode.rb, line 231 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 a else a end } end
Private Instance Methods
encode_instr_op(exe, instr, op)
click to toggle source
# File metasm/cpu/mips/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 # 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 if op.args.include? :i26 pl = Expression[postlabel, :&, 0xfc00_0000] else pl = postlabel end instr.args[-1] = Expression[[instr.args[-1], :-, pl], :>>, 2] postdata = EncodedData.new '', :export => {postlabel => 0} else postdata = '' end op.args.zip(instr.args).each { |sym, arg| case sym when :rs, :rt, :rd, :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, :i26, :it, :msbd, :sel, :idb val, mask, shift = arg, @fields_mask[sym], @fields_shift[sym] val = Expression[val, :-, 1] if sym == :msbd end } Expression[base, :|, [[val, :&, mask], :<<, shift]].encode(:u32, @endianness) << postdata end