|
| 1 | +# This file is part of Metasm, the Ruby assembly manipulation suite |
| 2 | +# Copyright (C) 2006-2010 Yoann GUILLOT |
| 3 | +# |
| 4 | +# Licence is LGPL, see LICENCE in the top-level directory |
| 5 | + |
| 6 | +require 'metasm/cpu/msp430/opcodes' |
| 7 | +require 'metasm/decode' |
| 8 | + |
| 9 | +module Metasm |
| 10 | +class MSP430 |
| 11 | + def build_opcode_bin_mask(op) |
| 12 | + op.bin_mask = 0 |
| 13 | + op.fields.each_key { |f| |
| 14 | + op.bin_mask |= @fields_mask[f] << @fields_shift[f] |
| 15 | + } |
| 16 | + op.bin_mask ^= 0xffff |
| 17 | + end |
| 18 | + |
| 19 | + def build_bin_lookaside |
| 20 | + lookaside = Array.new(256) { [] } |
| 21 | + opcode_list.each { |op| |
| 22 | + build_opcode_bin_mask op |
| 23 | + b = (op.bin >> 8) & 255 |
| 24 | + msk = (op.bin_mask >> 8) & 255 |
| 25 | + |
| 26 | + for i in b..(b | (255^msk)) |
| 27 | + lookaside[i] << op if i & msk == b & msk |
| 28 | + end |
| 29 | + } |
| 30 | + lookaside |
| 31 | + end |
| 32 | + |
| 33 | + def decode_findopcode(edata) |
| 34 | + di = DecodedInstruction.new(self) |
| 35 | + val = edata.decode_imm(:u16, @endianness) |
| 36 | + edata.ptr -= 2 |
| 37 | + di.opcode = @bin_lookaside[(val >> 8) & 0xff].find { |opcode| (val & opcode.bin_mask) == opcode.bin } |
| 38 | + di if di.opcode |
| 39 | + end |
| 40 | + |
| 41 | + def decode_instr_op(edata, di) |
| 42 | + before_ptr = edata.ptr |
| 43 | + op = di.opcode |
| 44 | + di.instruction.opname = op.name |
| 45 | + val = edata.decode_imm(:u16, @endianness) |
| 46 | + |
| 47 | + field_val = lambda{ |f| |
| 48 | + (val >> @fields_shift[f]) & @fields_mask[f] |
| 49 | + } |
| 50 | + |
| 51 | + # must decode rs first |
| 52 | + vals = {} |
| 53 | + ([:rs, :rd, :r_pc] & op.args).each { |a| |
| 54 | + mod = { :rs => :as, :rd => :ad, :r_pc => :ad }[a] |
| 55 | + mod = :as if mod == :ad and not op.fields[mod] # addop_macro1 -> rs + ad |
| 56 | + |
| 57 | + if a == :r_pc |
| 58 | + r = Reg.new(0) |
| 59 | + else |
| 60 | + r = Reg.new(field_val[a]) |
| 61 | + end |
| 62 | + |
| 63 | + w = op.props[:byte] ? 1 : 2 |
| 64 | + |
| 65 | + case field_val[mod] |
| 66 | + when 0 |
| 67 | + if r.i == 3 and a == :rs |
| 68 | + vals[a] = Expression[0] |
| 69 | + else |
| 70 | + vals[a] = r |
| 71 | + end |
| 72 | + when 1 |
| 73 | + if r.i == 3 and a == :rs |
| 74 | + vals[a] = Expression[1] |
| 75 | + else |
| 76 | + imm = edata.decode_imm(:u16, @endianness) |
| 77 | + r = nil if r.i == 2 # [imm] |
| 78 | + vals[a] = Memref.new(r, imm, w) |
| 79 | + end |
| 80 | + when 2 |
| 81 | + if r.i == 3 |
| 82 | + vals[a] = Expression[2] |
| 83 | + elsif r.i == 2 |
| 84 | + vals[a] = Expression[4] |
| 85 | + else |
| 86 | + vals[a] = Memref.new(r, 0, w) |
| 87 | + end |
| 88 | + when 3 |
| 89 | + if r.i == 3 |
| 90 | + vals[a] = Expression[-1] |
| 91 | + elsif r.i == 2 |
| 92 | + vals[a] = Expression[8] |
| 93 | + elsif r.i == 0 # pc++ |
| 94 | + # XXX order wrt other edata.decode_imm ? |
| 95 | + vals[a] = Expression[edata.decode_imm(:u16, @endianness)] |
| 96 | + else |
| 97 | + vals[a] = Memref.new(r, 0, w, true) |
| 98 | + end |
| 99 | + end |
| 100 | + } |
| 101 | + |
| 102 | + op.args.each { |a| |
| 103 | + di.instruction.args << case a |
| 104 | + when :joff; Expression[2 * Expression.make_signed(field_val[a], 10)] |
| 105 | + when :rs, :rd, :r_pc; vals[a] |
| 106 | + else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}" |
| 107 | + end |
| 108 | + } |
| 109 | + |
| 110 | + di.bin_length += edata.ptr - before_ptr |
| 111 | + |
| 112 | + return if edata.ptr > edata.length |
| 113 | + |
| 114 | + di |
| 115 | + end |
| 116 | + |
| 117 | + def decode_instr_interpret(di, addr) |
| 118 | + if di.opcode.props[:setip] and di.opcode.name =~ /^j/ |
| 119 | + delta = di.instruction.args.last.reduce |
| 120 | + arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce |
| 121 | + di.instruction.args[-1] = Expression[arg] |
| 122 | + end |
| 123 | + |
| 124 | + di |
| 125 | + end |
| 126 | + |
| 127 | + def backtrace_binding |
| 128 | + @backtrace_binding ||= init_backtrace_binding |
| 129 | + end |
| 130 | + |
| 131 | + def init_backtrace_binding |
| 132 | + @backtrace_binding ||= {} |
| 133 | + |
| 134 | + opcode_list.map { |ol| ol.name }.uniq.each { |op| |
| 135 | + @backtrace_binding[op] ||= case op |
| 136 | + when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] }} |
| 137 | + when 'cmp', 'test'; lambda { |di, *a| {} } # TODO |
| 138 | + when 'add', 'adc' ; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } } |
| 139 | + when 'sub', 'sbc'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } } |
| 140 | + when 'and'; lambda { |di, a0, a1| { a0 => Expression[a0, :&, a1] } } |
| 141 | + when 'or'; lambda { |di, a0, a1| { a0 => Expression[a0, :|, a1] } } |
| 142 | + when 'xor'; lambda { |di, a0, a1| { a0 => Expression[a0, :^, a1] } } |
| 143 | + when 'push'; lambda { |di, a0| { Indirection[:sp, 2] => Expression[a0], |
| 144 | + :sp => Expression[:sp, :-, 2] } } |
| 145 | + when 'call'; lambda { |di, a0| { Indirection[:sp, 2] => Expression[di.next_addr], |
| 146 | + :sp => Expression[:sp, :-, 2] } } |
| 147 | + when 'pop'; lambda { |di, a0| { a0 => Expression[Indirection[:sp, 2]], |
| 148 | + :sp => Expression[:sp, :+, 2] } } |
| 149 | + when 'ret'; lambda { |di| { :sp => Expression[:sp, :+, 2] } } |
| 150 | + when 'reti'; lambda { |di| { :sp => Expression[:sp, :+, 4] } } |
| 151 | + when /^j/; lambda { |di, a0| {} } |
| 152 | + end |
| 153 | + } |
| 154 | + |
| 155 | + @backtrace_binding |
| 156 | + end |
| 157 | + |
| 158 | + def get_backtrace_binding(di) |
| 159 | + a = di.instruction.args.map { |arg| |
| 160 | + case arg |
| 161 | + when Reg; arg.symbolic |
| 162 | + when Memref; arg.symbolic(di.address) |
| 163 | + else arg |
| 164 | + end |
| 165 | + } |
| 166 | + |
| 167 | + if binding = backtrace_binding[di.opcode.basename] |
| 168 | + bd = binding[di, *a] || {} |
| 169 | + di.instruction.args.grep(Memref).each { |m| |
| 170 | + next unless r = m.base and m.postincr |
| 171 | + r = m.base.symbolic |
| 172 | + bd[r] ||= Expression[r, :+, m.size] |
| 173 | + } |
| 174 | + bd |
| 175 | + else |
| 176 | + puts "unhandled instruction to backtrace: #{di}" if $VERBOSE |
| 177 | + { :incomplete_binding => Expression[1] } |
| 178 | + end |
| 179 | + end |
| 180 | + |
| 181 | + def get_xrefs_x(dasm, di) |
| 182 | + return [] if not di.opcode.props[:setip] |
| 183 | + |
| 184 | + case di.instruction.opname |
| 185 | + when 'ret' |
| 186 | + return [Indirection[:sp, 2, di.address]] |
| 187 | + when 'reti' |
| 188 | + return [Indirection[[:sp, :+, 2], 2, di.address]] |
| 189 | + end |
| 190 | + |
| 191 | + # XXX add pc, 42 ? |
| 192 | + val = di.instruction.args[0] |
| 193 | + case val |
| 194 | + when Reg; val = val.symbolic |
| 195 | + when Memref; val = val.symbolic(di.address) |
| 196 | + end |
| 197 | + |
| 198 | + [Expression[val]] |
| 199 | + end |
| 200 | + |
| 201 | + def backtrace_is_function_return(expr, di=nil) |
| 202 | + expr = Expression[expr].reduce_rec |
| 203 | + expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp] |
| 204 | + end |
| 205 | + |
| 206 | + # updates the function backtrace_binding |
| 207 | + # if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand) |
| 208 | + def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs) |
| 209 | + b = f.backtrace_binding |
| 210 | + |
| 211 | + bt_val = lambda { |r| |
| 212 | + next if not retaddrlist |
| 213 | + b[r] = Expression::Unknown |
| 214 | + bt = [] |
| 215 | + retaddrlist.each { |retaddr| |
| 216 | + bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true, |
| 217 | + :snapshot_addr => faddr, :origin => retaddr) |
| 218 | + } |
| 219 | + if bt.length != 1 |
| 220 | + b[r] = Expression::Unknown |
| 221 | + else |
| 222 | + b[r] = bt.first |
| 223 | + end |
| 224 | + } |
| 225 | + |
| 226 | + if not wantregs.empty? |
| 227 | + wantregs.each(&bt_val) |
| 228 | + else |
| 229 | + bt_val[:sp] |
| 230 | + end |
| 231 | + |
| 232 | + b |
| 233 | + end |
| 234 | + |
| 235 | + def replace_instr_arg_immediate(i, old, new) |
| 236 | + i.args.map! { |a| |
| 237 | + case a |
| 238 | + when Expression; a == old ? new : Expression[a.bind(old => new).reduce] |
| 239 | + when Memref |
| 240 | + a.base = (a.base == old ? new : Expression[a.base.bind(old => new).reduce]) if a.base.kind_of?(Expression) |
| 241 | + a |
| 242 | + else a |
| 243 | + end |
| 244 | + } |
| 245 | + end |
| 246 | +end |
| 247 | +end |
0 commit comments