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.
- 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
|