# 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 require 'metasm/cpu/arm/opcodes' require 'metasm/decode' module Metasm class ARM # create the bin_mask for a given opcode 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 # create the lookaside hash from the first byte of the opcode def build_bin_lookaside lookaside = Array.new(256) { [] } opcode_list.each { |op| build_opcode_bin_mask op b = (op.bin >> 20) & 0xff msk = (op.bin_mask >> 20) & 0xff b &= msk for i in b..(b | (255^msk)) lookaside[i] << op if i & msk == b end } lookaside end def decode_findopcode(edata) return if edata.ptr+4 > edata.length di = DecodedInstruction.new(self) val = edata.decode_imm(:u32, @endianness) di.misc = val di if di.opcode = @bin_lookaside[(val >> 20) & 0xff].find { |op| (not op.props[:cond] or ((val >> @fields_shift[:cond]) & @fields_mask[:cond]) != 0xf) and (op.bin & op.bin_mask) == (val & op.bin_mask) } end def disassembler_default_func df = DecodedFunction.new df end def decode_instr_op(edata, di) op = di.opcode di.instruction.opname = op.name val = di.misc # saved decoded u32 field_val = lambda { |f| r = (val >> @fields_shift[f]) & @fields_mask[f] case f when :i12; Expression.make_signed(r, 12) when :i24; Expression.make_signed(r, 24) when :i8_12; ((r >> 4) & 0xf0) | (r & 0xf) when :stype; [:lsl, :lsr, :asr, :ror][r] when :u; [:-, :+][r] else r end } if op.props[:cond] cd = %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al][field_val[:cond]] if cd != 'al' di.opcode = di.opcode.dup di.instruction.opname = di.opcode.name.dup di.instruction.opname[(op.props[:cond_name_off] || di.opcode.name.length), 0] = cd if di.opcode.props[:stopexec] di.opcode.props = di.opcode.props.dup di.opcode.props.delete :stopexec end end end op.args.each { |a| di.instruction.args << case a when :rd, :rn, :rm; Reg.new field_val[a] when :rm_rs; Reg.new field_val[:rm], field_val[:stype], Reg.new(field_val[:rs]) when :rm_is; Reg.new field_val[:rm], field_val[:stype], field_val[:shifti] when :i12; Expression[field_val[a]] when :i24; Expression[field_val[a] << 2] when :i8_r i = field_val[:i8] r = field_val[:rotate]*2 Expression[((i >> r) | (i << (32-r))) & 0xffff_ffff] when :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12 b = Reg.new(field_val[:rn]) o = case a when :mem_rn_rm; Reg.new(field_val[:rm]) when :mem_rn_i8_12; field_val[:i8_12] when :mem_rn_rms; Reg.new(field_val[:rm], field_val[:stype], field_val[:shifti]) when :mem_rn_i12; field_val[:i12] end Memref.new(b, o, field_val[:u], op.props[:baseincr]) when :reglist di.instruction.args.last.updated = true if op.props[:baseincr] msk = field_val[a] l = RegList.new((0..15).map { |n| Reg.new(n) if (msk & (1 << n)) > 0 }.compact) l.usermoderegs = true if op.props[:usermoderegs] l else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}" end } di.bin_length = 4 di end def decode_instr_interpret(di, addr) if di.opcode.args[-1] == :i24 di.instruction.args[-1] = Expression[di.instruction.args[-1] + addr + 8] end di end def init_backtrace_binding @backtrace_binding ||= {} end def get_backtrace_binding(di) a = di.instruction.args.map { |arg| case arg when Reg; arg.symbolic when Memref; arg.symbolic(di) else arg end } if binding = backtrace_binding[di.opcode.name] binding[di, *a] 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 def get_xrefs_x(dasm, di) if di.opcode.props[:setip] [di.instruction.args.last] else # TODO ldr pc, .. [] end end end end