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_binding() click to toggle source

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

# File metasm/cpu/mips/decode.rb, line 130
def backtrace_binding
        @backtrace_binding ||= init_backtrace_binding
end
backtrace_binding=(b) click to toggle source
# File metasm/cpu/mips/decode.rb, line 133
def backtrace_binding=(b) @backtrace_binding = b 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 254
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 232
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 236
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 212
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 261
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 267
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 176
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
                if di.instruction.opname[0] == ?b and di.opcode.props[:setip]
                else
                        puts "unknown instruction to emu #{di}" if $VERBOSE
                end
                {}
        end

        binding.delete 0      # allow add $zero, 42 => nop

        binding
end
get_xrefs_x(dasm, di) click to toggle source
# File metasm/cpu/mips/decode.rb, line 200
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 135
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 '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';        lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'sw';        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'; lambda { |di, a0, a1| { :hi => Expression[[a0, :*, a1], :>>, 32], :lo => Expression[[a0, :*, a1], :&, 0xffff_ffff] } }
                when 'div';  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 } }
                end

                @backtrace_binding[op] ||= binding if binding
        }
        @backtrace_binding
end
init_latest()
Alias for: init_mips32r2
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 => unconditionnal
                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 240
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