furnace-avm2 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +17 -0
  4. data/abcdump.abc +0 -0
  5. data/bin/furnace-avm2 +175 -0
  6. data/bin/furnace-avm2-benchmark +38 -0
  7. data/darkorbit.abc +0 -0
  8. data/furnace-avm2.gemspec +22 -0
  9. data/lib/avm2.rb +13 -0
  10. data/lib/avm2/abc.rb +65 -0
  11. data/lib/avm2/abc/metadata/const_pool_info.rb +18 -0
  12. data/lib/avm2/abc/metadata/exception_info.rb +29 -0
  13. data/lib/avm2/abc/metadata/file.rb +27 -0
  14. data/lib/avm2/abc/metadata/instance_info.rb +53 -0
  15. data/lib/avm2/abc/metadata/klass_info.rb +7 -0
  16. data/lib/avm2/abc/metadata/metadata_info.rb +9 -0
  17. data/lib/avm2/abc/metadata/method_body_info.rb +31 -0
  18. data/lib/avm2/abc/metadata/method_info.rb +57 -0
  19. data/lib/avm2/abc/metadata/multiname_info.rb +42 -0
  20. data/lib/avm2/abc/metadata/multiname_kind_genericname.rb +16 -0
  21. data/lib/avm2/abc/metadata/multiname_kind_multiname.rb +18 -0
  22. data/lib/avm2/abc/metadata/multiname_kind_multinamel.rb +17 -0
  23. data/lib/avm2/abc/metadata/multiname_kind_qname.rb +44 -0
  24. data/lib/avm2/abc/metadata/multiname_kind_rtqname.rb +17 -0
  25. data/lib/avm2/abc/metadata/multiname_kind_rtqnamel.rb +11 -0
  26. data/lib/avm2/abc/metadata/namespace_info.rb +22 -0
  27. data/lib/avm2/abc/metadata/ns_set_info.rb +13 -0
  28. data/lib/avm2/abc/metadata/option_detail.rb +26 -0
  29. data/lib/avm2/abc/metadata/option_info.rb +5 -0
  30. data/lib/avm2/abc/metadata/script_info.rb +7 -0
  31. data/lib/avm2/abc/metadata/trait_class.rb +9 -0
  32. data/lib/avm2/abc/metadata/trait_function.rb +9 -0
  33. data/lib/avm2/abc/metadata/trait_info.rb +55 -0
  34. data/lib/avm2/abc/metadata/trait_method.rb +12 -0
  35. data/lib/avm2/abc/metadata/trait_slot.rb +11 -0
  36. data/lib/avm2/abc/opcodes/arithmetic/as3_add.rb +8 -0
  37. data/lib/avm2/abc/opcodes/arithmetic/as3_add_i.rb +10 -0
  38. data/lib/avm2/abc/opcodes/arithmetic/as3_declocal.rb +14 -0
  39. data/lib/avm2/abc/opcodes/arithmetic/as3_declocal_i.rb +14 -0
  40. data/lib/avm2/abc/opcodes/arithmetic/as3_decrement.rb +10 -0
  41. data/lib/avm2/abc/opcodes/arithmetic/as3_decrement_i.rb +10 -0
  42. data/lib/avm2/abc/opcodes/arithmetic/as3_divide.rb +10 -0
  43. data/lib/avm2/abc/opcodes/arithmetic/as3_equals.rb +8 -0
  44. data/lib/avm2/abc/opcodes/arithmetic/as3_greaterequals.rb +8 -0
  45. data/lib/avm2/abc/opcodes/arithmetic/as3_greaterthan.rb +8 -0
  46. data/lib/avm2/abc/opcodes/arithmetic/as3_inclocal.rb +14 -0
  47. data/lib/avm2/abc/opcodes/arithmetic/as3_inclocal_i.rb +18 -0
  48. data/lib/avm2/abc/opcodes/arithmetic/as3_increment.rb +10 -0
  49. data/lib/avm2/abc/opcodes/arithmetic/as3_increment_i.rb +10 -0
  50. data/lib/avm2/abc/opcodes/arithmetic/as3_lessequals.rb +8 -0
  51. data/lib/avm2/abc/opcodes/arithmetic/as3_lessthan.rb +8 -0
  52. data/lib/avm2/abc/opcodes/arithmetic/as3_modulo.rb +10 -0
  53. data/lib/avm2/abc/opcodes/arithmetic/as3_multiply.rb +10 -0
  54. data/lib/avm2/abc/opcodes/arithmetic/as3_multiply_i.rb +10 -0
  55. data/lib/avm2/abc/opcodes/arithmetic/as3_negate.rb +10 -0
  56. data/lib/avm2/abc/opcodes/arithmetic/as3_negate_i.rb +10 -0
  57. data/lib/avm2/abc/opcodes/arithmetic/as3_not.rb +8 -0
  58. data/lib/avm2/abc/opcodes/arithmetic/as3_strictequals.rb +8 -0
  59. data/lib/avm2/abc/opcodes/arithmetic/as3_subtract.rb +10 -0
  60. data/lib/avm2/abc/opcodes/arithmetic/as3_subtract_i.rb +10 -0
  61. data/lib/avm2/abc/opcodes/arithmetic_opcode.rb +4 -0
  62. data/lib/avm2/abc/opcodes/bitwise/as3_bitand.rb +8 -0
  63. data/lib/avm2/abc/opcodes/bitwise/as3_bitnot.rb +8 -0
  64. data/lib/avm2/abc/opcodes/bitwise/as3_bitor.rb +8 -0
  65. data/lib/avm2/abc/opcodes/bitwise/as3_bitxor.rb +8 -0
  66. data/lib/avm2/abc/opcodes/bitwise/as3_lshift.rb +8 -0
  67. data/lib/avm2/abc/opcodes/bitwise/as3_rshift.rb +8 -0
  68. data/lib/avm2/abc/opcodes/bitwise/as3_urshift.rb +8 -0
  69. data/lib/avm2/abc/opcodes/bitwise_opcode.rb +4 -0
  70. data/lib/avm2/abc/opcodes/contextual_opcode.rb +32 -0
  71. data/lib/avm2/abc/opcodes/control_transfer/as3_ifeq.rb +14 -0
  72. data/lib/avm2/abc/opcodes/control_transfer/as3_iffalse.rb +14 -0
  73. data/lib/avm2/abc/opcodes/control_transfer/as3_ifge.rb +14 -0
  74. data/lib/avm2/abc/opcodes/control_transfer/as3_ifgt.rb +14 -0
  75. data/lib/avm2/abc/opcodes/control_transfer/as3_ifle.rb +14 -0
  76. data/lib/avm2/abc/opcodes/control_transfer/as3_iflt.rb +14 -0
  77. data/lib/avm2/abc/opcodes/control_transfer/as3_ifne.rb +14 -0
  78. data/lib/avm2/abc/opcodes/control_transfer/as3_ifnge.rb +14 -0
  79. data/lib/avm2/abc/opcodes/control_transfer/as3_ifngt.rb +14 -0
  80. data/lib/avm2/abc/opcodes/control_transfer/as3_ifnle.rb +14 -0
  81. data/lib/avm2/abc/opcodes/control_transfer/as3_ifnlt.rb +14 -0
  82. data/lib/avm2/abc/opcodes/control_transfer/as3_ifstricteq.rb +14 -0
  83. data/lib/avm2/abc/opcodes/control_transfer/as3_ifstrictne.rb +14 -0
  84. data/lib/avm2/abc/opcodes/control_transfer/as3_iftrue.rb +14 -0
  85. data/lib/avm2/abc/opcodes/control_transfer/as3_jump.rb +22 -0
  86. data/lib/avm2/abc/opcodes/control_transfer/as3_lookupswitch.rb +34 -0
  87. data/lib/avm2/abc/opcodes/control_transfer_opcode.rb +37 -0
  88. data/lib/avm2/abc/opcodes/exception/as3_newcatch.rb +16 -0
  89. data/lib/avm2/abc/opcodes/exception_opcode.rb +4 -0
  90. data/lib/avm2/abc/opcodes/function_invocation/as3_call.rb +16 -0
  91. data/lib/avm2/abc/opcodes/function_invocation/as3_callproperty.rb +7 -0
  92. data/lib/avm2/abc/opcodes/function_invocation/as3_callpropvoid.rb +7 -0
  93. data/lib/avm2/abc/opcodes/function_invocation/as3_callsuper.rb +7 -0
  94. data/lib/avm2/abc/opcodes/function_invocation/as3_callsupervoid.rb +7 -0
  95. data/lib/avm2/abc/opcodes/function_invocation_opcode.rb +17 -0
  96. data/lib/avm2/abc/opcodes/function_return/as3_returnvalue.rb +8 -0
  97. data/lib/avm2/abc/opcodes/function_return/as3_returnvoid.rb +8 -0
  98. data/lib/avm2/abc/opcodes/function_return_opcode.rb +4 -0
  99. data/lib/avm2/abc/opcodes/generic/as3_astypelate.rb +8 -0
  100. data/lib/avm2/abc/opcodes/generic/as3_checkfilter.rb +8 -0
  101. data/lib/avm2/abc/opcodes/generic/as3_dup.rb +8 -0
  102. data/lib/avm2/abc/opcodes/generic/as3_dxnslate.rb +8 -0
  103. data/lib/avm2/abc/opcodes/generic/as3_escxattr.rb +8 -0
  104. data/lib/avm2/abc/opcodes/generic/as3_getglobalscope.rb +8 -0
  105. data/lib/avm2/abc/opcodes/generic/as3_getlex.rb +16 -0
  106. data/lib/avm2/abc/opcodes/generic/as3_getscopeobject.rb +16 -0
  107. data/lib/avm2/abc/opcodes/generic/as3_getslot.rb +16 -0
  108. data/lib/avm2/abc/opcodes/generic/as3_hasnext.rb +8 -0
  109. data/lib/avm2/abc/opcodes/generic/as3_hasnext2.rb +17 -0
  110. data/lib/avm2/abc/opcodes/generic/as3_in.rb +8 -0
  111. data/lib/avm2/abc/opcodes/generic/as3_instanceof.rb +8 -0
  112. data/lib/avm2/abc/opcodes/generic/as3_istypelate.rb +8 -0
  113. data/lib/avm2/abc/opcodes/generic/as3_kill.rb +16 -0
  114. data/lib/avm2/abc/opcodes/generic/as3_label.rb +8 -0
  115. data/lib/avm2/abc/opcodes/generic/as3_nextname.rb +8 -0
  116. data/lib/avm2/abc/opcodes/generic/as3_nextvalue.rb +8 -0
  117. data/lib/avm2/abc/opcodes/generic/as3_nop.rb +8 -0
  118. data/lib/avm2/abc/opcodes/generic/as3_pop.rb +8 -0
  119. data/lib/avm2/abc/opcodes/generic/as3_popscope.rb +8 -0
  120. data/lib/avm2/abc/opcodes/generic/as3_setslot.rb +16 -0
  121. data/lib/avm2/abc/opcodes/generic/as3_swap.rb +8 -0
  122. data/lib/avm2/abc/opcodes/generic/as3_throw.rb +8 -0
  123. data/lib/avm2/abc/opcodes/generic/as3_typeof.rb +8 -0
  124. data/lib/avm2/abc/opcodes/load_store/as3_getlocal.rb +15 -0
  125. data/lib/avm2/abc/opcodes/load_store/as3_getlocal_0.rb +11 -0
  126. data/lib/avm2/abc/opcodes/load_store/as3_getlocal_1.rb +11 -0
  127. data/lib/avm2/abc/opcodes/load_store/as3_getlocal_2.rb +11 -0
  128. data/lib/avm2/abc/opcodes/load_store/as3_getlocal_3.rb +11 -0
  129. data/lib/avm2/abc/opcodes/load_store/as3_setlocal.rb +15 -0
  130. data/lib/avm2/abc/opcodes/load_store/as3_setlocal_0.rb +11 -0
  131. data/lib/avm2/abc/opcodes/load_store/as3_setlocal_1.rb +11 -0
  132. data/lib/avm2/abc/opcodes/load_store/as3_setlocal_2.rb +11 -0
  133. data/lib/avm2/abc/opcodes/load_store/as3_setlocal_3.rb +11 -0
  134. data/lib/avm2/abc/opcodes/load_store_opcode.rb +18 -0
  135. data/lib/avm2/abc/opcodes/object_manipulation/as3_construct.rb +12 -0
  136. data/lib/avm2/abc/opcodes/object_manipulation/as3_constructsuper.rb +16 -0
  137. data/lib/avm2/abc/opcodes/object_manipulation/as3_newactivation.rb +8 -0
  138. data/lib/avm2/abc/opcodes/object_manipulation/as3_newarray.rb +12 -0
  139. data/lib/avm2/abc/opcodes/object_manipulation/as3_newclass.rb +12 -0
  140. data/lib/avm2/abc/opcodes/object_manipulation/as3_newfunction.rb +12 -0
  141. data/lib/avm2/abc/opcodes/object_manipulation/as3_newobject.rb +12 -0
  142. data/lib/avm2/abc/opcodes/object_manipulation_opcode.rb +4 -0
  143. data/lib/avm2/abc/opcodes/opcode.rb +127 -0
  144. data/lib/avm2/abc/opcodes/property/as3_constructprop.rb +20 -0
  145. data/lib/avm2/abc/opcodes/property/as3_deleteproperty.rb +9 -0
  146. data/lib/avm2/abc/opcodes/property/as3_findproperty.rb +9 -0
  147. data/lib/avm2/abc/opcodes/property/as3_findpropstrict.rb +9 -0
  148. data/lib/avm2/abc/opcodes/property/as3_getdescendants.rb +9 -0
  149. data/lib/avm2/abc/opcodes/property/as3_getproperty.rb +9 -0
  150. data/lib/avm2/abc/opcodes/property/as3_getsuper.rb +9 -0
  151. data/lib/avm2/abc/opcodes/property/as3_initproperty.rb +9 -0
  152. data/lib/avm2/abc/opcodes/property/as3_setproperty.rb +9 -0
  153. data/lib/avm2/abc/opcodes/property/as3_setsuper.rb +9 -0
  154. data/lib/avm2/abc/opcodes/property_opcode.rb +13 -0
  155. data/lib/avm2/abc/opcodes/push_literal/as3_pushbyte.rb +11 -0
  156. data/lib/avm2/abc/opcodes/push_literal/as3_pushdouble.rb +11 -0
  157. data/lib/avm2/abc/opcodes/push_literal/as3_pushfalse.rb +7 -0
  158. data/lib/avm2/abc/opcodes/push_literal/as3_pushint.rb +11 -0
  159. data/lib/avm2/abc/opcodes/push_literal/as3_pushnan.rb +7 -0
  160. data/lib/avm2/abc/opcodes/push_literal/as3_pushnull.rb +7 -0
  161. data/lib/avm2/abc/opcodes/push_literal/as3_pushscope.rb +8 -0
  162. data/lib/avm2/abc/opcodes/push_literal/as3_pushshort.rb +11 -0
  163. data/lib/avm2/abc/opcodes/push_literal/as3_pushstring.rb +11 -0
  164. data/lib/avm2/abc/opcodes/push_literal/as3_pushtrue.rb +7 -0
  165. data/lib/avm2/abc/opcodes/push_literal/as3_pushundefined.rb +7 -0
  166. data/lib/avm2/abc/opcodes/push_literal/as3_pushwith.rb +8 -0
  167. data/lib/avm2/abc/opcodes/push_literal_opcode.rb +18 -0
  168. data/lib/avm2/abc/opcodes/type_conversion/as3_applytype.rb +12 -0
  169. data/lib/avm2/abc/opcodes/type_conversion/as3_coerce.rb +16 -0
  170. data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_a.rb +8 -0
  171. data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_b.rb +10 -0
  172. data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_s.rb +10 -0
  173. data/lib/avm2/abc/opcodes/type_conversion/as3_convert_d.rb +10 -0
  174. data/lib/avm2/abc/opcodes/type_conversion/as3_convert_i.rb +10 -0
  175. data/lib/avm2/abc/opcodes/type_conversion/as3_convert_o.rb +10 -0
  176. data/lib/avm2/abc/opcodes/type_conversion/as3_convert_s.rb +10 -0
  177. data/lib/avm2/abc/opcodes/type_conversion/as3_convert_u.rb +10 -0
  178. data/lib/avm2/abc/opcodes/type_conversion_opcode.rb +4 -0
  179. data/lib/avm2/abc/primitives/opcode_sequence.rb +195 -0
  180. data/lib/avm2/abc/primitives/record.rb +132 -0
  181. data/lib/avm2/binary/choice_definition.rb +21 -0
  182. data/lib/avm2/binary/record.rb +469 -0
  183. data/lib/avm2/transform.rb +6 -0
  184. data/lib/avm2/transform/ast_build.rb +206 -0
  185. data/lib/avm2/transform/ast_normalize.rb +0 -0
  186. data/lib/avm2/version.rb +3 -0
  187. data/test/exception.abc +0 -0
  188. data/test/exception.as +29 -0
  189. data/test/literal.abc +0 -0
  190. data/test/literal.as +5 -0
  191. data/test/logic.abc +0 -0
  192. data/test/logic.as +23 -0
  193. data/test/loops.abc +0 -0
  194. data/test/loops.as +30 -0
  195. data/test/number.abc +0 -0
  196. data/test/number.as +14 -0
  197. data/test/switch.abc +0 -0
  198. data/test/switch.as +38 -0
  199. data/test/ternary.abc +0 -0
  200. data/test/ternary.as +22 -0
  201. metadata +579 -0
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .rbx/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: ../furnace
3
+ specs:
4
+ furnace (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ trollop (1.16.2)
10
+
11
+ PLATFORMS
12
+ java
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ furnace!
17
+ trollop
data/abcdump.abc ADDED
Binary file
data/bin/furnace-avm2 ADDED
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require "trollop"
9
+ require "avm2"
10
+ require "thread"
11
+ require "benchmark"
12
+
13
+ opts = Trollop::options do
14
+ version "furnace-as3 #{AVM2::VERSION}"
15
+ banner <<-EOS
16
+ furnace-avm2 is a processing tool which operates on ActionScript3 bytecode.
17
+
18
+ Usage: #{__FILE__} [options]
19
+ EOS
20
+
21
+ opt :input, "Input file", :type => :string
22
+ opt :output, "Output file", :type => :string
23
+ opt :verbose, "Be verbose", :default => false
24
+
25
+ opt :only, "Only operate on methods <i+>", :type => :ints, :short => '-O'
26
+ opt :except, "Operate on all methods except <i+>", :type => :ints, :short => '-E'
27
+ opt :grep, "Search <s> in method names", :type => :string, :short => '-G'
28
+
29
+ opt :collect, "Collect failed methods instead of exiting", :default => false
30
+ opt :smallest, "Find method with smallest body", :default => false
31
+
32
+ opt :disasm_before, "Disassemble methods before transforming", :default => false, :short => '-B'
33
+ opt :disasm_after, "Disassemble methods after transforming", :default => false, :short => '-A'
34
+ opt :cfg, "Emit CFG in Graphviz format for methods", :default => false, :short => '-C'
35
+
36
+ opt :dce, "Eliminate dead code", :default => false
37
+ opt :ast, "Build AST", :default => false
38
+ end
39
+
40
+ Trollop::die "Input file is required" unless opts[:input]
41
+ Trollop::die "Stray arguments: #{ARGV}" unless ARGV.empty?
42
+
43
+ abc = nil
44
+ File.open(opts[:input]) do |file|
45
+ abc = AVM2::ABC::File.new
46
+ abc.read(file)
47
+ end
48
+
49
+ disasm = lambda do |body, after|
50
+ puts
51
+ puts "Method #{body.method_idx}," <<
52
+ " max stack #{body.max_stack}, local count #{body.local_count}"
53
+ if after
54
+ puts "After transformation"
55
+ else
56
+ puts "Before transformation"
57
+ end
58
+ puts body.code.disassemble
59
+
60
+ if body.exceptions.any?
61
+ puts
62
+ puts "Exceptions"
63
+ body.exceptions.each do |exception|
64
+ puts " #{exception.from_offset} -> #{exception.to_offset}: " <<
65
+ "catch(#{exception.exc_type} #{exception.var_name}) #{exception.target_offset}"
66
+ end
67
+ end
68
+ end
69
+
70
+ failed = []
71
+ dced = []
72
+ smallest = nil
73
+
74
+ if opts[:grep]
75
+ regexp = Regexp.new(opts[:grep])
76
+
77
+ (abc.klasses + abc.instances).each do |scope|
78
+ if scope.is_a? AVM2::ABC::InstanceInfo
79
+ if scope.name.to_s =~ regexp
80
+ puts "Inst Constructor #{scope.name} #{scope.initializer_idx}"
81
+ end
82
+
83
+ type = "Inst "
84
+ else
85
+ type = "Class"
86
+ end
87
+
88
+ scope.traits.each do |trait|
89
+ if [:Function, :Method].include? trait.kind
90
+ if trait.name.to_s =~ regexp
91
+ puts "#{type} #{trait.kind.to_s.ljust 12} #{trait.name} #{trait.data.method_idx}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ exit
98
+ end
99
+
100
+ Thread.abort_on_exception = true
101
+
102
+ threads = []
103
+ bodies = abc.method_bodies.dup
104
+ mutex = Mutex.new
105
+
106
+ 5.times do
107
+ threads << Thread.new do
108
+ loop do
109
+ body = mutex.synchronize { bodies.pop }
110
+ break if body.nil?
111
+
112
+ if (opts[:except] && opts[:except].include?(body.method_idx)) ||
113
+ (opts[:only] && !opts[:only].include?(body.method_idx))
114
+ next
115
+ end
116
+
117
+ begin
118
+ disasm[body, false] if opts[:disasm_before]
119
+
120
+ if opts[:smallest]
121
+ if smallest.nil? || smallest.code_length > body.code_length
122
+ smallest = body
123
+ end
124
+ end
125
+
126
+ if opts[:dce]
127
+ dced << body.method_idx if body.code.eliminate_dead!
128
+ end
129
+
130
+ if opts[:ast]
131
+ ast, = body.build_ast
132
+ puts ast.to_sexp
133
+ end
134
+
135
+ if opts[:cfg]
136
+ cfg = body.code.build_cfg
137
+ File.open("method-#{body.method_idx}.dot", "w") do |dot|
138
+ dot.write cfg.to_graphviz
139
+ end
140
+ end
141
+
142
+ disasm[body, true] if opts[:disasm_after]
143
+ rescue Exception => e
144
+ if opts[:collect]
145
+ #puts "Failure at method body idx=#{body.method_idx}: #{e.class} (#{e.message}) at #{e.backtrace.first}."
146
+ failed << body.method_idx
147
+ else
148
+ raise e
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ threads.each &:join
156
+
157
+ if opts[:verbose]
158
+ if opts[:dce]
159
+ puts "List of methods undergone DCE transform (#{dced.count}):"
160
+ puts " #{dced.join " "}"
161
+ end
162
+ end
163
+
164
+ if opts[:smallest]
165
+ puts "Smallest method is #{smallest.method_idx} with #{smallest.code_length} bytes"
166
+ end
167
+
168
+ if opts[:collect] && failed.any?
169
+ puts "To skip #{failed.count} failed methods, append this command-line argument:"
170
+ puts " --except #{failed.join " "}"
171
+ elsif opts[:output]
172
+ File.open(opts[:output], "w") do |file|
173
+ abc.write(file)
174
+ end
175
+ end
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require "avm2"
9
+ require "benchmark"
10
+
11
+ puts "Working on #{RUBY_DESCRIPTION}"
12
+
13
+ Benchmark.bm(7) do |x|
14
+ 5.times do
15
+ abc = nil
16
+
17
+ GC.start
18
+
19
+ x.report("read ") do
20
+ File.open(ARGV.first) do |file|
21
+ abc = AVM2::ABC::File.new
22
+ abc.read(file)
23
+ end
24
+ end
25
+
26
+ x.report("dce ") do
27
+ abc.method_bodies.each do |body|
28
+ body.code.eliminate_dead!
29
+ end
30
+ end
31
+
32
+ x.report("write ") do
33
+ File.open("/dev/null", "w") do |file|
34
+ abc.write(file)
35
+ end
36
+ end
37
+ end
38
+ end
data/darkorbit.abc ADDED
Binary file
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "avm2/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "furnace-avm2"
7
+ s.version = AVM2::VERSION
8
+ s.authors = ["Peter Zotov"]
9
+ s.email = ["whitequark@whitequark.org"]
10
+ s.homepage = "http://github.com/whitequark/furnace-avm2"
11
+ s.summary = %q{AVM2 analysis framework based on Furnace}
12
+ s.description = %q{furnace-avm2 allows one to load, modify and write back} <<
13
+ %q{Flash ActionScript3 bytecode. It can also decompile it.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_runtime_dependency "furnace"
21
+ s.add_runtime_dependency "trollop"
22
+ end
data/lib/avm2.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "furnace/cfg"
2
+ require "furnace/ast"
3
+ require "furnace/transform"
4
+
5
+ require "furnace/graphviz"
6
+
7
+ module AVM2
8
+ end
9
+
10
+ require "avm2/version"
11
+
12
+ require "avm2/abc"
13
+ require "avm2/transform"
data/lib/avm2/abc.rb ADDED
@@ -0,0 +1,65 @@
1
+ module AVM2::ABC
2
+ AST = Furnace::AST
3
+ CFG = Furnace::CFG
4
+ end
5
+
6
+ require "avm2/binary/choice_definition"
7
+ require "avm2/binary/record"
8
+
9
+ require "avm2/abc/primitives/record"
10
+ require "avm2/abc/primitives/opcode_sequence"
11
+
12
+ require "avm2/abc/opcodes/opcode"
13
+ require "avm2/abc/opcodes/contextual_opcode"
14
+
15
+ require "avm2/abc/opcodes/load_store_opcode"
16
+ require "avm2/abc/opcodes/arithmetic_opcode"
17
+ require "avm2/abc/opcodes/bitwise_opcode"
18
+ require "avm2/abc/opcodes/type_conversion_opcode"
19
+ require "avm2/abc/opcodes/push_literal_opcode"
20
+ require "avm2/abc/opcodes/control_transfer_opcode"
21
+ require "avm2/abc/opcodes/function_invocation_opcode"
22
+ require "avm2/abc/opcodes/function_return_opcode"
23
+ require "avm2/abc/opcodes/exception_opcode"
24
+
25
+ require "avm2/abc/opcodes/property_opcode"
26
+
27
+ Dir[File.join(File.dirname(__FILE__), "abc", "opcodes", "*", "*.rb")].each do |file|
28
+ require file
29
+ end
30
+
31
+ AVM2::ABC::Opcode::MAP.freeze
32
+
33
+ require "avm2/abc/metadata/namespace_info"
34
+ require "avm2/abc/metadata/ns_set_info"
35
+ require "avm2/abc/metadata/multiname_kind_multiname"
36
+ require "avm2/abc/metadata/multiname_kind_multinamel"
37
+ require "avm2/abc/metadata/multiname_kind_qname"
38
+ require "avm2/abc/metadata/multiname_kind_rtqname"
39
+ require "avm2/abc/metadata/multiname_kind_rtqnamel"
40
+ require "avm2/abc/metadata/multiname_kind_genericname"
41
+ require "avm2/abc/metadata/multiname_info"
42
+ require "avm2/abc/metadata/const_pool_info"
43
+
44
+ require "avm2/abc/metadata/option_detail"
45
+ require "avm2/abc/metadata/option_info"
46
+ require "avm2/abc/metadata/method_info"
47
+
48
+ require "avm2/abc/metadata/metadata_info"
49
+
50
+ require "avm2/abc/metadata/trait_slot"
51
+ require "avm2/abc/metadata/trait_method"
52
+ require "avm2/abc/metadata/trait_class"
53
+ require "avm2/abc/metadata/trait_function"
54
+ require "avm2/abc/metadata/trait_info"
55
+ require "avm2/abc/metadata/instance_info"
56
+ require "avm2/abc/metadata/klass_info"
57
+
58
+ require "avm2/abc/metadata/script_info"
59
+
60
+ require "avm2/abc/metadata/exception_info"
61
+ require "avm2/abc/metadata/method_body_info"
62
+
63
+ require "avm2/abc/metadata/file"
64
+
65
+ AVM2::Binary::Record.codegen_each
@@ -0,0 +1,18 @@
1
+ module AVM2::ABC
2
+ class ConstPoolInfo < Record
3
+ def self.cpool_array_of(name, type, options={})
4
+ field_size, field_array = :"#{name}_count", :"#{name}s"
5
+
6
+ vuint30 field_size, :value => lambda { send(field_array).count == 0 ? 0 : send(field_array).count + 1 }
7
+ array field_array, :type => type, :initial_length => lambda { send(field_size) - 1 }, :options => options
8
+ end
9
+
10
+ cpool_array_of :int, :vint32
11
+ cpool_array_of :uint, :vuint32
12
+ cpool_array_of :double, :double
13
+ cpool_array_of :string, :vstring
14
+ cpool_array_of :namespace, :nested, :class => NamespaceInfo
15
+ cpool_array_of :ns_set, :nested, :class => NsSetInfo
16
+ cpool_array_of :multiname, :nested, :class => MultinameInfo
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module AVM2::ABC
2
+ class ExceptionInfo < Record
3
+ vuint30 :from_offset
4
+ vuint30 :to_offset
5
+ vuint30 :target_offset
6
+ const_ref :exc_type, :string
7
+ const_ref :var_name, :string
8
+
9
+ attr_reader :from, :to, :target
10
+
11
+ def initialize_record(options)
12
+ @parent = options[:parent]
13
+ end
14
+
15
+ def resolve!
16
+ sequence = @parent.code
17
+
18
+ @from = sequence.opcode_at(@from_offset)
19
+ @to = sequence.opcode_at(@to_offset)
20
+ @target = sequence.opcode_at(@target_offset)
21
+ end
22
+
23
+ def lookup!
24
+ @from_offset = @from.offset
25
+ @to_offset = @to.offset
26
+ @target_offset = @target.offset
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ module AVM2::ABC
2
+ class File < Record
3
+ uint16 :minor_version
4
+ uint16 :major_version
5
+
6
+ nested :constant_pool, :class => ConstPoolInfo
7
+
8
+ abc_array_of :method, :nested, :class => MethodInfo
9
+
10
+ abc_array_of :metadata, :nested, :class => MetadataInfo
11
+
12
+ vuint30 :klass_count, :value => lambda { instances.count }
13
+ array :instances, :type => :nested, :initial_length => :klass_count,
14
+ :options => { :class => InstanceInfo }
15
+ array :klasses, :type => :nested, :initial_length => :klass_count,
16
+ :options => { :class => KlassInfo }
17
+ subset :interfaces, :instances, :interface?
18
+
19
+ abc_array_of :script, :nested, :class => ScriptInfo
20
+
21
+ abc_array_of :method_body, :nested, :class => MethodBodyInfo, :plural => :method_bodies
22
+
23
+ def root
24
+ self
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ module AVM2::ABC
2
+ class InstanceInfo < Record
3
+ CLASS_SEALED = 0x01
4
+ CLASS_FINAL = 0x02
5
+ CLASS_INTERFACE = 0x04
6
+ CLASS_PROTECTED_NS = 0x08
7
+
8
+ const_ref :name, :multiname
9
+ const_ref :super_name, :multiname
10
+
11
+ uint8 :flags
12
+ flag :sealed, :flags, CLASS_SEALED
13
+ flag :final, :flags, CLASS_FINAL
14
+ flag :interface, :flags, CLASS_INTERFACE
15
+ flag :protected_ns, :flags, CLASS_PROTECTED_NS
16
+
17
+ const_ref :protected_ns, :namespace, :if => :protected_ns?
18
+
19
+ const_array_of :interface, :multiname
20
+
21
+ root_ref :initializer, :method
22
+
23
+ abc_array_of :trait, :nested, :class => TraitInfo
24
+
25
+ def to_astlet
26
+ if interface?
27
+ root = AST::Node.new(:interface)
28
+ else
29
+ root = AST::Node.new(:instance)
30
+ end
31
+
32
+ root.children << name.to_astlet
33
+
34
+ unless interface?
35
+ if super_name
36
+ root.children << super_name.to_astlet
37
+ else
38
+ root.children << nil
39
+ end
40
+ end
41
+
42
+ if interfaces.any?
43
+ root.children << AST::Node.new(:interfaces, interfaces.map(&:to_astlet))
44
+ end
45
+
46
+ if traits.any?
47
+ root.children << AST::Node.new(:traits, traits.map(&:to_astlet))
48
+ end
49
+
50
+ root.normalize_hierarchy!
51
+ end
52
+ end
53
+ end