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