class Metasm::ARM64

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

Constants

OP_CC
OP_DATA_ALIAS

official name => usual name

Public Class Methods

new(endianness = :little) click to toggle source
Calls superclass method Metasm::CPU::new
# File metasm/cpu/arm64/main.rb, line 93
def initialize(endianness = :little)
        super()
        @endianness = endianness
        @size = 64
end

Public Instance Methods

backtrace_is_function_return(expr, di=nil) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 277
def backtrace_is_function_return(expr, di=nil)
        expr.reduce_rec == :x30
end
backtrace_is_stack_address(expr) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 281
def backtrace_is_stack_address(expr)
        Expression[expr].expr_externals.include? :sp
end
build_bin_lookaside() click to toggle source

create the lookaside hash from the first byte of the opcode

# File metasm/cpu/arm64/decode.rb, line 22
def build_bin_lookaside
        lookaside = Array.new(256) { [] }

        opcode_list.each { |op|
                build_opcode_bin_mask op

                b   = (op.bin >> 24) & 0xff
                msk = (op.bin_mask >> 24) & 0xff
                b &= msk

                for i in b..(b | (255^msk))
                        lookaside[i] << op if i & msk == b
                end
        }

        lookaside
end
build_opcode_bin_mask(op) click to toggle source

create the bin_mask for a given opcode

# File metasm/cpu/arm64/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.fields.each { |k, (m, s)|
                op.bin_mask |= m << s
        }
        op.bin_mask = 0xffffffff ^ op.bin_mask
end
dbg_end_stepout(dbg, addr, di) click to toggle source
# File metasm/cpu/arm64/debug.rb, line 34
def dbg_end_stepout(dbg, addr, di)
        di and di.opcode.name == 'foobar'
end
dbg_flag_list() click to toggle source
# File metasm/cpu/arm64/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/arm64/debug.rb, line 30
def dbg_need_stepover(dbg, addr, di)
        di and di.opcode.props[:saveip]
end
dbg_register_flags() click to toggle source
# File metasm/cpu/arm64/debug.rb, line 14
def dbg_register_flags
        @dbg_register_flags ||= :flags
end
dbg_register_list() click to toggle source
# File metasm/cpu/arm64/debug.rb, line 18
def dbg_register_list
        @dbg_register_list ||= Reg::Sym.sort.transpose[1] - [:xzr]
end
dbg_register_pc() click to toggle source
# File metasm/cpu/arm64/debug.rb, line 11
def dbg_register_pc
        @dbg_register_pc ||= :pc
end
dbg_register_size() click to toggle source
# File metasm/cpu/arm64/debug.rb, line 26
def dbg_register_size
        @dbg_register_size ||= Hash.new(64)
end
decode_findopcode(edata) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 40
def decode_findopcode(edata)
        return if edata.ptr+4 > edata.length
        di = DecodedInstruction.new(self)
        val = edata.decode_imm(:u32, @endianness)
        di.raw_data = val
        di if di.opcode = @bin_lookaside[(val >> 24) & 0xff].find { |op|
                (op.bin & op.bin_mask) == (val & op.bin_mask)
        }
end
decode_instr_interpret(di, addr) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 157
def decode_instr_interpret(di, addr)
        if di.opcode.props[:setip] and di.instruction.args.last.kind_of?(Expression)
                di.instruction.args[-1] = Expression[Expression[addr, :+, di.instruction.args[-1]].reduce]
        elsif di.opcode.props[:pcrel]
                di.instruction.args[-1] = Expression[Expression[addr, :+, di.instruction.args[-1]].reduce]
        elsif di.opcode.props[:pcrel_page]
                di.instruction.args[-1] = Expression[Expression[[addr, :&, ~0xfff], :+, [di.instruction.args[-1], :<<, 12]].reduce]
        end
        di
