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