metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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