end
decode_instr_op(edata, di) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 55
def decode_instr_op(edata, di)
        op = di.opcode
        di.instruction.opname = op.name
        val = di.raw_data

        field_val = lambda { |f|
                (val >> @fields_shift[f]) & @fields_mask[f]
        }

        op.args.each { |a|
                di.instruction.args << case a
                when :rn, :rt, :rt2, :rm
                        nr = field_val[a]
                        nr = 32 if nr == 31 and op.props[:r_z]
                        Reg.new nr, (op.props[:r_32] ? 32 : 64)
                when :rm_lsl_i6, :rm_lsr_i6, :rm_asr_i6, :rm_lsl_i5, :rm_lsr_i5, :rm_asr_i5
                        nr = field_val[:rm]
                        nr = 32 if nr == 31 and op.props[:r_z]
                        r = Reg.new nr, (op.props[:r_32] ? 32 : 64)
                        shift = field_val[:i6_10]
                        mode = { :rm_lsl_i6 => :lsl, :rm_lsl_i5 => :lsl,
                                 :rm_lsr_i6 => :lsr, :rm_lsr_i5 => :lsr,
                                 :rm_asr_i6 => :asr, :rm_asr_i5 => :asr }[a]
                        RegShift.new r, mode, shift
                when :m_rm_extend, :rm_extend_i3
                        nr = field_val[:rm]
                        nr = 32 if nr == 31
                        x = field_val[:regextend_13]
                        case a
                        when :m_rm_extend
                                shift = 0  # field_val[:i1_12] -- bug in arm doc ?
                                mode = [ :resv000, :resv001, :uxtw, :lsl, :resv100, :resv101, :sxtw, :sxtx ][x]
                                rm = RegShift.new Reg.new(nr, 64), mode, shift

                                rn = Reg.new field_val[:rn], 64

                                mem_sz = op.props[:mem_sz] || (op.props[:r_32] ? 4 : 8)
                                Memref.new(rn, rm, 1, nil, mem_sz)
                        when :rm_extend_i3
                                r = Reg.new nr, (op.props[:r_32] ? 32 : 64)
                                shift = field_val[:i3_10]
                                mode = [ :uxtb, :uxth, :uxtw, :uxtx, :sxtb, :sxth, :sxtw, :sxtx ][x]
                                RegShift.new r, mode, shift
                        end
                when :i16_5; Expression[field_val[a]]
                when :il18_5;
                        v = field_val[a]
                        s = (v >> 16) & 3
                        v = v & 0xffff
                        Expression[v, :<<, (16*s)]
                when :i19_5; Expression[Expression.make_signed(field_val[a], 19) << 2]
                when :i26_0; Expression[Expression.make_signed(field_val[a], 26) << 2]
                when :i12_10_s1
                        f = field_val[a]
                        f = (f & 0xfff) << 12 if (f >> 12) & 1 == 1
                        Expression[f]
                when :i19_5_2_29
                        Expression.make_signed((field_val[:i19_5] << 2) | field_val[:i2_29], 21)
                when :bitmask, :bitmask_imm
                        n = field_val[:bitmask_n]
                        s = field_val[:bitmask_s]
                        r = field_val[:bitmask_r]
                        # highestsetbit stuff
                        levels = ((n << 6) | (s ^ 0x3f)) >> 1
                        levels = levels | (levels >> 1)
                        levels = levels | (levels >> 2)
                        levels = levels | (levels >> 4)
                        esize = levels + 1
                        s &= levels
                        r &= levels
                        welem = (1 << (s+1)) - 1
                        # ROR(welem, r)
                        wmask = ((welem >> (r % esize)) | (welem << (esize - (r % esize))))
                        wmask &= (1 << esize) - 1
                        # duplicate(wmask, sz)
                        while esize < 64
                                wmask |= wmask << esize
                                esize *= 2
                        end
                        wmask &= (1 << di.instruction.args[0].sz) - 1
                        Expression[wmask]

                when :m_rn_s9, :m_rn_u12, :m_rn_s7
                        r = Reg.new(field_val[:rn], 64)
                        o = case a
                            when :m_rn_s9; Expression.make_signed(field_val[:s9_12], 9)
                            when :m_rn_s7; Expression.make_signed(field_val[:s7_15], 7)
                            when :m_rn_u12; field_val[:u12_10]
                            else raise SyntaxError, "Internal error #{a.inspect} in #{op.name}"
                            end
                        mem_sz = op.props[:mem_sz] || (op.props[:r_32] ? 4 : 8)
                        Memref.new(r, nil, nil, Expression[o*mem_sz], mem_sz, op.props[:mem_incr])
                when :cond_12
                        RegCC.new OP_CC[field_val[a]]
                else raise SyntaxError, "Internal error: invalid argument #{a.inspect} in #{op.name}"
                end
        }

        di.bin_length = 4
        di
