metasm 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (276) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -0
  4. data/.gitignore +3 -0
  5. data/.hgtags +3 -0
  6. data/Gemfile +3 -0
  7. data/INSTALL +61 -0
  8. data/LICENCE +458 -0
  9. data/README +29 -21
  10. data/Rakefile +10 -0
  11. data/TODO +10 -12
  12. data/doc/code_organisation.txt +3 -1
  13. data/doc/core/DynLdr.txt +247 -0
  14. data/doc/core/ExeFormat.txt +43 -0
  15. data/doc/core/Expression.txt +220 -0
  16. data/doc/core/GNUExports.txt +27 -0
  17. data/doc/core/Ia32.txt +236 -0
  18. data/doc/core/SerialStruct.txt +108 -0
  19. data/doc/core/VirtualString.txt +145 -0
  20. data/doc/core/WindowsExports.txt +61 -0
  21. data/doc/core/index.txt +1 -0
  22. data/doc/style.css +6 -3
  23. data/doc/usage/debugger.txt +327 -0
  24. data/doc/usage/index.txt +1 -0
  25. data/doc/use_cases.txt +2 -2
  26. data/metasm.gemspec +23 -0
  27. data/{lib/metasm.rb → metasm.rb} +15 -3
  28. data/{lib/metasm → metasm}/compile_c.rb +15 -9
  29. data/metasm/cpu/arc.rb +8 -0
  30. data/metasm/cpu/arc/decode.rb +404 -0
  31. data/metasm/cpu/arc/main.rb +191 -0
  32. data/metasm/cpu/arc/opcodes.rb +588 -0
  33. data/metasm/cpu/arm.rb +14 -0
  34. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  35. data/{lib/metasm → metasm/cpu}/arm/decode.rb +15 -18
  36. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  37. data/{lib/metasm → metasm/cpu}/arm/main.rb +3 -6
  38. data/metasm/cpu/arm/opcodes.rb +324 -0
  39. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  40. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  41. data/metasm/cpu/arm64.rb +15 -0
  42. data/metasm/cpu/arm64/debug.rb +38 -0
  43. data/metasm/cpu/arm64/decode.rb +285 -0
  44. data/metasm/cpu/arm64/encode.rb +41 -0
  45. data/metasm/cpu/arm64/main.rb +105 -0
  46. data/metasm/cpu/arm64/opcodes.rb +232 -0
  47. data/metasm/cpu/arm64/parse.rb +20 -0
  48. data/metasm/cpu/arm64/render.rb +95 -0
  49. data/{lib/metasm/mips/compile_c.rb → metasm/cpu/bpf.rb} +4 -2
  50. data/metasm/cpu/bpf/decode.rb +110 -0
  51. data/metasm/cpu/bpf/main.rb +60 -0
  52. data/metasm/cpu/bpf/opcodes.rb +81 -0
  53. data/metasm/cpu/bpf/render.rb +30 -0
  54. data/{lib/metasm/ppc.rb → metasm/cpu/cy16.rb} +2 -4
  55. data/metasm/cpu/cy16/decode.rb +247 -0
  56. data/metasm/cpu/cy16/main.rb +63 -0
  57. data/metasm/cpu/cy16/opcodes.rb +78 -0
  58. data/metasm/cpu/cy16/render.rb +30 -0
  59. data/metasm/cpu/dalvik.rb +11 -0
  60. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +34 -34
  61. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +71 -4
  62. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +21 -12
  63. data/{lib/metasm/mips.rb → metasm/cpu/ebpf.rb} +3 -4
  64. data/metasm/cpu/ebpf/debug.rb +61 -0
  65. data/metasm/cpu/ebpf/decode.rb +142 -0
  66. data/metasm/cpu/ebpf/main.rb +58 -0
  67. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  68. data/metasm/cpu/ebpf/render.rb +36 -0
  69. data/metasm/cpu/ia32.rb +17 -0
  70. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +23 -9
  71. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +44 -6
  72. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +342 -128
  73. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +75 -53
  74. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  75. data/{lib/metasm → metasm/cpu}/ia32/main.rb +66 -8
  76. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  77. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +55 -17
  78. data/{lib/metasm → metasm/cpu}/ia32/render.rb +32 -5
  79. data/metasm/cpu/mcs51.rb +8 -0
  80. data/metasm/cpu/mcs51/decode.rb +99 -0
  81. data/metasm/cpu/mcs51/main.rb +87 -0
  82. data/metasm/cpu/mcs51/opcodes.rb +120 -0
  83. data/metasm/cpu/mips.rb +14 -0
  84. data/metasm/cpu/mips/debug.rb +42 -0
  85. data/{lib/metasm → metasm/cpu}/mips/decode.rb +59 -38
  86. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  87. data/{lib/metasm → metasm/cpu}/mips/main.rb +13 -6
  88. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +87 -18
  89. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  90. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  91. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  92. data/metasm/cpu/msp430/decode.rb +243 -0
  93. data/metasm/cpu/msp430/main.rb +62 -0
  94. data/metasm/cpu/msp430/opcodes.rb +101 -0
  95. data/metasm/cpu/openrisc.rb +11 -0
  96. data/metasm/cpu/openrisc/debug.rb +106 -0
  97. data/metasm/cpu/openrisc/decode.rb +182 -0
  98. data/metasm/cpu/openrisc/decompile.rb +350 -0
  99. data/metasm/cpu/openrisc/main.rb +70 -0
  100. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  101. data/metasm/cpu/openrisc/render.rb +37 -0
  102. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  103. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  104. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  105. data/metasm/cpu/ppc.rb +11 -0
  106. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -37
  107. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  108. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  109. data/{lib/metasm → metasm/cpu}/ppc/main.rb +23 -18
  110. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -6
  111. data/metasm/cpu/ppc/parse.rb +55 -0
  112. data/metasm/cpu/python.rb +8 -0
  113. data/metasm/cpu/python/decode.rb +116 -0
  114. data/metasm/cpu/python/main.rb +36 -0
  115. data/metasm/cpu/python/opcodes.rb +180 -0
  116. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  117. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +50 -23
  118. data/{lib/metasm → metasm/cpu}/sh4/main.rb +38 -27
  119. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  120. data/metasm/cpu/st20.rb +9 -0
  121. data/metasm/cpu/st20/decode.rb +173 -0
  122. data/metasm/cpu/st20/decompile.rb +283 -0
  123. data/metasm/cpu/st20/main.rb +37 -0
  124. data/metasm/cpu/st20/opcodes.rb +140 -0
  125. data/{lib/metasm/arm.rb → metasm/cpu/webasm.rb} +4 -5
  126. data/metasm/cpu/webasm/debug.rb +31 -0
  127. data/metasm/cpu/webasm/decode.rb +321 -0
  128. data/metasm/cpu/webasm/decompile.rb +386 -0
  129. data/metasm/cpu/webasm/encode.rb +104 -0
  130. data/metasm/cpu/webasm/main.rb +81 -0
  131. data/metasm/cpu/webasm/opcodes.rb +214 -0
  132. data/metasm/cpu/x86_64.rb +15 -0
  133. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +40 -25
  134. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  135. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +58 -15
  136. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +59 -28
  137. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +18 -6
  138. data/metasm/cpu/x86_64/opcodes.rb +138 -0
  139. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +12 -4
  140. data/metasm/cpu/x86_64/render.rb +35 -0
  141. data/metasm/cpu/z80.rb +9 -0
  142. data/metasm/cpu/z80/decode.rb +286 -0
  143. data/metasm/cpu/z80/main.rb +67 -0
  144. data/metasm/cpu/z80/opcodes.rb +224 -0
  145. data/metasm/cpu/z80/render.rb +48 -0
  146. data/{lib/metasm/os/main.rb → metasm/debug.rb} +201 -407
  147. data/{lib/metasm → metasm}/decode.rb +104 -24
  148. data/{lib/metasm → metasm}/decompile.rb +804 -478
  149. data/{lib/metasm → metasm}/disassemble.rb +385 -170
  150. data/{lib/metasm → metasm}/disassemble_api.rb +684 -105
  151. data/{lib/metasm → metasm}/dynldr.rb +231 -138
  152. data/{lib/metasm → metasm}/encode.rb +20 -5
  153. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  154. data/{lib/metasm → metasm}/exe_format/autoexe.rb +3 -0
  155. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  156. data/{lib/metasm → metasm}/exe_format/coff.rb +35 -7
  157. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +70 -23
  158. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +24 -22
  159. data/{lib/metasm → metasm}/exe_format/dex.rb +26 -8
  160. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  161. data/{lib/metasm → metasm}/exe_format/elf.rb +108 -58
  162. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +202 -36
  163. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +126 -32
  164. data/metasm/exe_format/gb.rb +65 -0
  165. data/metasm/exe_format/javaclass.rb +424 -0
  166. data/{lib/metasm → metasm}/exe_format/macho.rb +218 -16
  167. data/{lib/metasm → metasm}/exe_format/main.rb +28 -3
  168. data/{lib/metasm → metasm}/exe_format/mz.rb +2 -0
  169. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  170. data/{lib/metasm → metasm}/exe_format/pe.rb +96 -11
  171. data/metasm/exe_format/pyc.rb +167 -0
  172. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  173. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  174. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  175. data/metasm/exe_format/swf.rb +205 -0
  176. data/metasm/exe_format/wasm.rb +402 -0
  177. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  178. data/metasm/exe_format/zip.rb +335 -0
  179. data/metasm/gui.rb +13 -0
  180. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  181. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  182. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +177 -114
  183. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  184. data/metasm/gui/dasm_graph.rb +1754 -0
  185. data/{lib/metasm → metasm}/gui/dasm_hex.rb +16 -12
  186. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  187. data/{lib/metasm → metasm}/gui/dasm_main.rb +360 -77
  188. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  189. data/{lib/metasm → metasm}/gui/debug.rb +109 -34
  190. data/{lib/metasm → metasm}/gui/gtk.rb +174 -44
  191. data/{lib/metasm → metasm}/gui/qt.rb +14 -4
  192. data/{lib/metasm → metasm}/gui/win32.rb +180 -43
  193. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  194. data/{lib/metasm → metasm}/main.rb +421 -286
  195. data/metasm/os/emulator.rb +175 -0
  196. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  197. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  198. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  199. data/metasm/os/main.rb +335 -0
  200. data/{lib/metasm → metasm}/os/windows.rb +151 -58
  201. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  202. data/{lib/metasm → metasm}/parse.rb +49 -36
  203. data/{lib/metasm → metasm}/parse_c.rb +405 -246
  204. data/{lib/metasm → metasm}/preprocessor.rb +71 -41
  205. data/{lib/metasm → metasm}/render.rb +14 -38
  206. data/misc/hexdump.rb +4 -3
  207. data/misc/lint.rb +58 -0
  208. data/misc/objdiff.rb +4 -1
  209. data/misc/objscan.rb +1 -1
  210. data/misc/openrisc-parser.rb +79 -0
  211. data/misc/txt2html.rb +9 -7
  212. data/samples/bindiff.rb +3 -4
  213. data/samples/dasm-plugins/bindiff.rb +15 -0
  214. data/samples/dasm-plugins/bookmark.rb +133 -0
  215. data/samples/dasm-plugins/c_constants.rb +57 -0
  216. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  217. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  218. data/samples/dasm-plugins/dasm_all.rb +70 -0
  219. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  220. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  221. data/samples/dasm-plugins/dump_text.rb +35 -0
  222. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  223. data/samples/dasm-plugins/findgadget.rb +75 -0
  224. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  225. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  226. data/samples/dasm-plugins/imm2off.rb +34 -0
  227. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  228. data/samples/dasm-plugins/patch_file.rb +95 -0
  229. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  230. data/samples/dasm-plugins/scanxrefs.rb +29 -0
  231. data/samples/dasm-plugins/selfmodify.rb +197 -0
  232. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  233. data/samples/dasmnavig.rb +1 -1
  234. data/samples/dbg-apihook.rb +24 -9
  235. data/samples/dbg-plugins/heapscan.rb +283 -0
  236. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  237. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  238. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  239. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  240. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  241. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  242. data/samples/dbg-plugins/trace_func.rb +214 -0
  243. data/samples/disassemble-gui.rb +48 -7
  244. data/samples/disassemble.rb +31 -6
  245. data/samples/dump_upx.rb +24 -12
  246. data/samples/dynamic_ruby.rb +35 -27
  247. data/samples/elfencode.rb +15 -0
  248. data/samples/emubios.rb +251 -0
  249. data/samples/emudbg.rb +127 -0
  250. data/samples/exeencode.rb +6 -5
  251. data/samples/factorize-headers-peimports.rb +1 -1
  252. data/samples/lindebug.rb +186 -391
  253. data/samples/metasm-shell.rb +68 -57
  254. data/samples/peldr.rb +2 -2
  255. data/tests/all.rb +1 -1
  256. data/tests/arc.rb +26 -0
  257. data/tests/dynldr.rb +22 -4
  258. data/tests/expression.rb +57 -0
  259. data/tests/graph_layout.rb +285 -0
  260. data/tests/ia32.rb +80 -26
  261. data/tests/mcs51.rb +27 -0
  262. data/tests/mips.rb +10 -3
  263. data/tests/preprocessor.rb +18 -0
  264. data/tests/x86_64.rb +66 -18
  265. metadata +465 -219
  266. metadata.gz.sig +2 -0
  267. data/lib/metasm/arm/opcodes.rb +0 -177
  268. data/lib/metasm/gui.rb +0 -23
  269. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  270. data/lib/metasm/ia32.rb +0 -14
  271. data/lib/metasm/ia32/opcodes.rb +0 -872
  272. data/lib/metasm/ppc/parse.rb +0 -52
  273. data/lib/metasm/x86_64.rb +0 -12
  274. data/lib/metasm/x86_64/opcodes.rb +0 -118
  275. data/samples/gdbclient.rb +0 -583
  276. data/samples/rubstop.rb +0 -399
@@ -17,16 +17,22 @@ class Indirection < ExpressionType
17
17
  alias pointer target
18
18
  alias pointer= target=
19
19
  # length in bytes of data referenced
20
- attr_accessor :len
20
+ attr_reader :len
21
21
  # address of the instruction who generated the indirection
22
22
  attr_accessor :origin
23
23
 
24
24
  def initialize(target, len, origin)
25
- @target, @len, @origin = target, len, origin
25
+ @target, @origin = target, origin
26
+ self.len = len
26
27
  end
27
28
 
28
- def reduce_rec
29
- ptr = Expression[@target.reduce]
29
+ def len=(len)
30
+ @len = len
31
+ @max_bits_mask ||= (1 << (len*8)) - 1 if len.kind_of?(::Integer)
32
+ end
33
+
34
+ def reduce_rec(cb=nil)
35
+ ptr = Expression[@target.reduce(&cb)]
30
36
  (ptr == Expression::Unknown) ? ptr : Indirection.new(ptr, @len, @origin)
31
37
  end
32
38
 
@@ -63,24 +69,25 @@ class Indirection < ExpressionType
63
69
  @target.externals
64
70
  end
65
71
 
66
- def match_rec(target, vars)
67
- return false if not target.kind_of? Indirection
68
- t = target.target
69
- if vars[t]
70
- return false if @target != vars[t]
71
- elsif vars.has_key? t
72
- vars[t] = @target
73
- elsif t.kind_of? ExpressionType
74
- return false if not @target.match_rec(t, vars)
72
+ def match_rec(pattern, vars)
73
+ return false if not pattern.kind_of? Indirection
74
+ pt = pattern.target
75
+ if vars[pt]
76
+ return false if @target != vars[pt]
77
+ elsif vars.has_key? pt
78
+ vars[pt] = @target
79
+ elsif pt.kind_of? ExpressionType
80
+ return false if not @target.match_rec(pt, vars)
75
81
  else
76
- return false if targ != @target
82
+ return false if pt != @target
77
83
  end
78
- if vars[target.len]
79
- return false if @len != vars[target.len]
80
- elsif vars.has_key? target.len
81
- vars[target.len] = @len
84
+ pl = pattern.len
85
+ if vars[pl]
86
+ return false if @len != vars[pl]
87
+ elsif vars.has_key? pl
88
+ vars[pl] = @len
82
89
  else
83
- return false if target.len != @len
90
+ return false if pl != @len
84
91
  end
85
92
  vars
86
93
  end
@@ -134,9 +141,10 @@ class EncodedData
134
141
  # bytes from rawsize to virtsize are returned as zeroes
135
142
  # ignores self.relocations
136
143
  def read(len=@virtsize-@ptr)
137
- len = @virtsize-@ptr if len > @virtsize-@ptr
138
- str = (@ptr < @data.length) ? @data[@ptr, len] : ''
139
- str = str.to_str.ljust(len, "\0") if str.length < len
144
+ vlen = len
145
+ vlen = @virtsize-@ptr if len > @virtsize-@ptr
146
+ str = (@ptr < @data.length) ? @data[@ptr, vlen] : ''
147
+ str = str.to_str.ljust(vlen, "\0") if str.length < vlen
140
148
  @ptr += len
141
149
  str
142
150
  end
@@ -178,11 +186,15 @@ class Expression
178
186
  end
179
187
 
180
188
  class CPU
189
+ def bin_lookaside
190
+ @bin_lookaside ||= build_bin_lookaside
191
+ end
192
+
181
193
  # decodes the instruction at edata.ptr, mapped at virtual address off
182
194
  # returns a DecodedInstruction or nil
183
195
  def decode_instruction(edata, addr)
184
- @bin_lookaside ||= build_bin_lookaside
185
- di = decode_findopcode edata
196
+ bin_lookaside
197
+ di = decode_findopcode edata if edata.ptr <= edata.length
186
198
  di.address = addr if di
187
199
  di = decode_instr_op(edata, di) if di
188
200
  decode_instr_interpret(di, addr) if di
@@ -205,9 +217,77 @@ class CPU
205
217
  di
206
218
  end
207
219
 
220
+ # return a symbolic representation of an instruction argument (eg Reg[0] => :eax)
221
+ def symbolic(arg, di=nil)
222
+ case arg
223
+ when ExpressionType
224
+ arg
225
+ when Integer
226
+ Expression[arg]
227
+ else
228
+ arg.symbolic(di)
229
+ end
230
+ end
231
+
208
232
  # number of instructions following a jump that are still executed
209
233
  def delay_slot(di=nil)
210
234
  0
211
235
  end
236
+
237
+ def disassembler_default_func
238
+ DecodedFunction.new
239
+ end
240
+
241
+ # hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
242
+ def backtrace_binding
243
+ @backtrace_binding ||= init_backtrace_binding
244
+ end
245
+ def backtrace_binding=(b) @backtrace_binding = b end
246
+
247
+ # return the backtrace binding for a specific di
248
+ def get_backtrace_binding(di)
249
+ a = di.instruction.args.map { |arg| symbolic(arg, di) }
250
+
251
+ if binding = backtrace_binding[di.opcode.name]
252
+ binding[di, *a]
253
+ else
254
+ puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
255
+ {:incomplete_binding => Expression[1]}
256
+ end
257
+ end
258
+
259
+ # return something like backtrace_binding in the forward direction
260
+ # set pc_reg to some reg name (eg :pc) to include effects on the instruction pointer
261
+ # pass a debugger to allow reading the context and actually resolve the next pc in case of conditional jumps
262
+ def get_fwdemu_binding(di, pc_reg=nil, dbg_ctx=nil)
263
+ fbd = di.backtrace_binding ||= get_backtrace_binding(di)
264
+ fbd = fix_fwdemu_binding(di, fbd)
265
+ if pc_reg
266
+ n_a = Expression[pc_reg, :+, di.bin_length]
267
+ if di.opcode.props[:setip]
268
+ xr = get_xrefs_x(nil, di).to_a
269
+ xr |= [n_a] if not di.opcode.props[:stopexec]
270
+ if xr.length == 1
271
+ fbd[pc_reg] = xr[0]
272
+ else
273
+ dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
274
+ end
275
+ else
276
+ fbd[pc_reg] = Expression[pc_reg, :+, di.bin_length]
277
+ end
278
+ end
279
+ fbd
280
+ end
281
+
282
+ # resolve the program counter following a conditional jump using a debugging context
283
+ def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
284
+ fbd[:incomplete_binding] = Expression[1]
285
+ end
286
+
287
+ # patch a forward binding from the backtrace binding
288
+ # useful only on specific instructions that update a register *and* dereference that register (eg push)
289
+ def fix_fwdemu_binding(di, fbd)
290
+ fbd
291
+ end
212
292
  end
213
293
  end
@@ -13,24 +13,19 @@ class C::Variable; attr_accessor :stackoff; end
13
13
  class C::Block; attr_accessor :decompdata; end
14
14
  class DecodedFunction; attr_accessor :decompdata; end
15
15
 
16
- class CPU
17
- def decompile_check_abi(dcmp, entry, func)
18
- end
19
- end
20
-
21
16
  class Decompiler
22
- # TODO add methods to C::CExpr
23
- AssignOp = [:'=', :'+=', :'-=', :'*=', :'/=', :'%=', :'^=', :'&=', :'|=', :'>>=', :'<<=', :'++', :'--']
24
-
25
17
  attr_accessor :dasm, :c_parser
26
- attr_accessor :forbid_optimize_dataflow, :forbid_optimize_code, :forbid_decompile_ifwhile, :forbid_decompile_types, :forbid_optimize_labels
18
+ attr_accessor :forbid_optimize_dataflow, :forbid_optimize_code, :forbid_decompile_ifwhile, :forbid_decompile_types, :forbid_optimize_labels, :forbid_all_optimizations
27
19
  # recursive flag: for each subfunction, recurse is decremented, when 0 only the prototype is decompiled, when <0 nothing is done
28
20
  attr_accessor :recurse
29
21
 
22
+ def disassembler ; dasm ; end
23
+
30
24
  def initialize(dasm, cp = dasm.c_parser)
31
25
  @dasm = dasm
32
26
  @recurse = 1/0.0 # Infinity
33
27
  @c_parser = cp || @dasm.cpu.new_cparser
28
+ @dasm.cpu.decompile_init(self) if @dasm.cpu.respond_to?(:decompile_init)
34
29
  end
35
30
 
36
31
  # decompile recursively function from an entrypoint, then perform global optimisation (static vars, ...)
@@ -69,7 +64,7 @@ class Decompiler
69
64
  @c_parser.toplevel.symbol.delete func.name
70
65
  decompile_func(entry)
71
66
  @recurse = pre_recurse
72
- if not dcl = @c_parser.toplevel.statements.grep(C::Declaration).find { |decl| decl.var.name == func.name }
67
+ if not @c_parser.toplevel.statements.grep(C::Declaration).find { |decl| decl.var.name == func.name }
73
68
  @c_parser.toplevel.statements << C::Declaration.new(func)
74
69
  end
75
70
  end
@@ -103,6 +98,7 @@ class Decompiler
103
98
  myblocks = listblocks_func(entry)
104
99
 
105
100
  # [esp+8] => [:frameptr-12]
101
+ # TODO slow
106
102
  makestackvars entry, myblocks.map { |b, to| @dasm.decoded[b].block }
107
103
 
108
104
  # find registry dependencies between blocks
@@ -110,24 +106,31 @@ class Decompiler
110
106
 
111
107
  scope = func.initializer = C::Block.new(@c_parser.toplevel)
112
108
  if df = @dasm.function[entry]
113
- scope.decompdata = df.decompdata ||= {:stackoff_type => {}, :stackoff_name => {}}
109
+ scope.decompdata = df.decompdata ||= {:unalias_type => {}, :unalias_name => {}}
114
110
  else
115
- scope.decompdata ||= {:stackoff_type => {}, :stackoff_name => {}}
111
+ scope.decompdata ||= {:unalias_type => {}, :unalias_name => {}}
116
112
  end
117
113
 
118
114
  # di blocks => raw c statements, declare variables
