metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,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
@@ -0,0 +1,8 @@
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/sh4/decode'
@@ -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