end
disassembler_default_func() click to toggle source
# File metasm/cpu/arm64/decode.rb, line 50
def disassembler_default_func
        df = DecodedFunction.new
        df
end
encode_instr_op(program, instr, op) click to toggle source
# File metasm/cpu/arm64/encode.rb, line 12
def encode_instr_op(program, instr, op)
        base = op.bin
        set_field = lambda { |f, v|
                v = v.reduce if v.kind_of?(Expression)
                case f
                when :i8_12
                        base = Expression[base, :|, [[v, :&, 0xf], :|, [[v, :<<, 4], :&, 0xf00]]]
                        next
                when :stype; v = [:lsl, :lsr, :asr, :ror].index(v)
                when :u; v = [:-, :+].index(v)
                end
                base = Expression[base, :|, [[v, :&, @fields_mask[f]], :<<, @fields_shift[f]]]
        }

        op.args.zip(instr.args).each { |sym, arg|
                case sym
                when :rd, :rs, :rn, :rm, :rt
                        if arg.sz == 32
                                set_field[:sf, 0]
                        elsif op.field[:sf]
                                set_field[:sf, 1]
                        end
                             set_field[sym, arg.i]
                end
        }

        Expression[base].encode(:u32, @endianness)
end
get_backtrace_binding(di) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 206
def get_backtrace_binding(di)
        a = di.instruction.args.map { |arg|
                case arg
                when Reg, RegShift, RegCC; arg.symbolic
                when Memref; arg.symbolic(di)
                else arg
                end
        }

        if binding = backtrace_binding[di.opcode.name]
                bd = binding[di, *a] || {}

                # handle pre-increment / post-increment memrefs
                di.instruction.args.grep(Memref).each { |m|
                        next unless r = m.base and r.kind_of?(Reg)
                        case m.incr
                        when :pre
                                # for di "str x1, [sp+10]!" ; bt_bind should be { sp += 10, [sp] = x1 } but memref.symbolic returns [sp+10]
                                # eg: str x30, [sp-20]! ; ldr x30, [sp], 20 ; ret  should backtrace as  x30 -> [sp] -!> x30
                                rs = r.symbolic
                                bd.dup.each_key { |k|
                                        if k.kind_of?(Indirection)
                                                bd[Indirection[k.target.bind(rs => Expression[rs, :-, m.offset]).reduce, k.len, k.origin]] = bd.delete(k)
                                        end
                                }
                                bd[rs] ||= Expression[rs, :+, m.offset]
                        when :post
                                bd[r.symbolic] ||= Expression[r.symbolic, :+, m.offset]
                        end
                }

                # handle subregisters (x30 -> w30)
                bd.keys.grep(Expression).each { |e|
                        # must be Expression[reg, :&, 0xffff_ffff]
                        if e.op == :& and e.rexpr == 0xffff_ffff
                                reg = e.lexpr
                                next if not reg.kind_of? Symbol
                                val = bd.delete e
                                bd[reg] = Expression[[reg, :&, 0xffff_ffff_0000_0000], :|, [val, :&, 0xffff_ffff]]
                        end
                }

                bd
        else
                puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
                # assume nothing except the 1st arg is modified
                case a[0]
                when Indirection, Symbol; { a[0] => Expression::Unknown }
                when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
                else {}
                end.update(:incomplete_binding => Expression[1])
        end
