metasm 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +3 -2
  5. data/metasm.gemspec +3 -2
  6. data/metasm.rb +4 -1
  7. data/metasm/compile_c.rb +2 -2
  8. data/metasm/cpu/arc/decode.rb +0 -21
  9. data/metasm/cpu/arc/main.rb +4 -4
  10. data/metasm/cpu/arm/decode.rb +1 -5
  11. data/metasm/cpu/arm/main.rb +3 -3
  12. data/metasm/cpu/arm64/decode.rb +2 -6
  13. data/metasm/cpu/arm64/main.rb +5 -5
  14. data/metasm/cpu/bpf/decode.rb +3 -35
  15. data/metasm/cpu/bpf/main.rb +5 -5
  16. data/metasm/cpu/bpf/render.rb +1 -12
  17. data/metasm/cpu/cy16/decode.rb +0 -6
  18. data/metasm/cpu/cy16/main.rb +3 -3
  19. data/metasm/cpu/cy16/render.rb +0 -11
  20. data/metasm/cpu/dalvik/decode.rb +4 -26
  21. data/metasm/cpu/dalvik/main.rb +20 -2
  22. data/metasm/cpu/dalvik/opcodes.rb +3 -2
  23. data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
  24. data/metasm/cpu/ebpf/debug.rb +61 -0
  25. data/metasm/cpu/ebpf/decode.rb +142 -0
  26. data/metasm/cpu/ebpf/main.rb +58 -0
  27. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  28. data/metasm/cpu/ebpf/render.rb +36 -0
  29. data/metasm/cpu/ia32/debug.rb +39 -1
  30. data/metasm/cpu/ia32/decode.rb +111 -90
  31. data/metasm/cpu/ia32/decompile.rb +45 -37
  32. data/metasm/cpu/ia32/main.rb +10 -0
  33. data/metasm/cpu/ia32/parse.rb +6 -0
  34. data/metasm/cpu/mcs51/decode.rb +1 -1
  35. data/metasm/cpu/mcs51/main.rb +11 -0
  36. data/metasm/cpu/mips/decode.rb +8 -18
  37. data/metasm/cpu/mips/main.rb +3 -3
  38. data/metasm/cpu/mips/opcodes.rb +1 -1
  39. data/metasm/cpu/msp430/decode.rb +2 -6
  40. data/metasm/cpu/msp430/main.rb +3 -3
  41. data/metasm/cpu/openrisc.rb +11 -0
  42. data/metasm/cpu/openrisc/debug.rb +106 -0
  43. data/metasm/cpu/openrisc/decode.rb +182 -0
  44. data/metasm/cpu/openrisc/decompile.rb +350 -0
  45. data/metasm/cpu/openrisc/main.rb +70 -0
  46. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  47. data/metasm/cpu/openrisc/render.rb +37 -0
  48. data/metasm/cpu/ppc/decode.rb +0 -25
  49. data/metasm/cpu/ppc/main.rb +6 -6
  50. data/metasm/cpu/ppc/opcodes.rb +3 -4
  51. data/metasm/cpu/python/decode.rb +0 -20
  52. data/metasm/cpu/python/main.rb +1 -1
  53. data/metasm/cpu/sh4/decode.rb +2 -6
  54. data/metasm/cpu/sh4/main.rb +25 -23
  55. data/metasm/cpu/st20/decode.rb +0 -7
  56. data/metasm/cpu/webasm.rb +11 -0
  57. data/metasm/cpu/webasm/debug.rb +31 -0
  58. data/metasm/cpu/webasm/decode.rb +321 -0
  59. data/metasm/cpu/webasm/decompile.rb +386 -0
  60. data/metasm/cpu/webasm/encode.rb +104 -0
  61. data/metasm/cpu/webasm/main.rb +81 -0
  62. data/metasm/cpu/webasm/opcodes.rb +214 -0
  63. data/metasm/cpu/x86_64/compile_c.rb +13 -9
  64. data/metasm/cpu/x86_64/parse.rb +1 -1
  65. data/metasm/cpu/z80/decode.rb +0 -27
  66. data/metasm/cpu/z80/main.rb +3 -3
  67. data/metasm/cpu/z80/render.rb +0 -11
  68. data/metasm/debug.rb +43 -8
  69. data/metasm/decode.rb +62 -14
  70. data/metasm/decompile.rb +793 -466
  71. data/metasm/disassemble.rb +188 -131
  72. data/metasm/disassemble_api.rb +30 -17
  73. data/metasm/dynldr.rb +2 -2
  74. data/metasm/encode.rb +8 -2
  75. data/metasm/exe_format/autoexe.rb +2 -0
  76. data/metasm/exe_format/coff.rb +21 -3
  77. data/metasm/exe_format/coff_decode.rb +12 -0
  78. data/metasm/exe_format/coff_encode.rb +6 -3
  79. data/metasm/exe_format/dex.rb +13 -3
  80. data/metasm/exe_format/elf.rb +12 -2
  81. data/metasm/exe_format/elf_decode.rb +59 -1
  82. data/metasm/exe_format/main.rb +2 -0
  83. data/metasm/exe_format/mz.rb +1 -0
  84. data/metasm/exe_format/pe.rb +25 -3
  85. data/metasm/exe_format/wasm.rb +402 -0
  86. data/metasm/gui/dasm_decomp.rb +171 -95
  87. data/metasm/gui/dasm_graph.rb +61 -2
  88. data/metasm/gui/dasm_hex.rb +2 -2
  89. data/metasm/gui/dasm_main.rb +45 -19
  90. data/metasm/gui/debug.rb +13 -4
  91. data/metasm/gui/gtk.rb +12 -4
  92. data/metasm/main.rb +108 -103
  93. data/metasm/os/emulator.rb +175 -0
  94. data/metasm/os/main.rb +11 -6
  95. data/metasm/parse.rb +23 -12
  96. data/metasm/parse_c.rb +189 -135
  97. data/metasm/preprocessor.rb +16 -1
  98. data/misc/openrisc-parser.rb +79 -0
  99. data/samples/dasm-plugins/scanxrefs.rb +6 -4
  100. data/samples/dasm-plugins/selfmodify.rb +8 -8
  101. data/samples/dbg-plugins/trace_func.rb +1 -1
  102. data/samples/disassemble-gui.rb +14 -3
  103. data/samples/emubios.rb +251 -0
  104. data/samples/emudbg.rb +127 -0
  105. data/samples/lindebug.rb +79 -78
  106. data/samples/metasm-shell.rb +8 -8
  107. data/tests/all.rb +1 -1
  108. data/tests/expression.rb +2 -0
  109. data/tests/graph_layout.rb +1 -1
  110. data/tests/ia32.rb +1 -0
  111. data/tests/mips.rb +1 -1
  112. data/tests/preprocessor.rb +18 -0
  113. metadata +124 -6
  114. metadata.gz.sig +0 -0