119
115
  @dasm.cpu.decompile_blocks(self, myblocks, deps, func)
116
+ puts "dcmp debug #{func.name} {", scope, '}' if $DEBUG
117
+
118
+ return if forbid_all_optimizations
120
119
 
121
120
  simplify_goto(scope)
122
121
  namestackvars(scope)
123
122
  unalias_vars(scope, func)
124
123
  decompile_c_types(scope)
125
- optimize(scope)
124
+ optimize_code(scope)
125
+ optimize_vars(scope)
126
+ optimize_vars(scope) # 1st run may transform i = i+1 into i++ which second run may coalesce into if(i)
126
127
  remove_unreferenced_vars(scope)
128
+ decompile_c_types_again(scope)
127
129
  cleanup_var_decl(scope, func)
128
130
  if @recurse > 0
129
131
  decompile_controlseq(scope)
130
132
  optimize_vars(scope)
133
+ optimize_code(scope)
131
134
  optimize_ctrl(scope)
132
135
  optimize_vars(scope)
133
136
  remove_unreferenced_vars(scope)
@@ -143,7 +146,7 @@ class Decompiler
143
146
  scope.statements.pop
144
147
  else
145
148
  v = ret.value
146
- v = v.rexpr if v.kind_of? C::CExpression and not v.op and v.rexpr.kind_of? C::Typed
149
+ v = v.rexpr if v.kind_of?(C::CExpression) and not v.op and v.rexpr.kind_of?(C::Typed)
147
150
  func.type.type = v.type
148
151
  end
149
152
  end
@@ -156,21 +159,21 @@ class Decompiler
156
159
 
157
160
  # redecompile a function, redecompiles functions calling it if its prototype changed
158
161
  def redecompile(name)
159
- @c_parser.toplevel.statements.delete_if { |st| st.kind_of? C::Declaration and st.var.name == name }
162
+ @c_parser.toplevel.statements.delete_if { |st| st.kind_of?(C::Declaration) and st.var.name == name }
160
163
  oldvar = @c_parser.toplevel.symbol.delete name
161
164
 
162
165
  decompile_func(name)
163
166
 
164
- if oldvar and newvar = @c_parser.toplevel.symbol[name] and oldvar.type.kind_of? C::Function and newvar.type.kind_of? C::Function
167
+ if oldvar and newvar = @c_parser.toplevel.symbol[name] and oldvar.type.kind_of?(C::Function) and newvar.type.kind_of?(C::Function)
165
168
  o, n = oldvar.type, newvar.type
166
169
  if o.type != n.type or o.args.to_a.length != n.args.to_a.length or o.args.to_a.zip(n.args.to_a).find { |oa, na| oa.type != na.type }
167
170
  # XXX a may depend on b and c, and b may depend on c -> redecompile c twice
168
171
  # XXX if the dcmp is unstable, may also infinite loop on mutually recursive funcs..
169
172
  @c_parser.toplevel.statements.dup.each { |st|
170
- next if not st.kind_of? C::Declaration
173
+ next if not st.kind_of?(C::Declaration)
171
174
  next if not st.var.initializer
172
175
  next if st.var.name == name
173
- next if not walk_ce(st) { |ce| break true if ce.op == :funcall and ce.lexpr.kind_of? C::Variable and ce.lexpr.name == name }
176
+ next if not walk_ce(st) { |ce| break true if ce.op == :funcall and ce.lexpr.kind_of?(C::Variable) and ce.lexpr.name == name }
174
177
  redecompile(st.var.name)
175
178
  }
176
179
  end
@@ -181,38 +184,39 @@ class Decompiler
181
184
  addr = @dasm.normalize(addr)
182
185
 
183
186
  # (almost) NULL ptr
184
- return if addr.kind_of? Fixnum and addr >= 0 and addr < 32
187
+ return if addr.kind_of?(Integer) and addr >= 0 and addr < 32
185
188
 
186
189
  # check preceding structure we're hitting
187
190
  # TODO check what we step over when defining a new static struct
188
191
  0x100.times { |i_|
189
192
  next if not n = @dasm.get_label_at(addr-i_)
190
193
  next if not v = @c_parser.toplevel.symbol[n]
191
- next if not v.type.pointer? or not v.type.pointed.untypedef.kind_of? C::Union
194
+ next if not v.type.pointer? or not v.type.pointed.untypedef.kind_of?(C::Union)
192
195
  break if i_ == 0 # XXX it crashes later if we dont break here
193
196
  next if sizeof(v.type.pointed) <= i_
194
197
  return structoffset(v.type.pointed.untypedef, C::CExpression[v], i_, nil)
195
198
  }
196
199
 
197
200
  ptype = type.pointed.untypedef if type.pointer?
198
- if ptype.kind_of? C::Function
201
+ if ptype.kind_of?(C::Function)
199
202
  name = @dasm.auto_label_at(addr, 'sub', 'xref', 'byte', 'word', 'dword', 'unk')
200
203
  if @dasm.get_section_at(addr) and @recurse > 0
201
204
  puts "found function pointer to #{name}" if $VERBOSE
202
205
  @dasm.disassemble(addr) if not @dasm.decoded[addr] # TODO disassemble_fast ?
203
206
  f = @dasm.function[addr] ||= DecodedFunction.new
204
207
  # TODO detect thunks (__noreturn)
205
- f.decompdata ||= { :stackoff_type => {}, :stackoff_name => {} }
206
- if not s = @c_parser.toplevel.symbol[name] or not s.initializer or not s.type.untypedef.kind_of? C::Function
208
+ f.decompdata ||= { :unalias_type => {}, :unalias_name => {} }
209
+ if not s = @c_parser.toplevel.symbol[name] or not s.initializer or not s.type.untypedef.kind_of?(C::Function)
207
210
  os = @c_parser.toplevel.symbol.delete name
208
- @c_parser.toplevel.statements.delete_if { |ts| ts.kind_of? C::Declaration and ts.var.name == name }
209
- aoff = 1
210
- ptype.args.to_a.each { |a|
211
- aoff = (aoff + @c_parser.typesize[:ptr] - 1) / @c_parser.typesize[:ptr] * @c_parser.typesize[:ptr]
212
- f.decompdata[:stackoff_type][aoff] ||= a.type
213
- f.decompdata[:stackoff_name][aoff] ||= a.name if a.name
214
- aoff += sizeof(a) # ary ?
215
- }
211
+ @c_parser.toplevel.statements.delete_if { |ts| ts.kind_of?(C::Declaration) and ts.var.name == name }
212
+ #aoff = 1
213
+ #ptype.args.to_a.each { |a|
214
+ # TODO
215
+ #aoff = (aoff + @c_parser.typesize[:ptr] - 1) / @c_parser.typesize[:ptr] * @c_parser.typesize[:ptr]
216
+ #f.decompdata[:unalias_type][aoff] ||= a.type
217
+ #f.decompdata[:unalias_name][aoff] ||= a.name if a.name
218
+ #aoff += sizeof(a) # ary ?
219
+ #}
216
220
  decompile_func_rec(addr)
217
221
  s = @c_parser.toplevel.symbol[name]
218
222
  walk_ce([@c_parser.toplevel, scope]) { |ce|
@@ -230,7 +234,7 @@ class Decompiler
230
234
  when 4; 'dword'
231
235
  else 'unk'
232
236
  end
233
- name = 'stru' if ptype.kind_of? C::Union
237
+ name = 'stru' if ptype.kind_of?(C::Union)
234
238
  name = @dasm.auto_label_at(addr, name, 'xref', 'byte', 'word', 'dword', 'unk', 'stru')
235
239
 
236
240
  if not var = @c_parser.toplevel.symbol[name]
@@ -240,28 +244,28 @@ class Decompiler
240
244
  @c_parser.toplevel.symbol[var.name] = var
241
245
  @c_parser.toplevel.statements << C::Declaration.new(var)
242
246
  end
243
- if ptype.kind_of? C::Union and type.pointer? and s = @dasm.get_section_at(name) and s[0].ptr < s[0].length
247
+ if ptype.kind_of?(C::Union) and type.pointer? and s = @dasm.get_section_at(name) and s[0].ptr < s[0].length
244
248
  # TODO struct init, array, fptrs..
245
- elsif type.pointer? and not type.pointed.untypedef.kind_of? C::Function and s = @dasm.get_section_at(name) and s[0].ptr < s[0].length and
246
- [1, 2, 4].include? tsz and (not var.type.pointer? or sizeof(var.type.pointed) != sizeof(type.pointed) or not var.initializer)
249
+ elsif type.pointer? and not type.pointed.untypedef.kind_of?(C::Function) and s = @dasm.get_section_at(name) and s[0].ptr < s[0].length and
250
+ [1, 2, 4].include?(tsz) and (not var.type.pointer? or sizeof(var.type.pointed) != sizeof(type.pointed) or not var.initializer)
247
251
  # TODO do not overlap other statics (but labels may refer to elements of the array...)
248
252
  data = (0..256).map {
249
253
  v = s[0].decode_imm("u#{tsz*8}".to_sym, @dasm.cpu.endianness)
250
- v = decompile_cexpr(v, @c_parser.toplevel) if v.kind_of? Expression # relocation
254
+ v = decompile_cexpr(v, @c_parser.toplevel) if v.kind_of?(Expression) # relocation
251
255
  v
252
256
  }
253
257
  var.initializer = data.map { |v| C::CExpression[v, C::BaseType.new(:int)] } unless (data - [0]).empty?
254
- if (tsz == 1 or tsz == 2) and eos = data.index(0) and (0..3).all? { |i| data[i] >= 0x20 and data[i] < 0x7f } # printable str
258
+ if (tsz == 1 or tsz == 2) and eos = data.index(0) and ((0..3).all? { |i| data[i] >= 0x20 and data[i] < 0x7f } or ptype.to_s == '(char)') # printable str
255
259
  # XXX 0x80 with ruby1.9...
256
260
  var.initializer = C::CExpression[data[0, eos].pack('C*'), C::Pointer.new(ptype)] rescue nil
257
261
  end
258
- if var.initializer.kind_of? ::Array and i = var.initializer.first and i.kind_of? C::CExpression and not i.op and i.rexpr.kind_of? C::Variable and
259
- i.rexpr.type.kind_of? C::Function and not @dasm.get_section_at(@dasm.normalize(i.rexpr.name)) # iat_ExternalFunc
262
+ if var.initializer.kind_of?(::Array) and i = var.initializer.first and i.kind_of?(C::CExpression) and not i.op and i.rexpr.kind_of?(C::Variable) and
263
+ i.rexpr.type.kind_of?(C::Function) and not @dasm.get_section_at(@dasm.normalize(i.rexpr.name)) # iat_ExternalFunc
260
264
  i.type = i.rexpr.type
261
265
  type = var.type = C::Array.new(C::Pointer.new(i.type))
262
266
  var.initializer = [i]
263
267
  end
264
- var.initializer = nil if var.initializer.kind_of? ::Array and not type.untypedef.kind_of? C::Array
268
+ var.initializer = nil if var.initializer.kind_of?(::Array) and not type.untypedef.kind_of?(C::Array)
265
269
  end
266
270
 
267
271
  # TODO patch existing references to addr ? (or would they have already triggered new_global_var?)
@@ -285,7 +289,7 @@ class Decompiler
285
289
  next if type == :indirect
286
290
  ta = dasm.normalize ta
287
291
  if type != :subfuncret and not @dasm.function[ta] and
288
- (not @dasm.function[entry] or @autofuncs.include? entry) and
292
+ (not @dasm.function[entry] or @autofuncs.include?(entry)) and
289
293
  di.block.list.last.opcode.props[:saveip]
290
294
  # possible noreturn function
291
295
  # XXX call $+5; pop eax
@@ -293,7 +297,7 @@ class Decompiler
293
297
  @dasm.function[ta] = DecodedFunction.new
294
298
  puts "autofunc #{Expression[ta]}" if $VERBOSE
295
299
  end
296
-
300
+
297
301
  if @dasm.function[ta] and type != :subfuncret
298
302
  f = dasm.auto_label_at(ta, 'func')
299
303
  ta = dasm.normalize($1) if f =~ /^thunk_(.*)/
@@ -317,7 +321,7 @@ class Decompiler
317
321
  return expr if n == Expression::Unknown
318
322
  n = Expression[n].reduce_rec
319
323
  n = @dasm.get_label_at(n) || n
320
- n = $1 if n.kind_of? ::String and n =~ /^thunk_(.*)/
324
+ n = $1 if n.kind_of?(::String) and n =~ /^thunk_(.*)/
321
325
  n
322
326
  else
323
327
  expr
@@ -329,28 +333,30 @@ class Decompiler
329
333
  blockstart = nil
330
334
  cache_di = nil
331
335
  cache = {} # [i_s, e, type] => backtrace
332
- tovar = lambda { |di, e, i_s|
336
+ @decomp_mkstackvars_terminals ||= [:frameptr]
337
+ tovar = lambda { |di, e, i_s_c|
338
+ i_s = (i_s_c > 0)
333
339
  case e
334
- when Expression; Expression[tovar[di, e.lexpr, i_s], e.op, tovar[di, e.rexpr, i_s]].reduce
335
- when Indirection; Indirection[tovar[di, e.target, i_s], e.len, e.origin]
340
+ when Expression; Expression[tovar[di, e.lexpr, i_s_c], e.op, tovar[di, e.rexpr, i_s_c]].reduce
341
+ when Indirection; Indirection[tovar[di, e.target, i_s_c-1], e.len, e.origin]
336
342
  when :frameptr; e
337
343
  when ::Symbol
338
344
  cache.clear if cache_di != di ; cache_di = di
339
345
  vals = cache[[e, i_s, 0]] ||= @dasm.backtrace(e, di.address, :snapshot_addr => blockstart,
340
- :include_start => i_s, :no_check => true, :terminals => [:frameptr])
346
+ :include_start => i_s, :no_check => true, :terminals => @decomp_mkstackvars_terminals)
341
347
  # backtrace only to blockstart first
342
- if vals.length == 1 and ee = vals.first and ee.kind_of? Expression and (ee == Expression[:frameptr] or
343
- (ee.lexpr == :frameptr and ee.op == :+ and ee.rexpr.kind_of? ::Integer) or
344
- (not ee.lexpr and ee.op == :+ and ee.rexpr.kind_of? Indirection and eep = ee.rexpr.pointer and
345
- (eep == Expression[:frameptr] or (eep.lexpr == :frameptr and eep.op == :+ and eep.rexpr.kind_of? ::Integer))))
348
+ if vals.length == 1 and ee = vals.first and ee.kind_of?(Expression) and (ee == Expression[:frameptr] or
349
+ (ee.lexpr == :frameptr and ee.op == :+ and ee.rexpr.kind_of?(::Integer)) or
350
+ (not ee.lexpr and ee.op == :+ and ee.rexpr.kind_of?(Indirection) and eep = ee.rexpr.pointer and
351
+ (eep == Expression[:frameptr] or (eep.lexpr == :frameptr and eep.op == :+ and eep.rexpr.kind_of?(::Integer)))))
346
352
  ee
347
353
  else
348
354
  # fallback on full run (could restart from blockstart with ee, but may reevaluate addr_binding..
349
355
  vals = cache[[e, i_s, 1]] ||= @dasm.backtrace(e, di.address, :snapshot_addr => funcstart,
350
- :include_start => i_s, :no_check => true, :terminals => [:frameptr])
351
- if vals.length == 1 and ee = vals.first and (ee.kind_of? Expression and (ee == Expression[:frameptr] or
352
- (ee.lexpr == :frameptr and ee.op == :+ and ee.rexpr.kind_of? ::Integer)))
353
- ee
356
+ :include_start => i_s, :no_check => true, :terminals => @decomp_mkstackvars_terminals)
357
+ if vals.length == 1 and ee = vals.first and (ee.kind_of?(Expression) and (ee == Expression[:frameptr] or
358
+ (ee.lexpr == :frameptr and ee.op == :+ and ee.rexpr.kind_of?(::Integer))))
359
+ ee
354
360
  else e
355
361
  end
356
362
  end
@@ -366,9 +372,9 @@ class Decompiler
366
372
  bd = di.backtrace_binding ||= @dasm.cpu.get_backtrace_binding(di)
367
373
  newbd = repl_bind[di] = {}
368
374
  bd.each { |k, v|
369
- k = tovar[di, k, true] if k.kind_of? Indirection
370
- next if k == Expression[:frameptr] or (k.kind_of? Expression and k.lexpr == :frameptr and k.op == :+ and k.rexpr.kind_of? ::Integer)
371
- newbd[k] = tovar[di, v, false]
375
+ k = tovar[di, k, 2] if k.kind_of?(Indirection)
376
+ next if k == Expression[:frameptr] or (k.kind_of?(Expression) and k.lexpr == :frameptr and k.op == :+ and k.rexpr.kind_of?( ::Integer))
377
+ newbd[k] = tovar[di, v, 0]
372
378
  }
373
379
  }
374
380
  }
@@ -391,9 +397,9 @@ class Decompiler
391
397
  def decompile_cexpr(e, scope, itype=nil)
392
398
  case e
393
399
  when Expression
394
- if e.op == :'=' and e.lexpr.kind_of? ::String and e.lexpr =~ /^dummy_metasm_/
400
+ if e.op == :'=' and e.lexpr.kind_of?(::String) and e.lexpr =~ /^dummy_metasm_/
395
401
  decompile_cexpr(e.rexpr, scope, itype)
396
- elsif e.op == :+ and e.rexpr.kind_of? ::Integer and e.rexpr < 0
402
+ elsif e.op == :+ and e.rexpr.kind_of?(::Integer) and e.rexpr < 0
397
403
  decompile_cexpr(Expression[e.lexpr, :-, -e.rexpr], scope, itype)
398
404
  elsif e.lexpr
399
405
  a = decompile_cexpr(e.lexpr, scope, itype)
@@ -414,7 +420,7 @@ class Decompiler
414
420
  end
415
421
  itype = C::Pointer.new(bt)
416
422
  p = decompile_cexpr(e.target, scope, itype)
417
- p = C::CExpression[[p], itype] if not p.type.kind_of? C::Pointer
423
+ p = C::CExpression[[p], itype]
418
424
  C::CExpression[:*, p]
419
425
  when ::Integer
420
426
  C::CExpression[e]
@@ -442,17 +448,17 @@ class Decompiler
442
448
 
443
449
  # simplify goto -> goto / goto -> return
444
450
  def simplify_goto(scope, keepret = false)
445
- if not keepret and scope.statements[-1].kind_of? C::Return and not scope.statements[-2].kind_of? C::Label
451
+ if not keepret and scope.statements[-1].kind_of?(C::Return) and not scope.statements[-2].kind_of?(C::Label)
446
452
  scope.statements.insert(-2, C::Label.new("ret_label"))
447
453
  end
448
454
 
449
455
  jumpto = {}