end
get_xrefs_x(dasm, di) click to toggle source
# File metasm/cpu/arm64/decode.rb, line 260
def get_xrefs_x(dasm, di)
        if di.opcode.props[:setip]
                tg = di.instruction.args.last
                case tg
                when nil
                        raise 'internal error: no jmp target' if di.opcode.name != 'ret'
                        tg = :x30
                when Expression
                else tg = tg.symbolic(di)
                end
                [tg]
        else
                # TODO ldr pc, ..
                []
        end
end
gui_hilight_word_regexp(word) click to toggle source
Calls superclass method Metasm::CPU#gui_hilight_word_regexp
# File metasm/cpu/arm64/render.rb, line 90
def gui_hilight_word_regexp(word)
        @gui_hilight_word_hash ||= gui_hilight_word_regexp_init
        @gui_hilight_word_hash[word] or super(word)
end
gui_hilight_word_regexp_init() click to toggle source
# File metasm/cpu/arm64/render.rb, line 80
def gui_hilight_word_regexp_init
        ret = {}
        (0..30).each { |i|
                ret["w#{i}"] = ret["x#{i}"] = "[wx]#{i}"
        }
        ret["sp"] = ret["wsp"] = "w?sp"
        ret["zr"] = ret["wzr"] = "w?zr"
        ret
end
init_arm_v8() click to toggle source

ARMv8 64-bits instruction set, aka AArch64

