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