metasm 1.0.0

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 (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,11 @@
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
+ require 'metasm/mips/parse'
9
+ require 'metasm/mips/encode'
10
+ require 'metasm/mips/decode'
11
+ require 'metasm/mips/render'
@@ -0,0 +1,7 @@
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/mips/parse'
7
+ require 'metasm/compile_c'
@@ -0,0 +1,253 @@
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/mips/opcodes'
8
+ require 'metasm/decode'
9
+
10
+ module Metasm
11
+ class MIPS
12
+ def build_opcode_bin_mask(op)
13
+ # bit = 0 if can be mutated by an field value, 1 if fixed by opcode
14
+ op.bin_mask = 0
15
+ op.args.each { |f|
16
+ op.bin_mask |= @fields_mask[f] << @fields_shift[f]
17
+ }
18
+ op.bin_mask = 0xffffffff ^ op.bin_mask
19
+ end
20
+
21
+ def build_bin_lookaside
22
+ lookaside = Array.new(256) { [] }
23
+ opcode_list.each { |op|
24
+ build_opcode_bin_mask op
25
+
26
+ b = op.bin >> 24
27
+ msk = op.bin_mask >> 24
28
+
29
+ for i in b..(b | (255^msk))
30
+ next if i & msk != b & msk
31
+ lookaside[i] << op
32
+ end
33
+ }
34
+ lookaside
35
+ end
36
+
37
+ def decode_findopcode(edata)
38
+ return if edata.ptr >= edata.data.length
39
+ # TODO handle relocations !!
40
+ di = DecodedInstruction.new(self)
41
+ val = edata.decode_imm(:u32, @endianness)
42
+ edata.ptr -= 4
43
+ di if di.opcode = @bin_lookaside[val >> 24].find { |op|
44
+ (op.bin & op.bin_mask) == (val & op.bin_mask)
45
+ }
46
+ end
47
+
48
+ def decode_instr_op(edata, di)
49
+ # TODO handle relocations !!
50
+ before_ptr = edata.ptr
51
+ op = di.opcode
52
+ di.instruction.opname = op.name
53
+ val = edata.decode_imm(:u32, @endianness)
54
+
55
+ field_val = lambda { |f|
56
+ r = (val >> @fields_shift[f]) & @fields_mask[f]
57
+ # XXX do that cleanly (Expr.decode_imm)
58
+ case f
59
+ when :sa, :i16, :it; r = Expression.make_signed(r, 16)
60
+ when :i20; r = Expression.make_signed(r, 20)
61
+ when :i26; r = Expression.make_signed(r, 26)
62
+ else r
63
+ end
64
+ }
65
+
66
+ op.args.each { |a|
67
+ di.instruction.args << case a
68
+ when :rs, :rt, :rd; Reg.new field_val[a]
69
+ when :sa, :i16, :i20, :i26, :it; Expression[field_val[a]]
70
+ when :rs_i16; Memref.new Reg.new(field_val[:rs]), Expression[field_val[:i16]]
71
+ when :ft; FpReg.new field_val[a]
72
+ when :idm1, :idb; Expression['unsupported']
73
+ else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
74
+ end
75
+ }
76
+ di.bin_length += edata.ptr - before_ptr
77
+
78
+ di
79
+ end
80
+
81
+ # converts relative branch offsets to absolute addresses
82
+ # else just add the offset +off+ of the instruction + its length (off may be an Expression)
83
+ # assumes edata.ptr points just after the instruction (as decode_instr_op left it)
84
+ # do not call twice on the same di !
85
+ def decode_instr_interpret(di, addr)
86
+ if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.opcode.name[0] != ?t
87
+ delta = Expression[di.instruction.args.last, :<<, 2].reduce
88
+ if di.opcode.args.include? :i26
89
+ arg = Expression[[[addr, :+, di.bin_length], :&, 0xfc00_0000], :+, delta].reduce
90
+ else
91
+ arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
92
+ end
93
+ di.instruction.args[-1] = Expression[arg]
94
+ end
95
+
96
+ di
97
+ end
98
+
99
+ # hash opname => lambda { |di, *sym_args| binding }
100
+ def backtrace_binding
101
+ @backtrace_binding ||= init_backtrace_binding
102
+ end
103
+ def backtrace_binding=(b) @backtrace_binding = b end
104
+
105
+ def init_backtrace_binding
106
+ @backtrace_binding ||= {}
107
+ opcode_list.map { |ol| ol.name }.uniq.each { |op|
108
+ binding = case op
109
+ when 'break'
110
+ when 'bltzal', 'bgezal'; lambda { |di, *a|
111
+ # XXX $ra is set only if branch is taken...
112
+ { :$ra => Expression[Expression[di.address, :+, 2*di.bin_length].reduce] }
113
+ }
114
+ when 'nop', 'j', 'jr', /^b/; lambda { |di, *a| {} }
115
+ when 'lui'; lambda { |di, a0, a1| { a0 => Expression[a1, :<<, 16] } }
116
+ when 'add', 'addu', 'addi', 'addiu'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :+, a2] } } # XXX addiu $sp, -40h should be addiu $sp, 0xffc0 from the books, but..
117
+ when 'sub', 'subu'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :-, a2] } }
118
+ when 'slt', 'slti'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :<, a2] } }
119
+ when 'and', 'andi'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :&, a2] } }
120
+ when 'or', 'ori'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :|, a2] } }
121
+ when 'nor'; lambda { |di, a0, a1, a2| { a0 => Expression[:~, [a1, :|, a2]] } }
122
+ when 'xor'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :^, a2] } }
123
+ when 'sll', 'sllv'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :>>, a2] } }
124
+ when 'srl', 'srlv', 'sra', 'srav'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :<<, a2] } } # XXX sign-extend
125
+ when 'lw'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
126
+ when 'sw'; lambda { |di, a0, a1| { a1 => Expression[a0] } }
127
+ when 'lh', 'lhu'; lambda { |di, a0, a1| { a0 => Expression[a1] } } # XXX sign-extend
128
+ when 'sh'; lambda { |di, a0, a1| { a1 => Expression[a0] } }
129
+ when 'lb', 'lbu'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
130
+ when 'sb'; lambda { |di, a0, a1| { a1 => Expression[a0] } }
131
+ when /^slti?u?/; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :<, a2] } } # XXX signedness
132
+ when 'mfhi'; lambda { |di, a0| { a0 => Expression[:hi] } }
133
+ when 'mflo'; lambda { |di, a0| { a0 => Expression[:lo] } }
134
+ when 'mult'; lambda { |di, a0, a1| { :hi => Expression[[a0, :*, a1], :>>, 32], :lo => Expression[[a0, :*, a1], :&, 0xffff_ffff] } }
135
+ when 'div'; lambda { |di, a0, a1| { :hi => Expression[a0, :%, a1], :lo => Expression[a0, :/, a1] } }
136
+ when 'jal', 'jalr'; lambda { |di, a0| { :$ra => Expression[Expression[di.address, :+, 2*di.bin_length].reduce] } }
137
+ when 'li', 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
138
+ when 'syscall'; lambda { |di, *a| { :$v0 => Expression::Unknown } }
139
+ end
140
+
141
+ @backtrace_binding[op] ||= binding if binding
142
+ }
143
+ @backtrace_binding
144
+ end
145
+
146
+ def get_backtrace_binding(di)
147
+ a = di.instruction.args.map { |arg|
148
+ case arg
149
+ when Memref; arg.symbolic(di.address)
150
+ when Reg; arg.symbolic
151
+ else arg
152
+ end
153
+ }
154
+
155
+ binding = if binding = backtrace_binding[di.instruction.opname]
156
+ binding[di, *a]
157
+ else
158
+ if di.instruction.opname[0] == ?b and di.opcode.props[:setip]
159
+ else
160
+ puts "unknown instruction to emu #{di}" if $VERBOSE
161
+ end
162
+ {}
163
+ end
164
+
165
+ binding.delete 0 # allow add $zero, 42 => nop
166
+
167
+ binding
168
+ end
169
+
170
+ def get_xrefs_x(dasm, di)
171
+ return [] if not di.opcode.props[:setip]
172
+
173
+ arg = di.instruction.args.last
174
+ [Expression[
175
+ case arg
176
+ when Memref; Indirection[[arg.base.to_s.to_sym, :+, arg.offset], @size/8, di.address]
177
+ when Reg; arg.to_s.to_sym
178
+ else arg
179
+ end]]
180
+ end
181
+
182
+ def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
183
+ retaddrlist.map! { |retaddr| dasm.decoded[retaddr] ? dasm.decoded[retaddr].block.list.last.address : retaddr } if retaddrlist
184
+ b = f.backtrace_binding
185
+
186
+ bt_val = lambda { |r|
187
+ next if not retaddrlist
188
+ bt = []
189
+ b[r] = Expression::Unknown # break recursive dep
190
+ retaddrlist.each { |retaddr|
191
+ bt |= dasm.backtrace(Expression[r], retaddr,
192
+ :include_start => true, :snapshot_addr => faddr, :origin => retaddr)
193
+ }
194
+ b[r] = ((bt.length == 1) ? bt.first : Expression::Unknown)
195
+ }
196
+ wantregs = Reg.i_to_s.values if wantregs.empty?
197
+ wantregs.map { |r| r.to_sym }.each(&bt_val)
198
+
199
+ puts "update_func_bind: #{Expression[faddr]} has sp -> #{b[:$sp]}" if not Expression[b[:$sp], :-, :$sp].reduce.kind_of?(::Integer) if $VERBOSE
200
+ end
201
+
202
+ def backtrace_is_function_return(expr, di=nil)
203
+ expr.reduce_rec == :$ra
204
+ end
205
+
206
+ def backtrace_is_stack_address(expr)
207
+ Expression[expr].expr_externals.include? :$sp
208
+ end
209
+
210
+ def replace_instr_arg_immediate(i, old, new)
211
+ i.args.map! { |a|
212
+ case a
213
+ when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
214
+ when Memref
215
+ a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset
216
+ a
217
+ else a
218
+ end
219
+ }
220
+ end
221
+
222
+ # make the target of the call know the value of $t9 (specified by the ABI)
223
+ # XXX hackish
224
+ def backtrace_found_result(dasm, di, expr, type, len)
225
+ if di.opcode.name == 'jalr' and di.instruction.args == [:$t9]
226
+ expr = dasm.normalize(expr)
227
+ (dasm.address_binding[expr] ||= {})[:$t9] ||= expr
228
+ end
229
+ end
230
+
231
+ def delay_slot(di=nil)
232
+ # branch.*likely has no delay slot
233
+ # bltzal/bgezal are 'link', not 'likely', hence the check for -2
234
+ (di and di.opcode.props[:setip] and (di.opcode.name[-1] != ?l or di.opcode.name[-2] == ?a)) ? 1 : 0
235
+ end
236
+
237
+ def disassembler_default_func
238
+ df = DecodedFunction.new
239
+ df.backtrace_binding = %w[v0 v1 a0 a1 a2 a3 t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 at k0 k1].inject({}) { |h, r| h.update "$#{r}".to_sym => Expression::Unknown }
240
+ df.backtrace_binding.update %w[gp sp fp ra s0 s1 s2 s3 s4 s5 s6 s7].inject({}) { |h, r| h.update "$#{r}".to_sym => "$#{r}".to_sym }
241
+ df.backtracked_for = [BacktraceTrace.new(Expression[:$ra], :default, Expression[:$ra], :x)]
242
+ df.btfor_callback = lambda { |dasm, btfor, funcaddr, calladdr|
243
+ if funcaddr != :default
244
+ btfor
245
+ elsif di = dasm.decoded[calladdr] and di.opcode.props[:saveip] and di.instruction.to_s != 'jr $ra'
246
+ btfor
247
+ else []
248
+ end
249
+ }
250
+ df
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,51 @@
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/mips/opcodes'
8
+ require 'metasm/encode'
9
+
10
+ module Metasm
11
+ class MIPS
12
+ private
13
+ def encode_instr_op(exe, instr, op)
14
+ base = op.bin
15
+ set_field = lambda { |f, v|
16
+ base |= (v & @fields_mask[f]) << @fields_shift[f]
17
+ }
18
+
19
+ val, mask, shift = 0, 0, 0
20
+
21
+ # convert label name for jmp/call/loop to relative offset
22
+ if op.props[:setip] and op.name[0] != ?t and instr.args.last.kind_of? Expression
23
+ postlabel = exe.new_label('jmp_offset')
24
+ instr = instr.dup
25
+ if op.args.include? :i26
26
+ pl = Expression[postlabel, :&, 0xfc00_0000]
27
+ else
28
+ pl = postlabel
29
+ end
30
+ instr.args[-1] = Expression[[instr.args[-1], :-, pl], :>>, 2]
31
+ postdata = EncodedData.new '', :export => {postlabel => 0}
32
+ else
33
+ postdata = ''
34
+ end
35
+
36
+ op.args.zip(instr.args).each { |sym, arg|
37
+ case sym
38
+ when :rs, :rt, :rd, :ft
39
+ set_field[sym, arg.i]
40
+ when :rs_i16
41
+ set_field[:rs, arg.base.i]
42
+ val, mask, shift = arg.offset, @fields_mask[:i16], @fields_shift[:i16]
43
+ when :sa, :i16, :i20, :i26
44
+ val, mask, shift = arg, @fields_mask[sym], @fields_shift[sym]
45
+ end
46
+ }
47
+
48
+ Expression[base, :+, [[val, :&, mask], :<<, shift]].encode(:u32, @endianness) << postdata
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,72 @@
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 MIPS < CPU
11
+ class Reg
12
+ class << self
13
+ attr_accessor :s_to_i, :i_to_s
14
+ end
15
+ @s_to_i = {}
16
+ @i_to_s = {}
17
+ (0..31).each { |i| @s_to_i["r#{i}"] = @s_to_i["$r#{i}"] = @s_to_i["$#{i}"] = i }
18
+ %w[zero at v0 v1 a0 a1 a2 a3
19
+ t0 t1 t2 t3 t4 t5 t6 t7
20
+ s0 s1 s2 s3 s4 s5 s6 s7
21
+ t8 t9 k0 k1 gp sp fp ra].each_with_index { |r, i| @s_to_i[r] = @s_to_i['$'+r] = i ; @i_to_s[i] = '$'+r }
22
+
23
+ attr_accessor :i
24
+ def initialize(i)
25
+ @i = i
26
+ end
27
+
28
+ Sym = @i_to_s.sort.map { |k, v| v.to_sym }
29
+ def symbolic ; @i == 0 ? 0 : Sym[@i] end
30
+ end
31
+
32
+ class FpReg
33
+ class << self
34
+ attr_accessor :s_to_i, :i_to_s
35
+ end
36
+ @i_to_s = (0..31).map { |i| "$f#{i}" }
37
+ @s_to_i = (0..31).inject({}) { |h, i| h.update "f#{i}" => i, "$f#{i}" => i }
38
+
39
+ attr_accessor :i
40
+ def initialize(i)
41
+ @i = i
42
+ end
43
+ end
44
+
45
+ class Memref
46
+ attr_accessor :base, :offset
47
+ def initialize(base, offset)
48
+ @base, @offset = base, offset
49
+ end
50
+
51
+ def symbolic(orig)
52
+ p = nil
53
+ p = Expression[p, :+, @base.symbolic] if base
54
+ p = Expression[p, :+, @offset] if offset
55
+ Indirection[p.reduce, 4, orig]
56
+ end
57
+ end
58
+
59
+ def initialize(endianness = :big, family = :latest)
60
+ super()
61
+ @endianness = endianness
62
+ @size = 32
63
+ @family = family
64
+ end
65
+
66
+ def init_opcode_list
67
+ send("init_#@family")
68
+ @opcode_list
69
+ end
70
+ end
71
+ end
72
+
@@ -0,0 +1,443 @@
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/mips/main'
8
+
9
+ # TODO coprocessors, floating point, 64bits, thumb mode
10
+
11
+ module Metasm
12
+
13
+ class MIPS
14
+ def addop(name, bin, *args)
15
+ o = Opcode.new name, bin
16
+ o.args.concat(args & @fields_mask.keys)
17
+ (args & @valid_props).each { |p| o.props[p] = true }
18
+ @opcode_list << o
19
+ end
20
+
21
+ def init_mips32_obsolete
22
+ addop 'beql', 0b010100 << 26, :rt, :rs, :i16, :setip # == , exec delay slot only if jump taken
23
+ addop 'bnel', 0b010101 << 26, :rt, :rs, :i16, :setip # !=
24
+ addop 'blezl',0b010110 << 26, :rt_z, :rs, :i16, :setip # <= 0
25
+ addop 'bgtzl',0b010111 << 26, :rt_z, :rs, :i16, :setip # > 0
26
+ addop 'bltzl',1 << 26 | 0b00010 << 16, :rs, :i16, :setip
27
+ addop 'bgezl',1 << 26 | 0b00011 << 16, :rs, :i16, :setip
28
+ addop 'bltzall', 1 << 26 | 0b10010 << 16, :rs, :i16, :setip
29
+ addop 'bgezall', 1 << 26 | 0b10011 << 16, :rs, :i16, :setip
30
+ end
31
+
32
+ def init_mips32_reserved
33
+ addop 'future111011', 0b111011 << 26, :i26
34
+
35
+ %w[011000 011001 011010 011011 100111 101100 101101 110100 110111 111100 111111].each { |b|
36
+ addop "reserved#{b}", b.to_i(2) << 26, :i26
37
+ }
38
+
39
+ addop 'ase_jalx', 0b011101 << 26, :i26
40
+ addop 'ase011110', 0b011110 << 26, :i26
41
+ # TODO add all special/regimm/...
42
+ end
43
+
44
+ def init_mips32
45
+ @opcode_list = []
46
+ @fields_mask.update :rs => 0x1f, :rt => 0x1f, :rd => 0x1f, :sa => 0x1f,
47
+ :i16 => 0xffff, :i26 => 0x3ffffff, :rs_i16 => 0x3e0ffff, :it => 0x1f,
48
+ :ft => 0x1f, :idm1 => 0x1f, :idb => 0x1f, :sel => 7, :i20 => 0xfffff #, :i32 => 0
49
+ @fields_shift.update :rs => 21, :rt => 16, :rd => 11, :sa => 6,
50
+ :i16 => 0, :i26 => 0, :rs_i16 => 0, :it => 16,
51
+ :ft => 16, :idm1 => 11, :idb => 11, :sel => 0, :i20 => 6 #, :i32 => 0
52
+
53
+ init_mips32_obsolete
54
+ init_mips32_reserved
55
+
56
+ addop 'j', 0b000010 << 26, :i26, :setip, :stopexec # sets the program counter to (i26 << 2) | ((pc+4) & 0xfc000000) ie i26*4 in the 256M-aligned section containing the instruction in the delay slot
57
+ addop 'jal', 0b000011 << 26, :i26, :setip, :stopexec, :saveip # same thing, saves return addr in r31
58
+
59
+ addop 'mov', 0b001000 << 26, :rt, :rs # rt <- rs+0
60
+ addop 'addi', 0b001000 << 26, :rt, :rs, :i16 # add rt <- rs+i
61
+ addop 'li', 0b001001 << 26, :rt, :i16 # add $0 # XXX liu ?
62
+ addop 'addiu',0b001001 << 26, :rt, :rs, :i16 # add unsigned
63
+ addop 'slti', 0b001010 << 26, :rt, :rs, :i16 # set on less than
64
+ addop 'sltiu',0b001011 << 26, :rt, :rs, :i16 # set on less than unsigned
65
+ addop 'andi', 0b001100 << 26, :rt, :rs, :i16 # and
66
+ addop 'li', 0b001101 << 26, :rt, :i16 # or $0
67
+ addop 'ori', 0b001101 << 26, :rt, :rs, :i16 # or
68
+ addop 'xori', 0b001110 << 26, :rt, :rs, :i16 # xor
69
+ addop 'lui', 0b001111 << 26, :rt, :i16 # load upper
70
+ # addop 'li', (0b001111 << 26) << 32 | (0b001101 << 26), :rt_64, :i32 # lui + ori
71
+
72
+ addop 'b', 0b000100 << 26, :i16, :setip, :stopexec # bz $zero
73
+ addop 'bz', 0b000100 << 26, :rs, :i16, :setip # == 0 (beq $0)
74
+ addop 'bz', 0b000100 << 26, :rt, :i16, :setip # == 0
75
+ addop 'bnz', 0b000101 << 26, :rs, :i16, :setip # != 0
76
+ addop 'bnz', 0b000101 << 26, :rt, :i16, :setip # != 0
77
+
78
+ addop 'beq', 0b000100 << 26, :rt, :rs, :i16, :setip # ==
79
+ addop 'bne', 0b000101 << 26, :rt, :rs, :i16, :setip # !=
80
+ addop 'blez', 0b000110 << 26, :rs, :i16, :setip # <= 0
81
+ addop 'bgtz', 0b000111 << 26, :rs, :i16, :setip # > 0
82
+
83
+ addop 'lb', 0b100000 << 26, :rt, :rs_i16 # load byte rs <- [rt+i]
84
+ addop 'lh', 0b100001 << 26, :rt, :rs_i16 # load halfword
85
+ addop 'lwl', 0b100010 << 26, :rt, :rs_i16 # load word left
86
+ addop 'lw', 0b100011 << 26, :rt, :rs_i16 # load word
87
+ addop 'lbu', 0b100100 << 26, :rt, :rs_i16 # load byte unsigned
88
+ addop 'lhu', 0b100101 << 26, :rt, :rs_i16 # load halfword unsigned
89
+ addop 'lwr', 0b100110 << 26, :rt, :rs_i16 # load word right
90
+
91
+ addop 'sb', 0b101000 << 26, :rt, :rs_i16 # store byte
92
+ addop 'sh', 0b101001 << 26, :rt, :rs_i16 # store halfword
93
+ addop 'swl', 0b101010 << 26, :rt, :rs_i16 # store word left
94
+ addop 'sw', 0b101011 << 26, :rt, :rs_i16 # store word
95
+ addop 'swr', 0b101110 << 26, :rt, :rs_i16 # store word right
96
+
97
+ addop 'll', 0b110000 << 26, :rt, :rs_i16 # load linked word (read for atomic r/modify/w, sc does the w)
98
+ addop 'sc', 0b111000 << 26, :rt, :rs_i16 # store conditional word
99
+
100
+ addop 'lwc1', 0b110001 << 26, :ft, :rs_i16 # load word in fpreg low
101
+ addop 'swc1', 0b111001 << 26, :ft, :rs_i16 # store low fpreg word
102
+ addop 'lwc2', 0b110010 << 26, :rt, :rs_i16 # load word to copro2 register low
103
+ addop 'swc2', 0b111010 << 26, :rt, :rs_i16 # store low coproc2 register
104
+
105
+ addop 'ldc1', 0b110101 << 26, :ft, :rs_i16 # load dword in fpreg low
106
+ addop 'sdc1', 0b111101 << 26, :ft, :rs_i16 # store fpreg
107
+ addop 'ldc2', 0b110110 << 26, :rt, :rs_i16 # load dword to copro2 register
108
+ addop 'sdc2', 0b111110 << 26, :rt, :rs_i16 # store coproc2 register
109
+
110
+ addop 'pref', 0b110011 << 26, :it, :rs_i16 # prefetch (it = %w[load store r2 r3 load_streamed store_streamed load_retained store_retained
111
+ # r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 writeback_invalidate
112
+ # id26 id27 id28 id29 prepare_for_store id31]
113
+ addop 'cache',0b101111 << 26, :it, :rs_i16 # do things with the proc cache
114
+
115
+ # special
116
+ addop 'nop', 0
117
+ addop 'ssnop',1<<6
118
+ addop 'ehb', 3<<6
119
+ addop 'sll', 0b000000, :rd, :rt, :sa
120
+ addop 'movf', 0b000001, :rd, :rs, :cc
121
+ addop 'movt', 0b000001 | (1<<16), :rd, :rs, :cc
122
+ addop 'srl', 0b000010, :rd, :rt, :sa
123
+ addop 'sra', 0b000011, :rd, :rt, :sa
124
+ addop 'sllv', 0b000100, :rd, :rt, :rs
125
+ addop 'srlv', 0b000110, :rd, :rt, :rs
126
+ addop 'srav', 0b000111, :rd, :rt, :rs
127
+
128
+ addop 'jr', 0b001000, :rs, :setip, :stopexec # hint field ?
129
+ addop 'jr.hb',0b001000 | (1<<10), :rs, :setip, :stopexec
130
+ addop 'jalr', 0b001001 | (31<<11), :rs, :setip, :stopexec, :saveip # rd = r31 implicit
131
+ addop 'jalr', 0b001001, :rd, :rs, :setip, :stopexec, :saveip
132
+ addop 'jalr.hb', 0b001001 | (1<<10) | (31<<11), :rs, :setip, :stopexec, :saveip
133
+ addop 'jalr.hb', 0b001001 | (1<<10), :rd, :rs, :setip, :stopexec, :saveip
134
+ addop 'movz', 0b001010, :rd, :rs, :rt # rt == 0 ? rd <- rs
135
+ addop 'movn', 0b001011, :rd, :rs, :rt
136
+ addop 'syscall', 0b001100, :i20
137
+ addop 'break',0b001101, :i20, :stopexec
138
+ addop 'sync', 0b001111 # type 0 implicit
139
+ addop 'sync', 0b001111, :sa
140
+
141
+ addop 'mfhi', 0b010000, :rd # copies special reg HI to reg
142
+ addop 'mthi', 0b010001, :rs # copies reg to special reg HI
143
+ addop 'mflo', 0b010010, :rd # copies special reg LO to reg
144
+ addop 'mtlo', 0b010011, :rs # copies reg to special reg LO
145
+
146
+ addop 'mult', 0b011000, :rs, :rt # multiplies the registers and store the result in HI:LO
147
+ addop 'multu',0b011001, :rs, :rt
148
+ addop 'div', 0b011010, :rs, :rt
149
+ addop 'divu', 0b011011, :rs, :rt
150
+ addop 'add', 0b100000, :rd, :rs, :rt
151
+ addop 'addu', 0b100001, :rd, :rs, :rt
152
+ addop 'sub', 0b100010, :rd, :rs, :rt
153
+ addop 'subu', 0b100011, :rd, :rs, :rt
154
+ addop 'and', 0b100100, :rd, :rs, :rt
155
+ addop 'or', 0b100101, :rd, :rs, :rt
156
+ addop 'xor', 0b100110, :rd, :rs, :rt
157
+ addop 'not', 0b100111, :rd, :rt # nor $0
158
+ addop 'not', 0b100111, :rd, :rs
159
+ addop 'nor', 0b100111, :rd, :rs, :rt
160
+
161
+ addop 'slt', 0b101010, :rd, :rs, :rt # rs<rt ? rd<-1 : rd<-0
162
+ addop 'sltu', 0b101011, :rd, :rs, :rt
163
+
164
+ addop 'tge', 0b110000, :rs, :rt # rs >= rt ? trap
165
+ addop 'tgeu', 0b110001, :rs, :rt
166
+ addop 'tlt', 0b110010, :rs, :rt
167
+ addop 'tltu', 0b110011, :rs, :rt
168
+ addop 'teq', 0b110100, :rs, :rt
169
+ addop 'tne', 0b110110, :rs, :rt
170
+
171
+
172
+ # regimm
173
+ addop 'bltz', (1<<26) | (0b00000<<16), :rs, :i16, :setip
174
+ addop 'bgez', (1<<26) | (0b00001<<16), :rs, :i16, :setip
175
+ addop 'tgei', (1<<26) | (0b01000<<16), :rs, :i16, :setip
176
+ addop 'tgfiu',(1<<26) | (0b01001<<16), :rs, :i16, :setip
177
+ addop 'tlti', (1<<26) | (0b01010<<16), :rs, :i16, :setip
178
+ addop 'tltiu',(1<<26) | (0b01011<<16), :rs, :i16, :setip
179
+ addop 'teqi', (1<<26) | (0b01100<<16), :rs, :i16, :setip
180
+ addop 'tnei', (1<<26) | (0b01110<<16), :rs, :i16, :setip
181
+ addop 'bltzal', (1<<26) | (0b10000<<16), :rs, :i16, :setip, :saveip
182
+ addop 'bgezal', (1<<26) | (0b10001<<16), :i16, :setip, :stopexec, :saveip # bgezal $zero => unconditionnal
183
+ addop 'bgezal', (1<<26) | (0b10001<<16), :rs, :i16, :setip, :saveip
184
+
185
+
186
+ # special2
187
+ addop 'madd', (0b011100<<26) | 0b000000, :rs, :rt
188
+ addop 'maddu',(0b011100<<26) | 0b000001, :rs, :rt
189
+ addop 'mul', (0b011100<<26) | 0b000010, :rd, :rs, :rt
190
+ addop 'msub', (0b011100<<26) | 0b000100, :rs, :rt
191
+ addop 'msubu',(0b011100<<26) | 0b000101, :rs, :rt
192
+ addop 'clz', (0b011100<<26) | 0b100000, :rd, :rs, :rt # must have rs == rt
193
+ addop 'clo', (0b011100<<26) | 0b100001, :rd, :rs, :rt # must have rs == rt
194
+ addop 'sdbbp',(0b011100<<26) | 0b111111, :i20
195
+
196
+
197
+ # cp0
198
+ addop 'mfc0', (0b010000<<26) | (0b00000<<21), :rt, :rd
199
+ addop 'mfc0', (0b010000<<26) | (0b00000<<21), :rt, :rd, :sel
200
+ addop 'mtc0', (0b010000<<26) | (0b00100<<21), :rt, :rd
201
+ addop 'mtc0', (0b010000<<26) | (0b00100<<21), :rt, :rd, :sel
202
+
203
+ addop 'tlbr', (0b010000<<26) | (1<<25) | 0b000001
204
+ addop 'tlbwi',(0b010000<<26) | (1<<25) | 0b000010
205
+ addop 'tlbwr',(0b010000<<26) | (1<<25) | 0b000110
206
+ addop 'tlbp', (0b010000<<26) | (1<<25) | 0b001000
207
+ addop 'eret', (0b010000<<26) | (1<<25) | 0b011000
208
+ addop 'deret',(0b010000<<26) | (1<<25) | 0b011111
209
+ addop 'wait', (0b010000<<26) | (1<<25) | 0b100000 # mode field ?
210
+ end
211
+
212
+ def init_mips32r2
213
+ init_mips32
214
+
215
+ addop 'rotr', 0b000010 | (1<<21), :rd, :rt, :sa
216
+ addop 'rotrv',0b000110 | (1<<6), :rd, :rt, :rs
217
+
218
+ addop 'synci',(1<<26) | (0b11111<<16), :rs_i16
219
+
220
+ # special3
221
+ addop 'ext', (0b011111<<26) | 0b000000, :rt, :rs, :sa, :idm1
222
+ addop 'ins', (0b011111<<26) | 0b000100, :rt, :rs, :sa, :idb
223
+ addop 'rdhwr',(0b011111<<26)| 0b111011, :rt, :rd
224
+ addop 'wsbh',(0b011111<<26) | (0b00010<<6) | 0b100000, :rd, :rt
225
+ addop 'seb', (0b011111<<26) | (0b10000<<6) | 0b100000, :rd, :rt
226
+ addop 'seh', (0b011111<<26) | (0b11000<<6) | 0b100000, :rd, :rt
227
+
228
+ # cp0
229
+ addop 'rdpgpr', (0b010000<<26) | (0b01010<<21), :rd, :rt
230
+ addop 'wrpgpr', (0b010000<<26) | (0b01110<<21), :rd, :rt
231
+ addop 'di', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (0<<5)
232
+ addop 'di', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (0<<5), :rt
233
+ addop 'ei', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (1<<5)
234
+ addop 'ei', (0b010000<<26) | (0b01011<<21) | (0b01100<<11) | (1<<5), :rt
235
+ end
236
+ alias init_latest init_mips32r2
237
+ end
238
+ end
239
+ __END__
240
+ def macro_addop_cop1(name, bin, *aprops)
241
+ flds = [ :rt, :fs ]
242
+ addop name, :cop1, bin, 'rt, fs', flds, *aprops
243
+ end
244
+
245
+ def macro_addop_cop1_precision(name, type, bin, fmt, *aprops)
246
+ flds = [ :ft, :fs, :fd ]
247
+ addop name+'.'+(type.to_s[5,7]), type, bin, fmt, flds, *aprops
248
+ end
249
+
250
+
251
+ public
252
+ # Initialize the instruction set with the MIPS32 Instruction Set
253
+ def init_mips32
254
+ :cc => [7, 18, :fpcc],
255
+ :op => [0x1F, 16, :op ], :cp2_rt => [0x1F, 16, :cp2_reg ],
256
+ :stype => [0x1F, 6, :imm ],
257
+ :code => [0xFFFFF, 6, :code ],
258
+ :sel => [3, 0, :sel ]})
259
+
260
+ # ---------------------------------------------------------------
261
+ # COP0, field rs
262
+ # ---------------------------------------------------------------
263
+
264
+ addop 'mfc0', :cop0, 0b00000, 'rt, rd, sel', [ :rt, :rd, :sel ]
265
+ addop 'mtc0', :cop0, 0b00100, 'rt, rd, sel', [ :rt, :rd, :sel ]
266
+
267
+ # ---------------------------------------------------------------
268
+ # COP0 when rs=C0
269
+ # ---------------------------------------------------------------
270
+
271
+ macro_addop_cop0_c0 'tlbr', 0b000001
272
+ macro_addop_cop0_c0 'tlbwi', 0b000010
273
+ macro_addop_cop0_c0 'tlwr', 0b000110
274
+ macro_addop_cop0_c0 'tlbp', 0b001000
275
+ macro_addop_cop0_c0 'eret', 0b011000
276
+ macro_addop_cop0_c0 'deret', 0b011111
277
+ macro_addop_cop0_c0 'wait', 0b100000
278
+
279
+ # ---------------------------------------------------------------
280
+ # COP1, field rs
281
+ # ---------------------------------------------------------------
282
+
283
+ macro_addop_cop1 'mfc1', 0b00000
284
+ macro_addop_cop1 'cfc1', 0b00010
285
+ macro_addop_cop1 'mtc1', 0b00100
286
+ macro_addop_cop1 'ctc1', 0b00110
287
+
288
+ addop "bc1f", :cop1, 0b01000, 'cc, off', [ :cc, :off ], :diff_bits, [ 16, 3, 0 ]
289
+ addop "bc1fl", :cop1, 0b01000, 'cc, off', [ :cc, :off ], :diff_bits, [ 16, 3, 2 ]
290
+ addop "bc1t", :cop1, 0b01000, 'cc, off', [ :cc, :off ], :diff_bits, [ 16, 3, 1 ]
291
+ addop "bc1tl", :cop1, 0b01000, 'cc, off', [ :cc, :off ], :diff_bits, [ 16, 3, 3 ]
292
+
293
+ # ---------------------------------------------------------------
294
+ # COP1, field rs=S/D
295
+ # ---------------------------------------------------------------
296
+
297
+ [ :cop1_s, :cop1_d ].each do |type|
298
+ type_str = type.to_s[5,7]
299
+
300
+ macro_addop_cop1_precision 'add', type, 0b000000, 'fd, fs, ft'
301
+ macro_addop_cop1_precision 'sub', type, 0b000001, 'fd, fs, ft'
302
+ macro_addop_cop1_precision 'mul', type, 0b000010, 'fd, fs, ft'
303
+ macro_addop_cop1_precision 'abs', type, 0b000101, 'fd, fs', :ft_zero
304
+ macro_addop_cop1_precision 'mov', type, 0b000110, 'fd, fs', :ft_zero
305
+ macro_addop_cop1_precision 'neg', type, 0b000111, 'fd, fs', :ft_zero
306
+
307
+ macro_addop_cop1_precision 'movz', type, 0b010010, 'fd, fs, ft'
308
+ macro_addop_cop1_precision 'movn', type, 0b010011, 'fd, fs, ft'
309
+
310
+ addop "movf.#{type_str}", type, 0b010001, 'fd, fs, cc', [ :cc, :fs, :fd ], :diff_bits, [ 16, 1, 0 ]
311
+ addop "movt.#{type_str}", type, 0b010001, 'fd, fs, cc', [ :cc, :fs, :fd ], :diff_bits, [ 16, 1, 1 ]
312
+
313
+ %w(f un eq ueq olt ult ole ule sf ngle seq ngl lt nge le ngt).each_with_index do |cond, index|
314
+ addop "c.#{cond}.#{type_str}", type, 0b110000+index, 'cc, fs, ft',
315
+ [ :ft, :fs, :cc ]
316
+ end
317
+ end
318
+
319
+ # S and D Without PS
320
+
321
+ [:cop1_s, :cop1_d].each do |type|
322
+ macro_addop_cop1_precision 'div', type, 0b000011, 'fd, fs, ft'
323
+ macro_addop_cop1_precision 'sqrt', type, 0b000100, 'fd, fs', :ft_zero
324
+
325
+ macro_addop_cop1_precision 'round.w', type, 0b001100, 'fd, fs', :ft_zero
326
+ macro_addop_cop1_precision 'trunc.w', type, 0b001101, 'fd, fs', :ft_zero
327
+ macro_addop_cop1_precision 'ceil.w', type, 0b001110, 'fd, fs', :ft_zero
328
+ macro_addop_cop1_precision 'floor.w', type, 0b001111, 'fd, fs', :ft_zero
329
+
330
+ end
331
+
332
+ # COP2 is not decoded (pretty useless)
333
+
334
+ [:cop1_d,:cop1_w].each { |type| macro_addop_cop1_precision 'cvt.s', type, 0b100000, 'fd, fs', :ft_zero }
335
+ [:cop1_s,:cop1_w].each { |type| macro_addop_cop1_precision 'cvt.d', type, 0b100001, 'fd, fs', :ft_zero }
336
+ [:cop1_s,:cop1_d].each { |type| macro_addop_cop1_precision 'cvt.w', type, 0b100100, 'fd, fs', :ft_zero }
337
+
338
+ [ :normal, :special, :regimm, :special2, :cop0, :cop0_c0, :cop1, :cop1_s,
339
+ :cop1_d, :cop1_w ].each \
340
+ { |t| @@opcodes_by_class[t] = opcode_list.find_all { |o| o.type == t } }
341
+ end
342
+
343
+ # Initialize the instruction set with the MIPS32 Instruction Set Release 2
344
+ def init_mips64
345
+ init_mips32
346
+
347
+ #SPECIAL
348
+ macro_addop_special "rotr", 0b000010, 'rd, rt, sa', :diff_bits, [ 26, 1, 1 ]
349
+ macro_addop_special "rotrv", 0b000110, 'rd, rt, rs', :diff_bits, [ 6, 1, 1 ]
350
+
351
+ # REGIMM
352
+ addop "synci", :regimm, 0b11111, '', {:base => [5,21], :off => [16, 0] }
353
+
354
+ # ---------------------------------------------------------------
355
+ # SPECIAL3 opcode encoding of function field
356
+ # ---------------------------------------------------------------
357
+
358
+ addop "ext", :special3, 0b00000, 'rt, rs, pos, size', { :rs => [5, 21], :rt => [5, 16],
359
+ :msbd => [5, 11], :lsb => [5, 6] }
360
+ addop "ins", :special3, 0b00100, 'rt, rs, pos, size', { :rs => [5, 21], :rt => [5, 16],
361
+ :msb => [5, 11], :lsb => [5, 6] }
362
+
363
+ addop "rdhwr", :special3, 0b111011, 'rt, rd', { :rt => [5, 16], :rd => [5, 11] }
364
+
365
+ addop "wsbh", :bshfl, 0b00010, 'rd, rt', { :rt => [5, 16], :rd => [5, 11] }
366
+ addop "seb", :bshfl, 0b10000, 'rd, rt', { :rt => [5, 16], :rd => [5, 11] }
367
+ addop "seh", :bshfl, 0b11000, 'rd, rt', { :rt => [5, 16], :rd => [5, 11] }
368
+
369
+ # ---------------------------------------------------------------
370
+ # COP0
371
+ # ---------------------------------------------------------------
372
+
373
+ addop "rdpgpr", :cop0, 0b01010, 'rt, rd', {:rt => [5, 16], :rd => [5, 11] }
374
+ addop "wdpgpr", :cop0, 0b01110, 'rt, rd', {:rt => [5, 16], :rd => [5, 11] }
375
+ addop "di", :cop0, 0b01011, '', {}, :diff_bits, [ 5, 1 , 0]
376
+ addop "ei", :cop0, 0b01011, '', {}, :diff_bits, [ 5, 1 , 1]
377
+
378
+ # ---------------------------------------------------------------
379
+ # COP1, field rs
380
+ # ---------------------------------------------------------------
381
+
382
+ macro_addop_cop1 "mfhc1", 0b00011
383
+ macro_addop_cop1 "mthc1", 0b00111
384
+
385
+ # Floating point
386
+
387
+ [:cop1_s, :cop1_d].each do |type|
388
+ macro_addop_cop1_precision 'round.l', type, 0b001000, 'fd, fs', :ft_zero
389
+ macro_addop_cop1_precision 'trunc.l', type, 0b001001, 'fd, fs', :ft_zero
390
+ macro_addop_cop1_precision 'ceil.l', type, 0b001010, 'fd, fs', :ft_zero
391
+ macro_addop_cop1_precision 'floor.l', type, 0b001011, 'fd, fs', :ft_zero
392
+
393
+ macro_addop_cop1_precision 'recip', type, 0b010101, 'fd, fs', :ft_zero
394
+ macro_addop_cop1_precision 'rsqrt', type, 0b010110, 'fd, fs', :ft_zero
395
+
396
+ macro_addop_cop1_precision 'cvt.l', type, 0b100101, 'fd, fs', :ft_zero
397
+ end
398
+ macro_addop_cop1_precision 'cvt.ps', :cop1_s, 0b100110, 'fd, fs', :ft_zero
399
+ macro_addop_cop1_precision 'cvt.s', :cop1_l, 0b100000, 'fd, fs', :ft_zero
400
+ macro_addop_cop1_precision 'cvt.d', :cop1_l, 0b100000, 'fd, fs', :ft_zero
401
+
402
+ macro_addop_cop1_precision 'add', :cop1_ps, 0b000000, 'fd, fs, ft'
403
+ macro_addop_cop1_precision 'sub', :cop1_ps, 0b000001, 'fd, fs, ft'
404
+ macro_addop_cop1_precision 'mul', :cop1_ps, 0b000010, 'fd, fs, ft'
405
+ macro_addop_cop1_precision 'abs', :cop1_ps, 0b000101, 'fd, fs', :ft_zero
406
+ macro_addop_cop1_precision 'mov', :cop1_ps, 0b000110, 'fd, fs', :ft_zero
407
+ macro_addop_cop1_precision 'neg', :cop1_ps, 0b000111, 'fd, fs', :ft_zero
408
+
409
+ macro_addop_cop1_precision 'movz', :cop1_ps, 0b010010, 'fd, fs, ft'
410
+ macro_addop_cop1_precision 'movn', :cop1_ps, 0b010011, 'fd, fs, ft'
411
+
412
+ addop "movf.#{:cop1_ps_str}", :cop1_ps, 0b010001, 'fd, fs, cc', [ :cc, :fs, :fd ]
413
+ addop "movt.#{:cop1_ps_str}", :cop1_ps, 0b010001, 'fd, fs, cc', [ :cc, :fs, :fd ]
414
+
415
+ %w(f un eq ueq olt ult ole ule sf ngle seq ngl lt nge le ngt).each_with_index do |cond, index|
416
+ addop "c.#{cond}.ps", :cop1_cond, 0b110000+index, 'cc, fs, ft',
417
+ [ :ft, :fs, :cc ]
418
+
419
+ # TODO: COP1X
420
+
421
+ [ :special3, :bshfl, :cop1_l, :cop1_ps ].each \
422
+ { |t| @@opcodes_by_class[t] = opcode_list.find_all { |o| o.type == t } }
423
+ end
424
+
425
+ end
426
+
427
+ # Reset all instructions
428
+ def reset
429
+ metaprops_allowed.clear
430
+ args_allowed.clear
431
+ props_allowed.clear
432
+ fields_spec.clear
433
+ opcode_list.clear
434
+ end
435
+
436
+ end
437
+ # Array containing all the supported opcodes
438
+ attr_accessor :opcode_list
439
+
440
+ init_mips32
441
+ end
442
+
443
+ end