# File metasm/cpu/arm64/opcodes.rb, line 88
def init_arm_v8
        @opcode_list = []

        [:stopexec, :setip, :saveip,
         :r_z,                # reg nr31 = flag ? zero : sp
         :r_32,               # reg size == 32bit
         :mem_incr,   # mem dereference is pre/post-increment
         :mem_sz,     # point to uint32 => 4
         :pcrel,      # immediate value is pc-relative
         :pcrel_page, # immediate value is a page offset, pc-relative
        ].each { |p| @valid_props[p] = true }

        [:rn, :rt, :rt2, :rm,
         :rm_lsl_i6, :rm_lsr_i6, :rm_asr_i6,
         :rm_lsl_i5, :rm_lsr_i5, :rm_asr_i5,
         :m_rm_extend, :rm_extend_i3,
         :i14_5, :i16_5, :il18_5, :i19_5, :i26_0, :i12_10_s1,
         :i19_5_2_29,
         :m_rn_s7, :m_rn_s9, :m_rn_u12,
         :bitmask, :bitmask_imm, :cond_12,
        ].each { |p| @valid_args[p] = true }

        @fields_mask.update :rn => 0x1f, :rt => 0x1f, :rt2 => 0x1f, :rm => 0x1f,
                :rm_lsl_i6 => 0x7ff, :rm_lsr_i6 => 0x7ff, :rm_asr_i6 => 0x7ff,
                :rm_lsl_i5 => 0x7df, :rm_lsr_i5 => 0x7df, :rm_asr_i5 => 0x7df,
                :m_rm_extend => ((0x1f << 11) | (0xb << 7) | 0x1f), :rm_extend_i3 => 0x7ff,
                :i14_5 => 0x3fff, :i16_5 => 0xffff, :il18_5 => 0x3ffff, :i26_0 => 0x3ffffff,
                :i12_10_s1 => 0x3fff, :i6_10 => 0x3f,
                :s7_15 => 0x7f, :s9_12 => 0x1ff, :u12_10 => 0xfff,
                :i19_5 => 0x7ffff, :i2_29 => 3,
                :i19_5_2_29 => 0x60ffffe0, :cond_12 => 0xf,
                :bitmask_n => 1, :bitmask_s => 0x3f, :bitmask_r => 0x3f,
                :regextend_13 => 7, :i1_12 => 1, :i3_10 => 7,
                :m_rn_s7  => ((0x7f << 10) | 0x1f),
                :m_rn_s9  => ((0x1ff << 7) | 0x1f),
                :m_rn_u12 => ((0xfff << 5) | 0x1f)

        @fields_shift.update :rn => 5, :rt => 0, :rt2 => 10, :rm => 16,
                :rm_lsl_i6 => 10, :rm_lsr_i6 => 10, :rm_asr_i6 => 10,
                :rm_lsl_i5 => 10, :rm_lsr_i5 => 10, :rm_asr_i5 => 10,
                :m_rm_extend => 5, :rm_extend_i3 => 10,
                :i14_5 => 5, :i16_5 => 5, :il18_5 => 5, :i26_0 => 0,
                :i12_10_s1 => 10, :i6_10 => 10,
                :s7_15 => 15, :s9_12 => 12, :u12_10 => 10,
                :i19_5 => 5, :i2_29 => 29,
                :i19_5_2_29 => 0, :cond_12 => 12,
                :bitmask_n => 22, :bitmask_s => 10, :bitmask_r => 16,
                :regextend_13 => 13, :i1_12 => 12, :i3_10 => 10,
                :m_rn_s7 => 5, :m_rn_s9 => 5, :m_rn_u12 => 5

        addop 'adr',  1 << 28, :rt, :i19_5_2_29, :pcrel
        addop 'adrp',(1 << 28) | (1 << 31), :rt, :i19_5_2_29, :pcrel_page

        addop_s31 'cbz',  0b0110100 << 24, :rt, :i19_5, :setip
        addop_s31 'cbnz', 0b0110101 << 24, :rt, :i19_5, :setip
        addop_cc 'b', 0b0101010 << 25, :i19_5, :setip

        addop_s31 'mov', (0b01_01010_00_0 << 21) | (0b11111 << 5), :rt, :rm, :r_z     # alias for orr rt, 0, rm
        addop_data_shifted_alias 'and',  0b00_01010_00_0 << 21
        addop_data_shifted_alias 'bic',  0b00_01010_00_1 << 21        # and not
        addop_data_shifted_alias 'orr',  0b01_01010_00_0 << 21
        addop_data_shifted_alias 'orn',  0b01_01010_00_1 << 21        # or not
        addop_data_shifted_alias 'eor',  0b10_01010_00_0 << 21
        addop_data_shifted_alias 'eorn', 0b10_01010_00_1 << 21
        addop_data_shifted_alias 'ands', 0b11_01010_00_0 << 21, :r_z  # same as and + set flags
        addop_data_shifted_alias 'bics', 0b11_01010_00_1 << 21, :r_z  # same as bic + set flags

        addop 'cmp', (0b11_01011_00_0 << 21) | (0b11111 << 0) | (0b00 << 22), :rn, :rm_lsl_i6, :r_32, :r_z # alias for subs 0, rn, rm
        addop 'cmp', (0b11_01011_00_0 << 21) | (0b11111 << 0) | (0b01 << 22), :rn, :rm_lsr_i6, :r_32, :r_z
        addop 'cmp', (0b11_01011_00_0 << 21) | (0b11111 << 0) | (0b10 << 22), :rn, :rm_asr_i6, :r_32, :r_z
        addop 'cmp', (0b11_01011_00_0 << 21) | (0b11111 << 0) | (0b00 << 22) | (1 << 31), :rn, :rm_lsl_i5, :r_z
        addop 'cmp', (0b11_01011_00_0 << 21) | (0b11111 << 0) | (0b01 << 22) | (1 << 31), :rn, :rm_lsr_i5, :r_z
        addop 'cmp', (0b11_01011_00_0 << 21) | (0b11111 << 0) | (0b10 << 22) | (1 << 31), :rn, :rm_asr_i5, :r_z
        addop_s31 'negs', (0b11_01011_00_0 << 21) | (0b11111 << 5), :rt, :rm, :r_z    # alias for subs rt, 0, rm
        addop_data_shifted_alias 'add', 0b00_01011_00_0 << 21
        addop_data_shifted_alias 'adds',0b01_01011_00_0 << 21, :r_z
        addop_data_shifted_alias 'sub', 0b10_01011_00_0 << 21
        addop_data_shifted_alias 'subs',0b11_01011_00_0 << 21, :r_z

        addop_s31 'add', 0b00_01011_00_1 << 21, :rt, :rn, :rm_extend_i3
        addop_s31 'adds',0b01_01011_00_1 << 21, :rt, :rn, :rm_extend_i3
        addop_s31 'sub', 0b10_01011_00_1 << 21, :rt, :rn, :rm_extend_i3
        addop_s31 'subs',0b11_01011_00_1 << 21, :rt, :rn, :rm_extend_i3

        addop_data_imm_alias 'and', 0b00_100100 << 23
        addop_data_imm_alias 'orr', 0b01_100100 << 23
        addop_data_imm_alias 'eor', 0b10_100100 << 23
        addop_data_imm_alias 'ands',0b11_100100 << 23, :r_z

        addop 'svc',   (0b11010100 << 24) | (0b000 << 21) | (0b00001), :i16_5
        addop 'hvc',   (0b11010100 << 24) | (0b000 << 21) | (0b00010), :i16_5, :stopexec
        addop 'smc',   (0b11010100 << 24) | (0b000 << 21) | (0b00011), :i16_5, :stopexec
        addop 'brk',   (0b11010100 << 24) | (0b001 << 21) | (0b00000), :i16_5, :stopexec
        addop 'hlt',   (0b11010100 << 24) | (0b010 << 21) | (0b00000), :i16_5, :stopexec
        addop 'dcps1', (0b11010100 << 24) | (0b101 << 21) | (0b00001), :i16_5, :stopexec
        addop 'dcps2', (0b11010100 << 24) | (0b101 << 21) | (0b00010), :i16_5, :stopexec
        addop 'dcps3', (0b11010100 << 24) | (0b101 << 21) | (0b00011), :i16_5, :stopexec

        addop_s31 'tbz', (0b0110110 << 24), :rt, :i14_5

        addop 'b',   (0b000101 << 26), :i26_0, :setip, :stopexec
        addop 'bl',  (0b100101 << 26), :i26_0, :setip, :stopexec, :saveip
        addop 'br',  (0b1101011 << 25) | (0b0000 << 21) | (0b11111 << 16), :rn, :setip, :stopexec
        addop 'blr', (0b1101011 << 25) | (0b0001 << 21) | (0b11111 << 16), :rn, :setip, :stopexec, :saveip
        addop 'ret', (0b1101011 << 25) | (0b0010 << 21) | (0b11111 << 16) | (0b11110 << 5), :setip, :stopexec
        addop 'ret', (0b1101011 << 25) | (0b0010 << 21) | (0b11111 << 16), :rn, :setip, :stopexec
        addop 'eret',(0b1101011 << 25) | (0b0100 << 21) | (0b11111 << 16) | (0b11111 << 5), :setip, :stopexec
        addop 'drps',(0b1101011 << 25) | (0b0101 << 21) | (0b11111 << 16) | (0b11111 << 5), :setip, :stopexec

        addop_s31 'mov',  (0b0010001 << 24), :rt, :rn                 # alias for add rt, rn, 0
        addop_s31 'add',  (0b0010001 << 24), :rt, :rn, :i12_10_s1
        addop_s31 'adds', (0b0110001 << 24), :rt, :rn, :i12_10_s1
        addop_s31 'sub',  (0b1010001 << 24), :rt, :rn, :i12_10_s1
        addop_s31 'subs', (0b1110001 << 24), :rt, :rn, :i12_10_s1

        addop_s31 'movn', (0b00100101 << 23), :rt, :il18_5
        addop_s31 'mov',  (0b10100101 << 23), :rt, :i16_5     # alias movz rt, i16 LSL 0
        addop_s31 'movz', (0b10100101 << 23), :rt, :il18_5
        addop_s31 'movk', (0b11100101 << 23), :rt, :il18_5

        addop_store 'str',   (0b10_111_0_00_00 << 22)
        addop_store 'ldr',   (0b10_111_0_00_01 << 22)
        addop_store 'ldrsw', (0b10_111_0_00_10 << 22)
        addop_store 'strb',  (0b00_111_0_00_00 << 22)
        addop_store 'ldrb',  (0b00_111_0_00_01 << 22)
        addop_s31 'stp',  0b00_101_0_001_0 << 22, :rt, :rt2, :m_rn_s7, :mem_incr => :post
        addop_s31 'stp',  0b00_101_0_011_0 << 22, :rt, :rt2, :m_rn_s7, :mem_incr => :pre
        addop_s31 'stp',  0b00_101_0_010_0 << 22, :rt, :rt2, :m_rn_s7
        addop_s31 'ldp',  0b00_101_0_001_1 << 22, :rt, :rt2, :m_rn_s7, :mem_incr => :post
        addop_s31 'ldp',  0b00_101_0_011_1 << 22, :rt, :rt2, :m_rn_s7, :mem_incr => :pre
        addop_s31 'ldp',  0b00_101_0_010_1 << 22, :rt, :rt2, :m_rn_s7

        addop_s31 'csel',  (0b0011010100 << 21) | (0b00 << 10), :rt, :rn, :rm, :cond_12, :r_z
        addop_s31 'csinc', (0b0011010100 << 21) | (0b01 << 10), :rt, :rn, :rm, :cond_12, :r_z
        addop_s31 'csinv', (0b1011010100 << 21) | (0b00 << 10), :rt, :rn, :rm, :cond_12, :r_z
        addop_s31 'csneg', (0b1011010100 << 21) | (0b01 << 10), :rt, :rn, :rm, :cond_12, :r_z

        addop_bitfield 'sbfm', 0b00_100110 << 23
        addop_bitfield 'bfm',  0b01_100110 << 23
        addop_bitfield 'ubfm', 0b10_100110 << 23
