metasm 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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