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
@@ -69,11 +69,11 @@ class Shellcode < ExeFormat
69
69
  parse(*a) if not a.empty?
70
70
  @encoded << assemble_sequence(@source, @cpu)
71
71
  @source.clear
72
- encode
72
+ self
73
73
  end
74
74
 
75
75
  def encode(binding={})
76
- @encoded.fixup! binding
76
+ @encoded.fixup! binding if binding.kind_of? Hash
77
77
  @encoded.fixup @encoded.binding(@base_addr)
78
78
  @encoded.fill @encoded.rawsize
79
79
  self
@@ -107,7 +107,11 @@ class Shellcode < ExeFormat
107
107
  # returns a virtual subclass of Shellcode whose cpu_from_headers will return cpu
108
108
  def self.withcpu(cpu)
109
109
  c = Class.new(self)
110
- c.send(:define_method, :cpu_from_headers) { cpu }
110
+ c.send(:define_method, :cpu_from_headers) {
111
+ cpu = Metasm.const_get(cpu) if cpu.kind_of?(::String)
112
+ cpu = cpu.new if cpu.kind_of?(::Class) and cpu.ancestors.include?(CPU)
113
+ cpu
114
+ }
111
115
  c
112
116
  end
113
117
  end
@@ -0,0 +1,114 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/exe_format/main'
8
+
9
+ module Metasm
10
+ # Similar to Shellcode, with distinct sections per memory permission (R / RW / RX)
11
+ # encoding-side only
12
+ class Shellcode_RWX < ExeFormat
13
+ # the array of source elements (Instr/Data etc)
14
+ attr_accessor :source_r, :source_w, :source_x
15
+ # base address per section
16
+ attr_accessor :base_r, :base_w, :base_x
17
+ # encodeddata
18
+ attr_accessor :encoded_r, :encoded_w, :encoded_x
19
+
20
+ def initialize(cpu=nil)
21
+ @base_r = @base_w = @base_x = nil
22
+ @encoded_r = EncodedData.new
23
+ @encoded_w = EncodedData.new
24
+ @encoded_x = EncodedData.new
25
+
26
+ super(cpu)
27
+ end
28
+
29
+ def parse_init
30
+ @source_r = []
31
+ @source_w = []
32
+ @source_x = []
33
+ @cursource = @source_x
34
+ super()
35
+ end
36
+
37
+ # allows definition of the base address
38
+ def parse_parser_instruction(instr)
39
+ case instr.raw.downcase
40
+ when '.base', '.baseaddr', '.base_addr'
41
+ # ".base_addr <expression>"
42
+ # expression should #reduce to integer
43
+ @lexer.skip_space
44
+ raise instr, 'syntax error' if not base = Expression.parse(@lexer).reduce
45
+ raise instr, 'syntax error' if tok = @lexer.nexttok and tok.type != :eol
46
+ if @cursource.equal?(@source_r)
47
+ @base_r = base
48
+ elsif @cursource.equal?(@source_w)
49
+ @base_w = base
50
+ elsif @cursource.equal?(@source_x)
51
+ @base_x = base
52
+ else raise instr, "Where am I ?"
53
+ end
54
+ when '.rdata', '.rodata'
55
+ @cursource = @source_r
56
+ when '.data', '.bss'
57
+ @cursource = @source_w
58
+ when '.text'
59
+ @cursource = @source_x
60
+ else super(instr)
61
+ end
62
+ end
63
+
64
+ # encodes the source found in self.source
65
+ # appends it to self.encoded
66
+ # clears self.source
67
+ # the optional parameter may contain a binding used to fixup! self.encoded
68
+ # uses self.base_addr if it exists
69
+ def assemble(*a)
70
+ parse(*a) if not a.empty?
71
+ @encoded_r << assemble_sequence(@source_r, @cpu); @source_r.clear
72
+ @encoded_w << assemble_sequence(@source_w, @cpu); @source_w.clear
73
+ @encoded_x << assemble_sequence(@source_x, @cpu); @source_x.clear
74
+ self
75
+ end
76
+
77
+ def encode(binding={})
78
+ bd = {}
79
+ bd.update @encoded_r.binding(@base_r)
80
+ bd.update @encoded_w.binding(@base_w)
81
+ bd.update @encoded_x.binding(@base_x)
82
+ bd.update binding if binding.kind_of?(Hash)
83
+ @encoded_r.fixup bd
84
+ @encoded_w.fixup bd
85
+ @encoded_x.fixup bd
86
+ self
87
+ end
88
+ alias fixup encode
89
+
90
+ # resolve inter-section xrefs, raise if unresolved relocations remain
91
+ # call this when you have assembled+allocated memory for every section
92
+ def fixup_check(base_r=nil, base_w=nil, base_x=nil, bd={})
93
+ if base_r.kind_of?(Hash)
94
+ bd = base_r
95
+ base_r = nil
96
+ end
97
+ @base_r = base_r if base_r
98
+ @base_w = base_w if base_w
99
+ @base_x = base_x if base_x
100
+ fixup bd
101
+ ed = EncodedData.new << @encoded_r << @encoded_w << @encoded_x
102
+ raise ["Unresolved relocations:", ed.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not ed.reloc.empty?
103
+ self
104
+ end
105
+
106
+ def encode_string(*a)
107
+ encode(*a)
108
+ ed = EncodedData.new << @encoded_r << @encoded_w << @encoded_x
109
+ ed.fixup(ed.binding)
110
+ raise ["Unresolved relocations:", ed.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not ed.reloc.empty?
111
+ ed.data
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,205 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ require 'metasm/exe_format/main'
7
+ require 'metasm/encode'
8
+ require 'metasm/decode'
9
+ begin
10
+ require 'zlib'
11
+ rescue LoadError
12
+ end
13
+
14
+ module Metasm
15
+ class SWF < ExeFormat
16
+ attr_accessor :signature, :version, :header, :chunks
17
+
18
+ CHUNK_TYPE = {
19
+ 0 => 'End', 1 => 'ShowFrame', 2 => 'DefineShape', 3 => 'FreeCharacter',
20
+ 4 => 'PlaceObject', 5 => 'RemoveObject', 6 => 'DefineBits', 7 => 'DefineButton',
21
+ 8 => 'JPEGTables', 9 => 'SetBackgroundColor', 10 => 'DefineFont', 11 => 'DefineText',
22
+ 12 => 'DoAction', 13 => 'DefineFontInfo', 14 => 'DefineSound', 15 => 'StartSound',
23
+ 16 => 'StopSound', 17 => 'DefineButtonSound', 18 => 'SoundStreamHead', 19 => 'SoundStreamBlock',
24
+ 20 => 'DefineBitsLossless', 21 => 'DefineBitsJPEG2', 22 => 'DefineShape2', 23 => 'DefineButtonCxform',
25
+ 24 => 'Protect', 25 => 'PathsArePostScript', 26 => 'PlaceObject2',
26
+ 28 => 'RemoveObject2', 29 => 'SyncFrame', 31 => 'FreeAll',
27
+ 32 => 'DefineShape3', 33 => 'DefineText2', 34 => 'DefineButton2', 35 => 'DefineBitsJPEG3',
28
+ 36 => 'DefineBitsLossless2', 37 => 'DefineEditText', 38 => 'DefineVideo', 39 => 'DefineSprite',
29
+ 40 => 'NameCharacter', 41 => 'ProductInfo', 42 => 'DefineTextFormat', 43 => 'FrameLabel',
30
+ 44 => 'DefineBehavior', 45 => 'SoundStreamHead2', 46 => 'DefineMorphShape', 47 => 'FrameTag',
31
+ 48 => 'DefineFont2', 49 => 'GenCommand', 50 => 'DefineCommandObj', 51 => 'CharacterSet',
32
+ 52 => 'FontRef', 53 => 'DefineFunction', 54 => 'PlaceFunction', 55 => 'GenTagObject',
33
+ 56 => 'ExportAssets', 57 => 'ImportAssets', 58 => 'EnableDebugger', 59 => 'DoInitAction',
34
+ 60 => 'DefineVideoStream', 61 => 'VideoFrame', 62 => 'DefineFontInfo2', 63 => 'DebugID',
35
+ 64 => 'EnableDebugger2', 65 => 'ScriptLimits', 66 => 'SetTabIndex', 67 => 'DefineShape4',
36
+ 68 => 'DefineMorphShape2', 69 => 'FileAttributes', 70 => 'PlaceObject3', 71 => 'ImportAssets2',
37
+ 72 => 'DoABC', 76 => 'SymbolClass', 82 => 'DoABC2',
38
+ }
39
+
40
+ class SerialStruct < Metasm::SerialStruct
41
+ new_int_field :u8, :u16, :u32, :f16, :f32
42
+ end
43
+
44
+ class Rectangle < SerialStruct
45
+ virtual :nbits, :xmin, :xmax, :ymin, :ymax
46
+
47
+ def decode(swf)
48
+ byte = swf.decode_u8
49
+ bleft = 3
50
+ @nbits = byte >> bleft
51
+ @xmin, @xmax, @ymin, @ymax = (0..3).map {
52
+ nb = @nbits
53
+ v = 0
54
+ while nb > bleft
55
+ nb -= bleft
56
+ v |= (byte & ((1<<bleft)-1)) << nb
57
+
58
+ bleft = 8
59
+ byte = swf.decode_u8
60
+ end
61
+ v |= (byte >> (bleft-nb)) & ((1<<nb)-1)
62
+ bleft -= nb
63
+
64
+ Expression.make_signed(v, @nbits)
65
+ }
66
+ end
67
+
68
+ def set_default_values(swf)
69
+ @xmin ||= 0
70
+ @xmax ||= 31
71
+ @ymin ||= 0
72
+ @ymax ||= 31
73
+ @nbits = (0..30).find { |nb|
74
+ [@xmin, @xmax, @ymin, @ymax].all? { |v|
75
+ if nb == 0
76
+ v == 0
77
+ elsif v >= 0
78
+ # reserve sign bit
79
+ (v >> (nb-1)) == 0
80
+ else
81
+ (v >> nb) == -1
82
+ end
83
+ } } || 31
84
+ end
85
+
86
+ def encode(swf)
87
+ ed = super(swf)
88
+
89
+ byte = @nbits << 3
90
+ bleft = 3
91
+ [@xmin, @xmax, @ymin, @ymax].each { |v|
92
+ nb = @nbits
93
+ while nb > bleft
94
+ byte |= (v >> (nb-bleft)) & ((1<<bleft)-1)
95
+ nb -= bleft
96
+
97
+ ed << byte
98
+ byte = 0
99
+ bleft = 8
100
+ end
101
+ byte |= (v & ((1<<nb)-1)) << (bleft-nb)
102
+ bleft -= nb
103
+ }
104
+ ed << byte if bleft < 8
105
+
106
+ ed
107
+ end
108
+ end
109
+
110
+ class Header < SerialStruct
111
+ virtual :view
112
+ u16 :framerate # XXX bigendian...
113
+ u16 :framecount
114
+
115
+ def bswap_framerate(swf)
116
+ @framerate = ((@framerate >> 8) & 0xff) | ((@framerate & 0xff) << 8) if swf.endianness == :little
117
+ end
118
+
119
+ def decode(swf)
120
+ @view = Rectangle.decode(swf)
121
+ super(swf)
122
+ bswap_framerate(swf)
123
+ end
124
+
125
+ def encode(swf)
126
+ ed = @view.encode(swf)
127
+ bswap_framerate(swf)
128
+ ed << super(swf)
129
+ bswap_framerate(swf)
130
+ ed
131
+ end
132
+ end
133
+
134
+ class Chunk < SerialStruct
135
+ bitfield :u16, 0 => :length_, 6 => :tag
136
+ fld_enum :tag, CHUNK_TYPE
137
+ attr_accessor :data
138
+
139
+ def decode(swf)
140
+ super(swf)
141
+ @length = (@length_ == 0x3f ? swf.decode_u32 : @length_)
142
+ @data = swf.encoded.read(@length)
143
+ end
144
+
145
+ def set_default_values(swf)
146
+ @length = @data.length
147
+ @length_ = [@length, 0x3f].min
148
+ end
149
+
150
+ def encode(swf)
151
+ super(swf) <<
152
+ (swf.encode_u32(@length) if @length >= 0x3f) <<
153
+ @data
154
+ end
155
+ end
156
+
157
+ def decode_u8( edata=@encoded) edata.decode_imm(:u8, @endianness) end
158
+ def decode_u16(edata=@encoded) edata.decode_imm(:u16, @endianness) end
159
+ def decode_u32(edata=@encoded) edata.decode_imm(:u32, @endianness) end
160
+ def decode_f16(edata=@encoded) edata.decode_imm(:i16, @endianness)/256.0 end
161
+ def decode_f32(edata=@encoded) edata.decode_imm(:i32, @endianness)/65536.0 end
162
+ def encode_u8(w) Expression[w].encode(:u8, @endianness) end
163
+ def encode_u16(w) Expression[w].encode(:u16, @endianness) end
164
+ def encode_u32(w) Expression[w].encode(:u32, @endianness) end
165
+ def encode_f16(w) Expression[(w*256).to_i].encode(:u16, @endianness) end
166
+ def encode_f32(w) Expression[(w*65536).to_i].encode(:u32, @endianness) end
167
+ def sizeof_u8 ; 1 ; end
168
+ def sizeof_u16 ; 2 ; end
169
+ def sizeof_u32 ; 4 ; end
170
+ def sizeof_f16 ; 2 ; end
171
+ def sizeof_f32 ; 4 ; end
172
+
173
+ attr_accessor :endianness
174
+ def initialize(cpu = nil)
175
+ @endianness = :little
176
+ @header = Header.new
177
+ @chunks = []
178
+ super(cpu)
179
+ end
180
+
181
+ def decode_header
182
+ @signature = @encoded.read(3)
183
+ @version = decode_u8
184
+ @data_length = decode_u32
185
+ case @signature
186
+ when 'FWS'
187
+ when 'CWS'
188
+ # data_length = uncompressed data length
189
+ data = @encoded.read(@encoded.length-8)
190
+ data = Zlib::Inflate.inflate(data)
191
+ @encoded = EncodedData.new(data)
192
+ else raise InvalidExeFormat, "Bad signature #{@signature.inspect}"
193
+ end
194
+ @data_length = [@data_length, @encoded.length].min
195
+ @header = Header.decode(self)
196
+ end
197
+
198
+ def decode
199
+ decode_header
200
+ while @encoded.ptr < @data_length
201
+ @chunks << Chunk.decode(self)
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,402 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/exe_format/main'
8
+ require 'metasm/encode'
9
+ require 'metasm/decode'
10
+
11
+
12
+ module Metasm
13
+ # WebAssembly
14
+ # leb integer encoding taken from dex.rb
15
+ class WasmFile < ExeFormat
16
+ MAGIC = "\0asm"
17
+ MAGIC.force_encoding('binary') if MAGIC.respond_to?(:force_encoding)
18
+
19
+ SECTION_NAME = { 1 => 'Type', 2 => 'Import', 3 => 'Function', 4 => 'Table',
20
+ 5 => 'Memory', 6 => 'Global', 7 => 'Export', 8 => 'Start',
21
+ 9 => 'Element', 10 => 'Code', 11 => 'Data' }
22
+
23
+ TYPE = { -1 => 'i32', -2 => 'i64', -3 => 'f32', -4 => 'f64',
24
+ -0x10 => 'anyfunc', -0x20 => 'func', -0x40 => 'none' }
25
+
26
+ EXTERNAL_KIND = { 0 => 'function', 1 => 'table', 2 => 'memory', 3 => 'global' }
27
+
28
+ # begin WTF
29
+ OPCODE_IMM_COUNT = Hash.new(0)
30
+ [2, 3, 4, 0xc, 0xd, 0x10].each { |op| OPCODE_IMM_COUNT[op] = 1 }
31
+ OPCODE_IMM_COUNT[0x11] = 2
32
+ (0x20..0x24).each { |op| OPCODE_IMM_COUNT[op] = 1 }
33
+ (0x28..0x3e).each { |op| OPCODE_IMM_COUNT[op] = 2 }
34
+ (0x3f..0x42).each { |op| OPCODE_IMM_COUNT[op] = 1 }
35
+ # 0x43 followed by uint32, 0x44 followed by uint64 (float constants)
36
+ # end WTF
37
+
38
+
39
+ class SerialStruct < Metasm::SerialStruct
40
+ # TODO move uleb/sleb to new_field for sizeof
41
+ new_int_field :u4, :uleb, :sleb
42
+ end
43
+
44
+ class Header < SerialStruct
45
+ mem :sig, 4, MAGIC
46
+ decode_hook { |exe, hdr| raise InvalidExeFormat, "E: invalid WasmFile signature #{hdr.sig.inspect}" if hdr.sig != MAGIC }
47
+ u4 :ver, 1
48
+ end
49
+
50
+ class Module < SerialStruct
51
+ uleb :id
52
+ fld_enum :id, SECTION_NAME
53
+ uleb :payload_len
54
+ attr_accessor :edata, :raw_offset, :name
55
+
56
+ def decode(exe)
57
+ super(exe)
58
+ @raw_offset = exe.encoded.ptr
59
+ @edata = exe.encoded[exe.encoded.ptr, @payload_len]
60
+ exe.encoded.ptr += @payload_len
61
+ end
62
+ end
63
+
64
+ attr_accessor :endianness
65
+
66
+ def encode_u4(val) Expression[val].encode(:u32, @endianness) end
67
+ def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end
68
+ def sizeof_u4 ; 4 ; end
69
+ def encode_uleb(val, signed=false)
70
+ v = val
71
+ out = EncodedData.new
72
+ while v > 0x7f or v < -0x40 or (signed and v > 0x3f)
73
+ out << Expression[0x80 | (v&0x7f)].encode(:u8, @endianness)
74
+ v >>= 7
75
+ end
76
+ out << Expression[v & 0x7f].encode(:u8, @endianness)
77
+ end
78
+ def decode_uleb(ed = @encoded, signed=false)
79
+ v = s = 0
80
+ while s < 10*7
81
+ b = ed.read(1).unpack('C').first.to_i
82
+ v |= (b & 0x7f) << s
83
+ s += 7
84
+ break if (b&0x80) == 0
85
+ end
86
+ v = Expression.make_signed(v, s) if signed
87
+ v
88
+ end
89
+ def encode_sleb(val) encode_uleb(val, true) end
90
+ def decode_sleb(ed = @encoded) decode_uleb(ed, true) end
91
+ attr_accessor :header, :modules, :type, :import, :function_signature,
92
+ :table, :memory, :global, :export, :start_function_index,
93
+ :element, :function_body, :data, :code_info
94
+
95
+ def initialize(endianness=:little)
96
+ @endianness = endianness
97
+ @encoded = EncodedData.new
98
+ super()
99
+ end
100
+
101
+ def decode_type(edata=@encoded)
102
+ form = decode_sleb(edata)
103
+ type = TYPE[form] || "unk_type_#{form}"
104
+ if type == 'func'
105
+ type = { :params => [], :ret => [] }
106
+ decode_uleb(edata).times {
107
+ type[:params] << decode_type(edata)
108
+ }
109
+ decode_uleb(edata).times {
110
+ type[:ret] << decode_type(edata)
111
+ }
112
+ end
113
+ type
114
+ end
115
+
116
+ # return the nth global
117
+ # use the @global array and the @import array
118
+ def get_global_nr(nr)
119
+ glob_imports = @import.to_a.find_all { |i| i[:kind] == 'global' }
120
+ return glob_imports[nr] if nr < glob_imports.length
121
+ nr -= glob_imports.length
122
+ @global[nr]
123
+ end
124
+
125
+ # return the nth function body
126
+ # use the @function_body array and the @import array
127
+ def get_function_nr(nr)
128
+ func_imports = @import.to_a.find_all { |i| i[:kind] == 'function' }
129
+ return func_imports[nr] if nr < func_imports.length
130
+ nr -= func_imports.length
131
+ @function_body[nr]
132
+ end
133
+
134
+ def type_to_s(t)
135
+ return t unless t.kind_of?(::Hash)
136
+ (t[:ret].map { |tt| type_to_s(tt) }.join(', ') << ' f(' << t[:params].map { |tt| type_to_s(tt) }.join(', ') << ')').strip
137
+ end
138
+
139
+ def decode_limits(edata=@encoded)
140
+ flags = decode_uleb(edata)
141
+ out = { :initial_size => decode_uleb(edata) }
142
+ out[:maximum] = decode_uleb(edata) if flags & 1
143
+ out
144
+ end
145
+
146
+ # wtf
147
+ # read wasm bytecode until reaching the end opcode
148
+ # return the byte offset
149
+ def read_code_until_end(m=nil)
150
+ if m
151
+ raw_offset = m.raw_offset + m.edata.ptr
152
+ edata = m.edata
153
+ else
154
+ edata = @encoded
155
+ end
156
+
157
+ while op = edata.decode_imm(:u8, @endianness)
158
+ case op
159
+ when 0xb
160
+ # end opcode
161
+ return raw_offset
162
+ when 0xe
163
+ # indirect branch wtf
164
+ decode_uleb(edata).times { decode_uleb(edata) }
165
+ decode_uleb(edata)
166
+ when 0x43
167
+ edata.read(4)
168
+ when 0x44
169
+ edata.read(8)
170
+ else
171
+ OPCODE_IMM_COUNT[op].times { decode_uleb(edata) }
172
+ end
173
+ end
174
+ raw_offset
175
+ end
176
+
177
+ def decode_header
178
+ @header = Header.decode(self)
179
+ @modules = []
180
+ end
181
+
182
+ def decode
183
+ decode_header
184
+ while @encoded.ptr < @encoded.length
185
+ @modules << Module.decode(self)
186
+ end
187
+ @modules.each { |m|
188
+ @encoded.add_export(new_label("module_#{m.id}"), m.raw_offset)
189
+ f = "decode_module_#{m.id.to_s.downcase}"
190
+ send(f, m) if respond_to?(f)
191
+ }
192
+ func_imports = @import.to_a.find_all { |i| i[:kind] == 'function' }
193
+ export.to_a.each { |e|
194
+ next if e[:kind] != 'function' # TODO resolve init_offset for globals etc?
195
+ idx = e[:index] - func_imports.length
196
+ next if not fb = function_body.to_a[idx]
197
+ @encoded.add_export(new_label(e[:field]), fb[:init_offset], true)
198
+ }
199
+ # bytecode start addr => { :local_var => [], :params => [], :ret => [] }
200
+ # :local_var absent for external code (imported funcs)
201
+ @code_info = {}
202
+ import.to_a.each { |i|
203
+ next unless i[:kind] == 'function'
204
+ @code_info["#{i[:module]}_#{i[:field]}"] = { :params => i[:type][:params], :ret => i[:type][:ret] }
205
+ }
206
+ function_body.to_a.each { |fb|
207
+ @code_info[fb[:init_offset]] = { :local_var => fb[:local_var], :params => fb[:type][:params], :ret => fb[:type][:ret] }
208
+ }
209
+ global_idx = import.to_a.find_all { |i| i[:kind] == 'global' }.length - 1
210
+ global.to_a.each { |g|
211
+ @code_info[g[:init_offset]] = { :local_var => [], :params => [], :ret => [g[:type]] }
212
+ @encoded.add_export new_label("global_#{global_idx += 1}_init"), g[:init_offset]
213
+ }
214
+ element.to_a.each { |e|
215
+ @code_info[e[:init_offset]] = { :local_var => [], :params => [], :ret => ['i32'] }
216
+ }
217
+ data.to_a.each { |d|
218
+ @code_info[d[:init_offset]] = { :local_var => [], :params => [], :ret => ['i32'] }
219
+ }
220
+ end
221
+
222
+ def decode_module_type(m)
223
+ @type = []
224
+ decode_uleb(m.edata).times {
225
+ @type << decode_type(m.edata)
226
+ }
227
+ end
228
+
229
+ def decode_module_import(m)
230
+ @import = []
231
+ decode_uleb(m.edata).times {
232
+ i = {}
233
+ i[:module] = m.edata.read(decode_uleb(m.edata))
234
+ i[:field] = m.edata.read(decode_uleb(m.edata))
235
+ kind = decode_uleb(m.edata)
236
+ i[:kind] = EXTERNAL_KIND[kind] || kind
237
+ case i[:kind]
238
+ when 'function'
239
+ i[:type] = @type[decode_uleb(m.edata)] # XXX keep index only, in case @type is not yet known ?
240
+ when 'table'
241
+ i[:type] = decode_type(m.edata)
242
+ i[:limits] = decode_limits(m.edata)
243
+ when 'memory'
244
+ i[:limits] = decode_limits(m.edata)
245
+ when 'global'
246
+ i[:type] = decode_type(m.edata)
247
+ i[:mutable] = decode_uleb(m.edata)
248
+ end
249
+ @import << i
250
+ }
251
+ end
252
+
253
+ def decode_module_function(m)
254
+ @function_signature = []
255
+ idx = 0
256
+ decode_uleb(m.edata).times {
257
+ @function_signature << @type[decode_uleb(m.edata)]
258
+ @function_body[idx][:type] = @function_signature[idx] if function_body
259
+ idx += 1
260
+ }
261
+ end
262
+
263
+ def decode_module_table(m)
264
+ @table = []
265
+ decode_uleb(m.edata).times {
266
+ @table << { :type => decode_type(m.edata), :limits => decode_limits(m.edata) }
267
+ }
268
+ end
269
+
270
+ def decode_module_memory(m)
271
+ @memory = []
272
+ decode_uleb(m.edata).times {
273
+ @memory << { :limits => decode_limits(m.edata) }
274
+ }
275
+ end
276
+
277
+ def decode_module_global(m)
278
+ @global = []
279
+ decode_uleb(m.edata).times {
280
+ @global << { :type => decode_type(m.edata), :mutable => decode_uleb(m.edata), :init_offset => read_code_until_end(m) }
281
+ }
282
+ end
283
+
284
+ def decode_module_export(m)
285
+ @export = []
286
+ decode_uleb(m.edata).times {
287
+ flen = decode_uleb(m.edata)
288
+ fld = m.edata.read(flen)
289
+ kind = decode_uleb(m.edata)
290
+ kind = EXTERNAL_KIND[kind] || kind
291
+ index = decode_uleb(m.edata)
292
+ @export << { :field => fld, :kind => kind, :index => index }
293
+ }
294
+ end
295
+
296
+ def decode_module_start(m)
297
+ @start_function_index = decode_uleb(m.edata)
298
+ end
299
+
300
+ def decode_module_element(m)
301
+ @element = []
302
+ decode_uleb(m.edata).times {
303
+ seg = { :table_index => decode_uleb(m.edata),
304
+ :init_offset => read_code_until_end(m),
305
+ :elems => [] }
306
+ decode_uleb(m.edata).times {
307
+ seg[:elems] << decode_uleb(m.edata)
308
+ }
309
+ @element << seg
310
+ @encoded.add_export new_label("element_#{@element.length-1}_init_addr"), @element.last[:init_offset]
311
+ }
312
+ end
313
+
314
+ def decode_module_code(m)
315
+ @function_body = []
316
+ idx = 0
317
+ decode_uleb(m.edata).times {
318
+ local_vars = []
319
+ body_size = decode_uleb(m.edata) # size of local defs + bytecode (in bytes)
320
+ next_ptr = m.edata.ptr + body_size
321
+ decode_uleb(m.edata).times { # nr of local vars types
322
+ n_vars_of_this_type = decode_uleb(m.edata) # nr of local vars of this type
323
+ type = decode_type(m.edata) # actual type
324
+ n_vars_of_this_type.times {
325
+ local_vars << type
326
+ }
327
+ }
328
+ code_offset = m.raw_offset + m.edata.ptr # bytecode comes next
329
+ m.edata.ptr = next_ptr
330
+ @function_body << { :local_var => local_vars, :init_offset => code_offset }
331
+ @function_body.last[:type] = @function_signature[idx] if function_signature
332
+ @encoded.add_export new_label("function_#{@function_body.length-1}"), @function_body.last[:init_offset]
333
+ idx += 1
334
+ }
335
+ end
336
+
337
+ def decode_module_data(m)
338
+ @data = []
339
+ decode_uleb(m.edata).times {
340
+ idx = decode_uleb(m.edata)
341
+ initoff = read_code_until_end(m)
342
+ data_len = decode_uleb(m.edata)
343
+ data_start_ptr = m.raw_offset + m.edata.ptr
344
+ data = m.edata.read(data_len)
345
+ data_end_ptr = m.raw_offset + m.edata.ptr
346
+
347
+ @data << { :index => idx, :init_offset => initoff, :data => data }
348
+ @encoded.add_export new_label("data_#{@data.length-1}_init_addr"), initoff
349
+ @encoded.add_export new_label("data_#{@data.length-1}_start"), data_start_ptr
350
+ @encoded.add_export new_label("data_#{@data.length-1}_end"), data_end_ptr
351
+ }
352
+ end
353
+
354
+ def decode_module_0(m)
355
+ # id == 0 for not well-known modules
356
+ # the module name is encoded at start of payload (uleb name length + actual name)
357
+ m.name = m.edata.read(decode_uleb(m.edata))
358
+ f = "decode_module_0_#{m.name.downcase}"
359
+ send(f, m) if respond_to?(f)
360
+ end
361
+
362
+ def decode_module_0_name(m)
363
+ # TODO parse stored names of local variables etc
364
+ end
365
+
366
+ def cpu_from_headers
367
+ WebAsm.new(self)
368
+ end
369
+
370
+ def init_disassembler
371
+ dasm = super()
372
+ function_body.to_a.each { |fb|
373
+ v = []
374
+ fb[:local_var].map { |lv| type_to_s(lv) }.each { |lv|
375
+ v.last && lv == v.last.last ? v.last << lv : v << [lv]
376
+ }
377
+ v.map! { |sublist|
378
+ # i32 ; i32 ; i32 ; i32 ; i32 ; i32 ; i64 -> 5 * i32 ; i64
379
+ sublist.length > 3 ? "#{sublist.length} * #{sublist.first}" : sublist.join(' ; ')
380
+ }
381
+ dasm.add_comment fb[:init_offset], "proto: #{fb[:type] ? type_to_s(fb[:type]) : 'unknown'}"
382
+ dasm.add_comment fb[:init_offset], "vars: #{v.join(' ; ')}"
383
+ }
384
+ global.to_a.each { |g|
385
+ dasm.add_comment g[:init_offset], "type: #{type_to_s(g[:type])}"
386
+ }
387
+ dasm.function[:default] = @cpu.disassembler_default_func
388
+ dasm
389
+ end
390
+
391
+ def each_section
392
+ yield @encoded, 0
393
+ end
394
+
395
+ def get_default_entrypoints
396
+ global.to_a.map { |g| g[:init_offset] } +
397
+ element.to_a.map { |e| e[:init_offset] } +
398
+ data.to_a.map { |d| d[:init_offset] } +
399
+ function_body.to_a.map { |f| f[:init_offset] }
400
+ end
401
+ end
402
+ end