end
Also aliased as: init_latest
init_backtrace_binding() click to toggle source
# File metasm/cpu/arm64/decode.rb, line 168
def init_backtrace_binding
        @backtrace_binding ||= {}

        opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
                binding = case op
                when 'mov', 'adr', 'adrp'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'movz'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'movn'; lambda { |di, a0, a1| { a0 => Expression[:~, a1] } }
                #when 'movk'; lambda { |di, a0, a1| a1 + lsl replace target bits of a0, other unchanged
                when 'and', 'ands', 'orr', 'or', 'eor', 'xor'
                        bin_op = { 'and' => :&, 'ands' => :&, 'orr' => :|,
                                'or' => :|, 'eor' => :^, 'xor' => :^ }[op]
                        lambda { |di, a0, a1, a2| { a0 => Expression[ a1, bin_op, a2 ] } }
                when 'orn', 'eorn', 'bic', 'bics', 'andn'
                        bin_op = { 'orn' => :|, 'eorn' => :^, 'andn' => :&, 'bic' => :&, 'bics' => :& }[op]
                        lambda { |di, a0, a1, a2| { a0 => Expression[ a1, bin_op, [ :~, a2 ] ] } }
                when 'add', 'adds', 'sub', 'subs'
                        bin_op = { 'add' => :+, 'adds' => :+, 'sub' => :-, 'subs' => :- }[op]
                        lambda { |di, a0, a1, a2| { a0 => Expression[ a1, bin_op, a2 ] } }
                when 'ldr', 'ldrb', 'ldrsw'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
                when 'str', 'strb', 'strsw'; lambda { |di, a0, a1| { a1 => Expression[a0] } }
                when 'stp'; lambda { |di, a0, a1, a2| ptr = a2.target
                        { Indirection[ptr, 8] => Expression[a0], Indirection[Expression[ptr, :+, 8].reduce, 8] => Expression[a1] } }
                when 'ldp'; lambda { |di, a0, a1, a2| ptr = a2.target
                        { a0 => Indirection[ptr, 8], a1 => Indirection[Expression[ptr, :+, 8].reduce, 8] } }
                when 'ret'; lambda { |di, *a| { } }
                when 'bl', 'blr'; lambda { |di, *a| { :x30 => Expression[di.next_addr] } }
                when 'cbz', 'cbnz', 'cmp', /^b/; lambda { |di, *a| {} }
                end

                # pre/post-increment memref done in def get_backtrace_binding(di)

                @backtrace_binding[op] ||= binding
        }

        @backtrace_binding
