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
|
@@ -0,0 +1,130 @@
|
|
|
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
|
+
|
|
11
|
+
# a Renderable element has a method #render that returns an array of [String or Renderable]
|
|
12
|
+
module Renderable
|
|
13
|
+
def to_s
|
|
14
|
+
render.join
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# yields each Expr seen in #render (recursive)
|
|
18
|
+
def each_expr
|
|
19
|
+
r = proc { |e|
|
|
20
|
+
case e
|
|
21
|
+
when Expression
|
|
22
|
+
yield e
|
|
23
|
+
r[e.lexpr] ; r[e.rexpr]
|
|
24
|
+
when Renderable
|
|
25
|
+
e.render.each { |re| r[re] }
|
|
26
|
+
end
|
|
27
|
+
}
|
|
28
|
+
r[self]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Instruction
|
|
34
|
+
include Renderable
|
|
35
|
+
def render
|
|
36
|
+
@cpu.render_instruction(self)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Label
|
|
41
|
+
include Renderable
|
|
42
|
+
def render
|
|
43
|
+
[@name + ':']
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class CPU
|
|
48
|
+
# renders an instruction
|
|
49
|
+
# may use instruction-global properties to render an argument (eg specify pointer size if not implicit)
|
|
50
|
+
def render_instruction(i)
|
|
51
|
+
r = []
|
|
52
|
+
r << i.opname
|
|
53
|
+
r << ' '
|
|
54
|
+
i.args.each { |a| r << a << ', ' }
|
|
55
|
+
r.pop
|
|
56
|
+
r
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# ease debugging in irb
|
|
60
|
+
def inspect
|
|
61
|
+
"#<#{self.class}:#{'%x' % object_id} ... >"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class Expression
|
|
66
|
+
include Renderable
|
|
67
|
+
attr_accessor :render_info
|
|
68
|
+
|
|
69
|
+
# this is an accessor to @@render_int, the lambda used to render integers > 10
|
|
70
|
+
# usage: Expression.render_int = lambda { |e| '0x%x' % e }
|
|
71
|
+
# or Expression.render_int { |e| '0x%x' % e }
|
|
72
|
+
# XXX the returned string should be suitable for inclusion in a label name etc
|
|
73
|
+
def self.render_int(&b)
|
|
74
|
+
if b
|
|
75
|
+
@@render_int = b
|
|
76
|
+
else
|
|
77
|
+
@@render_int
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
def self.render_int=(p)
|
|
81
|
+
@@render_int = p
|
|
82
|
+
end
|
|
83
|
+
@@render_int = nil
|
|
84
|
+
|
|
85
|
+
def render_integer(e)
|
|
86
|
+
if render_info and @render_info[:char]
|
|
87
|
+
ee = e
|
|
88
|
+
v = []
|
|
89
|
+
while ee > 0
|
|
90
|
+
v << (ee & 0xff)
|
|
91
|
+
ee >>= 8
|
|
92
|
+
end
|
|
93
|
+
v.reverse! if @render_info[:char] == :big
|
|
94
|
+
if not v.empty? and v.all? { |c| c < 0x7f }
|
|
95
|
+
# XXX endianness
|
|
96
|
+
return "'" + v.pack('C*').inspect.gsub("'") { '\\\'' }[1...-1] + "'"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
if e < 0
|
|
100
|
+
neg = true
|
|
101
|
+
e = -e
|
|
102
|
+
end
|
|
103
|
+
if e < 10; e = e.to_s
|
|
104
|
+
elsif @@render_int
|
|
105
|
+
e = @@render_int[e]
|
|
106
|
+
else
|
|
107
|
+
e = '%xh' % e
|
|
108
|
+
e = '0' << e unless (?0..?9).include? e[0]
|
|
109
|
+
end
|
|
110
|
+
e = '-' << e if neg
|
|
111
|
+
e
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
NOSQ1 = NOSQ2 = {:* => [:*], :+ => [:+, :-, :*], :- => [:+, :-, :*]}
|
|
115
|
+
NOSQ2[:-] = [:*]
|
|
116
|
+
def render
|
|
117
|
+
l = @lexpr.kind_of?(Integer) ? render_integer(@lexpr) : @lexpr
|
|
118
|
+
r = @rexpr.kind_of?(Integer) ? render_integer(@rexpr) : @rexpr
|
|
119
|
+
l = ['(', l, ')'] if @lexpr.kind_of? Expression and (not oa = NOSQ1[@op] or not oa.include?(@lexpr.op))
|
|
120
|
+
r = ['(', r, ')'] if @rexpr.kind_of? Expression and (not oa = NOSQ2[@op] or not oa.include?(@rexpr.op))
|
|
121
|
+
op = @op if l or @op != :+
|
|
122
|
+
if op == :+
|
|
123
|
+
r0 = [r].flatten.first
|
|
124
|
+
r0 = r0.render.flatten.first while r0.kind_of? Renderable
|
|
125
|
+
op = nil if (r0.kind_of? Integer and r0 < 0) or (r0.kind_of? String and r0[0] == ?-) or r0 == :-
|
|
126
|
+
end
|
|
127
|
+
[l, op, r].compact
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
data/lib/metasm/sh4.rb
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
2
|
+
# Copyright (C) 2006-2010 Yoann GUILLOT
|
|
3
|
+
#
|
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
|
+
|
|
6
|
+
require 'metasm/sh4/opcodes'
|
|
7
|
+
require 'metasm/decode'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class Sh4
|
|
11
|
+
def build_opcode_bin_mask(op)
|
|
12
|
+
op.bin_mask = 0
|
|
13
|
+
op.args.each { |f|
|
|
14
|
+
op.bin_mask |= @fields_mask[f] << @fields_shift[f]
|
|
15
|
+
}
|
|
16
|
+
op.bin_mask ^= 0xffff
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def build_bin_lookaside
|
|
20
|
+
lookaside = (0..0xf).inject({}) { |h, i| h.update i => [] }
|
|
21
|
+
opcode_list.each { |op|
|
|
22
|
+
build_opcode_bin_mask op
|
|
23
|
+
lookaside[(op.bin >> 12) & 0xf] << op
|
|
24
|
+
}
|
|
25
|
+
lookaside
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# depending on transfert size mode (sz flag), fmov instructions manipulate single ou double precision values
|
|
29
|
+
# instruction aliasing appears when sz is not handled
|
|
30
|
+
def transfer_size_mode(list)
|
|
31
|
+
return list if list.find { |op| not op.name.include? 'mov' }
|
|
32
|
+
@transfersz == 0 ? list.find_all { |op| op.name.include? 'fmov.s' } : list.reject { |op| op.name.include? 'fmov.s' }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# when pr flag is set, floating point instructions are executed as double-precision operations
|
|
36
|
+
# thus register pair is used (DRn registers)
|
|
37
|
+
def precision_mode(list)
|
|
38
|
+
@fpprecision == 0 ? list.reject { |op| op.args.include? :drn } : list.find_all { |op| op.args.include? :frn }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def decode_findopcode(edata)
|
|
42
|
+
return if edata.ptr >= edata.data.length
|
|
43
|
+
|
|
44
|
+
di = DecodedInstruction.new(self)
|
|
45
|
+
val = edata.decode_imm(:u16, @endianness)
|
|
46
|
+
edata.ptr -= 2
|
|
47
|
+
op = @bin_lookaside[(val >> 12) & 0xf].find_all { |opcode| (val & opcode.bin_mask) == opcode.bin }
|
|
48
|
+
|
|
49
|
+
op = transfer_size_mode(op) if op.length == 2
|
|
50
|
+
op = precision_mode(op) if op.length == 2
|
|
51
|
+
|
|
52
|
+
if op.length > 1
|
|
53
|
+
puts "current value: #{Expression[val]}, ambiguous matches:",
|
|
54
|
+
op.map { |opcode| " #{opcode.name} - #{opcode.args.inspect} - #{Expression[opcode.bin]} - #{Expression[opcode.bin_mask]}" }
|
|
55
|
+
#raise "Sh4 - Internal error"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if not op.empty?
|
|
59
|
+
di.opcode = op.first
|
|
60
|
+
di
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def decode_instr_op(edata, di)
|
|
65
|
+
before_ptr = edata.ptr
|
|
66
|
+
op = di.opcode
|
|
67
|
+
di.instruction.opname = op.name
|
|
68
|
+
di.opcode.props[:memsz] = (op.name =~ /\.l|mova/ ? 32 : (op.name =~ /\.w/ ? 16 : 8))
|
|
69
|
+
val = edata.decode_imm(:u16, @endianness)
|
|
70
|
+
|
|
71
|
+
field_val = lambda{ |f|
|
|
72
|
+
r = (val >> @fields_shift[f]) & @fields_mask[f]
|
|
73
|
+
case f
|
|
74
|
+
when :@rm, :@rn ,:@_rm, :@_rn, :@rm_, :@rn_; GPR.new(r)
|
|
75
|
+
when :@disppc
|
|
76
|
+
# The effective address is formed by calculating PC+4,
|
|
77
|
+
# clearing the lowest 2 bits, and adding the zero-extended 8-bit immediate i
|
|
78
|
+
# multiplied by 4 (32-bit)/ 2 (16-bit) / 1 (8-bit).
|
|
79
|
+
curaddr = di.address+4
|
|
80
|
+
curaddr = (curaddr & 0xffff_fffc) if di.opcode.props[:memsz] == 32
|
|
81
|
+
curaddr+r*(di.opcode.props[:memsz]/8)
|
|
82
|
+
when :@disprm, :@dispr0rn; (r & 0xf) * (di.opcode.props[:memsz]/8)
|
|
83
|
+
when :@disprmrn; (r & 0xf) * 4
|
|
84
|
+
when :@dispgbr; Expression.make_signed(r, 16)
|
|
85
|
+
when :disp8; di.address+4+2*Expression.make_signed(r, 8)
|
|
86
|
+
when :disp12; di.address+4+2*Expression.make_signed(r, 12)
|
|
87
|
+
when :s8; Expression.make_signed(r, 8)
|
|
88
|
+
else r
|
|
89
|
+
end
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
op.args.each { |a|
|
|
93
|
+
di.instruction.args << case a
|
|
94
|
+
when :r0; GPR.new 0
|
|
95
|
+
when :rm, :rn; GPR.new field_val[a]
|
|
96
|
+
when :rm_bank, :rn_bank; RBANK.new field_val[a]
|
|
97
|
+
when :drm, :drn; DR.new field_val[a]
|
|
98
|
+
when :frm, :frn; FR.new field_val[a]
|
|
99
|
+
when :xdm, :xdn; XDR.new field_val[a]
|
|
100
|
+
when :fvm, :fvn; FVR.new field_val[a]
|
|
101
|
+
when :vbr; VBR.new
|
|
102
|
+
when :gbr; GBR.new
|
|
103
|
+
when :sr; SR.new
|
|
104
|
+
when :ssr; SSR.new
|
|
105
|
+
when :spc; SPC.new
|
|
106
|
+
when :sgr; SGR.new
|
|
107
|
+
when :dbr; DBR.new
|
|
108
|
+
when :mach; MACH.new
|
|
109
|
+
when :macl; MACL.new
|
|
110
|
+
when :pr; PR.new
|
|
111
|
+
when :fpul; FPUL.new
|
|
112
|
+
when :fpscr; FPSCR.new
|
|
113
|
+
when :dbr; DBR.new
|
|
114
|
+
when :pc; PC.new
|
|
115
|
+
|
|
116
|
+
when :@rm, :@rn, :@disppc
|
|
117
|
+
Memref.new(field_val[a], nil)
|
|
118
|
+
when :@_rm, :@_rn
|
|
119
|
+
Memref.new(field_val[a], nil, :pre)
|
|
120
|
+
when :@rm_, :@rn_
|
|
121
|
+
Memref.new(field_val[a], nil, :post)
|
|
122
|
+
when :@r0rm
|
|
123
|
+
Memref.new(GPR.new(0), GPR.new(field_val[:rm]))
|
|
124
|
+
when :@r0rn, :@dispr0rn
|
|
125
|
+
Memref.new(GPR.new(0), GPR.new(field_val[:rn]))
|
|
126
|
+
when :@disprm
|
|
127
|
+
Memref.new(field_val[a], GPR.new(field_val[:rm]))
|
|
128
|
+
when :@disprmrn
|
|
129
|
+
Memref.new(field_val[a], GPR.new(field_val[:rn]))
|
|
130
|
+
|
|
131
|
+
when :disppc; Expression[field_val[:@disppc]]
|
|
132
|
+
when :s8, :disp8, :disp12; Expression[field_val[a]]
|
|
133
|
+
when :i16, :i8, :i5; Expression[field_val[a]]
|
|
134
|
+
|
|
135
|
+
else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
|
|
136
|
+
end
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
di.bin_length += edata.ptr - before_ptr
|
|
140
|
+
di
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def disassembler_default_func
|
|
144
|
+
df = DecodedFunction.new
|
|
145
|
+
df.backtrace_binding = {}
|
|
146
|
+
15.times { |i| df.backtrace_binding["r#{i}".to_sym] = Expression::Unknown }
|
|
147
|
+
df.backtracked_for = [BacktraceTrace.new(Expression[:pr], :default, Expression[:pr], :x)]
|
|
148
|
+
df.btfor_callback = lambda { |dasm, btfor, funcaddr, calladdr|
|
|
149
|
+
if funcaddr != :default
|
|
150
|
+
btfor
|
|
151
|
+
elsif di = dasm.decoded[calladdr] and di.opcode.props[:saveip]
|
|
152
|
+
btfor
|
|
153
|
+
else []
|
|
154
|
+
end
|
|
155
|
+
}
|
|
156
|
+
df
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# interprets a condition code (in an opcode name) as an expression
|
|
160
|
+
def decode_cmp_expr(di, a0, a1)
|
|
161
|
+
case di.opcode.name
|
|
162
|
+
when 'cmp/eq'; Expression[a0, :'==', a1]
|
|
163
|
+
when 'cmp/ge'; Expression[a0, :'>=', a1] # signed
|
|
164
|
+
when 'cmp/gt'; Expression[a0, :'>', a1] # signed
|
|
165
|
+
when 'cmp/hi'; Expression[a0, :'>', a1] # unsigned
|
|
166
|
+
when 'cmp/hs'; Expression[a0, :'>=', a1] # unsigned
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def decode_cmp_cst(di, a0)
|
|
171
|
+
case di.opcode.name
|
|
172
|
+
when 'cmp/pl'; Expression[a0, :'>', 0] # signed
|
|
173
|
+
when 'cmp/pz'; Expression[a0, :'>=', 0] # signed
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def backtrace_binding
|
|
178
|
+
@backtrace_binding ||= init_backtrace_binding
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def opsz(di)
|
|
182
|
+
ret = @size
|
|
183
|
+
ret = 8 if di and di.opcode.name =~ /\.b/
|
|
184
|
+
ret = 16 if di and di.opcode.name =~ /\.w/
|
|
185
|
+
ret
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def init_backtrace_binding
|
|
189
|
+
@backtrace_binding ||= {}
|
|
190
|
+
|
|
191
|
+
mask = lambda { |di| (1 << opsz(di)) - 1 } # 32bits => 0xffff_ffff
|
|
192
|
+
|
|
193
|
+
opcode_list.map { |ol| ol.name }.uniq.each { |op|
|
|
194
|
+
@backtrace_binding[op] ||= case op
|
|
195
|
+
when 'ldc', 'ldc.l', 'lds', 'lds.l', 'stc', 'stc.l', 'mov', 'mov.l', 'sts', 'sts.l'
|
|
196
|
+
lambda { |di, a0, a1| { a1 => Expression[a0] }}
|
|
197
|
+
when 'stc.w', 'stc.b', 'mov.w', 'mov.b'
|
|
198
|
+
lambda { |di, a0, a1| { a1 => Expression[a0, :&, mask[di]] }}
|
|
199
|
+
when 'movt'; lambda { |di, a0| { a0 => :t_bit }}
|
|
200
|
+
when 'exts.b', 'exts.w', 'extu.w'
|
|
201
|
+
lambda { |di, a0, a1| { a1 => Expression[a0, :&, mask[di]] }}
|
|
202
|
+
when 'cmp/eq', 'cmp/ge', 'cmp/ge', 'cmp/gt', 'cmp/hi', 'cmp/hs'
|
|
203
|
+
lambda { |di, a0, a1| { :t_bit => decode_cmp_expr(di, a0, a1) }}
|
|
204
|
+
when 'cmp/pl', 'cmp/pz'
|
|
205
|
+
lambda { |di, a0| { :t_bit => decode_cmp_cst(di, a0) }}
|
|
206
|
+
when 'tst'; lambda { |di, a0, a1| { :t_bit => Expression[[a0, :&, mask[di]], :==, [a1, :&, mask[di]]] }}
|
|
207
|
+
when 'rte'; lambda { |di| { :pc => :spc , :sr => :ssr }}
|
|
208
|
+
when 'rts'; lambda { |di| { :pc => :pr }}
|
|
209
|
+
when 'sets'; lambda { |di| { :s_bit => 1 }}
|
|
210
|
+
when 'sett'; lambda { |di| { :t_bit => 1 }}
|
|
211
|
+
when 'clrs'; lambda { |di| { :s_bit => 0 }}
|
|
212
|
+
when 'clrt'; lambda { |di| { :t_bit => 0 }}
|
|
213
|
+
when 'clrmac'; lambda { |di| { :macl => 0, :mach => 0 }}
|
|
214
|
+
when 'jmp'; lambda { |di, a0| { :pc => a0 }}
|
|
215
|
+
when 'jsr'; lambda { |di, a0| { :pc => Expression[a0], :pr => Expression[di.address+2*2] }}
|
|
216
|
+
when 'dt'; lambda { |di, a0|
|
|
217
|
+
res = Expression[a0, :-, 1]
|
|
218
|
+
{ :a0 => res, :t_bit => Expression[res, :==, 0] }
|
|
219
|
+
}
|
|
220
|
+
when 'add' ; lambda { |di, a0, a1| { a1 => Expression[a0, :+, a1] }}
|
|
221
|
+
when 'addc' ; lambda { |di, a0, a1|
|
|
222
|
+
res = Expression[[a0, :&, mask[di]], :+, [[a1, :&, mask[di]], :+, :t_bit]]
|
|
223
|
+
{ a1 => Expression[a0, :+, [a1, :+, :t_bit]], :t_bit => Expression[res, :>, mask[di]] }
|
|
224
|
+
}
|
|
225
|
+
when 'addv' ; lambda { |di, a0, a1|
|
|
226
|
+
res = Expression[[a0, :&, mask[di]], :+, [[a1, :&, mask[di]]]]
|
|
227
|
+
{ a1 => Expression[a0, :+, [a1, :+, :t_bit]], :t_bit => Expression[res, :>, mask[di]] }
|
|
228
|
+
}
|
|
229
|
+
when 'shll16', 'shll8', 'shll2', 'shll' ; lambda { |di, a0|
|
|
230
|
+
shift = { 'shll16' => 16, 'shll8' => 8, 'shll2' => 2, 'shll' => 1 }[op]
|
|
231
|
+
{ a0 => Expression[[a0, :<<, shift], :&, 0xffff] }
|
|
232
|
+
}
|
|
233
|
+
when 'shlr16', 'shlr8', 'shlr2','shlr'; lambda { |di, a0|
|
|
234
|
+
shift = { 'shlr16' => 16, 'shlr8' => 8, 'shlr2' => 2, 'shlr' => 1 }[op]
|
|
235
|
+
{ a0 => Expression[a0, :>>, shift] }
|
|
236
|
+
}
|
|
237
|
+
when 'rotcl'; lambda { |di, a0| { a0 => Expression[[a0, :<<, 1], :|, :t_bit], :t_bit => Expression[a0, :>>, [opsz[di], :-, 1]] }}
|
|
238
|
+
when 'rotcr'; lambda { |di, a0| { a0 => Expression[[a0, :>>, 1], :|, :t_bit], :t_bit => Expression[a0, :&, 1] }}
|
|
239
|
+
when 'rotl'; lambda { |di, a0|
|
|
240
|
+
shift_bit = [a0, :<<, [opsz[di], :-, 1]]
|
|
241
|
+
{ a0 => Expression[[a0, :<<, 1], :|, shift_bit], :t_bit => shift_bit }
|
|
242
|
+
}
|
|
243
|
+
when 'rotr'; lambda { |di, a0|
|
|
244
|
+
shift_bit = [a0, :>>, [opsz[di], :-, 1]]
|
|
245
|
+
{ a0 => Expression[[a0, :>>, 1], :|, shift_bit], :t_bit => shift_bit }
|
|
246
|
+
}
|
|
247
|
+
when 'shal'; lambda { |di, a0|
|
|
248
|
+
shift_bit = [a0, :<<, [opsz[di], :-, 1]]
|
|
249
|
+
{ a0 => Expression[a0, :<<, 1], :t_bit => shift_bit }
|
|
250
|
+
}
|
|
251
|
+
when 'shar'; lambda { |di, a0|
|
|
252
|
+
shift_bit = Expression[a0, :&, 1]
|
|
253
|
+
{ a0 => Expression[a0, :>>, 1], :t_bit => shift_bit }
|
|
254
|
+
}
|
|
255
|
+
when 'sub'; lambda { |di, a0, a1| { a1 => Expression[a0, :-, a1] }}
|
|
256
|
+
when 'subc'; lambda { |di, a0, a1| { a1 => Expression[a0, :-, [a1, :-, :t_bit]] }}
|
|
257
|
+
when 'and', 'and.b'; lambda { |di, a0, a1| { a1 => Expression[[a0, :&, mask[di]], :|, [[a1, :&, mask[di]]]] }}
|
|
258
|
+
when 'or', 'or.b'; lambda { |di, a0, a1| { a1 => Expression[[a0, :|, mask[di]], :|, [[a1, :&, mask[di]]]] }}
|
|
259
|
+
when 'xor', 'xor.b'; lambda { |di, a0, a1| { a1 => Expression[[a0, :|, mask[di]], :^, [[a1, :&, mask[di]]]] }}
|
|
260
|
+
when 'add', 'addc', 'addv'; lambda { |di, a0, a1| { a1 => Expression[a0, :+, a1] }}
|
|
261
|
+
when 'neg' ; lambda { |di, a0, a1| { a1 => Expression[mask[di], :-, a0] }}
|
|
262
|
+
when 'negc' ; lambda { |di, a0, a1| { a1 => Expression[[[mask[di], :-, a0], :-, :t_bit], :&, mask[di]] }}
|
|
263
|
+
when 'not'; lambda { |di, a0, a1| { a1 => Expression[a0, :^, mask[di]] }}
|
|
264
|
+
when 'nop'; lambda { {} }
|
|
265
|
+
when /^b/; lambda { {} } # branches
|
|
266
|
+
end
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
@backtrace_binding
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def get_backtrace_binding(di)
|
|
273
|
+
a = di.instruction.args.map { |arg|
|
|
274
|
+
case arg
|
|
275
|
+
when GPR, XFR, XDR, FVR, DR, FR, XMTRX; arg.symbolic
|
|
276
|
+
when MACH, MACL, PR, FPUL, PC, FPSCR; arg.symbolic
|
|
277
|
+
when SR, SSR, SPC, GBR, VBR, SGR, DBR; arg.symbolic
|
|
278
|
+
when Memref; arg.symbolic(di.address, di.opcode.props[:memsz]/8)
|
|
279
|
+
else arg
|
|
280
|
+
end
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if binding = backtrace_binding[di.opcode.basename]
|
|
284
|
+
bd = binding[di, *a] || {}
|
|
285
|
+
di.instruction.args.grep(Memref).each { |m|
|
|
286
|
+
if m.post
|
|
287
|
+
# TODO preincrement/postdecrement
|
|
288
|
+
bd.each { |k, v| bd[k] = v.bind(r => Expression[r, :+, 1]) }
|
|
289
|
+
bd[r] ||= Expression[r, :+, 1]
|
|
290
|
+
end
|
|
291
|
+
} if false
|
|
292
|
+
bd
|
|
293
|
+
else
|
|
294
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
|
295
|
+
{:incomplete_binding => Expression[1]}
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def get_xrefs_x(dasm, di)
|
|
300
|
+
return [] if not di.opcode.props[:setip]
|
|
301
|
+
|
|
302
|
+
val = case di.instruction.opname
|
|
303
|
+
when 'rts'; :pr
|
|
304
|
+
else di.instruction.args.last
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
val = case val
|
|
308
|
+
when Reg; val.symbolic
|
|
309
|
+
when Memref; arg.symbolic(di.address, 4)
|
|
310
|
+
else val
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
[Expression[val]]
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def backtrace_is_function_return(expr, di=nil)
|
|
317
|
+
expr.reduce_rec == :pr
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def delay_slot(di=nil)
|
|
321
|
+
(di and di.opcode.props[:delay_slot]) ? 1 : 0
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def replace_instr_arg_immediate(i, old, new)
|
|
325
|
+
i.args.map! { |a|
|
|
326
|
+
case a
|
|
327
|
+
when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
|
|
328
|
+
when Memref
|
|
329
|
+
a.base = (a.base == old ? new : Expression[a.base.bind(old => new).reduce]) if a.base.kind_of?(Expression)
|
|
330
|
+
a
|
|
331
|
+
else a
|
|
332
|
+
end
|
|
333
|
+
}
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|