@@ -0,0 +1,350 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/cpu/openrisc/main'
8
+
9
+ module Metasm
10
+ class OpenRisc
11
+ # temporarily setup dasm.address_binding so that backtracking
12
+ # stack-related offsets resolve in :frameptr (relative to func start)
13
+ def decompile_makestackvars(dasm, funcstart, blocks)
14
+ oldfuncbd = dasm.address_binding[funcstart]
15
+ dasm.address_binding[funcstart] = { :r1 => :frameptr }
16
+ blocks.each { |block| yield block }
17
+ dasm.address_binding[funcstart] = oldfuncbd if oldfuncbd
18
+ end
19
+
20
+ # add di-specific registry written/accessed
21
+ def decompile_func_finddeps_di(dcmp, func, di, a, w)
22
+ a << abi_funcall[:retval] if di.instruction.to_s == 'jr r9' and (not func.type.kind_of?(C::BaseType) or func.type.type.name != :void) # standard ABI
23
+ end
24
+
25
+ # list of register symbols
26
+ def register_symbols
27
+ @dbg_register_list ||= (1..31).to_a.map { |i| "r#{i}".to_sym }
28
+ end
29
+
30
+ # returns a hash { :retval => r, :changed => [] }
31
+ def abi_funcall
32
+ { :retval => :r11, :changed => [3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].map { |n| "r#{n}".to_sym }, :args => [:r3, :r4, :r5, :r6, :r7, :r8] }
33
+ end
34
+
35
+ # list variable dependency for each block, remove useless writes
36
+ # returns { blockaddr => [list of vars that are needed by a following block] }
37
+ def decompile_func_finddeps(dcmp, blocks, func)
38
+ deps_r = {} ; deps_w = {} ; deps_to = {}
39
+ deps_subfunc = {} # things read/written by subfuncs
40
+
41
+ # find read/writes by each block
42
+ blocks.each { |b, to|
43
+ deps_r[b] = [] ; deps_w[b] = [] ; deps_to[b] = to
44
+ deps_subfunc[b] = []
45
+
46
+ blk = dcmp.dasm.decoded[b].block
47
+ blk.list.each { |di|
48
+ a = di.backtrace_binding.values
49
+ w = []
50
+ di.backtrace_binding.keys.each { |k|
51
+ case k
52
+ when ::Symbol; w |= [k]
53
+ else a |= Expression[k].externals # if dword [eax] <- 42, eax is read
54
+ end
55
+ }
56
+ decompile_func_finddeps_di(dcmp, func, di, a, w)
57
+
58
+ deps_r[b] |= a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - deps_w[b]
59
+ deps_w[b] |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
60
+ }
61
+ subfunccall = false
62
+ blk.each_to_normal { |t|
63
+ t = dcmp.backtrace_target(t, blk.list.last.address)
64
+ next if not t = dcmp.c_parser.toplevel.symbol[t]
65
+ t.type = C::Function.new(C::BaseType.new(:int)) if not t.type.kind_of?(C::Function) # XXX this may seem a bit extreme, and yes, it is.
66
+ subfunccall = true
67
+ t.type.args.to_a.each { |arg|
68
+ if reg = arg.has_attribute('register')
69
+ deps_subfunc[b] |= [reg.to_sym]
70
+ end
71
+ }
72
+ }
73
+ if subfunccall # last block instr == subfunction call
74
+ deps_r[b] |= deps_subfunc[b] - deps_w[b]
75
+ deps_w[b] |= abi_funcall[:changed]
76
+ end
77
+ }
78
+
79
+ bt = blocks.transpose
80
+ roots = bt[0] - bt[1].flatten # XXX jmp 1stblock ?
81
+
82
+ # find regs read and never written (must have been set by caller and are part of the func ABI)
83
+ uninitialized = lambda { |b, r, done|
84
+ if not deps_r[b]
85
+ elsif deps_r[b].include?(r)
86
+ blk = dcmp.dasm.decoded[b].block
87
+ bw = []
88
+ rdi = blk.list.find { |di|
89
+ a = di.backtrace_binding.values
90
+ w = []
91
+ di.backtrace_binding.keys.each { |k|
92
+ case k
93
+ when ::Symbol; w |= [k]
94
+ else a |= Expression[k].externals # if dword [eax] <- 42, eax is read
95
+ end
96
+ }
97
+ decompile_func_finddeps_di(dcmp, func, di, a, w)
98
+
99
+ next true if (a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - bw).include?(r)
100
+ bw |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
101
+ false
102
+ }
103
+ if decompile_func_abi_fcallret(r, rdi, blk)
104
+ func.type.type = C::BaseType.new(:void)
105
+ false
106
+ elsif rdi and rdi.backtrace_binding[r]
107
+ false # mov al, 42 ; ret -> don't regarg eax
108
+ else
109
+ true
110
+ end
111
+ elsif deps_w[b].include?(r)
112
+ else
113
+ done << b
114
+ (deps_to[b] - done).find { |tb| uninitialized[tb, r, done] }
115
+ end
116
+ }
117
+
118
+ regargs = []
119
+ register_symbols.each { |r|
120
+ if roots.find { |root| uninitialized[root, r, []] }
121
+ regargs << r
122
+ end
123
+ }
124
+
125
+ # TODO honor user-defined prototype if available (eg no, really, eax is not read in this function returning al)
126
+ regargs.sort_by { |r| r.to_s }.each { |r|
127
+ a = C::Variable.new(r.to_s, C::BaseType.new(:int, :unsigned))
128
+ a.add_attribute("register(#{r})")
129
+ func.type.args << a
130
+ }
131
+
132
+ # remove writes from a block if no following block read the value
133
+ dw = {}
134
+ deps_w.each { |b, deps|
135
+ dw[b] = deps.reject { |dep|
136
+ ret = true
137
+ done = []
138
+ todo = deps_to[b].dup
139
+ while a = todo.pop
140
+ next if done.include?(a)
141
+ done << a
142
+ if not deps_r[a] or deps_r[a].include?(dep)
143
+ ret = false
144
+ break
145
+ elsif not deps_w[a].include?(dep)
146
+ todo.concat deps_to[a]
147
+ end
148
+ end
149
+ ret
150
+ }
151
+ }
152
+
153
+ dw
154
+ end
155
+
156
+ # return true if r is the implicit register read made by the subfunction return instruction to symbolize the return value ABI
157
+ def decompile_func_abi_fcallret(r, rdi, blk)
158
+ rdi ||= blk.list[-1-@delay_slot]
159
+ return if not rdi
160
+ r == abi_funcall[:retval] and rdi.instruction.to_s == 'jr r9'
161
+ end
162
+
163
+ def decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil)
164
+ scope = func.initializer
165
+ func.type.args.each { |a| scope.symbol[a.name] = a }
166
+ stmts = scope.statements
167
+ blocks_toclean = myblocks.dup
168
+ func_entry = myblocks.first[0]
169
+ until myblocks.empty?
170
+ b, to = myblocks.shift
171
+ if l = dcmp.dasm.get_label_at(b)
172
+ stmts << C::Label.new(l)
173
+ end
174
+
175
+ # list of assignments [[dest reg, expr assigned]]
176
+ ops = []
177
+ # reg binding (reg => value, values.externals = regs at block start)
178
+ binding = {}
179
+ # Expr => CExpr
180
+ ce = lambda { |*e| dcmp.decompile_cexpr(Expression[Expression[*e].reduce], scope) }
181
+ # Expr => Expr.bind(binding) => CExpr
182
+ ceb = lambda { |*e| ce[Expression[*e].bind(binding)] }
183
+
184
+ # dumps a CExprs that implements an assignment to a reg (uses ops[], patches op => [reg, nil])
185
+ commit = lambda {
186
+ deps[b].map { |k|
187
+ [k, ops.rindex(ops.reverse.find { |r, v| r == k })]
188
+ }.sort_by { |k, i| i.to_i }.each { |k, i|
189
+ next if not i or not binding[k]
190
+ e = k
191
+ final = []
192
+ ops[0..i].reverse_each { |r, v|
193
+ final << r if not v
194
+ e = Expression[e].bind(r => v).reduce if not final.include?(r)
195
+ }
196
+ ops[i][1] = nil
197
+ binding.delete k
198
+ stmts << ce[k, :'=', e] if k != e
199
+ }
200
+ }
201
+
202
+ # returns an array to use as funcall arguments
203
+ get_func_args = lambda { |di, f|
204
+ # XXX see remarks in #finddeps
205
+ args_todo = f.type.args.to_a.dup
206
+ args = []
207
+ args_abi = abi_funcall[:args].dup
208
+ args_todo.each { |a_|
209
+ if r = a_.has_attribute_var('register')
210
+ args << Expression[r.to_sym]
211
+ args_abi.delete r.to_sym
212
+ else
213
+ args << Expression[args_abi.shift]
214
+ end
215
+ }
216
+
217
+ if f.type.varargs
218
+ nargs = 1
219
+ if f.type.args.last.type.pointer?
220
+ # check if last arg is a fmtstring
221
+ bt = dcmp.dasm.backtrace(args.last, di.block.list.last.address, :snapshot_addr => func_entry, :include_start => true)
222
+ if bt.length == 1 and s = dcmp.dasm.get_section_at(bt.first)
223
+ fmt = s[0].read(512)
224
+ fmt = fmt.unpack('v*').pack('C*') if dcmp.sizeof(f.type.args.last.type.untypedef.type) == 2
225
+ if fmt.index(?\0)
226
+ fmt = fmt[0...fmt.index(?\0)]
227
+ nargs = fmt.gsub('%%', '').count('%') # XXX %.*s etc..
228
+ end
229
+ end
230
+ end
231
+ bt = dcmp.dasm.backtrace(:r1, di.block.list.last.address, :snapshot_addr => func_entry, :include_start => true)
232
+ stackoff = Expression[bt, :-, :r1].bind(:r1 => :frameptr).reduce rescue nil
233
+ if stackoff and nargs > 0
234
+ nargs.times {
235
+ args << Indirection[[:frameptr, :+, stackoff], @size/8]
236
+ stackoff += @size/8
237
+ }
238
+ end
239
+ end
240
+
241
+ args.map { |e| ceb[e] }
242
+ }
243
+
244
+ # go !
245
+ di_list = dcmp.dasm.decoded[b].block.list.dup
246
+ if di_list[-2] and di_list[-2].opcode.props[:setip] and @delay_slot > 0
247
+ di_list[-1], di_list[-2] = di_list[-2], di_list[-1]
248
+ end
249
+ di_list.each { |di|
250
+ if di.opcode.props[:setip] and not di.opcode.props[:stopexec]
251
+ # conditional jump
252
+ commit[]
253
+ n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
254
+ if di.opcode.name == /bfeq/
255
+ cc = ceb[:flag]
256
+ else
257
+ cc = ceb[:!, :flag]
258
+ end
259
+ # XXX switch/indirect/multiple jmp
260
+ stmts << C::If.new(C::CExpression[cc], C::Goto.new(n))
261
+ to.delete dcmp.dasm.normalize(n)
262
+ next
263
+ end
264
+
265
+ if di.instruction.to_s == 'jr r9'
266
+ commit[]
267
+ ret = C::CExpression[ceb[abi_funcall[:retval]]] unless func.type.type.kind_of?(C::BaseType) and func.type.type.name == :void
268
+ stmts << C::Return.new(ret)
269
+ elsif di.opcode.name == 'jal' or di.opcode.name == 'jalr'
270
+ n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
271
+ args = []
272
+ if f = dcmp.c_parser.toplevel.symbol[n] and f.type.kind_of?(C::Function) and f.type.args
273
+ args = get_func_args[di, f]
274
+ end
275
+ commit[]
276
+ #next if not di.block.to_subfuncret
277
+
278
+ if not n.kind_of?(::String) or (f and not f.type.kind_of?(C::Function))
279
+ # indirect funcall
280
+ fptr = ceb[n]
281
+ binding.delete n
282
+ proto = C::Function.new(C::BaseType.new(:int))
283
+ proto = f.type if f and f.type.kind_of?(C::Function)
284
+ f = C::CExpression[[fptr], C::Pointer.new(proto)]
285
+ elsif not f
286
+ # internal functions are predeclared, so this one is extern
287
+ f = C::Variable.new
288
+ f.name = n
289
+ f.type = C::Function.new(C::BaseType.new(:int))
290
+ if dcmp.recurse > 0
291
+ dcmp.c_parser.toplevel.symbol[n] = f
292
+ dcmp.c_parser.toplevel.statements << C::Declaration.new(f)
293
+ end
294
+ end
295
+ commit[]
296
+ binding.delete abi_funcall[:retval]
297
+ e = C::CExpression[f, :funcall, args]
298
+ e = C::CExpression[ce[abi_funcall[:retval]], :'=', e, f.type.type] if deps[b].include?(abi_funcall[:retval]) and f.type.type != C::BaseType.new(:void)
299
+ stmts << e
300
+ else
301
+ bd = get_fwdemu_binding(di)
302
+ if di.backtrace_binding[:incomplete_binding]
303
+ commit[]
304
+ stmts << C::Asm.new(di.instruction.to_s, nil, nil, nil, nil, nil)
305
+ else
306
+ update = {}
307
+ bd.each { |k, v|
308
+ if k.kind_of?(::Symbol) and not deps[b].include?(k)
309
+ ops << [k, v]
310
+ update[k] = Expression[Expression[v].bind(binding).reduce]
311
+ else
312
+ stmts << ceb[k, :'=', v]
313
+ stmts.pop if stmts.last.kind_of?(C::Variable) # [:eflag_s, :=, :unknown].reduce
314
+ end
315
+ }
316
+ binding.update update
317
+ end
318
+ end
319
+ }
320
+ commit[]
321
+
322
+ case to.length
323
+ when 0
324
+ if not myblocks.empty? and (dcmp.dasm.decoded[b].block.list[-1-@delay_slot].instruction.to_s != 'jr r9' rescue true)
325
+ puts " block #{Expression[b]} has no to and don't end in ret"
326
+ end
327
+ when 1
328
+ if (myblocks.empty? ? nextaddr != to[0] : myblocks.first.first != to[0])
329
+ stmts << C::Goto.new(dcmp.dasm.auto_label_at(to[0], 'unknown_goto'))
330
+ end
331
+ else
332
+ puts " block #{Expression[b]} with multiple to"
333
+ end
334
+ end
335
+
336
+ # cleanup di.bt_binding (we set :frameptr etc in those, this may confuse the dasm)
337
+ blocks_toclean.each { |b_, to_|
338
+ dcmp.dasm.decoded[b_].block.list.each { |di|
339
+ di.backtrace_binding = nil
340
+ }
341
+ }
342
+ end
343
+
344
+ def decompile_check_abi(dcmp, entry, func)
345
+ a = func.type.args || []
346
+ # TODO check abi_funcall[:args], dont delete r4 __unused if r5 is used
347
+ a.delete_if { |arg| arg.has_attribute_var('register') and arg.has_attribute('unused') }
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,70 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/main'
8
+
9
+ module Metasm
10
+ class OpenRisc < CPU
11
+ class Reg
12
+ attr_accessor :v
13
+ def initialize(v)
14
+ @v = v
15
+ end
16
+
17
+ def symbolic(di=nil)
18
+ if @v != 0 or not di or di.instruction.args[0].object_id == self.object_id
19
+ "r#@v".to_sym
20
+ else
21
+ # r0 is always 0, but we still return :r0 when writing to it (ie its the 1st instr arg)
22
+ Expression[0]
23
+ end
24
+ end
25
+ end
26
+
27
+ class FpReg
28
+ attr_accessor :v
29
+ def initialize(v)
30
+ @v = v
31
+ end
32
+
33
+ def symbolic(di=nil) ; "f#@v".to_sym ; end
34
+ end
35
+
36
+ class Memref
37
+ attr_accessor :base, :offset, :msz
38
+
39
+ def initialize(base, offset, msz)
40
+ @base = base
41
+ @offset = offset
42
+ @msz = msz
43
+ end
44
+
45
+ def symbolic(di)
46
+ p = Expression[@base.symbolic] if base
47
+ p = Expression[p, :+, @offset] if offset
48
+ Indirection[p.reduce, @msz, (di.address if di)]
49
+ end
50
+ end
51
+
52
+ def initialize(family = :latest, endianness = :big, delay_slot = 1)
53
+ super()
54
+ @endianness = endianness
55
+ @size = 32
56
+ @family = family
57
+ @delay_slot = delay_slot
58
+ end
59
+
60
+ def init_opcode_list
61
+ send("init_#@family")
62
+ @opcode_list
63
+ end
64
+
65
+ def delay_slot(di=nil)
66
+ @delay_slot
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,109 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ require 'metasm/cpu/openrisc/main'
7
+
8
+ module Metasm
9
+
10
+ # https://github.com/s-macke/jor1k/blob/master/js/worker/or1k/safecpu.js
11
+ class OpenRisc
12
+ def addop(name, bin, *args)
13
+ o = Opcode.new name, bin
14
+ args.each { |a|
15
+ o.bin_mask = a if a.kind_of?(Integer)
16
+ o.args << a if @valid_args[a]
17
+ o.props.update a if a.kind_of?(::Hash)
18
+ }
19
+ @opcode_list << o
20
+ end
21
+
22
+ def init_or1k
23
+ @opcode_list = []
24
+ @valid_args = [ :rA, :rB, :rD, :fA, :fB, :fD, :disp26, :uimm16, :simm16, :uimm5, :rA_simm16, :rA_smoo ].inject({}) { |h, a| h.update a => true }
25
+ @fields_off = { :rD => 21, :rA => 16, :rB => 11, :disp26 => 0, :uimm16 => 0, :simm16 => 0, :uimm5 => 0, :smoo => 0 }
26
+ @fields_mask = { :rD => 0x1F, :rA => 0x1F, :rB => 0x1F, :disp26 => 0x3FFFFFF, :simm16 => 0xFFFF, :uimm16 => 0xFFFF, :uimm5 => 0x1F, :smoo => 0x3E007FF }
27
+
28
+ addop 'j', 0x0000_0000, 0x03FF_FFFF, :disp26, :setip => true, :stopexec => true
29
+ addop 'jal', 0x0400_0000, 0x03FF_FFFF, :disp26, :setip => true, :stopexec => true, :saveip => true
30
+ addop 'bnf', 0x0C00_0000, 0x03FF_FFFF, :disp26, :setip => true # branch if not flag
31
+ addop 'bf', 0x1000_0000, 0x03FF_FFFF, :disp26, :setip => true
32
+ addop 'nop', 0x1400_0000, 0x03FF_FFFF
33
+ addop 'movhi', 0x1800_0000, 0x03FE_FFFF, :rD, :uimm16
34
+ addop 'macrc', 0x1801_0000, 0x03FE_FFFF
35
+ addop 'trap', 0x2100_0000, 0x0000_FFFF
36
+ addop 'sys', 0x2000_0000, 0x03FF_FFFF # args ?
37
+ addop 'rfe', 0x2400_0000, 0x03FF_FFFF
38
+ addop 'jr', 0x4400_0000, 0x03FF_FFFF, :rB, :setip => true, :stopexec => true
39
+ addop 'jalr', 0x4800_0000, 0x03FF_FFFF, :rB, :setip => true, :stopexec => true, :saveip => true
40
+ addop 'lwa', 0x6C00_0000, 0x03FF_FFFF, :rD, :rA_simm16
41
+ addop 'lwz', 0x8400_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 4
42
+ addop 'lbz', 0x8C00_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 1
43
+ addop 'lbs', 0x9000_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 1 # lbz + sign-expand byte
44
+ addop 'lhz', 0x9400_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 2
45
+ addop 'lhs', 0x9800_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 2
46
+ addop 'add', 0x9C00_0000, 0x03FF_FFFF, :rD, :rA, :simm16
47
+ addop 'and', 0xA400_0000, 0x03FF_FFFF, :rD, :rA, :uimm16
48
+ addop 'or', 0xA800_0000, 0x03FF_FFFF, :rD, :rA, :uimm16
49
+ addop 'xor', 0xAC00_0000, 0x03FF_FFFF, :rD, :rA, :simm16
50
+ addop 'mfspr', 0xB400_0000, 0x03FF_FFFF, :rD, :rA, :simm16
51
+ addop 'shl', 0xB800_0000, 0x03FF_FF3F, :rD, :rA, :uimm5
52
+ addop 'ror', 0xB800_0040, 0x03FF_FF3F, :rD, :rA, :uimm5
53
+ addop 'sar', 0xB800_0080, 0x03FF_FF3F, :rD, :rA, :uimm5
54
+ addop 'sfeq', 0xBC00_0000, 0x001F_FFFF, :rA, :simm16
55
+ addop 'sfne', 0xBC20_0000, 0x001F_FFFF, :rA, :simm16
56
+ addop 'sfgtu', 0xBC40_0000, 0x001F_FFFF, :rA, :uimm16
57
+ addop 'sfgeu', 0xBC60_0000, 0x001F_FFFF, :rA, :uimm16
58
+ addop 'sfltu', 0xBC80_0000, 0x001F_FFFF, :rA, :uimm16
59
+ addop 'sfleu', 0xBCA0_0000, 0x001F_FFFF, :rA, :uimm16
60
+ addop 'sfgts', 0xBD40_0000, 0x001F_FFFF, :rA, :simm16
61
+ addop 'sfges', 0xBD60_0000, 0x001F_FFFF, :rA, :simm16
62
+ addop 'sflts', 0xBD80_0000, 0x001F_FFFF, :rA, :simm16
63
+ addop 'sfles', 0xBDA0_0000, 0x001F_FFFF, :rA, :simm16
64
+ addop 'mtspr', 0xC000_0000, 0x03FF_FFFF, :rA_smoo, :rB # smoo = (ins & 0x7ff) | ((ins >> 10) & 0xf800) ; setspr((rA|smoo), rB)
65
+ addop 'add', 0xC800_0000, 0x03FF_FF00, :fD, :fA, :fB # FPU
66
+ addop 'sub', 0xC800_0001, 0x03FF_FF00, :fD, :fA, :fB
67
+ addop 'mul', 0xC800_0002, 0x03FF_FF00, :fD, :fA, :fB
68
+ addop 'div', 0xC800_0003, 0x03FF_FF00, :fD, :fA, :fB
69
+ addop 'itof', 0xC800_0004, 0x03FF_FF00, :fD, :rA
70
+ addop 'ftoi', 0xC800_0005, 0x03FF_FF00, :rD, :fA
71
+ addop 'madd', 0xC800_0007, 0x03FF_FF00, :fD, :fA, :fB # fD += fA*fB
72
+ addop 'sfeq', 0xC800_0008, 0x03FF_FF00, :fA, :fB
73
+ addop 'sfne', 0xC800_0009, 0x03FF_FF00, :fA, :fB
74
+ addop 'sfgt', 0xC800_000A, 0x03FF_FF00, :fA, :fB
75
+ addop 'sfge', 0xC800_000B, 0x03FF_FF00, :fA, :fB
76
+ addop 'sflt', 0xC800_000C, 0x03FF_FF00, :fA, :fB
77
+ addop 'sfle', 0xC800_000D, 0x03FF_FF00, :fA, :fB
78
+ addop 'swa', 0xCC00_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 4 # sw + setf(ra_smoo == current_EA ?)
79
+ addop 'sw', 0xD400_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 4
80
+ addop 'sb', 0xD800_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 1
81
+ addop 'sh', 0xDC00_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 2
82
+ addop 'add', 0xE000_0000, 0x03FF_FC30, :rD, :rA, :rB
83
+ addop 'sub', 0xE000_0002, 0x03FF_FC30, :rD, :rA, :rB
84
+ addop 'and', 0xE000_0003, 0x03FF_FC30, :rD, :rA, :rB
85
+ addop 'or', 0xE000_0004, 0x03FF_FC30, :rD, :rA, :rB
86
+ addop 'xor', 0xE000_0005, 0x03FF_FC30, :rD, :rA, :rB
87
+ addop 'shl', 0xE000_0008, 0x03FF_FC30, :rD, :rA, :rB
88
+ addop 'ff1', 0xE000_000F, 0x03FF_FC30, :rD, :rA, :rB # find first bit == 1
89
+ addop 'shr', 0xE000_0048, 0x03FF_FC30, :rD, :rA, :rB
90
+ addop 'sar', 0xE000_0088, 0x03FF_FC30, :rD, :rA, :rB
91
+ addop 'fl1', 0xE000_010F, 0x03FF_FC30, :rD, :rA, :rB # find last bit
92
+ addop 'mul', 0xE000_0306, 0x03FF_FC30, :rD, :rA, :rB # signed multiply ?
93
+ addop 'div', 0xE000_0309, 0x03FF_FC30, :rD, :rA, :rB
94
+ addop 'divu', 0xE000_030A, 0x03FF_FC30, :rD, :rA, :rB # rD = rA&0xffffffff / rB&0xffffffff
95
+ addop 'sfeq', 0xE400_0000, 0x001F_FFFF, :rA, :rB
96
+ addop 'sfne', 0xE420_0000, 0x001F_FFFF, :rA, :rB
97
+ addop 'sfgtu', 0xE440_0000, 0x001F_FFFF, :rA, :rB
98
+ addop 'sfgeu', 0xE460_0000, 0x001F_FFFF, :rA, :rB
99
+ addop 'sfltu', 0xE480_0000, 0x001F_FFFF, :rA, :rB
100
+ addop 'sfleu', 0xE4A0_0000, 0x001F_FFFF, :rA, :rB
101
+ addop 'sfgts', 0xE540_0000, 0x001F_FFFF, :rA, :rB
102
+ addop 'sfges', 0xE560_0000, 0x001F_FFFF, :rA, :rB
103
+ addop 'sflts', 0xE580_0000, 0x001F_FFFF, :rA, :rB
104
+ addop 'sfles', 0xE5A0_0000, 0x001F_FFFF, :rA, :rB
105
+ end
106
+
107
+ alias init_latest init_or1k
108
+ end
109
+ end