end
init_latest()
Alias for: init_arm_v8
init_opcode_list() click to toggle source
# File metasm/cpu/arm64/main.rb, line 99
def init_opcode_list
        init_latest
        @opcode_list
end
parse_arg_valid?(op, sym, arg) click to toggle source
# File metasm/cpu/arm64/parse.rb, line 12
def parse_arg_valid?(op, sym, arg)
        false
end
parse_argument(lexer) click to toggle source
# File metasm/cpu/arm64/parse.rb, line 16
def parse_argument(lexer)
        raise lexer, 'fu'
end

Private Instance Methods

addop(name, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 13
def addop(name, bin, *args)
        o = Opcode.new name, bin
        args.each { |a|
                o.args << a if @valid_args[a]
                o.props[a] = true if @valid_props[a]
                o.props.update a if a.kind_of?(::Hash)
        }

        args.each { |a| o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a] }

        @opcode_list << o
end
addop_bitfield(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 50
def addop_bitfield(n, bin, *args)
        addop n, bin, :rt, :rn, :bitmask, :bitmask_s, :bitmask_r, *args
        addop n, bin | (1 << 31) | (1 << 22), :rt, :rn, :bitmask, :bitmask_s, :bitmask_r,  *args
end
addop_cc(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 79
def addop_cc(n, bin, *args)
        OP_CC.each_with_index { |e, i|
                args << :stopexec if e == 'al' and args.include?(:setip)
                addop n+e, bin | i, *args
        }
end
addop_data_imm(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 45
def addop_data_imm(n, bin, *args)
        addop n, bin, :rt, :rn, :bitmask_imm, :bitmask_s, :bitmask_r, *args
        addop n, bin | (1 << 31), :rt, :rn, :bitmask_imm, :bitmask_n, :bitmask_s, :bitmask_r,  *args
end
addop_data_imm_alias(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 64
def addop_data_imm_alias(n, bin, *args)
        if a = OP_DATA_ALIAS[n]
                addop_data_imm a, bin, *args
        end
        addop_data_imm n, bin, *args
end
addop_data_shifted(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 36
def addop_data_shifted(n, bin, *args)
        addop n, bin | (0b00 << 22), :rt, :rn, :rm_lsl_i6, :r_32, *args
        addop n, bin | (0b01 << 22), :rt, :rn, :rm_lsr_i6, :r_32, *args
        addop n, bin | (0b10 << 22), :rt, :rn, :rm_asr_i6, :r_32, *args
        addop n, bin | (0b00 << 22) | (1 << 31), :rt, :rn, :rm_lsl_i5, *args
        addop n, bin | (0b01 << 22) | (1 << 31), :rt, :rn, :rm_lsr_i5, *args
        addop n, bin | (0b10 << 22) | (1 << 31), :rt, :rn, :rm_asr_i5, *args
end
addop_data_shifted_alias(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 57
def addop_data_shifted_alias(n, bin, *args)
        if a = OP_DATA_ALIAS[n]
                addop_data_shifted a, bin, *args
        end
        addop_data_shifted n, bin, *args
end
addop_s30(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 31
def addop_s30(n, bin, *args)
        addop n, bin, :r_32, *args
        addop n, (1 << 30) | bin, *args
end
addop_s31(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 26
def addop_s31(n, bin, *args)
        addop n, bin, :r_32, *args
        addop n, (1 << 31) | bin, *args
end
addop_store(n, bin, *args) click to toggle source
# File metasm/cpu/arm64/opcodes.rb, line 71
def addop_store(n, bin, *args)
        addop_s30 n, bin | (0b01 << 10), :rt, :m_rn_s9, :mem_incr => :post
        addop_s30 n, bin | (0b11 << 10), :rt, :m_rn_s9, :mem_incr => :pre
        addop_s30 n, bin | (1 << 21) | (0b10 << 10) | (1 << 14), :rt, :m_rm_extend
        addop_s30 n, bin | (1 << 24), :rt, :m_rn_u12
end