metasm 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/BUGS +11 -0
- data/CREDITS +17 -0
- data/README +270 -0
- data/TODO +114 -0
- data/doc/code_organisation.txt +146 -0
- data/doc/const_missing.txt +16 -0
- data/doc/core_classes.txt +75 -0
- data/doc/feature_list.txt +53 -0
- data/doc/index.txt +59 -0
- data/doc/install_notes.txt +170 -0
- data/doc/style.css +3 -0
- data/doc/use_cases.txt +18 -0
- data/lib/metasm.rb +80 -0
- data/lib/metasm/arm.rb +12 -0
- data/lib/metasm/arm/debug.rb +39 -0
- data/lib/metasm/arm/decode.rb +167 -0
- data/lib/metasm/arm/encode.rb +77 -0
- data/lib/metasm/arm/main.rb +75 -0
- data/lib/metasm/arm/opcodes.rb +177 -0
- data/lib/metasm/arm/parse.rb +130 -0
- data/lib/metasm/arm/render.rb +55 -0
- data/lib/metasm/compile_c.rb +1457 -0
- data/lib/metasm/dalvik.rb +8 -0
- data/lib/metasm/dalvik/decode.rb +196 -0
- data/lib/metasm/dalvik/main.rb +60 -0
- data/lib/metasm/dalvik/opcodes.rb +366 -0
- data/lib/metasm/decode.rb +213 -0
- data/lib/metasm/decompile.rb +2659 -0
- data/lib/metasm/disassemble.rb +2068 -0
- data/lib/metasm/disassemble_api.rb +1280 -0
- data/lib/metasm/dynldr.rb +1329 -0
- data/lib/metasm/encode.rb +333 -0
- data/lib/metasm/exe_format/a_out.rb +194 -0
- data/lib/metasm/exe_format/autoexe.rb +82 -0
- data/lib/metasm/exe_format/bflt.rb +189 -0
- data/lib/metasm/exe_format/coff.rb +455 -0
- data/lib/metasm/exe_format/coff_decode.rb +901 -0
- data/lib/metasm/exe_format/coff_encode.rb +1078 -0
- data/lib/metasm/exe_format/dex.rb +457 -0
- data/lib/metasm/exe_format/dol.rb +145 -0
- data/lib/metasm/exe_format/elf.rb +923 -0
- data/lib/metasm/exe_format/elf_decode.rb +979 -0
- data/lib/metasm/exe_format/elf_encode.rb +1375 -0
- data/lib/metasm/exe_format/macho.rb +827 -0
- data/lib/metasm/exe_format/main.rb +228 -0
- data/lib/metasm/exe_format/mz.rb +164 -0
- data/lib/metasm/exe_format/nds.rb +172 -0
- data/lib/metasm/exe_format/pe.rb +437 -0
- data/lib/metasm/exe_format/serialstruct.rb +246 -0
- data/lib/metasm/exe_format/shellcode.rb +114 -0
- data/lib/metasm/exe_format/xcoff.rb +167 -0
- data/lib/metasm/gui.rb +23 -0
- data/lib/metasm/gui/cstruct.rb +373 -0
- data/lib/metasm/gui/dasm_coverage.rb +199 -0
- data/lib/metasm/gui/dasm_decomp.rb +369 -0
- data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
- data/lib/metasm/gui/dasm_graph.rb +1354 -0
- data/lib/metasm/gui/dasm_hex.rb +543 -0
- data/lib/metasm/gui/dasm_listing.rb +599 -0
- data/lib/metasm/gui/dasm_main.rb +906 -0
- data/lib/metasm/gui/dasm_opcodes.rb +291 -0
- data/lib/metasm/gui/debug.rb +1228 -0
- data/lib/metasm/gui/gtk.rb +884 -0
- data/lib/metasm/gui/qt.rb +495 -0
- data/lib/metasm/gui/win32.rb +3004 -0
- data/lib/metasm/gui/x11.rb +621 -0
- data/lib/metasm/ia32.rb +14 -0
- data/lib/metasm/ia32/compile_c.rb +1523 -0
- data/lib/metasm/ia32/debug.rb +193 -0
- data/lib/metasm/ia32/decode.rb +1167 -0
- data/lib/metasm/ia32/decompile.rb +564 -0
- data/lib/metasm/ia32/encode.rb +314 -0
- data/lib/metasm/ia32/main.rb +233 -0
- data/lib/metasm/ia32/opcodes.rb +872 -0
- data/lib/metasm/ia32/parse.rb +327 -0
- data/lib/metasm/ia32/render.rb +91 -0
- data/lib/metasm/main.rb +1193 -0
- data/lib/metasm/mips.rb +11 -0
- data/lib/metasm/mips/compile_c.rb +7 -0
- data/lib/metasm/mips/decode.rb +253 -0
- data/lib/metasm/mips/encode.rb +51 -0
- data/lib/metasm/mips/main.rb +72 -0
- data/lib/metasm/mips/opcodes.rb +443 -0
- data/lib/metasm/mips/parse.rb +51 -0
- data/lib/metasm/mips/render.rb +43 -0
- data/lib/metasm/os/gnu_exports.rb +270 -0
- data/lib/metasm/os/linux.rb +1112 -0
- data/lib/metasm/os/main.rb +1686 -0
- data/lib/metasm/os/remote.rb +527 -0
- data/lib/metasm/os/windows.rb +2027 -0
- data/lib/metasm/os/windows_exports.rb +745 -0
- data/lib/metasm/parse.rb +876 -0
- data/lib/metasm/parse_c.rb +3938 -0
- data/lib/metasm/pic16c/decode.rb +42 -0
- data/lib/metasm/pic16c/main.rb +17 -0
- data/lib/metasm/pic16c/opcodes.rb +68 -0
- data/lib/metasm/ppc.rb +11 -0
- data/lib/metasm/ppc/decode.rb +264 -0
- data/lib/metasm/ppc/decompile.rb +251 -0
- data/lib/metasm/ppc/encode.rb +51 -0
- data/lib/metasm/ppc/main.rb +129 -0
- data/lib/metasm/ppc/opcodes.rb +410 -0
- data/lib/metasm/ppc/parse.rb +52 -0
- data/lib/metasm/preprocessor.rb +1277 -0
- data/lib/metasm/render.rb +130 -0
- data/lib/metasm/sh4.rb +8 -0
- data/lib/metasm/sh4/decode.rb +336 -0
- data/lib/metasm/sh4/main.rb +292 -0
- data/lib/metasm/sh4/opcodes.rb +381 -0
- data/lib/metasm/x86_64.rb +12 -0
- data/lib/metasm/x86_64/compile_c.rb +1025 -0
- data/lib/metasm/x86_64/debug.rb +59 -0
- data/lib/metasm/x86_64/decode.rb +268 -0
- data/lib/metasm/x86_64/encode.rb +264 -0
- data/lib/metasm/x86_64/main.rb +135 -0
- data/lib/metasm/x86_64/opcodes.rb +118 -0
- data/lib/metasm/x86_64/parse.rb +68 -0
- data/misc/bottleneck.rb +61 -0
- data/misc/cheader-findpppath.rb +58 -0
- data/misc/hexdiff.rb +74 -0
- data/misc/hexdump.rb +55 -0
- data/misc/metasm-all.rb +13 -0
- data/misc/objdiff.rb +47 -0
- data/misc/objscan.rb +40 -0
- data/misc/pdfparse.rb +661 -0
- data/misc/ppc_pdf2oplist.rb +192 -0
- data/misc/tcp_proxy_hex.rb +84 -0
- data/misc/txt2html.rb +440 -0
- data/samples/a.out.rb +31 -0
- data/samples/asmsyntax.rb +77 -0
- data/samples/bindiff.rb +555 -0
- data/samples/compilation-steps.rb +49 -0
- data/samples/cparser_makestackoffset.rb +55 -0
- data/samples/dasm-backtrack.rb +38 -0
- data/samples/dasmnavig.rb +318 -0
- data/samples/dbg-apihook.rb +228 -0
- data/samples/dbghelp.rb +143 -0
- data/samples/disassemble-gui.rb +102 -0
- data/samples/disassemble.rb +133 -0
- data/samples/dump_upx.rb +95 -0
- data/samples/dynamic_ruby.rb +1929 -0
- data/samples/elf_list_needed.rb +46 -0
- data/samples/elf_listexports.rb +33 -0
- data/samples/elfencode.rb +25 -0
- data/samples/exeencode.rb +128 -0
- data/samples/factorize-headers-elfimports.rb +77 -0
- data/samples/factorize-headers-peimports.rb +109 -0
- data/samples/factorize-headers.rb +43 -0
- data/samples/gdbclient.rb +583 -0
- data/samples/generate_libsigs.rb +102 -0
- data/samples/hotfix_gtk_dbg.rb +59 -0
- data/samples/install_win_env.rb +78 -0
- data/samples/lindebug.rb +924 -0
- data/samples/linux_injectsyscall.rb +95 -0
- data/samples/machoencode.rb +31 -0
- data/samples/metasm-shell.rb +91 -0
- data/samples/pe-hook.rb +69 -0
- data/samples/pe-ia32-cpuid.rb +203 -0
- data/samples/pe-mips.rb +35 -0
- data/samples/pe-shutdown.rb +78 -0
- data/samples/pe-testrelocs.rb +51 -0
- data/samples/pe-testrsrc.rb +24 -0
- data/samples/pe_listexports.rb +31 -0
- data/samples/peencode.rb +19 -0
- data/samples/peldr.rb +494 -0
- data/samples/preprocess-flatten.rb +19 -0
- data/samples/r0trace.rb +308 -0
- data/samples/rubstop.rb +399 -0
- data/samples/scan_pt_gnu_stack.rb +54 -0
- data/samples/scanpeexports.rb +62 -0
- data/samples/shellcode-c.rb +40 -0
- data/samples/shellcode-dynlink.rb +146 -0
- data/samples/source.asm +34 -0
- data/samples/struct_offset.rb +47 -0
- data/samples/testpe.rb +32 -0
- data/samples/testraw.rb +45 -0
- data/samples/win32genloader.rb +132 -0
- data/samples/win32hooker-advanced.rb +169 -0
- data/samples/win32hooker.rb +96 -0
- data/samples/win32livedasm.rb +33 -0
- data/samples/win32remotescan.rb +133 -0
- data/samples/wintrace.rb +92 -0
- data/tests/all.rb +8 -0
- data/tests/dasm.rb +39 -0
- data/tests/dynldr.rb +35 -0
- data/tests/encodeddata.rb +132 -0
- data/tests/ia32.rb +82 -0
- data/tests/mips.rb +116 -0
- data/tests/parse_c.rb +239 -0
- data/tests/preprocessor.rb +269 -0
- data/tests/x86_64.rb +62 -0
- metadata +255 -0
data/lib/metasm/mips.rb
ADDED
@@ -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,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
|