# This file is part of Metasm, the Ruby assembly manipulation suite # Copyright (C) 2006-2010 Yoann GUILLOT # # Licence is LGPL, see LICENCE in the top-level directory require 'metasm/cpu/msp430/opcodes' require 'metasm/decode' module Metasm class MSP430 def build_opcode_bin_mask(op) op.bin_mask = 0 op.fields.each_key { |f| op.bin_mask |= @fields_mask[f] << @fields_shift[f] } op.bin_mask ^= 0xffff end def build_bin_lookaside lookaside = Array.new(256) { [] } opcode_list.each { |op| build_opcode_bin_mask op b = (op.bin >> 8) & 255 msk = (op.bin_mask >> 8) & 255 for i in b..(b | (255^msk)) lookaside[i] << op if i & msk == b & msk end } lookaside end def decode_findopcode(edata) di = DecodedInstruction.new(self) val = edata.decode_imm(:u16, @endianness) edata.ptr -= 2 di.opcode = @bin_lookaside[(val >> 8) & 0xff].find { |opcode| (val & opcode.bin_mask) == opcode.bin } di if di.opcode end def decode_instr_op(edata, di) before_ptr = edata.ptr op = di.opcode di.instruction.opname = op.name val = edata.decode_imm(:u16, @endianness) field_val = lambda{ |f| (val >> @fields_shift[f]) & @fields_mask[f] } # must decode rs first vals = {} ([:rs, :rd, :r_pc] & op.args).each { |a| mod = { :rs => :as, :rd => :ad, :r_pc => :ad }[a] mod = :as if mod == :ad and not op.fields[mod] # addop_macro1 -> rs + ad if a == :r_pc r = Reg.new(0) else r = Reg.new(field_val[a]) end w = op.props[:byte] ? 1 : 2 case field_val[mod] when 0 if r.i == 3 and a == :rs vals[a] = Expression[0] else vals[a] = r end when 1 if r.i == 3 and a == :rs vals[a] = Expression[1] else imm = edata.decode_imm(:u16, @endianness) r = nil if r.i == 2 # [imm] vals[a] = Memref.new(r, imm, w) end when 2 if r.i == 3 vals[a] = Expression[2] elsif r.i == 2 vals[a] = Expression[4] else vals[a] = Memref.new(r, 0, w) end when 3 if r.i == 3 vals[a] = Expression[-1] elsif r.i == 2 vals[a] = Expression[8] elsif r.i == 0 # pc++ # XXX order wrt other edata.decode_imm ? vals[a] = Expression[edata.decode_imm(:u16, @endianness)] else vals[a] = Memref.new(r, 0, w, true) end end } op.args.each { |a| di.instruction.args << case a when :joff; Expression[2 * Expression.make_signed(field_val[a], 10)] when :rs, :rd, :r_pc; vals[a] else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}" end } di.bin_length += edata.ptr - before_ptr return if edata.ptr > edata.length di end def decode_instr_interpret(di, addr) if di.opcode.props[:setip] and di.opcode.name =~ /^j/ delta = di.instruction.args.last.reduce arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce di.instruction.args[-1] = Expression[arg] end di end def init_backtrace_binding @backtrace_binding ||= {} opcode_list.map { |ol| ol.name }.uniq.each { |op| @backtrace_binding[op] ||= case op when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] }} when 'cmp', 'test'; lambda { |di, *a| {} } # TODO when 'add', 'adc' ; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } } when 'sub', 'sbc'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } } when 'and'; lambda { |di, a0, a1| { a0 => Expression[a0, :&, a1] } } when 'or'; lambda { |di, a0, a1| { a0 => Expression[a0, :|, a1] } } when 'xor'; lambda { |di, a0, a1| { a0 => Expression[a0, :^, a1] } } when 'push'; lambda { |di, a0| { Indirection[:sp, 2] => Expression[a0], :sp => Expression[:sp, :-, 2] } } when 'call'; lambda { |di, a0| { Indirection[:sp, 2] => Expression[di.next_addr], :sp => Expression[:sp, :-, 2] } } when 'pop'; lambda { |di, a0| { a0 => Expression[Indirection[:sp, 2]], :sp => Expression[:sp, :+, 2] } } when 'ret'; lambda { |di| { :sp => Expression[:sp, :+, 2] } } when 'reti'; lambda { |di| { :sp => Expression[:sp, :+, 4] } } when /^j/; lambda { |di, a0| {} } end } @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.basename] bd = binding[di, *a] || {} di.instruction.args.grep(Memref).each { |m| next unless r = m.base and m.postincr r = m.base.symbolic bd[r] ||= Expression[r, :+, m.size] } bd else puts "unhandled instruction to backtrace: #{di}" if $VERBOSE { :incomplete_binding => Expression[1] } end end def get_xrefs_x(dasm, di) return [] if not di.opcode.props[:setip] case di.instruction.opname when 'ret' return [Indirection[:sp, 2, di.address]] when 'reti' return [Indirection[[:sp, :+, 2], 2, di.address]] end # XXX add pc, 42 ? val = di.instruction.args[0] case val when Reg; val = val.symbolic when Memref; val = val.symbolic(di) end [Expression[val]] end def backtrace_is_function_return(expr, di=nil) expr = Expression[expr].reduce_rec expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp] end # updates the function backtrace_binding # if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand) def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs) b = f.backtrace_binding bt_val = lambda { |r| next if not retaddrlist b[r] = Expression::Unknown bt = [] retaddrlist.each { |retaddr| bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true, :snapshot_addr => faddr, :origin => retaddr) } if bt.length != 1 b[r] = Expression::Unknown else b[r] = bt.first end } if not wantregs.empty? wantregs.each(&bt_val) else bt_val[:sp] end b end 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.base = (a.base == old ? new : Expression[a.base.bind(old => new).reduce]) if a.base.kind_of?(Expression) a else a end } end end end