450
456
  walk(scope) { |s|
451
- next if not s.kind_of? C::Block
457
+ next if not s.kind_of?(C::Block)
452
458
  s.statements.each_with_index { |ss, i|
453
459
  case ss
454
460
  when C::Goto, C::Return
455
- while l = s.statements[i -= 1] and l.kind_of? C::Label
461
+ while l = s.statements[i -= 1] and l.kind_of?(C::Label)
456
462
  jumpto[l.name] = ss
457
463
  end
458
464
  end
@@ -464,11 +470,11 @@ class Decompiler
464
470
  when C::Goto
465
471
  if jumpto[s.target]
466
472
  r = jumpto[s.target].dup
467
- r.value = r.value.deep_dup if r.kind_of? C::Return and r.value.kind_of? C::CExpression
473
+ r.value = r.value.deep_dup if r.kind_of?(C::Return) and r.value.kind_of?(C::CExpression)
468
474
  r
469
475
  end
470
476
  when C::Return
471
- if not keepret and scope.statements[-1].kind_of? C::Return and s.value == scope.statements[-1].value and s != scope.statements[-1]
477
+ if not keepret and scope.statements[-1].kind_of?(C::Return) and s.value == scope.statements[-1].value and s != scope.statements[-1]
472
478
  C::Goto.new(scope.statements[-2].name)
473
479
  end
474
480
  end
@@ -493,7 +499,7 @@ class Decompiler
493
499
  remove_labels(scope)
494
500
 
495
501
  walk(scope) { |s|
496
- next if not s.kind_of? C::Block
502
+ next if not s.kind_of?(C::Block)
497
503
  del = false
498
504
  # remove dead code goto a; goto b; if (0) { z: bla; } => rm goto b
499
505
  s.statements.delete_if { |st|
@@ -508,10 +514,10 @@ class Decompiler
508
514
  }
509
515
  # if () { goto x; } x:
510
516
  s.statements.each_with_index { |ss, i|
511
- if ss.kind_of? C::If
517
+ if ss.kind_of?(C::If)
512
518
  t = ss.bthen
513
- t = t.statements.first if t.kind_of? C::Block
514
- if t.kind_of? C::Goto and s.statements[i+1].kind_of? C::Label and s.statements[i+1].name == t.target
519
+ t = t.statements.first if t.kind_of?(C::Block)
520
+ if t.kind_of?(C::Goto) and s.statements[i+1].kind_of?(C::Label) and s.statements[i+1].name == t.target
515
521
  ss.bthen = C::Block.new(scope)
516
522
  end
517
523
  end
@@ -548,8 +554,8 @@ class Decompiler
548
554
  e.each_with_index { |st, i|
549
555
  case st
550
556
  when C::While, C::DoWhile
551
- l1 = (e[i+1].name if e[i+1].kind_of? C::Label)
552
- l2 = (e[i-1].name if e[i-1].kind_of? C::Label)
557
+ l1 = (e[i+1].name if e[i+1].kind_of?(C::Label))
558
+ l2 = (e[i-1].name if e[i-1].kind_of?(C::Label))
553
559
  e[i].body = walk[st.body, l1, l2]
554
560
  else
555
561
  e[i] = walk[st, brk, cnt]
@@ -578,20 +584,20 @@ class Decompiler
578
584
  remove_labels(scope)
579
585
 
580
586
  # while (1) { a; if(b) { c; return; }; d; } => while (1) { a; if (b) break; d; } c;
581
- while st = scope.statements.last and st.kind_of? C::While and st.test.kind_of? C::CExpression and
582
- not st.test.op and st.test.rexpr == 1 and st.body.kind_of? C::Block
587
+ while st = scope.statements.last and st.kind_of?(C::While) and st.test.kind_of?(C::CExpression) and
588
+ not st.test.op and st.test.rexpr == 1 and st.body.kind_of?(C::Block)
583
589
  break if not i = st.body.statements.find { |ist|
584
- ist.kind_of? C::If and not ist.belse and ist.bthen.kind_of? C::Block and ist.bthen.statements.last.kind_of? C::Return
590
+ ist.kind_of?(C::If) and not ist.belse and ist.bthen.kind_of?(C::Block) and ist.bthen.statements.last.kind_of?(C::Return)
585
591
  }
586
- walk(i.bthen.statements) { |sst| sst.outer = i.bthen.outer if sst.kind_of? C::Block and sst.outer == i.bthen }
592
+ walk(i.bthen.statements) { |sst| sst.outer = i.bthen.outer if sst.kind_of?(C::Block) and sst.outer == i.bthen }
587
593
  scope.statements.concat i.bthen.statements
588
594
  i.bthen = C::Break.new
589
595
  end
590
596
 
591
597
  patch_test = lambda { |ce|
592
- ce = ce.rexpr if ce.kind_of? C::CExpression and ce.op == :'!'
598
+ ce = ce.rexpr if ce.kind_of?(C::CExpression) and ce.op == :'!'
593
599
  # if (a+1) => if (a != -1)
594
- if ce.kind_of? C::CExpression and (ce.op == :+ or ce.op == :-) and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? ::Integer and ce.lexpr
600
+ if ce.kind_of?(C::CExpression) and (ce.op == :+ or ce.op == :-) and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer) and ce.lexpr
595
601
  ce.rexpr.rexpr = -ce.rexpr.rexpr if ce.op == :+
596
602
  ce.op = :'!='
597
603
  end
@@ -601,30 +607,30 @@ class Decompiler
601
607
  case ce
602
608
  when C::If
603
609
  patch_test[ce.test]
604
- if ce.bthen.kind_of? C::Block
605
- case ce.bthen.statements.length
610
+ if ce.bthen.kind_of?(C::Block)
611
+ case ce.bthen.statements.length
606
612
  when 1
607
- walk(ce.bthen.statements) { |sst| sst.outer = ce.bthen.outer if sst.kind_of? C::Block and sst.outer == ce.bthen }
613
+ walk(ce.bthen.statements) { |sst| sst.outer = ce.bthen.outer if sst.kind_of?(C::Block) and sst.outer == ce.bthen }
608
614
  ce.bthen = ce.bthen.statements.first
609
615
  when 0
610
- if not ce.belse and i = ce.bthen.outer.statements.index(ce)
616
+ if not ce.belse and i = ce.bthen.outer.statements.index(ce)
611
617
  ce.bthen.outer.statements[i] = ce.test # TODO remove sideeffectless parts
612
618
  end
613
619
  end
614
620
  end
615
- if ce.belse.kind_of? C::Block and ce.belse.statements.length == 1
616
- walk(ce.belse.statements) { |sst| sst.outer = ce.belse.outer if sst.kind_of? C::Block and sst.outer == ce.belse }
621
+ if ce.belse.kind_of?(C::Block) and ce.belse.statements.length == 1
622
+ walk(ce.belse.statements) { |sst| sst.outer = ce.belse.outer if sst.kind_of?(C::Block) and sst.outer == ce.belse }
617
623
  ce.belse = ce.belse.statements.first
618
624
  end
619
625
  when C::While, C::DoWhile
620
626
  patch_test[ce.test]
621
- if ce.body.kind_of? C::Block
627
+ if ce.body.kind_of?(C::Block)
622
628
  case ce.body.statements.length
623
629
  when 1
624
- walk(ce.body.statements) { |sst| sst.outer = ce.body.outer if sst.kind_of? C::Block and sst.outer == ce.body }
630
+ walk(ce.body.statements) { |sst| sst.outer = ce.body.outer if sst.kind_of?(C::Block) and sst.outer == ce.body }
625
631
  ce.body = ce.body.statements.first
626
632
  when 0
627
- if ce.kind_of? C::DoWhile and i = ce.body.outer.statements.index(ce)
633
+ if ce.kind_of?(C::DoWhile) and i = ce.body.outer.statements.index(ce)
628
634
  ce = ce.body.outer.statements[i] = C::While.new(ce.test, ce.body)
629
635
  end
630
636
  ce.body = nil
@@ -632,14 +638,33 @@ class Decompiler
632
638
  end
633
639
  end
634
640
  }
641
+
642
+ walk(scope, false, true) { |ce|
643
+ # while (1) { a; if (b) break; } => do { a } while (!b);
644
+ if ce.kind_of?(C::While) and ce.test.kind_of?(C::CExpression) and not ce.test.op and ce.test.rexpr == 1 and ce.body.kind_of?(C::Block)
645
+ i = ce.body.statements.last
646
+ if i.kind_of?(C::If) and not i.belse and i.bthen.kind_of?(C::Break)
647
+ ce.body.statements.pop
648
+ next C::DoWhile.new(i.test.negate, ce.body)
649
+ end
650
+ end
651
+
652
+ # if (a) b = 1; else b = 2; => b = a ? 1 : 2
653
+ if ce.kind_of?(C::If) and ce.belse.kind_of?(C::CExpression) and ce.belse.op == :'=' and ce.belse.lexpr.kind_of?(C::Variable) and ce.bthen.kind_of?(C::CExpression) and ce.bthen.op == :'=' and ce.bthen.lexpr == ce.belse.lexpr
654
+ next C::CExpression[ce.bthen.lexpr, :'=', [ce.test, :'?:', [ce.bthen.rexpr, ce.belse.rexpr]]]
655
+ end
656
+ }
657
+
658
+ # TODO for (;;) {}
659
+
635
660
  walk(scope) { |ce|
636
- next if not ce.kind_of? C::Block
661
+ next if not ce.kind_of?(C::Block)
637
662
  st = ce.statements
638
663
  st.length.times { |n|
639
- while st[n].kind_of? C::If and st[n+1].kind_of? C::If and not st[n].belse and not st[n+1].belse and (
640
- (st[n].bthen.kind_of? C::Return and st[n+1].bthen.kind_of? C::Return and st[n].bthen.value == st[n+1].bthen.value) or
641
- (st[n].bthen.kind_of? C::Break and st[n+1].bthen.kind_of? C::Break) or
642
- (st[n].bthen.kind_of? C::Continue and st[n+1].bthen.kind_of? C::Continue))
664
+ while st[n].kind_of?(C::If) and st[n+1].kind_of?(C::If) and not st[n].belse and not st[n+1].belse and (
665
+ (st[n].bthen.kind_of?(C::Return) and st[n+1].bthen.kind_of?(C::Return) and st[n].bthen.value == st[n+1].bthen.value) or
666
+ (st[n].bthen.kind_of?(C::Break) and st[n+1].bthen.kind_of?(C::Break)) or
667
+ (st[n].bthen.kind_of?(C::Continue) and st[n+1].bthen.kind_of?(C::Continue)))
643
668
  # if (a) return x; if (b) return x; => if (a || b) return x;
644
669
  st[n].test = C::CExpression[st[n].test, :'||', st[n+1].test]
645
670
  st.delete_at(n+1)
@@ -659,19 +684,19 @@ class Decompiler
659
684
  inner_labels = ary.grep(C::Label).map { |l| l.name }
660
685
  while s = ary.shift
661
686
  # recurse if it's not the first run
662
- if s.kind_of? C::If
663
- s.bthen.statements = decompile_cseq_if(s.bthen.statements, s.bthen) if s.bthen.kind_of? C::Block
664
- s.belse.statements = decompile_cseq_if(s.belse.statements, s.belse) if s.belse.kind_of? C::Block
687
+ if s.kind_of?(C::If)
688
+ s.bthen.statements = decompile_cseq_if(s.bthen.statements, s.bthen) if s.bthen.kind_of?(C::Block)
689
+ s.belse.statements = decompile_cseq_if(s.belse.statements, s.belse) if s.belse.kind_of?(C::Block)
665
690
  end
666
691
 
667
692
  # if (a) goto x; if (b) goto x; => if (a || b) goto x;
668
- while s.kind_of? C::If and s.bthen.kind_of? C::Goto and not s.belse and ary.first.kind_of? C::If and ary.first.bthen.kind_of? C::Goto and
693
+ while s.kind_of?(C::If) and s.bthen.kind_of?(C::Goto) and not s.belse and ary.first.kind_of?(C::If) and ary.first.bthen.kind_of?(C::Goto) and
669
694
  not ary.first.belse and s.bthen.target == ary.first.bthen.target
670
695
  s.test = C::CExpression[s.test, :'||', ary.shift.test]
671
696
  end
672
697
 
673
698
  # if (a) goto x; b; x: => if (!a) { b; }
674
- if s.kind_of? C::If and s.bthen.kind_of? C::Goto and l = ary.grep(C::Label).find { |l_| l_.name == s.bthen.target }
699
+ if s.kind_of?(C::If) and s.bthen.kind_of?(C::Goto) and l = ary.grep(C::Label).find { |l_| l_.name == s.bthen.target }
675
700
  # if {goto l;} a; l: => if (!) {a;}
676
701
  s.test = C::CExpression.negate s.test
677
702
  s.bthen = C::Block.new(scope)
@@ -680,20 +705,20 @@ class Decompiler
680
705
  ary[0...ary.index(l)] = []
681
706
  end
682
707
 
683
- if s.kind_of? C::If and (s.bthen.kind_of? C::Block or s.bthen.kind_of? C::Goto)
684
- s.bthen = C::Block.new(scope, [s.bthen]) if s.bthen.kind_of? C::Goto
708
+ if s.kind_of?(C::If) and (s.bthen.kind_of?(C::Block) or s.bthen.kind_of?(C::Goto))
709
+ s.bthen = C::Block.new(scope, [s.bthen]) if s.bthen.kind_of?(C::Goto)
685
710
 
686
711
  bts = s.bthen.statements
687
712
 
688
713
  # if (a) if (b) { c; } => if (a && b) { c; }
689
- if bts.length == 1 and bts.first.kind_of? C::If and not bts.first.belse
714
+ if bts.length == 1 and bts.first.kind_of?(C::If) and not bts.first.belse
690
715
  s.test = C::CExpression[s.test, :'&&', bts.first.test]
691
716
  bts = bts.first.bthen
692
717
  bts = s.bthen.statements = bts.kind_of?(C::Block) ? bts.statements : [bts]
693
718
  end
694
719
 
695
720
  # if (a) { if (b) goto c; d; } c: => if (a && !b) { d; }
696
- if bts.first.kind_of? C::If and l = bts.first.bthen and (l = l.kind_of?(C::Block) ? l.statements.first : l) and l.kind_of? C::Goto and ary[0].kind_of? C::Label and l.target == ary[0].name
721
+ if bts.first.kind_of?(C::If) and l = bts.first.bthen and (l = l.kind_of?(C::Block) ? l.statements.first : l) and l.kind_of?(C::Goto) and ary[0].kind_of?(C::Label) and l.target == ary[0].name
697
722
  s.test = C::CExpression[s.test, :'&&', C::CExpression.negate(bts.first.test)]
698
723
  if e = bts.shift.belse
699
724
  bts.unshift e
@@ -701,18 +726,18 @@ class Decompiler
701
726
  end
702
727
 
703
728
  # if () { goto a; } a:
704
- if bts.last.kind_of? C::Goto and ary[0].kind_of? C::Label and bts.last.target == ary[0].name
729
+ if bts.last.kind_of?(C::Goto) and ary[0].kind_of?(C::Label) and bts.last.target == ary[0].name
705
730
  bts.pop
706
731
  end
707
732
 
708
733
  # if { a; goto outer; } b; return; => if (!) { b; return; } a; goto outer;
709
- if bts.last.kind_of? C::Goto and not inner_labels.include? bts.last.target and g = ary.find { |ss| ss.kind_of? C::Goto or ss.kind_of? C::Return } and g.kind_of? C::Return
734
+ if bts.last.kind_of?(C::Goto) and not inner_labels.include?(bts.last.target) and g = ary.find { |ss| ss.kind_of?(C::Goto) or ss.kind_of?(C::Return) } and g.kind_of?(C::Return)
710
735
  s.test = C::CExpression.negate s.test
711
736
  ary[0..ary.index(g)], bts[0..-1] = bts, ary[0..ary.index(g)]
712
737
  end
713
738
 
714
739
  # if { a; goto l; } b; l: => if {a;} else {b;}
715
- if bts.last.kind_of? C::Goto and l = ary.grep(C::Label).find { |l_| l_.name == bts.last.target }
740
+ if bts.last.kind_of?(C::Goto) and l = ary.grep(C::Label).find { |l_| l_.name == bts.last.target }
716
741
  s.belse = C::Block.new(scope)
717
742
  s.belse.statements = decompile_cseq_if(ary[0...ary.index(l)], s.belse)
718
743
  ary[0...ary.index(l)] = []
@@ -720,7 +745,7 @@ class Decompiler
720
745
  end
721
746
 
722
747
  # if { a; l: b; goto any;} c; goto l; => if { a; } else { c; } b; goto any;
723
- if not s.belse and (bts.last.kind_of? C::Goto or bts.last.kind_of? C::Return) and g = ary.grep(C::Goto).first and l = bts.grep(C::Label).find { |l_| l_.name == g.target }
748
+ if not s.belse and (bts.last.kind_of?(C::Goto) or bts.last.kind_of?(C::Return)) and g = ary.grep(C::Goto).first and l = bts.grep(C::Label).find { |l_| l_.name == g.target }
724
749
  s.belse = C::Block.new(scope)
725
750
  s.belse.statements = decompile_cseq_if(ary[0...ary.index(g)], s.belse)
726
751
  ary[0..ary.index(g)], bts[bts.index(l)..-1] = bts[bts.index(l)..-1], []
@@ -730,8 +755,8 @@ class Decompiler
730
755
  if s.belse
731
756
  bes = s.belse.statements
732
757
  while not bts.empty?
733
- if bts.last.kind_of? C::Label; ary.unshift bts.pop
734
- elsif bes.last.kind_of? C::Label; ary.unshift bes.pop
758
+ if bts.last.kind_of?(C::Label); ary.unshift bts.pop
759
+ elsif bes.last.kind_of?(C::Label); ary.unshift bes.pop
735
760
  elsif bts.last.to_s == bes.last.to_s; ary.unshift bes.pop ; bts.pop
736
761
  else break
737
762
  end
@@ -754,24 +779,24 @@ class Decompiler
754
779
  end
755
780
 
756
781
  # l1: l2: if () goto l1; goto l2; => if(!) goto l2; goto l1;
757
- if s.kind_of? C::If
782
+ if s.kind_of?(C::If)
758
783
  ls = s.bthen
759
- ls = ls.statements.last if ls.kind_of? C::Block
760
- if ls.kind_of? C::Goto
784
+ ls = ls.statements.last if ls.kind_of?(C::Block)
785
+ if ls.kind_of?(C::Goto)
761
786
  if li = inner_labels.index(ls.target)
762
787
  table = inner_labels
763
788
  else
764
- table = ary.map { |st| st.name if st.kind_of? C::Label }.compact.reverse
789
+ table = ary.map { |st| st.name if st.kind_of?(C::Label) }.compact.reverse
765
790
  li = table.index(ls.target) || table.length
766
791
  end
767
792
  g = ary.find { |ss|
768
- break if ss.kind_of? C::Return
769
- next if not ss.kind_of? C::Goto
793
+ break if ss.kind_of?(C::Return)
794
+ next if not ss.kind_of?(C::Goto)
770
795
  table.index(ss.target).to_i > li
771
796
  }
772
797
  if g
773
798
  s.test = C::CExpression.negate s.test
774
- if not s.bthen.kind_of? C::Block
799
+ if not s.bthen.kind_of?(C::Block)
775
800
  ls = C::Block.new(scope)
776
801
  ls.statements << s.bthen
777
802
  s.bthen = ls
@@ -790,81 +815,96 @@ class Decompiler
790
815
  return if forbid_decompile_ifwhile
791
816
 
792
817
  # find the next instruction that is not a label
793
- ni = lambda { |l| ary[ary.index(l)..-1].find { |s| not s.kind_of? C::Label } }
794
-
795
- # TODO XXX get rid of #index
796
- finished = false ; while not finished ; finished = true # 1.9 does not support 'retry'
797
- ary.each { |s|
818
+ ni = lambda { |li| (li..ary.length).find { |ni_| not ary[ni_].kind_of?(C::Label) } }
819
+
820
+ finished = false; while not finished; finished = true # ruby1.9 does not support 'retry'
821
+ i = 0
822
+ while i < ary.length
823
+ si = i
824
+ s = ary[si]
825
+ i += 1
798
826
  case s
799
827
  when C::Label
800
- if ss = ni[s] and ss.kind_of? C::If and not ss.belse and ss.bthen.kind_of? C::Block
801
- if ss.bthen.statements.last.kind_of? C::Goto and ss.bthen.statements.last.target == s.name
828
+ if ssi = ni[si] and ss = ary[ssi] and ss.kind_of?(C::If) and not ss.belse and ss.bthen.kind_of?(C::Block)
829
+ if ss.bthen.statements.last.kind_of?(C::Goto) and ss.bthen.statements.last.target == s.name
830
+ # l: if (a) { b; goto l; } => while(a) { b; }
802
831
  ss.bthen.statements.pop
803
- if l = ary[ary.index(ss)+1] and l.kind_of? C::Label
804
- ss.bthen.statements.grep(C::If).each { |i|
805
- i.bthen = C::Break.new if i.bthen.kind_of? C::Goto and i.bthen.target == l.name
832
+ if l = ary[ssi+1] and l.kind_of?(C::Label)
833
+ ss.bthen.statements.grep(C::If).each { |it|
834
+ it.bthen = C::Break.new if it.bthen.kind_of?(C::Goto) and it.bthen.target == l.name
806
835
  }
807
836
  end
808
- ary[ary.index(ss)] = C::While.new(ss.test, ss.bthen)
809
- elsif ss.bthen.statements.last.kind_of? C::Return and g = ary[ary.index(s)+1..-1].reverse.find { |_s| _s.kind_of? C::Goto and _s.target == s.name }
837
+ ary[ssi] = C::While.new(ss.test, ss.bthen)
838
+ elsif ss.bthen.statements.last.kind_of?(C::Return) and gi = ((si+1)..ary.length).to_a.reverse.find { |_si| ary[_si].kind_of?(C::Goto) and ary[_si].target == s.name }
839
+ # l: if (a) { b; return; } c; goto l; => while (!a) { c; } b; return;
810
840
  wb = C::Block.new(scope)
811
- wb.statements = decompile_cseq_while(ary[ary.index(ss)+1...ary.index(g)], wb)
841
+ wb.statements = decompile_cseq_while(ary[ssi+1...gi], wb)
812
842
  w = C::While.new(C::CExpression.negate(ss.test), wb)
813
- ary[ary.index(ss)..ary.index(g)] = [w, *ss.bthen.statements]
843
+ ary[ssi..gi] = [w, *ss.bthen.statements]
814
844
  finished = false ; break #retry
815
845
  end
816
846
  end
817
- if g = ary[ary.index(s)..-1].reverse.find { |_s| _s.kind_of? C::Goto and _s.target == s.name }
847
+ if gi = (si..ary.length).to_a.reverse.find { |_si| ary[_si].kind_of?(C::Goto) and ary[_si].target == s.name }
848
+ # l: a; goto l; => while(1) { a; }
818
849
  wb = C::Block.new(scope)
819
- wb.statements = decompile_cseq_while(ary[ary.index(s)...ary.index(g)], wb)
850
+ wb.statements = decompile_cseq_while(ary[si...gi], wb)
820
851
  w = C::While.new(C::CExpression[1], wb)
821
- ary[ary.index(s)..ary.index(g)] = [w]
852
+ ary[si..gi] = [w]
822
853
  finished = false ; break #retry
823
854
  end
824
- if g = ary[ary.index(s)..-1].reverse.find { |_s| _s.kind_of? C::If and not _s.belse and gt = _s.bthen and
825
- (gt = gt.kind_of?(C::Block) && gt.statements.length == 1 ? gt.statements.first : gt) and gt.kind_of? C::Goto and gt.target == s.name }
855
+ if gi = (si..ary.length).to_a.reverse.find { |_si| ary[_si].kind_of?(C::If) and not ary[_si].belse and gt = ary[_si].bthen and
856
+ (gt = gt.kind_of?(C::Block) ? gt.statements.last : gt) and gt.kind_of?(C::Goto) and gt.target == s.name }
857
+ # l: a; if (b) goto l; => do { a; } while (b);
858
+ # l: a; if (b) { c; goto l; } => do { a; if (!b) break; c; } while(1);
826
859
  wb = C::Block.new(scope)
827
- wb.statements = decompile_cseq_while(ary[ary.index(s)...ary.index(g)], wb)
828
- w = C::DoWhile.new(g.test, wb)
829
- ary[ary.index(s)..ary.index(g)] = [w]
860
+ g = ary[gi]
861
+ if g.bthen.kind_of?(C::Block) and g.bthen.statements.length > 1
862
+ nary = ary[si...gi] + [C::If.new(C::CExpression.negate(g.test), C::Break.new)] + g.bthen.statements[0...-1]
863
+ wb.statements = decompile_cseq_while(nary, wb)
864
+ w = C::DoWhile.new(C::CExpression[1], wb)
865
+ else
866
+ wb.statements = decompile_cseq_while(ary[si...gi], wb)
867
+ w = C::DoWhile.new(g.test, wb)
868
+ end
869
+ ary[si..gi] = [w]
830
870
  finished = false ; break #retry
831
871
  end
832
872
  when C::If
833
- decompile_cseq_while(s.bthen.statements, s.bthen) if s.bthen.kind_of? C::Block
834
- decompile_cseq_while(s.belse.statements, s.belse) if s.belse.kind_of? C::Block
873
+ decompile_cseq_while(s.bthen.statements, s.bthen) if s.bthen.kind_of?(C::Block)
874
+ decompile_cseq_while(s.belse.statements, s.belse) if s.belse.kind_of?(C::Block)
835
875
  when C::While, C::DoWhile
836
- decompile_cseq_while(s.body.statements, s.body) if s.body.kind_of? C::Block
876
+ decompile_cseq_while(s.body.statements, s.body) if s.body.kind_of?(C::Block)
837
877
  end
838
- }
839
878
  end
879
+ end # while finished
840
880
  ary
841
881
  end
842
882
 
843
883
  # TODO
844
884
  def decompile_cseq_switch(scope)
845
- uncast = lambda { |e| e = e.rexpr while e.kind_of? C::CExpression and not e.op ; e }
885
+ uncast = lambda { |e| e = e.rexpr while e.kind_of?(C::CExpression) and not e.op ; e }
846
886
  walk(scope) { |s|
847
887
  # XXX pfff...
848
- next if not s.kind_of? C::If
888
+ next if not s.kind_of?(C::If)
849
889
  # if (v < 12) return ((void(*)())(tableaddr+4*v))();
850
890
  t = s.bthen
851
- t = t.statements.first if t.kind_of? C::Block and t.statements.length == 1
852
- next if not t.kind_of? C::Return or not t.respond_to? :from_instr
853
- next if t.from_instr.comment.to_a.include? 'switch'
854
- next if not t.value.kind_of? C::CExpression or t.value.op != :funcall or t.value.rexpr != [] or not t.value.lexpr.kind_of? C::CExpression or t.value.lexpr.op
891
+ t = t.statements.first if t.kind_of?(C::Block) and t.statements.length == 1
892
+ next if not t.kind_of?(C::Return) or not t.respond_to?(:from_instr)
893
+ next if t.from_instr.comment.to_a.include?('switch')
894
+ next if not t.value.kind_of?(C::CExpression) or t.value.op != :funcall or t.value.rexpr != [] or not t.value.lexpr.kind_of?(C::CExpression) or t.value.lexpr.op
855
895
  p = uncast[t.value.lexpr.rexpr]
856
- next if not p.kind_of? C::CExpression or p.op != :* or p.lexpr
896
+ next if not p.kind_of?(C::CExpression) or p.op != :* or p.lexpr
857
897
  p = uncast[p.rexpr]
858
- next if not p.kind_of? C::CExpression or p.op != :+
898
+ next if not p.kind_of?(C::CExpression) or p.op != :+
859
899
  r, l = uncast[p.rexpr], uncast[p.lexpr]
860
- r, l = l, r if r.kind_of? C::CExpression
861
- next if not r.kind_of? ::Integer or not l.kind_of? C::CExpression or l.op != :* or not l.lexpr
900
+ r, l = l, r if r.kind_of?(C::CExpression)
901
+ next if not r.kind_of?(::Integer) or not l.kind_of?(C::CExpression) or l.op != :* or not l.lexpr
862
902
  lr, ll = uncast[l.rexpr], uncast[l.lexpr]
863
- lr, ll = ll, lr if not ll.kind_of? ::Integer
903
+ lr, ll = ll, lr if not ll.kind_of?(::Integer)
864
904
  next if ll != sizeof(nil, C::Pointer.new(C::BaseType.new(:void)))
865
905
  base, index = r, lr
866
- if s.test.kind_of? C::CExpression and (s.test.op == :<= or s.test.op == :<) and s.test.lexpr == index and
867
- s.test.rexpr.kind_of? C::CExpression and not s.test.rexpr.op and s.test.rexpr.rexpr.kind_of? ::Integer
906
+ if s.test.kind_of?(C::CExpression) and (s.test.op == :<= or s.test.op == :<) and s.test.lexpr == index and
907
+ s.test.rexpr.kind_of?(C::CExpression) and not s.test.rexpr.op and s.test.rexpr.rexpr.kind_of?(::Integer)
868
908
  t.from_instr.add_comment 'switch'
869
909
  sup = s.test.rexpr.rexpr
870
910
  rng = ((s.test.op == :<) ? (0...sup) : (0..sup))
@@ -883,19 +923,19 @@ class Decompiler
883
923
 
884
924
  used = []
885
925
  walk(scope) { |ss|
886
- used |= [ss.target] if ss.kind_of? C::Goto
926
+ used |= [ss.target] if ss.kind_of?(C::Goto)
887
927
  }
888
928
  walk(scope) { |s|
889
- next if not s.kind_of? C::Block
929
+ next if not s.kind_of?(C::Block)
890
930
  s.statements.delete_if { |l|
891
- l.kind_of? C::Label and not used.include? l.name
931
+ l.kind_of?(C::Label) and not used.include?(l.name)
892
932
  }
893
933
  }
894
934
 
895
935
  # remove implicit continue; at end of loop
896
936
  walk(scope) { |s|
897
- next if not s.kind_of? C::While
898
- if s.body.kind_of? C::Block and s.body.statements.last.kind_of? C::Continue
937
+ next if not s.kind_of?(C::While)
938
+ if s.body.kind_of?(C::Block) and s.body.statements.last.kind_of?(C::Continue)
899
939
  s.body.statements.pop
900
940
  end
901
941
  }
@@ -903,11 +943,11 @@ class Decompiler
903
943
 
904
944
  # checks if expr is a var (var or *&var)
905
945
  def isvar(ce, var)
906
- if var.stackoff and ce.kind_of? C::CExpression
946
+ if var.stackoff and ce.kind_of?(C::CExpression)
907
947
  return unless ce.op == :* and not ce.lexpr
908
948
  ce = ce.rexpr
909
- ce = ce.rexpr while ce.kind_of? C::CExpression and not ce.op
910
- return unless ce.kind_of? C::CExpression and ce.op == :& and not ce.lexpr
949
+ ce = ce.rexpr while ce.kind_of?(C::CExpression) and not ce.op
950
+ return unless ce.kind_of?(C::CExpression) and ce.op == :& and not ce.lexpr
911
951
  ce = ce.rexpr
912
952
  end
913
953
  ce == var
@@ -929,7 +969,7 @@ class Decompiler
929
969
  # checks if expr writes var
930
970
  def ce_write(ce_, var)
931
971
  walk_ce(ce_) { |ce|
932
- break true if AssignOp.include?(ce.op) and (isvar(ce.lexpr, var) or
972
+ break true if C::CExpression::AssignOp.include?(ce.op) and (isvar(ce.lexpr, var) or
933
973
  (((ce.op == :'++' or ce.op == :'--') and isvar(ce.rexpr, var))))
934
974
  }
935
975
  end
@@ -971,6 +1011,8 @@ class Decompiler
971
1011
  write = {}
972
1012
  ro = {}
973
1013
  wo = {}
1014
+ g_exprs = {}
1015
+ g.exprs_var[var.name].to_h.each { |k, v| g_exprs[k] = v.map { |i| g.exprs[k][i] } }
974
1016
 
975
1017
  # list of [l, i] for which domain is not known
976
1018
  unchecked = []
@@ -978,7 +1020,7 @@ class Decompiler
978
1020
  # mark all exprs of the graph
979
1021
  # TODO handle var_14 __attribute__((out)) = &curvar <=> curvar write
980
1022
  r = var.has_attribute_var('register')
981
- g.exprs.each { |label, exprs|
1023
+ g_exprs.each { |label, exprs|
982
1024
  exprs.each_with_index { |ce, i|
983
1025
  if ce_read(ce, var)
984
1026
  if (ce.op == :'=' and isvar(ce.lexpr, var) and not ce_write(ce.rexpr, var)) or
@@ -1006,28 +1048,29 @@ class Decompiler
1006
1048
  todo_w = [[l, i-1]]
1007
1049
  done_w = []
1008
1050
  while o = todo_w.pop
1009
- next if done_w.include? o
1051
+ next if done_w.include?(o)
1010
1052
  done_w << o
1011
1053
  l, i = o
1012
1054
  loop do
1013
- if read[l].to_a.include? i
1055
+ if read[l].to_a.include?(i)
1014
1056
  # XXX not optimal (should mark only the uppest read)
1015
- todo_down |= [[l, i]] if not dom.include? [l, i]
1057
+ todo_down |= [[l, i]] if not dom.include?([l, i])
1016
1058
  dom |= [[l, i]]
1017
- elsif write[l].to_a.include? i
1018
- todo_down |= [[l, i]] if not dom.include? [l, i]
1059
+ elsif write[l].to_a.include?(i)
1060
+ todo_down |= [[l, i]] if not dom.include?([l, i])
1019
1061
  dom |= [[l, i]]
1020
1062
  break
1021
- elsif wo[l].to_a.include? i
1022
- todo_down |= [[l, i]] if not dom_wo.include? [l, i, :down]
1063
+ elsif wo[l].to_a.include?(i)
1064
+ todo_down |= [[l, i]] if not dom_wo.include?([l, i, :down])
1023
1065
  dom_wo |= [[l, i, :down]]
1024
1066
  break
1025
1067
  end
1026
1068
  i -= 1
1027
1069
  if i < 0
1028
1070
  g.from_optim[l].to_a.each { |ll|
1029
- todo_w << [ll, g.exprs[ll].to_a.length-1]
1071
+ todo_w << [ll, g_exprs[ll].to_a.length-1]
1030
1072
  }
1073
+ # read unitialized
1031
1074
  func_top = true if g.from_optim[l].to_a.empty?
1032
1075
  break
1033
1076
  end
@@ -1036,27 +1079,27 @@ class Decompiler
1036
1079
  }
1037
1080
 
1038
1081
  # flood by walking the graph down from [l, i] (excluded)
1039
- # malks stuff to walk up
1082
+ # marks stuff to walk up
1040
1083
  walk_down = lambda { |l, i|
1041
1084
  todo_w = [[l, i+1]]
1042
1085
  done_w = []
1043
1086
  while o = todo_w.pop
1044
- next if done_w.include? o
1087
+ next if done_w.include?(o)
1045
1088
  done_w << o
1046
1089
  l, i = o
1047
1090
  loop do
1048
- if read[l].to_a.include? i
1049
- todo_up |= [[l, i]] if not dom.include? [l, i]
1091
+ if read[l].to_a.include?(i)
1092
+ todo_up |= [[l, i]] if not dom.include?([l, i])
1050
1093
  dom |= [[l, i]]
1051
- elsif write[l].to_a.include? i
1094
+ elsif write[l].to_a.include?(i)
1052
1095
  break
1053
- elsif ro[l].to_a.include? i
1054
- todo_up |= [[l, i]] if not dom_ro.include? [l, i, :up]
1096
+ elsif ro[l].to_a.include?(i)
1097
+ todo_up |= [[l, i]] if not dom_ro.include?([l, i, :up])
1055
1098
  dom_ro |= [[l, i, :up]]
1056
1099
  break
1057
1100
  end
1058
1101
  i += 1
1059
- if i >= g.exprs[l].to_a.length
1102
+ if i >= g_exprs[l].to_a.length
1060
1103
  g.to_optim[l].to_a.each { |ll|
1061
1104
  todo_w << [ll, 0]
1062
1105
  }
@@ -1077,11 +1120,11 @@ class Decompiler
1077
1120
  todo_down = []
1078
1121
 
1079
1122
  # init
1080
- if read[o[0]].to_a.include? o[1]
1123
+ if read[o[0]].to_a.include?(o[1])
1081
1124
  todo_up << o
1082
1125
  todo_down << o
1083
1126
  dom << o
1084
- elsif write[o[0]].to_a.include? o[1]
1127
+ elsif write[o[0]].to_a.include?(o[1])
1085
1128
  todo_down << o
1086
1129
  dom << o
1087
1130
  elsif o[2] == :up
@@ -1111,25 +1154,29 @@ class Decompiler
1111
1154
  n_i += 1 while scope.symbol_ancestors[newvarname = "#{var.name}_a#{n_i}"]
1112
1155
 
1113
1156
  nv = var.dup
1157
+ nv.misc = var.misc ? var.misc.dup : {}
1114
1158
  nv.storage = :register if nv.has_attribute_var('register')
1115
1159
  nv.attributes = nv.attributes.dup if nv.attributes
1116
1160
  nv.name = newvarname
1161
+ nv.misc[:unalias_name] = newvarname
1117
1162
  scope.statements << C::Declaration.new(nv)
1118
1163
  scope.symbol[nv.name] = nv
1119
1164
 
1120
- dom.each { |oo| ce_patch(g.exprs[oo[0]][oo[1]], var, nv) }
1165
+ dom.each { |oo| ce_patch(g_exprs[oo[0]][oo[1]], var, nv) }
1121
1166
  dom_ro.each { |oo|
1122
- ce = g.exprs[oo[0]][oo[1]]
1123
- if ce.op == :funcall or ce.rexpr.kind_of? C::CExpression
1167
+ ce = g_exprs[oo[0]][oo[1]]
1168
+ if ce.op == :funcall
1169
+ ce_patch(ce, var, nv)
1170
+ elsif ce.rexpr.kind_of?(C::CExpression)
1124
1171
  ce_patch(ce.rexpr, var, nv)
1125
1172
  else
1126
1173
  ce.rexpr = nv
1127
1174
  end
1128
1175
  }
1129
1176
  dom_wo.each { |oo|
1130
- ce = g.exprs[oo[0]][oo[1]]
1177
+ ce = g_exprs[oo[0]][oo[1]]
1131
1178
  if ce.op == :funcall
1132
- elsif ce.lexpr.kind_of? C::CExpression
1179
+ elsif ce.lexpr.kind_of?(C::CExpression)
1133
1180
  ce_patch(ce.lexpr, var, nv)
1134
1181
  else
1135
1182
  ce.lexpr = nv
@@ -1174,13 +1221,10 @@ class Decompiler
1174
1221
  v
1175
1222
  }
1176
1223
 
1177
- scope.decompdata[:stackoff_name].each { |o, n| newvar[o, n] }
1178
- scope.decompdata[:stackoff_type].each { |o, t| newvar[o, stackoff_to_varname(o)] }
1179
-
1180
1224
  walk_ce(scope) { |e|
1181
1225
  next if e.op != :+ and e.op != :-
1182
- next if not e.lexpr.kind_of? C::Variable or e.lexpr.name != 'frameptr'
1183
- next if not e.rexpr.kind_of? C::CExpression or e.rexpr.op or not e.rexpr.rexpr.kind_of? ::Integer
1226
+ next if not e.lexpr.kind_of?(C::Variable) or e.lexpr.name != 'frameptr'
1227
+ next if not e.rexpr.kind_of?(C::CExpression) or e.rexpr.op or not e.rexpr.rexpr.kind_of?(::Integer)
1184
1228
  off = e.rexpr.rexpr
1185
1229
  off = -off if e.op == :-
1186
1230
  v = newvar[off, stackoff_to_varname(off)]
@@ -1200,24 +1244,24 @@ class Decompiler
1200
1244
  types = {}
1201
1245
 
1202
1246
  pscopevar = lambda { |e|
1203
- e = e.rexpr while e.kind_of? C::CExpression and not e.op and e.rexpr.kind_of? C::CExpression
1204
- if e.kind_of? C::CExpression and e.op == :& and not e.lexpr and e.rexpr.kind_of? C::Variable
1247
+ e = e.rexpr while e.kind_of?(C::CExpression) and not e.op and e.rexpr.kind_of?(C::CExpression)
1248
+ if e.kind_of?(C::CExpression) and e.op == :& and not e.lexpr and e.rexpr.kind_of?(C::Variable)
1205
1249
  e.rexpr.name if scope.symbol[e.rexpr.name]
1206
1250
  end
1207
1251
  }
1208
1252
  scopevar = lambda { |e|
1209
- e = e.rexpr if e.kind_of? C::CExpression and not e.op
1210
- if e.kind_of? C::Variable and scope.symbol[e.name]
1253
+ e = e.rexpr if e.kind_of?(C::CExpression) and not e.op
1254
+ if e.kind_of?(C::Variable) and scope.symbol[e.name]
1211
1255
  e.name
1212
- elsif e.kind_of? C::CExpression and e.op == :* and not e.lexpr
1256
+ elsif e.kind_of?(C::CExpression) and e.op == :* and not e.lexpr
1213
1257
  pscopevar[e.rexpr]
1214
1258
  end
1215
1259
  }
1216
1260
  globalvar = lambda { |e|
1217
- e = e.rexpr if e.kind_of? C::CExpression and not e.op
1218
- if e.kind_of? ::Integer and @dasm.get_section_at(e)
1261
+ e = e.rexpr if e.kind_of?(C::CExpression) and not e.op
1262
+ if e.kind_of?(::Integer) and e > 0x10000 and @dasm.get_section_at(e)
1219
1263
  e
1220
- elsif e.kind_of? C::Variable and not scope.symbol[e.name] and @c_parser.toplevel.symbol[e.name] and @dasm.get_section_at(e.name)
1264
+ elsif e.kind_of?(C::Variable) and not scope.symbol[e.name] and @c_parser.toplevel.symbol[e.name] and @dasm.get_section_at(e.name)
1221
1265
  e.name
1222
1266
  end
1223
1267
  }
@@ -1225,8 +1269,8 @@ class Decompiler
1225
1269
  # check if a newly found type for o is better than current type
1226
1270
  # order: foo* > void* > foo
1227
1271
  better_type = lambda { |t0, t1|
1228
- t1 == C::BaseType.new(:void) or (t0.pointer? and t1.kind_of? C::BaseType) or t0.untypedef.kind_of? C::Union or
1229
- (t0.kind_of? C::BaseType and t1.kind_of? C::BaseType and (@c_parser.typesize[t0.name] > @c_parser.typesize[t1.name] or (t0.name == t1.name and t0.qualifier))) or
1272
+ t1 == C::BaseType.new(:void) or (t0.pointer? and t1.kind_of?(C::BaseType)) or t0.untypedef.kind_of?(C::Union) or
1273
+ (t0.kind_of?(C::BaseType) and t1.kind_of?(C::BaseType) and (@c_parser.typesize[t0.name] > @c_parser.typesize[t1.name] or (t0.name == t1.name and t0.qualifier))) or
1230
1274
  (t0.pointer? and t1.pointer? and better_type[t0.pointed, t1.pointed])
1231
1275
  }
1232
1276
 
@@ -1234,11 +1278,11 @@ class Decompiler
1234
1278
  if ne = new_global_var(e, t, scope)
1235
1279
  ne.type = t if better_type[t, ne.type] # TODO patch existing scopes using ne
1236
1280
  # TODO rename (dword_xx -> byte_xx etc)
1237
- e = scope.symbol_ancestors[e] || e if e.kind_of? String # exe reloc
1281
+ e = scope.symbol_ancestors[e] || e if e.kind_of?(String) # exe reloc
1238
1282
  walk_ce(scope) { |ce|
1239
1283
  ce.lexpr = ne if ce.lexpr == e
1240
1284
  ce.rexpr = ne if ce.rexpr == e
1241
- if ce.op == :* and not ce.lexpr and ce.rexpr == ne and ne.type.pointer? and ne.type.pointed.untypedef.kind_of? C::Union
1285
+ if ce.op == :* and not ce.lexpr and ce.rexpr == ne and ne.type.pointer? and ne.type.pointed.untypedef.kind_of?(C::Union)
1242
1286
  # *struct -> struct->bla
1243
1287
  ce.rexpr = structoffset(ne.type.pointed.untypedef, ce.rexpr, 0, sizeof(ce.type))
1244
1288
  elsif ce.lexpr == ne or ce.rexpr == ne
@@ -1255,10 +1299,10 @@ class Decompiler
1255
1299
  # check if need to change the type of a var
1256
1300
  # propagate_type if type is updated
1257
1301
  update_type = lambda { |n, t|
1258
- next if propagating.include? n
1302
+ next if propagating.include?(n)
1259
1303
  o = scope.symbol[n].stackoff
1260
- next if not o and t.untypedef.kind_of? C::Union
1261
- next if o and scope.decompdata[:stackoff_type][o] and t != scope.decompdata[:stackoff_type][o]
1304
+ next if not o and t.untypedef.kind_of?(C::Union)
1305
+ next if scope.decompdata[:unalias_type][n] and t != scope.decompdata[:unalias_type][n]
1262
1306
  next if t0 = types[n] and not better_type[t, t0]
1263
1307
  next if o and (t.integral? or t.pointer?) and o % sizeof(t) != 0 # keep vars aligned
1264
1308
  types[n] = t
@@ -1268,7 +1312,7 @@ class Decompiler
1268
1312
  propagating.delete n
1269
1313
  next if not o
1270
1314
  t = t.untypedef
1271
- if t.kind_of? C::Struct
1315
+ if t.kind_of?(C::Struct)
1272
1316
  t.members.to_a.each { |m|
1273
1317
  mo = t.offsetof(@c_parser, m.name)
1274
1318
  next if mo == 0
@@ -1282,23 +1326,23 @@ class Decompiler
1282
1326
  # try to update the type of a var from knowing the type of an expr (through dereferences etc)
1283
1327
  known_type = lambda { |e, t|
1284
1328
  loop do
1285
- e = e.rexpr while e.kind_of? C::CExpression and not e.op and e.type == t
1329
+ e = e.rexpr while e.kind_of?(C::CExpression) and not e.op and e.type == t
1286
1330
  if o = scopevar[e]
1287
1331
  update_type[o, t]
1288
1332
  elsif o = globalvar[e]
1289
1333
  update_global_type[o, t]
1290
- elsif not e.kind_of? C::CExpression
1334
+ elsif not e.kind_of?(C::CExpression)
1291
1335
  elsif o = pscopevar[e] and t.pointer?
1292
1336
  update_type[o, t.pointed]
1293
1337
  elsif e.op == :* and not e.lexpr
1294
1338
  e = e.rexpr
1295
1339
  t = C::Pointer.new(t)
1296
1340
  next
1297
- elsif t.pointer? and e.op == :+ and e.lexpr.kind_of? C::CExpression and e.lexpr.type.integral? and e.rexpr.kind_of? C::Variable
1341
+ elsif t.pointer? and e.op == :+ and e.lexpr.kind_of?(C::CExpression) and e.lexpr.type.integral? and e.rexpr.kind_of?(C::Variable)
1298
1342
  e.lexpr, e.rexpr = e.rexpr, e.lexpr
1299
1343
  next
1300
- elsif e.op == :+ and e.lexpr and e.rexpr.kind_of? C::CExpression
1301
- if not e.rexpr.op and e.rexpr.rexpr.kind_of? ::Integer
1344
+ elsif e.op == :+ and e.lexpr and e.rexpr.kind_of?(C::CExpression)
1345
+ if not e.rexpr.op and e.rexpr.rexpr.kind_of?(::Integer)
1302
1346
  if t.pointer? and e.rexpr.rexpr < 0x1000 and (e.rexpr.rexpr % sizeof(t.pointed)) == 0 # XXX relocatable + base=0..
1303
1347
  e = e.lexpr # (int)*(x+2) === (int) *x
1304
1348
  next
@@ -1307,13 +1351,13 @@ class Decompiler
1307
1351
  e = e.rexpr
1308
1352
  next
1309
1353
  end
1310
- elsif t.pointer? and (e.lexpr.kind_of? C::CExpression and e.lexpr.lexpr and [:<<, :>>, :*, :&].include? e.lexpr.op) or
1354
+ elsif t.pointer? and (e.lexpr.kind_of?(C::CExpression) and e.lexpr.lexpr and [:<<, :>>, :*, :&].include?(e.lexpr.op)) or
1311
1355
  (o = scopevar[e.lexpr] and types[o] and types[o].integral? and
1312
1356
  !(o = scopevar[e.rexpr] and types[o] and types[o].integral?))
1313
1357
  e.lexpr, e.rexpr = e.rexpr, e.lexpr # swap
1314
1358
  e = e.lexpr
1315
1359
  next
1316
- elsif t.pointer? and ((e.rexpr.kind_of? C::CExpression and e.rexpr.lexpr and [:<<, :>>, :*, :&].include? e.rexpr.op) or
1360
+ elsif t.pointer? and ((e.rexpr.kind_of?(C::CExpression) and e.rexpr.lexpr and [:<<, :>>, :*, :&].include?(e.rexpr.op)) or
1317
1361
  (o = scopevar[e.rexpr] and types[o] and types[o].integral? and
1318
1362
  !(o = scopevar[e.lexpr] and types[o] and types[o].integral?)))
1319
1363
  e = e.lexpr
@@ -1329,11 +1373,11 @@ class Decompiler
1329
1373
  walk_ce(scope) { |ce|
1330
1374
  next if ce.op != :'='
1331
1375
 
1332
- if ce.lexpr.kind_of? C::Variable and ce.lexpr.name == var
1376
+ if ce.lexpr.kind_of?(C::Variable) and ce.lexpr.name == var
1333
1377
  known_type[ce.rexpr, type]
1334
1378
  next
1335
1379
  end
1336
- if ce.rexpr.kind_of? C::Variable and ce.rexpr.name == var
1380
+ if ce.rexpr.kind_of?(C::Variable) and ce.rexpr.name == var
1337
1381
  known_type[ce.lexpr, type]
1338
1382
  next
1339
1383
  end
@@ -1341,7 +1385,7 @@ class Decompiler
1341
1385
  # int **x; y = **x => int y
1342
1386
  t = type
1343
1387
  l = ce.lexpr
1344
- while l.kind_of? C::CExpression and l.op == :* and not l.lexpr
1388
+ while l.kind_of?(C::CExpression) and l.op == :* and not l.lexpr
1345
1389
  if var == pscopevar[l.rexpr]
1346
1390
  known_type[ce.rexpr, t]
1347
1391
  break
@@ -1355,7 +1399,7 @@ class Decompiler
1355
1399
  # int **x; **x = y => int y
1356
1400
  t = type
1357
1401
  r = ce.rexpr
1358
- while r.kind_of? C::CExpression and r.op == :* and not r.lexpr
1402
+ while r.kind_of?(C::CExpression) and r.op == :* and not r.lexpr
1359
1403
  if var == pscopevar[r.rexpr]
1360
1404
  known_type[ce.lexpr, t]
1361
1405
  break
@@ -1373,32 +1417,32 @@ class Decompiler
1373
1417
  # put all those macros in use
1374
1418
  # use user-defined types first
1375
1419
  scope.symbol.each_value { |v|
1376
- next if not v.kind_of? C::Variable or not v.stackoff or not t = scope.decompdata[:stackoff_type][v.stackoff]
1420
+ next if not v.kind_of?(C::Variable) or not t = scope.decompdata[:unalias_type][v.name]
1377
1421
  known_type[v, t]
1378
1422
  }
1379
1423
 
1380
1424
  # try to infer types from C semantics
1381
1425
  later = []
1382
1426
  walk_ce(scope) { |ce|
1383
- if ce.op == :'=' and ce.rexpr.kind_of? C::CExpression and (ce.rexpr.op == :funcall or (ce.rexpr.op == nil and ce.rexpr.rexpr.kind_of? ::Integer and
1384
- ce.rexpr.rexpr.abs < 0x10000 and (not ce.lexpr.kind_of? C::CExpression or ce.lexpr.op != :'*' or ce.lexpr.lexpr)))
1427
+ if ce.op == :'=' and ce.rexpr.kind_of?(C::CExpression) and (ce.rexpr.op == :funcall or (ce.rexpr.op == nil and ce.rexpr.rexpr.kind_of?(::Integer) and
1428
+ ce.rexpr.rexpr.abs < 0x10000 and (not ce.lexpr.kind_of?(C::CExpression) or ce.lexpr.op != :'*' or ce.lexpr.lexpr)))
1385
1429
  # var = int
1386
1430
  known_type[ce.lexpr, ce.rexpr.type]
1387
1431
  elsif ce.op == :funcall
1388
1432
  f = ce.lexpr.type
1389
1433
  f = f.pointed if f.pointer?
1390
- next if not f.kind_of? C::Function
1434
+ next if not f.kind_of?(C::Function)
1391
1435
  # cast func args to arg prototypes
1392
1436
  f.args.to_a.zip(ce.rexpr).each_with_index { |(proto, arg), i| ce.rexpr[i] = C::CExpression[arg, proto.type] ; known_type[arg, proto.type] }
1393
1437
  elsif ce.op == :* and not ce.lexpr
1394
- if e = ce.rexpr and e.kind_of? C::CExpression and not e.op and e = e.rexpr and e.kind_of? C::CExpression and
1395
- e.op == :& and not e.lexpr and e.rexpr.kind_of? C::Variable and e.rexpr.stackoff
1438
+ if e = ce.rexpr and e.kind_of?(C::CExpression) and not e.op and e = e.rexpr and e.kind_of?(C::CExpression) and
1439
+ e.op == :& and not e.lexpr and e.rexpr.kind_of?(C::Variable) and e.rexpr.stackoff
1396
1440
  # skip *(__int32*)&var_12 for now, avoid saying var12 is an int if it may be a ptr or anything
1397
1441
  later << [ce.rexpr, C::Pointer.new(ce.type)]
1398
1442
  next
1399
1443
  end
1400
1444
  known_type[ce.rexpr, C::Pointer.new(ce.type)]
1401
- elsif not ce.op and ce.type.pointer? and ce.type.pointed.kind_of? C::Function
1445
+ elsif not ce.op and ce.type.pointer? and ce.type.pointed.kind_of?(C::Function)
1402
1446
  # cast to fptr: must be a fptr
1403
1447
  known_type[ce.rexpr, ce.type]
1404
1448
  end
@@ -1423,7 +1467,7 @@ class Decompiler
1423
1467
  v = scope.symbol[n]
1424
1468
  next if not o = v.stackoff
1425
1469
  t = t.untypedef
1426
- if t.kind_of? C::Struct
1470
+ if t.kind_of?(C::Struct)
1427
1471
  t.members.to_a.each { |tm|
1428
1472
  moff = t.offsetof(@c_parser, tm.name)
1429
1473
  next if moff == 0
@@ -1469,7 +1513,7 @@ class Decompiler
1469
1513
  }
1470
1514
  when o = scopevar[ce.lexpr]; ce.lexpr = maycast[varat[o], ce.lexpr]
1471
1515
  when o = scopevar[ce.rexpr]; ce.rexpr = maycast[varat[o], ce.rexpr]
1472
- ce.rexpr = C::CExpression[ce.rexpr] if not ce.op and ce.rexpr.kind_of? C::Variable
1516
+ ce.rexpr = C::CExpression[ce.rexpr] if not ce.op and ce.rexpr.kind_of?(C::Variable)
1473
1517
  when o = pscopevar[ce.lexpr]; ce.lexpr = maycast_p[varat[o], ce.lexpr]
1474
1518
  when o = pscopevar[ce.rexpr]; ce.rexpr = maycast_p[varat[o], ce.rexpr]
1475
1519
  when o = scopevar[ce]; ce.replace C::CExpression[maycast[varat[o], ce]]
@@ -1485,14 +1529,14 @@ class Decompiler
1485
1529
  varandff = Hash.new(0)
1486
1530
  varandffff = Hash.new(0)
1487
1531
  walk_ce(scope) { |ce|
1488
- if ce.op == :& and ce.lexpr.kind_of? C::Variable and ce.lexpr.type.integral? and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? ::Integer
1532
+ if ce.op == :& and ce.lexpr.kind_of?(C::Variable) and ce.lexpr.type.integral? and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer)
1489
1533
  case ce.rexpr.rexpr
1490
1534
  when 0xff; varandff[ce.lexpr.name] += 1
1491
1535
  when 0xffff; varandffff[ce.lexpr.name] += 1
1492
1536
  end
1493
1537
  end
1494
- varuse[ce.lexpr.name] += 1 if ce.lexpr.kind_of? C::Variable
1495
- varuse[ce.rexpr.name] += 1 if ce.rexpr.kind_of? C::Variable
1538
+ varuse[ce.lexpr.name] += 1 if ce.lexpr.kind_of?(C::Variable)
1539
+ varuse[ce.rexpr.name] += 1 if ce.rexpr.kind_of?(C::Variable)
1496
1540
  }
1497
1541
  varandff.each { |k, v|
1498
1542
  scope.symbol[k].type = C::BaseType.new(:__int8, :unsigned) if varuse[k] == v
@@ -1505,28 +1549,96 @@ class Decompiler
1505
1549
  walk_ce(scope, true) { |ce|
1506
1550
  if ce.op
1507
1551
  ce.type = C::CExpression[ce.lexpr, ce.op, ce.rexpr].type rescue next
1508
- if ce.op == :'=' and ce.rexpr.kind_of? C::Typed and ce.rexpr.type != ce.type and (not ce.rexpr.type.integral? or not ce.type.integral?)
1509
- known_type[ce.rexpr, ce.type] if ce.type.pointer? and ce.type.pointed.untypedef.kind_of? C::Function # localvar = &struct with fptr
1552
+ if ce.op == :'=' and ce.rexpr.kind_of?(C::Typed) and ce.rexpr.type != ce.type and (not ce.rexpr.type.integral? or not ce.type.integral?)
1553
+ known_type[ce.rexpr, ce.type] if ce.type.pointer? and ce.type.pointed.untypedef.kind_of?(C::Function) # localvar = &struct with fptr
1510
1554
  ce.rexpr = C::CExpression[[ce.rexpr], ce.type]
1511
1555
  end
1512
- elsif ce.type.pointer? and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :& and not ce.rexpr.lexpr and sizeof(ce.rexpr.rexpr.type) == sizeof(ce.type.pointed)
1556
+ elsif ce.type.pointer? and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :& and not ce.rexpr.lexpr and sizeof(ce.rexpr.rexpr.type) == sizeof(ce.type.pointed)
1513
1557
  ce.type = ce.rexpr.type
1514
1558
  end
1515
1559
  }
1516
1560
  end
1517
1561
 
1562
+ # use casts to determine variable types after code optimization
1563
+ # if all uses of var_42 are through *(int*)(&var_42), set type to int
1564
+ def decompile_c_types_again(scope)
1565
+ return if forbid_decompile_types
1566
+
1567
+ update_type = lambda { |n, t|
1568
+ o = scope.symbol[n].stackoff
1569
+ next if not o and t.untypedef.kind_of?(C::Union)
1570
+ next if scope.decompdata[:unalias_type][n] and t != scope.decompdata[:unalias_type][n]
1571
+ scope.symbol[n].type = t
1572
+ }
1573
+
1574
+ # true if e is a cast of a var address
1575
+ is_cast = lambda { |ce|
1576
+ true if not ce.op and not ce.lexpr and ce.rexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :& and not ce.rexpr.lexpr
1577
+ }
1578
+
1579
+ # scan code for casts
1580
+ uses = {}
1581
+ count_refs = Hash.new(0)
1582
+ walk_ce(scope) { |ce|
1583
+ count_refs[ce.lexpr.name] += 1 if ce.lexpr.kind_of?(C::Variable)
1584
+ count_refs[ce.rexpr.name] += 1 if ce.rexpr.kind_of?(C::Variable)
1585
+ if is_cast[ce] and ce.rexpr.rexpr.kind_of?(C::Variable)
1586
+ (uses[ce.rexpr.rexpr.name] ||= []) << ce.type.pointed
1587
+ end
1588
+ }
1589
+
1590
+ # given a list of types, return a type compatible with all
1591
+ summary_type = lambda { |type_list|
1592
+ t = type_list.first
1593
+ type_list.each { |tt|
1594
+ if sizeof(t) != sizeof(tt) or t.integral? != tt.integral? or t.pointer? != tt.pointer?
1595
+ t = nil
1596
+ break
1597
+ elsif t != tt
1598
+ t = tt if t.to_s =~ /__/
1599
+ end
1600
+ }
1601
+ t
1602
+ }
1603
+
1604
+ updated = {}
1605
+ uses.each { |n, tl|
1606
+ if tl.length == count_refs[n] and t = summary_type[tl] and update_type[n, t]
1607
+ updated[n] = true
1608
+ end
1609
+ }
1610
+ return if updated.empty?
1611
+
1612
+ walk_ce(scope, true) { |ce|
1613
+ if is_cast[ce] and updated[ce.rexpr.rexpr.name]
1614
+ ce.op = :&
1615
+ ce.rexpr = ce.rexpr.rexpr
1616
+ elsif ce.op == :* and not ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :& and not ce.rexpr.lexpr and ce.rexpr.rexpr.kind_of?(C::Variable) and updated[ce.rexpr.rexpr.name]
1617
+ ce.op = nil
1618
+ ce.rexpr = ce.rexpr.rexpr
1619
+ elsif ce.op
1620
+ if ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(C::Variable) and updated[ce.rexpr.rexpr.name]
1621
+ ce.rexpr = ce.rexpr.rexpr
1622
+ end
1623
+ if ce.lexpr.kind_of?(C::CExpression) and not ce.lexpr.op and ce.lexpr.rexpr.kind_of?(C::Variable) and updated[ce.lexpr.rexpr.name]
1624
+ ce.lexpr = ce.lexpr.rexpr
1625
+ end
1626
+ end
1627
+ }
1628
+ end
1629
+
1518
1630
  # struct foo { int i; int j; struct { int k; int l; } m; }; bla+12 => &bla->m.l
1519
1631
  # st is a struct, ptr is an expr pointing to a struct, off is a numeric offset from ptr, msz is the size of the pointed member (nil ignored)
1520
1632
  def structoffset(st, ptr, off, msz)
1521
1633
  tabidx = off / sizeof(st)
1522
1634
  off -= tabidx * sizeof(st)
1523
- ptr = C::CExpression[:&, [ptr, :'[]', [tabidx]]] if tabidx != 0 or ptr.type.untypedef.kind_of? C::Array
1524
- return ptr if off == 0 and (not msz or # avoid infinite recursion with eg chained list
1525
- (ptr.kind_of? C::CExpression and ((ptr.op == :& and not ptr.lexpr and s=ptr.rexpr) or (ptr.op == :'.' and s=ptr)) and
1526
- not s.type.untypedef.kind_of? C::Union))
1635
+ ptr = C::CExpression[:&, [ptr, :'[]', [tabidx]]] if tabidx != 0 or ptr.type.untypedef.kind_of?(C::Array)
1636
+ return ptr if off == 0 and (not msz or # avoid infinite recursion with eg chained list
1637
+ (ptr.kind_of?(C::CExpression) and ((ptr.op == :& and not ptr.lexpr and s=ptr.rexpr) or (ptr.op == :'.' and s=ptr)) and
1638
+ not s.type.untypedef.kind_of?(C::Union)))
1527
1639
 
1528
1640
  m_ptr = lambda { |m|
1529
- if ptr.kind_of? C::CExpression and ptr.op == :& and not ptr.lexpr
1641
+ if ptr.kind_of?(C::CExpression) and ptr.op == :& and not ptr.lexpr
1530
1642
  C::CExpression[ptr.rexpr, :'.', m.name]
1531
1643
  else
1532
1644
  C::CExpression[ptr, :'->', m.name]
@@ -1544,7 +1656,7 @@ class Decompiler
1544
1656
  sst = sm.type.untypedef
1545
1657
  #return ptr if mo[sm] == 0 and sst.pointer? and sst.type.untypedef == st # TODO fix infinite recursion on mutually recursive ptrs
1546
1658
  ptr = C::CExpression[:&, m_ptr[sm]]
1547
- if sst.kind_of? C::Union
1659
+ if sst.kind_of?(C::Union)
1548
1660
  return structoffset(sst, ptr, off, msz)
1549
1661
  end
1550
1662
  end
@@ -1561,15 +1673,15 @@ class Decompiler
1561
1673
  # must be run only once, right after type setting
1562
1674
  def fix_pointer_arithmetic(scope)
1563
1675
  walk_ce(scope, true) { |ce|
1564
- if ce.lexpr and ce.lexpr.type.pointer? and [:&, :>>, :<<].include? ce.op
1676
+ if ce.lexpr and ce.lexpr.type.pointer? and [:&, :>>, :<<].include?(ce.op)
1565
1677
  ce.lexpr = C::CExpression[[ce.lexpr], C::BaseType.new(:int)]
1566
1678
  end
1567
1679
 
1568
- if ce.op == :+ and ce.lexpr and ((ce.lexpr.type.integral? and ce.rexpr.type.pointer?) or (ce.rexpr.type.pointer? and ce.rexpr.type.pointed.untypedef.kind_of? C::Union))
1680
+ if ce.op == :+ and ce.lexpr and ((ce.lexpr.type.integral? and ce.rexpr.type.pointer?) or (ce.rexpr.type.pointer? and ce.rexpr.type.pointed.untypedef.kind_of?(C::Union)))
1569
1681
  ce.rexpr, ce.lexpr = ce.lexpr, ce.rexpr
1570
1682
  end
1571
1683
 
1572
- if ce.op == :* and not ce.lexpr and ce.rexpr.type.pointer? and ce.rexpr.type.pointed.untypedef.kind_of? C::Struct
1684
+ if ce.op == :* and not ce.lexpr and ce.rexpr.type.pointer? and ce.rexpr.type.pointed.untypedef.kind_of?(C::Struct)
1573
1685
  s = ce.rexpr.type.pointed.untypedef
1574
1686
  m = s.members.to_a.find { |m_| s.offsetof(@c_parser, m_.name) == 0 }
1575
1687
  if sizeof(m) != sizeof(ce)
@@ -1582,7 +1694,7 @@ class Decompiler
1582
1694
  ce.rexpr = m.name
1583
1695
  ce.type = m.type
1584
1696
  next
1585
- elsif ce.op == :'=' and ce.lexpr.type.untypedef.kind_of? C::Struct
1697
+ elsif ce.op == :'=' and ce.lexpr.type.untypedef.kind_of?(C::Struct)
1586
1698
  s = ce.lexpr.type.untypedef
1587
1699
  m = s.members.to_a.find { |m_| s.offsetof(@c_parser, m_.name) == 0 }
1588
1700
  ce.lexpr = C::CExpression.new(ce.lexpr, :'.', m.name, m.type)
@@ -1594,18 +1706,18 @@ class Decompiler
1594
1706
  ce.type = ce.lexpr.type
1595
1707
  end
1596
1708
 
1597
- if ce.op == :& and not ce.lexpr and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :* and not ce.rexpr.lexpr
1709
+ if ce.op == :& and not ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :* and not ce.rexpr.lexpr
1598
1710
  ce.replace C::CExpression[ce.rexpr.rexpr]
1599
1711
  end
1600
1712
 
1601
1713
  next if not ce.lexpr or not ce.lexpr.type.pointer?
1602
- if ce.op == :+ and (s = ce.lexpr.type.pointed.untypedef).kind_of? C::Union and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and
1603
- ce.rexpr.rexpr.kind_of? ::Integer and o = ce.rexpr.rexpr
1714
+ if ce.op == :+ and (s = ce.lexpr.type.pointed.untypedef).kind_of?(C::Union) and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and
1715
+ ce.rexpr.rexpr.kind_of?(::Integer) and o = ce.rexpr.rexpr
1604
1716
  # structptr + 4 => &structptr->member
1605
1717
  ce.replace structoffset(s, ce.lexpr, o, nil)
1606
- elsif [:+, :-, :'+=', :'-='].include? ce.op and ce.rexpr.kind_of? C::CExpression and ((not ce.rexpr.op and i = ce.rexpr.rexpr) or
1607
- (ce.rexpr.op == :* and i = ce.rexpr.lexpr and ((i.kind_of? C::CExpression and not i.op and i = i.rexpr) or true))) and
1608
- i.kind_of? ::Integer and psz = sizeof(nil, ce.lexpr.type.pointed) and i % psz == 0
1718
+ elsif [:+, :-, :'+=', :'-='].include?(ce.op) and ce.rexpr.kind_of?(C::CExpression) and ((not ce.rexpr.op and i = ce.rexpr.rexpr) or
1719
+ (ce.rexpr.op == :* and i = ce.rexpr.lexpr and ((i.kind_of?(C::CExpression) and not i.op and i = i.rexpr) or true))) and
1720
+ i.kind_of?(::Integer) and psz = sizeof(nil, ce.lexpr.type.pointed) and i % psz == 0
1609
1721
  # ptr += 4 => ptr += 1
1610
1722
  if not ce.rexpr.op
1611
1723
  ce.rexpr.rexpr /= psz
@@ -1646,9 +1758,10 @@ class Decompiler
1646
1758
  # XXX o1 may overlap o2 AND another (int32 v_10; int32 v_E; int32 v_C;)
1647
1759
  # TODO should check stuff with aliasing domains
1648
1760
  next if v1.name == v2.name or o1 >= o2+l2 or o1+l1 <= o2 or l1 > l2 or (l2 == l1 and o2 >= o1)
1761
+ next if o1 == o2 and l1 != l2
1649
1762
  # v1 => *(&v2+delta)
1650
1763
  p = C::CExpression[:&, v2]
1651
- p = C::CExpression[p, :+, [o1-o2]]
1764
+ p = C::CExpression[p, :+, [o1-o2]] if o1 != o2
1652
1765
  p = C::CExpression[p, C::Pointer.new(v1.type)] if v1.type != p.type.type
1653
1766
  p = C::CExpression[:*, p]
1654
1767
  walk_ce(scope) { |ce|
@@ -1656,20 +1769,9 @@ class Decompiler
1656
1769
  ce.rexpr = p if ce.rexpr == v1
1657
1770
  }
1658
1771
  }
1659
-
1660
1772
  }
1661
1773
  end
1662
1774
 
1663
- # to be run with scope = function body with only CExpr/Decl/Label/Goto/IfGoto/Return, with correct variables types
1664
- # will transform += 1 to ++, inline them to prev/next statement ('++x; if (x)..' => 'if (++x)..')
1665
- # remove useless variables ('int i;', i never used or 'i = 1; j = i;', i never read after => 'j = 1;')
1666
- # remove useless casts ('(int)i' with 'int i;' => 'i')
1667
- def optimize(scope)
1668
- optimize_code(scope)
1669
- optimize_vars(scope)
1670
- optimize_vars(scope) # 1st run may transform i = i+1 into i++ which second run may coalesce into if(i)
1671
- end
1672
-
1673
1775
  # simplify cexpressions (char & 255, redundant casts, etc)
1674
1776
  def optimize_code(scope)
1675
1777
  return if forbid_optimize_code
@@ -1677,12 +1779,12 @@ class Decompiler
1677
1779
  sametype = lambda { |t1, t2|
1678
1780
  t1 = t1.untypedef
1679
1781
  t2 = t2.untypedef
1680
- t1 = t1.pointed.untypedef if t1.pointer? and t1.pointed.untypedef.kind_of? C::Function
1681
- t2 = t2.pointed.untypedef if t2.pointer? and t2.pointed.untypedef.kind_of? C::Function
1782
+ t1 = t1.pointed.untypedef if t1.pointer? and t1.pointed.untypedef.kind_of?(C::Function)
1783
+ t2 = t2.pointed.untypedef if t2.pointer? and t2.pointed.untypedef.kind_of?(C::Function)
1682
1784
  t1 == t2 or
1683
- (t1.kind_of? C::Function and t2.kind_of? C::Function and sametype[t1.type, t2.type] and t1.args.to_a.length == t2.args.to_a.length and
1684
- t1.args.to_a.zip(t2.args.to_a).all? { |st1, st2| sametype[st1.type, st2.type] }) or
1685
- (t1.kind_of? C::BaseType and t1.integral? and t2.kind_of? C::BaseType and t2.integral? and sizeof(nil, t1) == sizeof(nil, t2)) or
1785
+ (t1.kind_of?(C::Function) and t2.kind_of?(C::Function) and sametype[t1.type, t2.type] and t1.args.to_a.length == t2.args.to_a.length and
1786
+ t1.args.to_a.zip(t2.args.to_a).all? { |st1, st2| sametype[st1.type, st2.type] }) or
1787
+ (t1.kind_of?(C::BaseType) and t1.integral? and t2.kind_of?(C::BaseType) and t2.integral? and sizeof(nil, t1) == sizeof(nil, t2)) or
1686
1788
  (t1.pointer? and t2.pointer? and sametype[t1.type, t2.type])
1687
1789
  }
1688
1790
 
@@ -1690,56 +1792,92 @@ class Decompiler
1690
1792
  future_array = []
1691
1793
  walk_ce(scope, true) { |ce|
1692
1794
  # (whatever)0 => 0
1693
- if not ce.op and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 0
1795
+ if not ce.op and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 0
1694
1796
  ce.replace ce.rexpr
1695
1797
  end
1696
1798
 
1697
1799
  # *&bla => bla if types ok
1698
- if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :& and not ce.rexpr.lexpr and sametype[ce.rexpr.type.pointed, ce.rexpr.rexpr.type]
1800
+ if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :& and not ce.rexpr.lexpr and sametype[ce.rexpr.type.pointed, ce.rexpr.rexpr.type]
1699
1801
  ce.replace C::CExpression[ce.rexpr.rexpr]
1700
1802
  end
1701
1803
 
1702
- # int x + 0xffffffff -> x-1
1703
- if ce.lexpr and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and [:+, :-, :'+=', :'-=', :'!=', :==, :>, :<, :>=, :<=].include? ce.op and
1804
+ # int x + 0xffffffff => x-1
1805
+ if ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and [:+, :-, :'+=', :'-=', :'!=', :==, :>, :<, :>=, :<=].include?(ce.op) and
1704
1806
  ce.rexpr.rexpr == (1 << (8*sizeof(ce.lexpr)))-1
1705
1807
  ce.op = {:+ => :-, :- => :+, :'+=' => :'-=', :'-=' => :'+='}[ce.op]
1706
1808
  ce.rexpr.rexpr = 1
1707
1809
  end
1708
1810
 
1811
+ # i + ptr => ptr + i
1812
+ if ce.op == :+ and ce.lexpr and ce.rexpr.type.pointer? and ce.lexpr.type.integral?
1813
+ ce.rexpr, ce.lexpr = ce.lexpr, ce.rexpr
1814
+ end
1815
+
1816
+ # i + v => v + i
1817
+ if ce.op == :+ and ce.lexpr.kind_of?(C::CExpression) and not ce.lexpr.op and ce.lexpr.rexpr.kind_of?(::Integer)
1818
+ # avoid infinite swapping
1819
+ if not ce.rexpr.kind_of?(C::CExpression) or ce.rexpr.op or not ce.rexpr.rexpr.kind_of?(::Integer)
1820
+ ce.rexpr, ce.lexpr = ce.lexpr, ce.rexpr
1821
+ end
1822
+ end
1823
+
1824
+ # (a + b) + c => a + (b + c)
1825
+ if ce.op == :+ and ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == :+ and ce.lexpr.lexpr
1826
+ ce.lexpr, ce.rexpr = ce.lexpr.lexpr, C::CExpression[ce.lexpr.rexpr, :+, ce.rexpr]
1827
+ optimize_code(ce)
1828
+ end
1829
+
1830
+ # 1 + 2 => 3
1831
+ if (ce.op == :+ or ce.op == :- or ce.op == :*) and ce.lexpr.kind_of?(C::CExpression) and ce.type.integral? and not ce.lexpr.op and ce.lexpr.rexpr.kind_of?(::Integer) and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer)
1832
+ ce.lexpr, ce.op, ce.rexpr = nil, nil, ce.lexpr.rexpr.send(ce.op, ce.rexpr.rexpr)
1833
+ end
1834
+
1835
+ # 4 * (a + 1) => 4*a + 4
1836
+ if ce.op == :* and ce.lexpr.kind_of?(C::CExpression) and ce.type.integral? and not ce.lexpr.op and ce.lexpr.rexpr.kind_of?(::Integer) and ce.rexpr.kind_of?(C::CExpression) and (ce.rexpr.op == :+ or ce.rexpr.op == :-) and ce.rexpr.lexpr and ce.rexpr.rexpr.kind_of?(C::CExpression) and not ce.rexpr.rexpr.op and ce.rexpr.rexpr.rexpr.kind_of?(::Integer)
1837
+ ce.replace C::CExpression[[ce.lexpr, ce.op, ce.rexpr.lexpr], ce.rexpr.op, [ce.lexpr.rexpr * ce.rexpr.rexpr.rexpr]]
1838
+ optimize_code(ce)
1839
+ end
1840
+
1709
1841
  # int *ptr; *(ptr + 4) => ptr[4]
1710
- if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :+ and var = ce.rexpr.lexpr and var.kind_of? C::Variable and var.type.pointer?
1842
+ if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :+ and var = ce.rexpr.lexpr and var.kind_of?(C::Variable) and var.type.pointer?
1711
1843
  ce.lexpr, ce.op, ce.rexpr = ce.rexpr.lexpr, :'[]', ce.rexpr.rexpr
1712
1844
  future_array << var.name
1713
1845
  end
1714
1846
 
1847
+ # ptr + (i << 3) => ptr + 8*i
1848
+ if (ce.op == :+ or ce.op == :[]) and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :<< and ce.rexpr.rexpr.kind_of?(C::CExpression) and not ce.rexpr.rexpr.op and ce.rexpr.rexpr.rexpr.kind_of?(::Integer)
1849
+ ce.rexpr.rexpr.rexpr = 1 << ce.rexpr.rexpr.rexpr
1850
+ ce.rexpr.lexpr, ce.rexpr.op, ce.rexpr.rexpr = ce.rexpr.rexpr, :*, ce.rexpr.lexpr
1851
+ end
1852
+
1715
1853
  # char x; x & 255 => x
1716
- if ce.op == :& and ce.lexpr and (ce.lexpr.type.integral? or ce.lexpr.type.pointer?) and ce.rexpr.kind_of? C::CExpression and
1717
- not ce.rexpr.op and ce.rexpr.rexpr.kind_of? ::Integer and m = (1 << (8*sizeof(ce.lexpr))) - 1 and
1854
+ if ce.op == :& and ce.lexpr and (ce.lexpr.type.integral? or ce.lexpr.type.pointer?) and ce.rexpr.kind_of?(C::CExpression) and
1855
+ not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer) and m = (1 << (8*sizeof(ce.lexpr))) - 1 and
1718
1856
  ce.rexpr.rexpr & m == m
1719
1857
  ce.replace C::CExpression[ce.lexpr]
1720
1858
  end
1721
1859
 
1722
1860
  # a + -b => a - b
1723
- if ce.op == :+ and ce.lexpr and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :- and not ce.rexpr.lexpr
1861
+ if ce.op == :+ and ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :- and not ce.rexpr.lexpr
1724
1862
  ce.op, ce.rexpr = :-, ce.rexpr.rexpr
1725
1863
  end
1726
1864
 
1727
1865
  # (((int) i >> 31) & 1) => i < 0
1728
- if ce.op == :& and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 1 and
1729
- ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == :>> and ce.lexpr.rexpr.kind_of? C::CExpression and
1866
+ if ce.op == :& and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 1 and
1867
+ ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == :>> and ce.lexpr.rexpr.kind_of?(C::CExpression) and
1730
1868
  not ce.lexpr.rexpr.op and ce.lexpr.rexpr.rexpr == sizeof(ce.lexpr.lexpr) * 8 - 1
1731
1869
  ce.replace C::CExpression[ce.lexpr.lexpr, :<, [0]]
1732
1870
  end
1733
1871
 
1734
1872
  # a-b == 0 => a == b
1735
- if ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 0 and [:==, :'!=', :<, :>, :<=, :>=].include? ce.op and
1736
- ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == :- and ce.lexpr.lexpr
1873
+ if ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 0 and [:==, :'!=', :<, :>, :<=, :>=].include?(ce.op) and
1874
+ ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == :- and ce.lexpr.lexpr
1737
1875
  ce.lexpr, ce.rexpr = ce.lexpr.lexpr, ce.lexpr.rexpr
1738
1876
  end
1739
1877
 
1740
1878
  # (a > 0) != 0
1741
- if ce.op == :'!=' and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 0 and ce.lexpr.kind_of? C::CExpression and
1742
- [:<, :<=, :>, :>=, :'==', :'!=', :'!'].include? ce.lexpr.op
1879
+ if ce.op == :'!=' and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 0 and ce.lexpr.kind_of?(C::CExpression) and
1880
+ [:<, :<=, :>, :>=, :'==', :'!=', :'!'].include?(ce.lexpr.op)
1743
1881
  ce.replace ce.lexpr
1744
1882
  end
1745
1883
 
@@ -1748,21 +1886,21 @@ class Decompiler
1748
1886
  # a>=b => true if r => a<0 == b>=0 and a<0 => a<0 and b>=0
1749
1887
 
1750
1888
  # x != (a && (b != x)) => [x && (!a || b)] || [!x && !(!a || b)]
1751
- if ce.op == :'!=' and ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == :< and ce.rexpr.kind_of? C::CExpression and
1752
- ce.rexpr.op == :'&&' and ce.rexpr.rexpr.kind_of? C::CExpression and ce.rexpr.rexpr.op == :'!=' and
1889
+ if ce.op == :'!=' and ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == :< and ce.rexpr.kind_of?(C::CExpression) and
1890
+ ce.rexpr.op == :'&&' and ce.rexpr.rexpr.kind_of?(C::CExpression) and ce.rexpr.rexpr.op == :'!=' and
1753
1891
  ce.rexpr.rexpr.rexpr == ce.lexpr and not walk_ce(ce) { |ce_| break true if ce_.op == :funcall }
1754
1892
  x, a, b = ce.lexpr, ce.rexpr.lexpr, ce.rexpr.rexpr.lexpr
1755
1893
  ce.replace C::CExpression[ [x, :'&&', [[:'!',a],:'||',b]] , :'||', [[:'!', x], :'&&', [:'!', [[:'!',a],:'||',b]]] ]
1756
1894
  optimize_code(ce)
1757
1895
  end
1758
1896
  # (a != b) || a => a || b
1759
- if ce.op == :'||' and ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == :'!=' and ce.lexpr.lexpr == ce.rexpr and not walk_ce(ce) { |ce_| break true if ce_.op == :funcall }
1897
+ if ce.op == :'||' and ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == :'!=' and ce.lexpr.lexpr == ce.rexpr and not walk_ce(ce) { |ce_| break true if ce_.op == :funcall }
1760
1898
  ce.lexpr, ce.rexpr = ce.rexpr, ce.lexpr.rexpr
1761
1899
  optimize_code(ce)
1762
1900
  end
1763
1901
  # (a<b) && !(a>=0 && b<0) || (a>=b) && (a>=0 && b<0) => (signed)a < (signed)b
1764
- if ce.op == :'||' and ce.lexpr.kind_of? C::CExpression and ce.rexpr.kind_of? C::CExpression and ce.lexpr.op == :'&&' and ce.rexpr.op == :'&&' and
1765
- ce.lexpr.lexpr.kind_of? C::CExpression and ce.lexpr.lexpr.op == :<
1902
+ if ce.op == :'||' and ce.lexpr.kind_of?(C::CExpression) and ce.rexpr.kind_of?(C::CExpression) and ce.lexpr.op == :'&&' and ce.rexpr.op == :'&&' and
1903
+ ce.lexpr.lexpr.kind_of?(C::CExpression) and ce.lexpr.lexpr.op == :<
1766
1904
  a, b = ce.lexpr.lexpr.lexpr, ce.lexpr.lexpr.rexpr
1767
1905
  if ce.lexpr.rexpr === C::CExpression[[a, :'>=', [0]], :'&&', [b, :'<', [0]]].negate and
1768
1906
  ce.rexpr.lexpr === ce.lexpr.lexpr.negate and ce.rexpr.rexpr === ce.lexpr.rexpr.negate
@@ -1770,7 +1908,7 @@ class Decompiler
1770
1908
  end
1771
1909
  end
1772
1910
  # a && 1
1773
- if (ce.op == :'||' or ce.op == :'&&') and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? ::Integer
1911
+ if (ce.op == :'||' or ce.op == :'&&') and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer)
1774
1912
  if ((ce.op == :'||' and ce.rexpr.rexpr == 0) or (ce.op == :'&&' and ce.rexpr.rexpr != 0))
1775
1913
  ce.replace C::CExpression[ce.lexpr]
1776
1914
  elsif not walk_ce(ce) { |ce_| break true if ce.op == :funcall } # cannot wipe if sideeffect
@@ -1783,82 +1921,76 @@ class Decompiler
1783
1921
  end
1784
1922
 
1785
1923
  # (a < b) | (a == b) => a <= b
1786
- if ce.op == :| and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :== and ce.lexpr.kind_of? C::CExpression and
1924
+ if ce.op == :| and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :== and ce.lexpr.kind_of?(C::CExpression) and
1787
1925
  (ce.lexpr.op == :< or ce.lexpr.op == :>) and ce.lexpr.lexpr == ce.rexpr.lexpr and ce.lexpr.rexpr == ce.rexpr.rexpr
1788
1926
  ce.op = {:< => :<=, :> => :>=}[ce.lexpr.op]
1789
1927
  ce.lexpr, ce.rexpr = ce.lexpr.lexpr, ce.lexpr.rexpr
1790
1928
  end
1791
1929
 
1792
1930
  # a == 0 => !a
1793
- if ce.op == :== and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 0
1931
+ if ce.op == :== and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 0
1794
1932
  ce.lexpr, ce.op, ce.rexpr = nil, :'!', ce.lexpr
1795
1933
  end
1796
1934
 
1797
- if ce.op == :'!' and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? ::Integer
1935
+ if ce.op == :'!' and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer)
1798
1936
  ce.replace C::CExpression[[ce.rexpr.rexpr == 0 ? 1 : 0]]
1799
1937
  end
1800
1938
 
1801
1939
  # !(bool) => bool
1802
- if ce.op == :'!' and ce.rexpr.kind_of? C::CExpression and [:'==', :'!=', :<, :>, :<=, :>=, :'||', :'&&', :'!'].include? ce.rexpr.op
1940
+ if ce.op == :'!' and ce.rexpr.kind_of?(C::CExpression) and [:'==', :'!=', :<, :>, :<=, :>=, :'||', :'&&', :'!'].include?(ce.rexpr.op)
1803
1941
  ce.replace ce.rexpr.negate
1804
1942
  end
1805
1943
 
1806
1944
  # (foo)(bar)x => (foo)x
1807
- if not ce.op and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? C::CExpression
1945
+ if not ce.op and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(C::CExpression)
1808
1946
  ce.rexpr = ce.rexpr.rexpr
1809
1947
  end
1810
1948
 
1811
1949
  # &struct.1stmember => &struct
1812
- if ce.op == :& and not ce.lexpr and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :'.' and s = ce.rexpr.lexpr.type and
1813
- s.kind_of? C::Union and s.offsetof(@c_parser, ce.rexpr.rexpr) == 0
1950
+ if ce.op == :& and not ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :'.' and s = ce.rexpr.lexpr.type and
1951
+ s.kind_of?(C::Union) and s.offsetof(@c_parser, ce.rexpr.rexpr) == 0
1814
1952
  ce.rexpr = ce.rexpr.lexpr
1815
1953
  ce.type = C::Pointer.new(ce.rexpr.type)
1816
1954
  end
1817
1955
 
1818
1956
  # (1stmember*)structptr => &structptr->1stmember
1819
- if not ce.op and ce.type.pointer? and not ce.type.pointed.void? and ce.rexpr.kind_of? C::Typed and ce.rexpr.type.pointer? and
1820
- s = ce.rexpr.type.pointed.untypedef and s.kind_of? C::Union and ce.type.pointed.untypedef != s
1957
+ if not ce.op and ce.type.pointer? and not ce.type.pointed.void? and ce.rexpr.kind_of?(C::Typed) and ce.rexpr.type.pointer? and
1958
+ s = ce.rexpr.type.pointed.untypedef and s.kind_of?(C::Union) and ce.type.pointed.untypedef != s
1821
1959
  ce.rexpr = C::CExpression[structoffset(s, ce.rexpr, 0, sizeof(ce.type.pointed))]
1822
- #ce.replace ce.rexpr if not ce.type.pointed.untypedef.kind_of? C::Function or (ce.rexpr.type.pointer? and
1823
- #ce.rexpr.type.pointed.untypedef.kind_of? C::Function) # XXX ugly
1960
+ #ce.replace ce.rexpr if not ce.type.pointed.untypedef.kind_of?(C::Function) or (ce.rexpr.type.pointer? and
1961
+ #ce.rexpr.type.pointed.untypedef.kind_of?(C::Function)) # XXX ugly
1824
1962
  # int32* v1 = (int32*)pstruct;
1825
1963
  # z = v1+4 if v1 is not cast, the + is invalid (sizeof pointed changes)
1826
1964
  # TODO when finding type of pstruct, set type of v1 accordingly
1827
1965
  end
1828
1966
 
1829
1967
  # (&foo)->bar => foo.bar
1830
- if ce.op == :'->' and ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == :& and not ce.lexpr.lexpr
1968
+ if ce.op == :'->' and ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == :& and not ce.lexpr.lexpr
1831
1969
  ce.lexpr = ce.lexpr.rexpr
1832
1970
  ce.op = :'.'
1833
1971
  end
1834
1972
 
1835
1973
  # (foo)bla => bla if bla of type foo
1836
- if not ce.op and ce.rexpr.kind_of? C::Typed and sametype[ce.type, ce.rexpr.type]
1974
+ if not ce.op and ce.rexpr.kind_of?(C::Typed) and sametype[ce.type, ce.rexpr.type]
1837
1975
  ce.replace C::CExpression[ce.rexpr]
1838
1976
  end
1839
- if ce.lexpr.kind_of? C::CExpression and not ce.lexpr.op and ce.lexpr.rexpr.kind_of? C::Variable and ce.lexpr.type == ce.lexpr.rexpr.type
1977
+ if ce.lexpr.kind_of?(C::CExpression) and not ce.lexpr.op and ce.lexpr.rexpr.kind_of?(C::Variable) and ce.lexpr.type == ce.lexpr.rexpr.type
1840
1978
  ce.lexpr = ce.lexpr.rexpr
1841
1979
  end
1842
-
1843
- if ce.op == :'=' and ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == :* and not ce.lexpr.lexpr and ce.lexpr.rexpr.kind_of? C::CExpression and
1844
- not ce.lexpr.rexpr.op and ce.lexpr.rexpr.type.pointer? and ce.lexpr.rexpr.type.pointed != ce.rexpr.type
1845
- ce.lexpr.rexpr.type = C::Pointer.new(ce.rexpr.type)
1846
- optimize_code(ce.lexpr)
1847
- end
1848
1980
  }
1849
1981
 
1850
1982
  # if there is a ptr[4], change all *ptr to ptr[0] for consistency
1851
1983
  # do this after the first pass, which may change &*ptr to ptr
1852
1984
  walk_ce(scope) { |ce|
1853
- if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of? C::Variable and future_array.include? ce.rexpr.name
1985
+ if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of?(C::Variable) and future_array.include?(ce.rexpr.name)
1854
1986
  ce.lexpr, ce.op, ce.rexpr = ce.rexpr, :'[]', C::CExpression[0]
1855
1987
  end
1856
1988
  } if not future_array.empty?
1857
1989
 
1858
1990
  # if (x != 0) => if (x)
1859
1991
  walk(scope) { |st|
1860
- if st.kind_of? C::If and st.test.kind_of? C::CExpression and st.test.op == :'!=' and
1861
- st.test.rexpr.kind_of? C::CExpression and not st.test.rexpr.op and st.test.rexpr.rexpr == 0
1992
+ if st.kind_of?(C::If) and st.test.kind_of?(C::CExpression) and st.test.op == :'!=' and
1993
+ st.test.rexpr.kind_of?(C::CExpression) and not st.test.rexpr.op and st.test.rexpr.rexpr == 0
1862
1994
  st.test = C::CExpression[st.test.lexpr]
1863
1995
  end
1864
1996
  }
@@ -1869,9 +2001,9 @@ class Decompiler
1869
2001
  case exp
1870
2002
  when nil, ::Numeric, ::String; false
1871
2003
  when ::Array; exp.any? { |_e| sideeffect _e, scope }
1872
- when C::Variable; (scope and not scope.symbol[exp.name]) or exp.type.qualifier.to_a.include? :volatile
1873
- when C::CExpression; (exp.op == :* and not exp.lexpr) or exp.op == :funcall or AssignOp.include?(exp.op) or
1874
- sideeffect(exp.lexpr, scope) or sideeffect(exp.rexpr, scope)
2004
+ when C::Variable; (scope and not scope.symbol[exp.name]) or exp.type.qualifier.to_a.include?(:volatile)
2005
+ when C::CExpression; (exp.op == :* and not exp.lexpr) or exp.op == :funcall or C::CExpression::AssignOp.include?(exp.op) or
2006
+ sideeffect(exp.lexpr, scope) or sideeffect(exp.rexpr, scope)
1875
2007
  else true # failsafe
1876
2008
  end
1877
2009
  end
@@ -1879,97 +2011,153 @@ class Decompiler
1879
2011
  # converts C code to a graph of cexprs (nodes = cexprs, edges = codepaths)
1880
2012
  # returns a CGraph
1881
2013
  class CGraph
1882
- # exprs: label => [exprs], to: label => [labels], block: label => are exprs standalone (vs If#test), start: 1st label
2014
+ # exprs: label => [exprs], to: label => [labels], block: label => are exprs in a block (vs If#test), start: 1st label
1883
2015
  attr_accessor :exprs, :to, :block, :start, :to_optim, :from_optim
1884
- end
1885
- def c_to_graph(st)
1886
- g = CGraph.new
1887
- g.exprs = {} # label => [exprs]
1888
- g.to = {} # label => [labels]
1889
- g.block = {} # label => is label in a block? (vs If#test)
1890
- anon_label = 0 # when no label is there, use anon_label++
2016
+
2017
+ def initialize
2018
+ @exprs = {} # label => [exprs]
2019
+ @to = {} # label => [labels]
2020
+ @block = {} # label => is label in a block? (vs If#test)
2021
+ @anon_label = 0 # when no label is there, use anon_label++
2022
+ @exprs_var = nil # similar to @exprs, indexed by var name, lazy initialization
2023
+ end
2024
+
2025
+ def build(stmt)
2026
+ @start = @anon_label
2027
+ to_graph(stmt, @start, nil, nil, nil)
2028
+ optimize
2029
+ self
2030
+ end
2031
+
1891
2032
  # converts C code to a graph of codepath of cexprs
1892
- to_graph = lambda { |stmt, l_cur, l_after, l_cont, l_break|
2033
+ def to_graph(stmt, l_cur, l_after, l_cont, l_break)
1893
2034
  case stmt
1894
- when C::Label; g.to[l_cur] = [stmt.name] ; g.to[stmt.name] = [l_after]
1895
- when C::Goto; g.to[l_cur] = [stmt.target]
1896
- when C::Continue; g.to[l_cur] = [l_cont]
1897
- when C::Break; g.to[l_cur] = [l_break]
2035
+ when C::Label; @to[l_cur] = [stmt.name] ; @to[stmt.name] = [l_after]
2036
+ when C::Goto; @to[l_cur] = [stmt.target]
2037
+ when C::Continue; @to[l_cur] = [l_cont]
2038
+ when C::Break; @to[l_cur] = [l_break]
1898
2039
  when C::CExpression
1899
- g.exprs[l_cur] = [stmt]
1900
- g.to[l_cur] = [l_after]
2040
+ @exprs[l_cur] = [stmt]
2041
+ @to[l_cur] = [l_after]
1901
2042
  when C::Return
1902
- g.exprs[l_cur] = [stmt.value] if stmt.value
1903
- g.to[l_cur] = []
2043
+ @exprs[l_cur] = [stmt.value] if stmt.value
2044
+ @to[l_cur] = []
1904
2045
  when C::Block
1905
- to_graph[stmt.statements, l_cur, l_after, l_cont, l_break]
2046
+ to_graph(stmt.statements, l_cur, l_after, l_cont, l_break)
1906
2047
  when ::Array
1907
- g.exprs[l_cur] = []
1908
- g.block[l_cur] = true
2048
+ @exprs[l_cur] = []
2049
+ @block[l_cur] = true
1909
2050
  stmt.each_with_index { |s, i|
1910
2051
  case s
1911
2052
  when C::Declaration
1912
2053
  when C::CExpression
1913
- g.exprs[l_cur] << s
2054
+ @exprs[l_cur] << s
1914
2055
  else
1915
- l = anon_label += 1
1916
- ll = anon_label += 1
1917
- g.to[l_cur] = [l]
1918
- g.block[l_cur] = true
1919
- to_graph[stmt[i], l, ll, l_cont, l_break]
2056
+ l = @anon_label += 1
2057
+ ll = @anon_label += 1
2058
+ @to[l_cur] = [l]
2059
+ @block[l_cur] = true
2060
+ to_graph(stmt[i], l, ll, l_cont, l_break)
1920
2061
  l_cur = ll
1921
- g.exprs[l_cur] = []
2062
+ @exprs[l_cur] = []
1922
2063
  end
1923
2064
  }
1924
- g.to[l_cur] = [l_after].compact
2065
+ @to[l_cur] = [l_after].compact
1925
2066
  when C::If
1926
- g.exprs[l_cur] = [stmt.test]
1927
- lt = anon_label += 1
1928
- to_graph[stmt.bthen, lt, l_after, l_cont, l_break]
1929
- le = anon_label += 1
1930
- to_graph[stmt.belse, le, l_after, l_cont, l_break]
1931
- g.to[l_cur] = [lt, le]
2067
+ @exprs[l_cur] = [stmt.test]
2068
+ lt = @anon_label += 1
2069
+ to_graph(stmt.bthen, lt, l_after, l_cont, l_break)
2070
+ le = @anon_label += 1
2071
+ to_graph(stmt.belse, le, l_after, l_cont, l_break)
2072
+ @to[l_cur] = [lt, le]
1932
2073
  when C::While, C::DoWhile
1933
- la = anon_label += 1
1934
- if stmt.kind_of? C::DoWhile
2074
+ la = @anon_label += 1
2075
+ if stmt.kind_of?(C::DoWhile)
1935
2076
  lt, lb = la, l_cur
1936
2077
  else
1937
2078
  lt, lb = l_cur, la
1938
2079
  end
1939
- g.exprs[lt] = [stmt.test]
1940
- g.to[lt] = [lb, l_after]
1941
- to_graph[stmt.body, lb, lt, lt, l_after]
1942
- when C::Asm, nil; g.to[l_cur] = [l_after]
2080
+ @exprs[lt] = [stmt.test]
2081
+ @to[lt] = [lb, l_after]
2082
+ to_graph(stmt.body, lb, lt, lt, l_after)
2083
+ when C::Asm, nil; @to[l_cur] = [l_after]
1943
2084
  else puts "to_graph unhandled #{stmt.class}: #{stmt}" if $VERBOSE
1944
2085
  end
1945
- }
1946
-
1947
- g.start = anon_label
1948
- to_graph[st, g.start, nil, nil, nil]
2086
+ end
1949
2087
 
1950
2088
  # optimize graph
1951
- g.to_optim = {}
1952
- g.to.each { |k, v| g.to_optim[k] = v.uniq }
1953
- g.exprs.delete_if { |k, v| v == [] }
1954
- g.to_optim.delete_if { |k, v|
1955
- if v.length == 1 and not g.exprs[k] and v != [k]
1956
- g.to_optim.each_value { |t| if i = t.index(k) ; t[i] = v.first ; end }
1957
- true
1958
- elsif v.length == 0 and not g.exprs[k]
1959
- g.to_optim.each_value { |t| t.delete k }
1960
- true
2089
+ def optimize
2090
+ @to_optim = {}
2091
+ @to.each { |k, v| @to_optim[k] = v.uniq }
2092
+ @exprs.delete_if { |k, v| v == [] }
2093
+ @to_optim.delete_if { |k, v|
2094
+ if v.length == 1 and not @exprs[k] and v != [k]
2095
+ @to_optim.each_value { |t| if i = t.index(k) ; t[i] = v.first ; end }
2096
+ true
2097
+ elsif v.length == 0 and not @exprs[k]
2098
+ @to_optim.each_value { |t| t.delete k }
2099
+ true
2100
+ end
2101
+ }
2102
+
2103
+ @from_optim = {}
2104
+ @to_optim.each { |k, v| v.each { |t| (@from_optim[t] ||= []) << k } }
2105
+ end
2106
+
2107
+ # varname => { label => [list of indices of @exprs[label] referencing varname] }
2108
+ def exprs_var
2109
+ @exprs_var ||= init_exprs_var
2110
+ end
2111
+
2112
+ # returns the list of variable names referenced by a CExpr
2113
+ def get_expr_vars(e)
2114
+ case e
2115
+ when C::CExpression; get_expr_vars(e.lexpr) + get_expr_vars(e.rexpr)
2116
+ when ::Array; e.inject([]) { |a, ee| a.concat get_expr_vars(ee) }
2117
+ when C::Variable; [e.name]
2118
+ else; []
1961
2119
  end
1962
- }
2120
+ end
1963
2121
 
1964
- g.from_optim = {}
1965
- g.to_optim.each { |k, v| v.each { |t| (g.from_optim[t] ||= []) << k } }
2122
+ # initialize @exprs_var
2123
+ def init_exprs_var
2124
+ @exprs_var = {}
2125
+ @exprs.each_key { |label| update_exprs_var(label) }
2126
+ @exprs_var
2127
+ end
1966
2128
 
1967
- g
2129
+ # populate one label of @exprs_var
2130
+ def update_exprs_var(label)
2131
+ @exprs[label].each_with_index { |e, idx|
2132
+ get_expr_vars(e).uniq.each { |varname|
2133
+ @exprs_var[varname] ||= {}
2134
+ @exprs_var[varname][label] ||= []
2135
+ @exprs_var[varname][label] << idx
2136
+ }
2137
+ }
2138
+ end
2139
+
2140
+ # invalidates one label (eg exprs were deleted)
2141
+ # rebuilds @exprs_var if necessary
2142
+ def invalidate(label=nil)
2143
+ if @exprs_var
2144
+ if label
2145
+ @exprs_var.each { |v, h| h.delete(label) }
2146
+ update_exprs_var(label)
2147
+ else
2148
+ @exprs_var = nil
2149
+ end
2150
+ end
2151
+ end
2152
+ end
2153
+ def c_to_graph(stmt)
2154
+ CGraph.new.build(stmt)
1968
2155
  end
1969
2156
 
1970
2157
  # dataflow optimization
1971
2158
  # condenses expressions (++x; if (x) => if (++x))
1972
2159
  # remove local var assignment (x = 1; f(x); x = 2; g(x); => f(1); g(2); etc)
2160
+ # XXX omg
1973
2161
  def optimize_vars(scope)
1974
2162
  return if forbid_optimize_dataflow
1975
2163
 
@@ -1997,36 +2185,40 @@ class Decompiler
1997
2185
 
1998
2186
  # badlabels is a list of labels that may be reached without passing through the first invocation block
1999
2187
  find_next_read_rec = lambda { |label, idx, var, done, badlabels|
2000
- next if done.include? label
2188
+ next if done.include?(label)
2001
2189
  done << label if idx == 0
2190
+ list = g.exprs_var[var.name][label].to_a.find_all { |i| i >= idx }
2191
+ idx = list.shift
2002
2192
 
2003
- idx += 1 while ce = g.exprs[label].to_a[idx] and not ret = find_next_read_ce[ce, var]
2193
+ idx = list.shift while idx and not ret = find_next_read_ce[g.exprs[label][idx], var]
2004
2194
  next ret if ret
2005
2195
 
2006
2196
  to = g.to_optim[label].to_a.map { |t|
2007
- break [:split] if badlabels.include? t
2197
+ break [:split] if badlabels.include?(t)
2008
2198
  find_next_read_rec[t, 0, var, done, badlabels]
2009
2199
  }.compact
2010
2200
 
2011
2201
  tw = to - [:write]
2012
- if to.include? :split or tw.length > 1
2202
+ if to.include?(:split) or tw.length > 1
2013
2203
  :split
2014
2204
  elsif tw.length == 1
2015
2205
  tw.first
2016
- elsif to.include? :write
2206
+ elsif to.include?(:write)
2017
2207
  :write
2018
2208
  end
2019
2209
  }
2020
2210
  # return the previous subexpr reading var with no fwd path to another reading (otherwise split), see loop comment for reason
2021
2211
  find_next_read = nil
2022
2212
  find_prev_read_rec = lambda { |label, idx, var, done|
2023
- next if done.include? label
2213
+ next if done.include?(label)
2024
2214
  done << label if idx == g.exprs[label].length-1
2215
+ list = g.exprs_var[var.name][label].to_a.find_all { |i| i <= idx }
2216
+ idx = list.pop
2025
2217
 
2026
- idx -= 1 while idx >= 0 and ce = g.exprs[label].to_a[idx] and not ret = find_next_read_ce[ce, var]
2027
- if ret.kind_of? C::CExpression
2218
+ idx = list.pop while idx and not ret = find_next_read_ce[g.exprs[label][idx], var]
2219
+ if ret.kind_of?(C::CExpression)
2028
2220
  fwchk = find_next_read[label, idx+1, var]
2029
- ret = fwchk if not fwchk.kind_of? C::CExpression
2221
+ ret = fwchk if not fwchk.kind_of?(C::CExpression)
2030
2222
  end
2031
2223
  next ret if ret
2032
2224
 
@@ -2034,25 +2226,25 @@ class Decompiler
2034
2226
  find_prev_read_rec[f, g.exprs[f].to_a.length-1, var, done]
2035
2227
  }.compact
2036
2228
 
2037
- next :split if from.include? :split
2229
+ next :split if from.include?(:split)
2038
2230
  fw = from - [:write]
2039
2231
  if fw.length == 1
2040
2232
  fw.first
2041
2233
  elsif fw.length > 1
2042
2234
  :split
2043
- elsif from.include? :write
2235
+ elsif from.include?(:write)
2044
2236
  :write
2045
2237
  end
2046
2238
  }
2047
2239
 
2048
- # list of labels reachable without using a label
2240
+ # list of labels reachable without passing through label
2049
2241
  badlab = {}
2050
2242
  build_badlabel = lambda { |label|
2051
2243
  next if badlab[label]
2052
2244
  badlab[label] = []
2053
2245
  todo = [g.start]
2054
2246
  while l = todo.pop
2055
- next if l == label or badlab[label].include? l
2247
+ next if l == label or badlab[label].include?(l)
2056
2248
  badlab[label] << l
2057
2249
  todo.concat g.to_optim[l].to_a
2058
2250
  end
@@ -2086,10 +2278,10 @@ class Decompiler
2086
2278
 
2087
2279
  # TODO x = x + 1 => x += 1 => ++x here, move all other optimizations after (in optim_code)
2088
2280
  # needs also int & 0xffffffff -> int, *&var etc (decomp_type? optim_type?)
2089
- if (e.op == :'++' or e.op == :'--') and v = (e.lexpr || e.rexpr) and v.kind_of? C::Variable and
2090
- scope.symbol[v.name] and not v.type.qualifier.to_a.include? :volatile
2091
- next if !((pos = :post.to_sym) and (oe = find_next_read_bl[label, i, v]) and oe.kind_of? C::CExpression) and
2092
- !((pos = :prev.to_sym) and (oe = find_prev_read[label, i-2, v]) and oe.kind_of? C::CExpression)
2281
+ if (e.op == :'++' or e.op == :'--') and v = (e.lexpr || e.rexpr) and v.kind_of?(C::Variable) and
2282
+ scope.symbol[v.name] and not v.type.qualifier.to_a.include?(:volatile)
2283
+ next if !((pos = :post.to_sym) and (oe = find_next_read_bl[label, i, v]) and oe.kind_of?(C::CExpression)) and
2284
+ !((pos = :prev.to_sym) and (oe = find_prev_read[label, i-2, v]) and oe.kind_of?(C::CExpression))
2093
2285
  next if oe.op == :& and not oe.lexpr # no &(++eax)
2094
2286
 
2095
2287
  # merge pre/postincrement into next/prev var usage
@@ -2122,7 +2314,7 @@ class Decompiler
2122
2314
  when :'+=', :'-='
2123
2315
  # TODO i++; i += 4 => i += 5
2124
2316
  next
2125
- when *AssignOp
2317
+ when *C::CExpression::AssignOp
2126
2318
  next # ++i; i |= 4 => ignore
2127
2319
  else
2128
2320
  if pos == :post and v == oe.lexpr; oe.lexpr = C::CExpression[e.op, v]
@@ -2135,16 +2327,27 @@ class Decompiler
2135
2327
 
2136
2328
  i -= 1
2137
2329
  exprs.delete_at(i)
2330
+ g.invalidate(label)
2138
2331
  e.lexpr = e.op = e.rexpr = nil
2139
2332
 
2140
2333
 
2141
- elsif e.op == :'=' and v = e.lexpr and v.kind_of? C::Variable and scope.symbol[v.name] and
2142
- not v.type.qualifier.to_a.include? :volatile and not find_next_read_ce[e.rexpr, v]
2334
+ elsif e.op == :'=' and v = e.lexpr and v.kind_of?(C::Variable) and scope.symbol[v.name] and
2335
+ not v.type.qualifier.to_a.include?(:volatile) and not find_next_read_ce[e.rexpr, v]
2143
2336
 
2144
2337
  # reduce trivial static assignments
2145
- if (e.rexpr.kind_of? C::CExpression and iv = e.rexpr.reduce(@c_parser) and iv.kind_of? ::Integer) or
2146
- (e.rexpr.kind_of? C::CExpression and e.rexpr.op == :& and not e.rexpr.lexpr and e.rexpr.lexpr.kind_of? C::Variable) or
2147
- (e.rexpr.kind_of? C::Variable and e.rexpr.type.kind_of? C::Array)
2338
+ # b = a + 1 ; a = b => a = a + 1 ; b = a
2339
+ if ne = g.exprs[label][i] and ne.op == :'=' and ne.rexpr == e.lexpr and ne.lexpr.kind_of?(C::Variable) and find_next_read_ce[e.rexpr, ne.lexpr]
2340
+ e.lexpr, ne.lexpr, ne.rexpr = ne.lexpr, ne.rexpr, ne.lexpr
2341
+ optimize_code(e)
2342
+ i -= 1
2343
+ g.invalidate(label)
2344
+ next
2345
+ end
2346
+
2347
+ # i = 4 ; f(i) => f(4)
2348
+ if (e.rexpr.kind_of?(C::CExpression) and iv = e.rexpr.reduce(@c_parser) and iv.kind_of?(::Integer)) or
2349
+ (e.rexpr.kind_of?(C::CExpression) and e.rexpr.op == :& and not e.rexpr.lexpr and e.rexpr.lexpr.kind_of?(C::Variable)) or
2350
+ (e.rexpr.kind_of?(C::Variable) and e.rexpr.type.kind_of?(C::Array))
2148
2351
  rewritten = false
2149
2352
  readers = []
2150
2353
  discard = [e]
@@ -2174,7 +2377,7 @@ class Decompiler
2174
2377
  end
2175
2378
  end
2176
2379
 
2177
- case nr = find_next_read[label, i, v]
2380
+ case find_next_read[label, i, v]
2178
2381
  when C::CExpression
2179
2382
  # read in one place only, try to patch rexpr in there
2180
2383
  r = e.rexpr
@@ -2184,12 +2387,12 @@ class Decompiler
2184
2387
  isfunc = false
2185
2388
  depend_vars = []
2186
2389
  walk_ce(C::CExpression[r]) { |ce|
2187
- isfunc = true if ce.op == :func and (not ce.lexpr.kind_of? C::Variable or
2390
+ isfunc = true if ce.op == :func and (not ce.lexpr.kind_of?(C::Variable) or
2188
2391
  not ce.lexpr.has_attribute('pure')) # XXX is there a C attr for func depending only on staticvars+param ?
2189
- depend_vars << ce.lexpr if ce.lexpr.kind_of? C::Variable
2190
- depend_vars << ce.rexpr if ce.rexpr.kind_of? C::Variable and (ce.lexpr or ce.op != :&) # a = &v; v = 12; func(a) => func(&v)
2392
+ depend_vars << ce.lexpr if ce.lexpr.kind_of?(C::Variable)
2393
+ depend_vars << ce.rexpr if ce.rexpr.kind_of?(C::Variable) and (ce.lexpr or ce.op != :&) # a = &v; v = 12; func(a) => func(&v)
2191
2394
  depend_vars << ce if ce.lvalue?
2192
- depend_vars.concat(ce.rexpr.grep(C::Variable)) if ce.rexpr.kind_of? ::Array
2395
+ depend_vars.concat(ce.rexpr.grep(C::Variable)) if ce.rexpr.kind_of?(::Array)
2193
2396
  }
2194
2397
  depend_vars.uniq!
2195
2398
 
@@ -2210,24 +2413,24 @@ class Decompiler
2210
2413
  ce.rexpr.each { |a| cnt += 1 if a == v }
2211
2414
  cnt += 1 if ce.lexpr == v
2212
2415
  when :'='
2213
- bad = true if depend_vars.include? ce.lexpr
2416
+ bad = true if depend_vars.include?(ce.lexpr)
2214
2417
  cnt += 1 if ce.rexpr == v
2215
2418
  else
2216
- bad = true if (ce.op == :'++' or ce.op == :'--') and depend_vars.include? ce.rexpr
2217
- bad = true if AssignOp.include? ce.op and depend_vars.include? ce.lexpr
2419
+ bad = true if (ce.op == :'++' or ce.op == :'--') and depend_vars.include?(ce.rexpr)
2420
+ bad = true if C::CExpression::AssignOp.include?(ce.op) and depend_vars.include?(ce.lexpr)
2218
2421
  cnt += 1 if ce.lexpr == v
2219
2422
  cnt += 1 if ce.rexpr == v
2220
2423
  end
2221
2424
  }
2222
2425
  case cnt
2223
2426
  when 0
2224
- break if bad
2427
+ break if bad
2225
2428
  next
2226
2429
  when 1 # good
2227
2430
  break if e.complexity > 10 and ce_.complexity > 3 # try to keep the C readable
2228
2431
  # x = 1; y = x; z = x; => cannot suppress x
2229
2432
  nr = find_next_read[l_l, n_i+1, v]
2230
- break if (nr.kind_of? C::CExpression or nr == :split) and not walk_ce(ce_) { |ce| break true if ce.op == :'=' and ce.lexpr == v }
2433
+ break if (nr.kind_of?(C::CExpression) or nr == :split) and not walk_ce(ce_) { |ce| break true if ce.op == :'=' and ce.lexpr == v }
2231
2434
  else break # a = 1; b = a + a => fail
2232
2435
  end
2233
2436
 
@@ -2247,12 +2450,12 @@ class Decompiler
2247
2450
  elsif isfunc
2248
2451
  break :fail
2249
2452
  end
2250
- when *AssignOp
2251
- break :fail if not ce.lexpr and depend_vars.include? ce.rexpr # ++depend
2453
+ when *C::CExpression::AssignOp
2454
+ break :fail if not ce.lexpr and depend_vars.include?(ce.rexpr) # ++depend
2252
2455
  if ce.rexpr == v
2253
2456
  ce.rexpr = r
2254
2457
  break :done
2255
- elsif ce.lexpr == v or depend_vars.include? ce.lexpr
2458
+ elsif ce.lexpr == v or depend_vars.include?(ce.lexpr)
2256
2459
  break :fail
2257
2460
  end
2258
2461
  else
@@ -2271,6 +2474,8 @@ class Decompiler
2271
2474
  when :done
2272
2475
  i -= 1
2273
2476
  exprs.delete_at(i)
2477
+ g.invalidate(label)
2478
+ g.invalidate(l_l) if l_l != label
2274
2479
  e.lexpr = e.op = e.rexpr = nil
2275
2480
  break
2276
2481
  when :fail
@@ -2278,8 +2483,9 @@ class Decompiler
2278
2483
  end
2279
2484
  }
2280
2485
  # ignore branches that will never reuse v
2281
- may_to = g.to_optim[l_l].find_all { |to| find_next_read[to, 0, v].kind_of? C::CExpression }
2282
- if may_to.length == 1 and to = may_to.first and to != l_l and g.from_optim[to] == [l_l]
2486
+ may_to = g.to_optim[l_l].find_all { |to| find_next_read[to, 0, v].kind_of?(C::CExpression) }
2487
+ if may_to.length == 1 and to = may_to.first and to != l_l and g.from_optim[to] == [l_l] and
2488
+ not sideeffect(e.rexpr) # dont do cross-block var optimization, eg 'a = f() ; if() return a' =!> 'if () return f()'
2283
2489
  l_i = 0
2284
2490
  l_l = to
2285
2491
  else break
@@ -2293,10 +2499,10 @@ class Decompiler
2293
2499
  # remove sideeffectless subexprs
2294
2500
  loop do
2295
2501
  case e.op
2296
- when :funcall, *AssignOp
2502
+ when :funcall, *C::CExpression::AssignOp
2297
2503
  else
2298
- l = (e.lexpr.kind_of? C::CExpression and sideeffect(e.lexpr))
2299
- r = (e.rexpr.kind_of? C::CExpression and sideeffect(e.rexpr))
2504
+ l = (e.lexpr.kind_of?(C::CExpression) and sideeffect(e.lexpr))
2505
+ r = (e.rexpr.kind_of?(C::CExpression) and sideeffect(e.rexpr))
2300
2506
  if l and r # could split...
2301
2507
  elsif l
2302
2508
  e.replace(e.lexpr)
@@ -2312,87 +2518,183 @@ class Decompiler
2312
2518
  end
2313
2519
  break
2314
2520
  end
2521
+ g.invalidate(label)
2315
2522
  end
2316
2523
  end
2317
2524
  end
2318
2525
  }
2319
2526
 
2527
+
2528
+ # var propagation
2529
+ # find vars who are written only once, and replace all their use by their assignment value
2530
+ # XXX this may supercede some of the ugly stuff just before
2531
+ loop do
2532
+ g.invalidate
2533
+ writtenonce = {} # var => [label, offset] of assignment
2534
+ neverwritten = {} # var => true (eg args)
2535
+ g.exprs_var.each { |varname, h1|
2536
+ next if not var = scope.symbol[varname]
2537
+ neverwritten[varname] = true
2538
+ h1.each { |label, idx_list|
2539
+ idx_list.each { |expr_idx|
2540
+ e = g.exprs[label][expr_idx]
2541
+ if ce_write(e, var)
2542
+ neverwritten.delete varname
2543
+ if writtenonce[varname]
2544
+ # written twice, abort
2545
+ writtenonce.delete varname
2546
+ break
2547
+ elsif e.op == :'=' and e.lexpr == var and not ce_write(e.rexpr, var) and not ce_read(e.rexpr, var)
2548
+ # good !
2549
+ writtenonce[varname] = [label, expr_idx]
2550
+ else
2551
+ # unhandled write, abort
2552
+ break
2553
+ end
2554
+ end
2555
+ }
2556
+ }
2557
+ }
2558
+ # XXX check cycles ?
2559
+
2560
+ is_trivial_assign = lambda { |e, rec_max|
2561
+ case e
2562
+ when C::Variable; writtenonce[e.name] or neverwritten[e.name]
2563
+ when ::Integer, nil; true
2564
+ when C::CExpression
2565
+ rec_max > 0 and
2566
+ not sideeffect(e) and
2567
+ (e.op == :+ or e.op == :- or e.op == nil) and
2568
+ is_trivial_assign[e.lexpr, rec_max-1] and
2569
+ is_trivial_assign[e.rexpr, rec_max-1]
2570
+ end
2571
+ }
2572
+ break if not trivial_var = writtenonce.keys.find { |var|
2573
+ l, i = writtenonce[var]
2574
+ e = g.exprs[l][i].rexpr
2575
+ is_trivial_assign[e, 3]
2576
+ }
2577
+ label, idx = writtenonce[trivial_var]
2578
+ assign_expr = g.exprs[label][idx]
2579
+ var = assign_expr.lexpr
2580
+ value = assign_expr.rexpr
2581
+ g.exprs_var[trivial_var].each { |l, list|
2582
+ list.each { |i|
2583
+ e = g.exprs[l][i]
2584
+ if l == label and i == idx
2585
+ e.lexpr = e.op = e.rexpr = nil
2586
+ else
2587
+ ce_patch(e, var, value)
2588
+ optimize_code(e)
2589
+ end
2590
+ }
2591
+ }
2592
+ end
2593
+
2594
+
2320
2595
  # wipe cexprs marked in the previous step
2321
2596
  walk(scope) { |st|
2322
- next if not st.kind_of? C::Block
2323
- st.statements.delete_if { |e| e.kind_of? C::CExpression and not e.lexpr and not e.op and not e.rexpr }
2597
+ next if not st.kind_of?(C::Block)
2598
+ st.statements.delete_if { |e| e.kind_of?(C::CExpression) and not e.lexpr and not e.op and not e.rexpr }
2324
2599
  }
2600
+ g.invalidate
2325
2601
 
2326
2602
  # reoptimize cexprs
2327
2603
  walk_ce(scope, true) { |ce|
2328
2604
  # redo some simplification that may become available after variable propagation
2329
2605
  # int8 & 255 => int8
2330
- if ce.op == :& and ce.lexpr and ce.lexpr.type.integral? and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == (1 << (8*sizeof(ce.lexpr))) - 1
2606
+ if ce.op == :& and ce.lexpr and ce.lexpr.type.integral? and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == (1 << (8*sizeof(ce.lexpr))) - 1
2331
2607
  ce.replace C::CExpression[ce.lexpr]
2332
2608
  end
2333
2609
 
2334
2610
  # int *ptr; *(ptr + 4) => ptr[4]
2335
- if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :+ and var = ce.rexpr.lexpr and var.kind_of? C::Variable and var.type.pointer?
2611
+ if ce.op == :* and not ce.lexpr and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :+ and var = ce.rexpr.lexpr and var.kind_of?(C::Variable) and var.type.pointer?
2336
2612
  ce.lexpr, ce.op, ce.rexpr = ce.rexpr.lexpr, :'[]', ce.rexpr.rexpr
2337
2613
  end
2338
2614
 
2339
2615
  # useless casts
2340
- if not ce.op and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and (ce.rexpr.rexpr.kind_of? C::CExpression or
2341
- (ce.type.pointer? and ce.rexpr.rexpr == 0 and not ce.type.pointed.untypedef.kind_of? C::Union)) # keep ((struct*)0)->memb
2616
+ if not ce.op and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and (ce.rexpr.rexpr.kind_of?(C::CExpression) or
2617
+ (ce.type.pointer? and ce.rexpr.rexpr == 0 and not ce.type.pointed.untypedef.kind_of?(C::Union))) # keep ((struct*)0)->memb
2342
2618
  ce.rexpr = ce.rexpr.rexpr
2343
2619
  end
2344
- if not ce.op and ce.rexpr.kind_of? C::CExpression and (ce.type == ce.rexpr.type or (ce.type.integral? and ce.rexpr.type.integral?))
2620
+ if not ce.op and ce.rexpr.kind_of?(C::CExpression) and (ce.type == ce.rexpr.type or (ce.type.integral? and ce.rexpr.type.integral?))
2345
2621
  ce.replace ce.rexpr
2346
2622
  end
2347
2623
  # useless casts (type)*((oeua)Ptype)
2348
- if not ce.op and ce.rexpr.kind_of? C::CExpression and ce.rexpr.op == :* and not ce.rexpr.lexpr and ce.rexpr.rexpr.kind_of? C::CExpression and not ce.rexpr.rexpr.op and
2349
- p = ce.rexpr.rexpr.rexpr and p.kind_of? C::Typed and p.type.pointer? and ce.type == p.type.pointed
2624
+ if not ce.op and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.op == :* and not ce.rexpr.lexpr and ce.rexpr.rexpr.kind_of?(C::CExpression) and not ce.rexpr.rexpr.op and
2625
+ p = ce.rexpr.rexpr.rexpr and p.kind_of?(C::Typed) and p.type.pointer? and ce.type == p.type.pointed
2350
2626
  ce.op = ce.rexpr.op
2351
2627
  ce.rexpr = ce.rexpr.rexpr.rexpr
2352
2628
  end
2629
+
2630
+ # (char *)42 => new global var
2631
+ if not ce.op and ce.type.pointer? and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer)
2632
+ ce.rexpr = new_global_var(ce.rexpr.rexpr, ce.type, scope) || ce.rexpr
2633
+ end
2634
+
2353
2635
  # (a > 0) != 0
2354
- if ce.op == :'!=' and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 0 and ce.lexpr.kind_of? C::CExpression and
2355
- [:<, :<=, :>, :>=, :'==', :'!=', :'!'].include? ce.lexpr.op
2636
+ if ce.op == :'!=' and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 0 and ce.lexpr.kind_of?(C::CExpression) and
2637
+ [:<, :<=, :>, :>=, :'==', :'!=', :'!'].include?(ce.lexpr.op)
2356
2638
  ce.replace ce.lexpr
2357
2639
  end
2358
2640
  # a == 0 => !a
2359
- if ce.op == :== and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 0
2641
+ if ce.op == :== and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 0
2360
2642
  ce.replace C::CExpression[:'!', ce.lexpr]
2361
2643
  end
2362
2644
  # !(int)a => !a
2363
- if ce.op == :'!' and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? C::CExpression
2645
+ if ce.op == :'!' and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(C::CExpression)
2364
2646
  ce.rexpr = ce.rexpr.rexpr
2365
2647
  end
2366
2648
  # (int)a < (int)b => a < b TODO uint <-> int
2367
- if [:<, :<=, :>, :>=].include? ce.op and ce.rexpr.kind_of? C::CExpression and ce.lexpr.kind_of? C::CExpression and not ce.rexpr.op and not ce.lexpr.op and
2368
- ce.rexpr.rexpr.kind_of? C::CExpression and ce.rexpr.rexpr.type.pointer? and ce.lexpr.rexpr.kind_of? C::CExpression and ce.lexpr.rexpr.type.pointer?
2649
+ if [:<, :<=, :>, :>=].include?(ce.op) and ce.rexpr.kind_of?(C::CExpression) and ce.lexpr.kind_of?(C::CExpression) and not ce.rexpr.op and not ce.lexpr.op and
2650
+ ce.rexpr.rexpr.kind_of?(C::CExpression) and ce.rexpr.rexpr.type.pointer? and ce.lexpr.rexpr.kind_of?(C::CExpression) and ce.lexpr.rexpr.type.pointer?
2369
2651
  ce.rexpr = ce.rexpr.rexpr
2370
2652
  ce.lexpr = ce.lexpr.rexpr
2371
2653
  end
2372
2654
 
2373
2655
  # a & 3 & 1
2374
- while (ce.op == :& or ce.op == :|) and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr.kind_of? ::Integer and
2375
- ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == ce.op and ce.lexpr.lexpr and
2376
- ce.lexpr.rexpr.kind_of? C::CExpression and ce.lexpr.rexpr.rexpr.kind_of? ::Integer
2656
+ while (ce.op == :& or ce.op == :|) and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer) and
2657
+ ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == ce.op and ce.lexpr.lexpr and
2658
+ ce.lexpr.rexpr.kind_of?(C::CExpression) and ce.lexpr.rexpr.rexpr.kind_of?(::Integer)
2377
2659
  ce.lexpr, ce.rexpr.rexpr = ce.lexpr.lexpr, ce.lexpr.rexpr.rexpr.send(ce.op, ce.rexpr.rexpr)
2378
2660
  end
2379
2661
 
2380
2662
  # x = x | 4 => x |= 4
2381
- if ce.op == :'=' and ce.rexpr.kind_of? C::CExpression and [:+, :-, :*, :/, :|, :&, :^, :>>, :<<].include? ce.rexpr.op and ce.rexpr.lexpr == ce.lexpr
2663
+ if ce.op == :'=' and ce.rexpr.kind_of?(C::CExpression) and [:+, :-, :*, :/, :|, :&, :^, :>>, :<<].include?(ce.rexpr.op) and ce.rexpr.lexpr == ce.lexpr
2382
2664
  ce.op = (ce.rexpr.op.to_s + '=').to_sym
2383
2665
  ce.rexpr = ce.rexpr.rexpr
2384
2666
  end
2385
2667
 
2668
+ # x = 4 | x => x |= 4
2669
+ if ce.op == :'=' and ce.rexpr.kind_of?(C::CExpression) and [:+, :*, :|, :&, :^].include?(ce.rexpr.op) and ce.rexpr.rexpr == ce.lexpr
2670
+ ce.op = (ce.rexpr.op.to_s + '=').to_sym
2671
+ ce.rexpr = ce.rexpr.lexpr
2672
+ end
2673
+
2386
2674
  # x += 1 => ++x
2387
- if (ce.op == :'+=' or ce.op == :'-=') and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 1
2388
- ce.lexpr, ce.op, ce.rexpr = nil, {:'+=' => :'++', :'-=' => :'--'}[ce.op], ce.lexpr
2675
+ if (ce.op == :'+=' or ce.op == :'-=') and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and (ce.rexpr.rexpr == 1 or ce.rexpr.rexpr == -1)
2676
+ if ce.rexpr.rexpr == 1
2677
+ ce.op = {:'+=' => :'++', :'-=' => :'--'}[ce.op]
2678
+ else
2679
+ ce.op = {:'+=' => :'--', :'-=' => :'++'}[ce.op]
2680
+ end
2681
+ ce.rexpr = ce.lexpr
2682
+ ce.lexpr = nil
2389
2683
  end
2390
2684
 
2391
2685
  # --x+1 => x--
2392
- if (ce.op == :+ or ce.op == :-) and ce.lexpr.kind_of? C::CExpression and ce.lexpr.op == {:+ => :'--', :- => :'++'}[ce.op] and
2393
- ce.lexpr.rexpr and ce.rexpr.kind_of? C::CExpression and not ce.rexpr.op and ce.rexpr.rexpr == 1
2686
+ if (ce.op == :+ or ce.op == :-) and ce.lexpr.kind_of?(C::CExpression) and ce.lexpr.op == {:+ => :'--', :- => :'++'}[ce.op] and
2687
+ ce.lexpr.rexpr and ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr == 1
2394
2688
  ce.lexpr, ce.op, ce.rexpr = ce.lexpr.rexpr, ce.lexpr.op, nil
2395
2689
  end
2690
+
2691
+ # 1+2 => 3
2692
+ if ce.lexpr.kind_of?(C::CExpression) and not ce.lexpr.op and ce.lexpr.rexpr.kind_of?(::Integer) and
2693
+ ce.rexpr.kind_of?(C::CExpression) and not ce.rexpr.op and ce.rexpr.rexpr.kind_of?(::Integer) and
2694
+ [:+, :-, :*, :/, :|, :&, :^, :>, :'==', :'!=', :<, :>=, :<=].include?(ce.op)
2695
+ ce.rexpr = ce.reduce(@c_parser)
2696
+ ce.lexpr = ce.op = nil
2697
+ end
2396
2698
  }
2397
2699
  end
2398
2700
 
@@ -2400,14 +2702,14 @@ class Decompiler
2400
2702
  used = {}
2401
2703
  walk_ce(scope) { |ce|
2402
2704
  # remove unreferenced local vars
2403
- used[ce.rexpr.name] = true if ce.rexpr.kind_of? C::Variable
2404
- used[ce.lexpr.name] = true if ce.lexpr.kind_of? C::Variable
2405
- ce.rexpr.each { |v| used[v.name] = true if v.kind_of? C::Variable } if ce.rexpr.kind_of?(::Array)
2705
+ used[ce.rexpr.name] = true if ce.rexpr.kind_of?(C::Variable)
2706
+ used[ce.lexpr.name] = true if ce.lexpr.kind_of?(C::Variable)
2707
+ ce.rexpr.each { |v| used[v.name] = true if v.kind_of?(C::Variable) } if ce.rexpr.kind_of?(::Array)
2406
2708
  }
2407
2709
  unused = scope.symbol.keys.find_all { |n| not used[n] }
2408
2710
  unused.each { |v| scope.symbol[v].add_attribute 'unused' } # fastcall args need it
2409
- scope.statements.delete_if { |sm| sm.kind_of? C::Declaration and unused.include? sm.var.name }
2410
- scope.symbol.delete_if { |n, v| unused.include? n }
2711
+ scope.statements.delete_if { |sm| sm.kind_of?(C::Declaration) and unused.include?(sm.var.name) }
2712
+ scope.symbol.delete_if { |n, v| unused.include?(n) }
2411
2713
  end
2412
2714
 
2413
2715
  def finalize
@@ -2418,17 +2720,17 @@ class Decompiler
2418
2720
  def optimize_global
2419
2721
  # check all global vars (pointers to global data)
2420
2722
  tl = @c_parser.toplevel
2421
- vars = tl.symbol.keys.find_all { |k| tl.symbol[k].kind_of? C::Variable and not tl.symbol[k].type.kind_of? C::Function }
2723
+ vars = tl.symbol.keys.find_all { |k| tl.symbol[k].kind_of?(C::Variable) and not tl.symbol[k].type.kind_of?(C::Function) and not tl.symbol[k].storage == :extern and not tl.symbol[k].storage == :static }
2422
2724
  countref = Hash.new(0)
2423
2725
 
2424
2726
  walk_ce(tl) { |ce|
2425
2727
  # XXX int foo; void bar() { int foo; } => false negative
2426
- countref[ce.rexpr.name] += 1 if ce.rexpr.kind_of? C::Variable
2427
- countref[ce.lexpr.name] += 1 if ce.lexpr.kind_of? C::Variable
2728
+ countref[ce.rexpr.name] += 1 if ce.rexpr.kind_of?(C::Variable)
2729
+ countref[ce.lexpr.name] += 1 if ce.lexpr.kind_of?(C::Variable)
2428
2730
  }
2429
2731
 
2430
2732
  vars.delete_if { |v| countref[v] == 0 }
2431
- countref.delete_if { |k, v| not vars.include? k }
2733
+ countref.delete_if { |k, v| not vars.include?(k) }
2432
2734
 
2433
2735
  # by default globals are C::Arrays
2434
2736
  # if all references are *foo, dereference the var type
@@ -2442,18 +2744,18 @@ class Decompiler
2442
2744
  else next
2443
2745
  end
2444
2746
  # compare type.type cause var is an Array and the cast is a Pointer
2445
- countderef[r.rexpr.name] += 1 if r.kind_of? C::CExpression and not r.op and r.rexpr.kind_of? C::Variable and
2446
- sizeof(nil, r.type.type) == sizeof(nil, r.rexpr.type.type) rescue nil
2747
+ countderef[r.rexpr.name] += 1 if r.kind_of?(C::CExpression) and not r.op and r.rexpr.kind_of?(C::Variable) and
2748
+ sizeof(nil, r.type.type) == sizeof(nil, r.rexpr.type.type) rescue nil
2447
2749
  }
2448
2750
  vars.each { |n|
2449
2751
  if countref[n] == countderef[n]
2450
2752
  v = tl.symbol[n]
2451
2753
  target = C::CExpression[:*, [v]]
2452
2754
  v.type = v.type.type
2453
- v.initializer = v.initializer.first if v.initializer.kind_of? ::Array
2755
+ v.initializer = v.initializer.first if v.initializer.kind_of?(::Array)
2454
2756
  walk_ce(tl) { |ce|
2455
2757
  if ce.op == :'->' and C::CExpression[ce.lexpr] == C::CExpression[v]
2456
- ce.op = :'.'
2758
+ ce.op = :'.'
2457
2759
  elsif ce.lexpr == target
2458
2760
  ce.lexpr = v
2459
2761
  end
@@ -2465,28 +2767,28 @@ class Decompiler
2465
2767
 
2466
2768
  # if a global var appears only in one function, make it a static variable
2467
2769
  tl.statements.each { |st|
2468
- next if not st.kind_of? C::Declaration or not st.var.type.kind_of? C::Function or not scope = st.var.initializer
2770
+ next if not st.kind_of?(C::Declaration) or not st.var.type.kind_of?(C::Function) or not scope = st.var.initializer
2469
2771
  localcountref = Hash.new(0)
2470
2772
  walk_ce(scope) { |ce|
2471
- localcountref[ce.rexpr.name] += 1 if ce.rexpr.kind_of? C::Variable
2472
- localcountref[ce.lexpr.name] += 1 if ce.lexpr.kind_of? C::Variable
2773
+ localcountref[ce.rexpr.name] += 1 if ce.rexpr.kind_of?(C::Variable)
2774
+ localcountref[ce.lexpr.name] += 1 if ce.lexpr.kind_of?(C::Variable)
2473
2775
  }
2474
2776
 
2475
2777
  vars.delete_if { |n|
2476
2778
  next if scope.symbol[n]
2477
2779
  next if localcountref[n] != countref[n]
2478
2780
  v = tl.symbol.delete(n)
2479
- tl.statements.delete_if { |d| d.kind_of? C::Declaration and d.var.name == n }
2781
+ tl.statements.delete_if { |d| d.kind_of?(C::Declaration) and d.var.name == n }
2480
2782
 
2481
- if countref[n] == 1 and v.initializer.kind_of? C::CExpression and v.initializer.rexpr.kind_of? String
2783
+ if countref[n] == 1 and v.initializer.kind_of?(C::CExpression) and v.initializer.rexpr.kind_of?(String)
2482
2784
  walk_ce(scope) { |ce|
2483
- if ce.rexpr.kind_of? C::Variable and ce.rexpr.name == n
2785
+ if ce.rexpr.kind_of?(C::Variable) and ce.rexpr.name == n
2484
2786
  if not ce.op
2485
2787
  ce.replace v.initializer
2486
2788
  else
2487
2789
  ce.rexpr = v.initializer
2488
2790
  end
2489
- elsif ce.lexpr.kind_of? C::Variable and ce.lexpr.name == n
2791
+ elsif ce.lexpr.kind_of?(C::Variable) and ce.lexpr.name == n
2490
2792
  ce.lexpr = v.initializer
2491
2793
  end
2492
2794
  }
@@ -2508,7 +2810,7 @@ class Decompiler
2508
2810
  args = func.type.args
2509
2811
  decl = []
2510
2812
  scope.statements.delete_if { |sm|
2511
- next if not sm.kind_of? C::Declaration
2813
+ next if not sm.kind_of?(C::Declaration)
2512
2814
  if sm.var.stackoff.to_i > 0 and sm.var.name !~ /_a(\d+)$/ # aliased vars: use 1st domain only
2513
2815
  args << sm.var
2514
2816
  else
@@ -2521,8 +2823,8 @@ class Decompiler
2521
2823
  # XXX a = 1 ; b = a ; a = 2
2522
2824
  go = true # break from delete_if does not delete..
2523
2825
  scope.statements.delete_if { |st|
2524
- if go and st.kind_of? C::CExpression and st.op == :'=' and st.rexpr.kind_of? C::CExpression and not st.rexpr.op and
2525
- st.rexpr.rexpr.kind_of? ::Integer and st.lexpr.kind_of? C::Variable and scope.symbol[st.lexpr.name]
2826
+ if go and st.kind_of?(C::CExpression) and st.op == :'=' and st.rexpr.kind_of?(C::CExpression) and not st.rexpr.op and
2827
+ st.rexpr.rexpr.kind_of?(::Integer) and st.lexpr.kind_of?(C::Variable) and scope.symbol[st.lexpr.name]
2526
2828
  st.lexpr.initializer = st.rexpr
2527
2829
  else
2528
2830
  go = false
@@ -2543,7 +2845,7 @@ class Decompiler
2543
2845
  end
2544
2846
  while curoff > argoff
2545
2847
  wantarg = C::Variable.new
2546
- wantarg.name = scope.decompdata[:stackoff_name][argoff] || stackoff_to_varname(argoff)
2848
+ wantarg.name = stackoff_to_varname(argoff)
2547
2849
  wantarg.type = C::BaseType.new(:int)
2548
2850
  wantarg.attributes = ['unused']
2549
2851
  func.type.args << wantarg
@@ -2553,6 +2855,18 @@ class Decompiler
2553
2855
  func.type.args << a
2554
2856
  argoff += @c_parser.typesize[:ptr]
2555
2857
  }
2858
+
2859
+ # use user-supplied names
2860
+ scope.symbol.keys.each { |s|
2861
+ v = scope.symbol[s]
2862
+ next if not v.kind_of?(C::Variable)
2863
+ v.misc ||= {}
2864
+ uan = v.misc[:unalias_name] ||= s
2865
+ if newname = scope.decompdata[:unalias_name][uan] and newname != s
2866
+ v.name = newname
2867
+ scope.symbol[newname] = scope.symbol.delete(s)
2868
+ end
2869
+ }
2556
2870
  end
2557
2871
 
2558
2872
  # rename local variables from subfunc arg names
@@ -2564,12 +2878,12 @@ class Decompiler
2564
2878
  walk_ce(scope) { |ce|
2565
2879
  funcs << ce if ce.op == :funcall
2566
2880
  cntrs << (ce.lexpr || ce.rexpr) if ce.op == :'++'
2567
- cmpi << ce.lexpr if [:<, :>, :<=, :>=, :==, :'!='].include? ce.op and ce.rexpr.kind_of? C::CExpression and ce.rexpr.rexpr.kind_of? ::Integer
2881
+ cmpi << ce.lexpr if [:<, :>, :<=, :>=, :==, :'!='].include?(ce.op) and ce.rexpr.kind_of?(C::CExpression) and ce.rexpr.rexpr.kind_of?(::Integer)
2568
2882
  }
2569
2883
 
2570
2884
  rename = lambda { |var, name|
2571
- var = var.rexpr if var.kind_of? C::CExpression and not var.op
2572
- next if not var.kind_of? C::Variable or not scope.symbol[var.name] or not name
2885
+ var = var.rexpr if var.kind_of?(C::CExpression) and not var.op
2886
+ next if not var.kind_of?(C::Variable) or not scope.symbol[var.name] or not name
2573
2887
  next if (var.name !~ /^(var|arg)_/ and not var.storage == :register) or not scope.symbol[var.name] or name =~ /^(var|arg)_/
2574
2888
  s = scope.symbol_ancestors
2575
2889
  n = name
@@ -2580,13 +2894,13 @@ class Decompiler
2580
2894
  }
2581
2895
 
2582
2896
  funcs.each { |ce|
2583
- next if not ce.lexpr.kind_of? C::Variable or not ce.lexpr.type.kind_of? C::Function
2897
+ next if not ce.lexpr.kind_of?(C::Variable) or not ce.lexpr.type.kind_of?(C::Function)
2584
2898
  ce.rexpr.to_a.zip(ce.lexpr.type.args.to_a).each { |a, fa| rename[a, fa.name] if fa }
2585
2899
  }
2586
2900
  funcs.each { |ce|
2587
- next if not ce.lexpr.kind_of? C::Variable or not ce.lexpr.type.kind_of? C::Function
2901
+ next if not ce.lexpr.kind_of?(C::Variable) or not ce.lexpr.type.kind_of?(C::Function)
2588
2902
  ce.rexpr.to_a.zip(ce.lexpr.type.args.to_a).each { |a, fa|
2589
- next if not a.kind_of? C::CExpression or a.op != :& or a.lexpr
2903
+ next if not a.kind_of?(C::CExpression) or a.op != :& or a.lexpr
2590
2904
  next if not fa or not fa.name
2591
2905
  rename[a.rexpr, fa.name.sub(/^l?p/, '')]
2592
2906
  }
@@ -2625,34 +2939,46 @@ class Decompiler
2625
2939
  end
2626
2940
 
2627
2941
  # yields each statement (recursive)
2628
- def walk(scope, post=false, &b)
2942
+ # replace the element by the block return value if patch is true
2943
+ def walk(scope, post=false, patch=false, &b)
2629
2944
  case scope
2630
- when ::Array; scope.each { |s| walk(s, post, &b) }
2945
+ when ::Array
2946
+ scope.each_with_index { |s, i|
2947
+ v = walk(s, post, patch, &b)
2948
+ scope[i] = v if patch and v
2949
+ }
2950
+ nil
2631
2951
  when C::Statement
2632
- yield scope if not post
2952
+ v = yield scope if not post
2633
2953
  case scope
2634
- when C::Block; walk(scope.statements, post, &b)
2954
+ when C::Block
2955
+ walk(scope.statements, post, patch, &b)
2635
2956
  when C::If
2636
- yield scope.test
2637
- walk(scope.bthen, post, &b)
2638
- walk(scope.belse, post, &b) if scope.belse
2957
+ vv = yield scope.test
2958
+ scope.test = vv if patch and vv
2959
+ walk(scope.bthen, post, patch, &b)
2960
+ walk(scope.belse, post, patch, &b) if scope.belse
2639
2961
  when C::While, C::DoWhile
2640
- yield scope.test
2641
- walk(scope.body, post, &b)
2962
+ vv = yield scope.test
2963
+ scope.test = vv if patch and vv
2964
+ walk(scope.body, post, patch, &b)
2642
2965
  when C::Return
2643
- yield scope.value
2966
+ vv = yield scope.value
2967
+ scope.value = vv if patch and vv
2644
2968
  end
2645
- yield scope if post
2969
+ v = yield scope if post
2970
+ v
2646
2971
  when C::Declaration
2647
- walk(scope.var.initializer, post, &b) if scope.var.initializer
2972
+ walk(scope.var.initializer, post, patch, &b) if scope.var.initializer
2973
+ nil
2648
2974
  end
2649
2975
  end
2650
2976
 
2651
2977
  # forwards to @c_parser, handles cast to Array (these should not happen btw...)
2652
2978
  def sizeof(var, type=nil)
2653
- var, type = nil, var if var.kind_of? C::Type and not type
2979
+ var, type = nil, var if var.kind_of?(C::Type) and not type
2654
2980
  type ||= var.type
2655
- return @c_parser.typesize[:ptr] if type.kind_of? C::Array and not var.kind_of? C::Variable
2981
+ return @c_parser.typesize[:ptr] if type.kind_of?(C::Array) and not var.kind_of?(C::Variable)
2656
2982
  @c_parser.sizeof(var, type) rescue -1
2657
2983
  end
2658
2984
  end