metasm 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/Gemfile +3 -2
- data/metasm.gemspec +3 -2
- data/metasm.rb +4 -1
- data/metasm/compile_c.rb +2 -2
- data/metasm/cpu/arc/decode.rb +0 -21
- data/metasm/cpu/arc/main.rb +4 -4
- data/metasm/cpu/arm/decode.rb +1 -5
- data/metasm/cpu/arm/main.rb +3 -3
- data/metasm/cpu/arm64/decode.rb +2 -6
- data/metasm/cpu/arm64/main.rb +5 -5
- data/metasm/cpu/bpf/decode.rb +3 -35
- data/metasm/cpu/bpf/main.rb +5 -5
- data/metasm/cpu/bpf/render.rb +1 -12
- data/metasm/cpu/cy16/decode.rb +0 -6
- data/metasm/cpu/cy16/main.rb +3 -3
- data/metasm/cpu/cy16/render.rb +0 -11
- data/metasm/cpu/dalvik/decode.rb +4 -26
- data/metasm/cpu/dalvik/main.rb +20 -2
- data/metasm/cpu/dalvik/opcodes.rb +3 -2
- data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
- data/metasm/cpu/ebpf/debug.rb +61 -0
- data/metasm/cpu/ebpf/decode.rb +142 -0
- data/metasm/cpu/ebpf/main.rb +58 -0
- data/metasm/cpu/ebpf/opcodes.rb +97 -0
- data/metasm/cpu/ebpf/render.rb +36 -0
- data/metasm/cpu/ia32/debug.rb +39 -1
- data/metasm/cpu/ia32/decode.rb +111 -90
- data/metasm/cpu/ia32/decompile.rb +45 -37
- data/metasm/cpu/ia32/main.rb +10 -0
- data/metasm/cpu/ia32/parse.rb +6 -0
- data/metasm/cpu/mcs51/decode.rb +1 -1
- data/metasm/cpu/mcs51/main.rb +11 -0
- data/metasm/cpu/mips/decode.rb +8 -18
- data/metasm/cpu/mips/main.rb +3 -3
- data/metasm/cpu/mips/opcodes.rb +1 -1
- data/metasm/cpu/msp430/decode.rb +2 -6
- data/metasm/cpu/msp430/main.rb +3 -3
- data/metasm/cpu/openrisc.rb +11 -0
- data/metasm/cpu/openrisc/debug.rb +106 -0
- data/metasm/cpu/openrisc/decode.rb +182 -0
- data/metasm/cpu/openrisc/decompile.rb +350 -0
- data/metasm/cpu/openrisc/main.rb +70 -0
- data/metasm/cpu/openrisc/opcodes.rb +109 -0
- data/metasm/cpu/openrisc/render.rb +37 -0
- data/metasm/cpu/ppc/decode.rb +0 -25
- data/metasm/cpu/ppc/main.rb +6 -6
- data/metasm/cpu/ppc/opcodes.rb +3 -4
- data/metasm/cpu/python/decode.rb +0 -20
- data/metasm/cpu/python/main.rb +1 -1
- data/metasm/cpu/sh4/decode.rb +2 -6
- data/metasm/cpu/sh4/main.rb +25 -23
- data/metasm/cpu/st20/decode.rb +0 -7
- data/metasm/cpu/webasm.rb +11 -0
- data/metasm/cpu/webasm/debug.rb +31 -0
- data/metasm/cpu/webasm/decode.rb +321 -0
- data/metasm/cpu/webasm/decompile.rb +386 -0
- data/metasm/cpu/webasm/encode.rb +104 -0
- data/metasm/cpu/webasm/main.rb +81 -0
- data/metasm/cpu/webasm/opcodes.rb +214 -0
- data/metasm/cpu/x86_64/compile_c.rb +13 -9
- data/metasm/cpu/x86_64/parse.rb +1 -1
- data/metasm/cpu/z80/decode.rb +0 -27
- data/metasm/cpu/z80/main.rb +3 -3
- data/metasm/cpu/z80/render.rb +0 -11
- data/metasm/debug.rb +43 -8
- data/metasm/decode.rb +62 -14
- data/metasm/decompile.rb +793 -466
- data/metasm/disassemble.rb +188 -131
- data/metasm/disassemble_api.rb +30 -17
- data/metasm/dynldr.rb +2 -2
- data/metasm/encode.rb +8 -2
- data/metasm/exe_format/autoexe.rb +2 -0
- data/metasm/exe_format/coff.rb +21 -3
- data/metasm/exe_format/coff_decode.rb +12 -0
- data/metasm/exe_format/coff_encode.rb +6 -3
- data/metasm/exe_format/dex.rb +13 -3
- data/metasm/exe_format/elf.rb +12 -2
- data/metasm/exe_format/elf_decode.rb +59 -1
- data/metasm/exe_format/main.rb +2 -0
- data/metasm/exe_format/mz.rb +1 -0
- data/metasm/exe_format/pe.rb +25 -3
- data/metasm/exe_format/wasm.rb +402 -0
- data/metasm/gui/dasm_decomp.rb +171 -95
- data/metasm/gui/dasm_graph.rb +61 -2
- data/metasm/gui/dasm_hex.rb +2 -2
- data/metasm/gui/dasm_main.rb +45 -19
- data/metasm/gui/debug.rb +13 -4
- data/metasm/gui/gtk.rb +12 -4
- data/metasm/main.rb +108 -103
- data/metasm/os/emulator.rb +175 -0
- data/metasm/os/main.rb +11 -6
- data/metasm/parse.rb +23 -12
- data/metasm/parse_c.rb +189 -135
- data/metasm/preprocessor.rb +16 -1
- data/misc/openrisc-parser.rb +79 -0
- data/samples/dasm-plugins/scanxrefs.rb +6 -4
- data/samples/dasm-plugins/selfmodify.rb +8 -8
- data/samples/dbg-plugins/trace_func.rb +1 -1
- data/samples/disassemble-gui.rb +14 -3
- data/samples/emubios.rb +251 -0
- data/samples/emudbg.rb +127 -0
- data/samples/lindebug.rb +79 -78
- data/samples/metasm-shell.rb +8 -8
- data/tests/all.rb +1 -1
- data/tests/expression.rb +2 -0
- data/tests/graph_layout.rb +1 -1
- data/tests/ia32.rb +1 -0
- data/tests/mips.rb +1 -1
- data/tests/preprocessor.rb +18 -0
- metadata +124 -6
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
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/os/main'
|
|
8
|
+
require 'metasm/debug'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
# a VirtualString mapping the segments from a disassembler
|
|
12
|
+
class VirtualMemoryDasm < VirtualString
|
|
13
|
+
attr_accessor :disassembler
|
|
14
|
+
|
|
15
|
+
def initialize(disassembler, addr_start = 0, length = nil)
|
|
16
|
+
@disassembler = disassembler
|
|
17
|
+
length ||= disassembler.sections.map { |k, v| k.kind_of?(Integer) ? k + v.length : 0 }.max
|
|
18
|
+
super(addr_start, length)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def dup(addr = @addr_start, len = @length)
|
|
22
|
+
self.class.new(@disassembler, addr, len)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# reads an aligned page from the file, at file offset addr
|
|
26
|
+
def read_range(addr, len=@pagelength)
|
|
27
|
+
@disassembler.read_raw_data(addr, len)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def page_invalid?(addr)
|
|
31
|
+
!@disassembler.get_section_at(addr)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# overwrite a section of the file
|
|
35
|
+
def rewrite_at(addr, data)
|
|
36
|
+
if e = @disassembler.get_section_at(addr)
|
|
37
|
+
e[0].data[addr - e[1], data.length] = data
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def decode_imm(addr, len, cpu)
|
|
42
|
+
@disassembler.decode_int(addr, len)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# this class implements a virtual debugger over an emulated cpu (based on cpu#get_backtrace_binding)
|
|
47
|
+
class EmuDebugger < Debugger
|
|
48
|
+
attr_accessor :ctx
|
|
49
|
+
# lambda called everytime we emulate a di
|
|
50
|
+
# receives the di as parameter
|
|
51
|
+
# if it returns nil, the di is emulated as usual, if it returns true no further processing is done for this di
|
|
52
|
+
# dont forget to handle reg_pc !
|
|
53
|
+
attr_accessor :callback_emulate_di
|
|
54
|
+
# lambda called everytime we cannot find an instruction at the current PC
|
|
55
|
+
# return true if the context was fixed
|
|
56
|
+
attr_accessor :callback_unknown_pc
|
|
57
|
+
|
|
58
|
+
def initialize(disassembler)
|
|
59
|
+
@pid = @tid = 0
|
|
60
|
+
attach(disassembler)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def shortname; 'emudbg'; end
|
|
64
|
+
|
|
65
|
+
def attach(disassembler)
|
|
66
|
+
@memory = VirtualMemoryDasm.new(disassembler)
|
|
67
|
+
@cpu = disassembler.cpu
|
|
68
|
+
@disassembler = disassembler
|
|
69
|
+
@ctx = {}
|
|
70
|
+
@state = :stopped
|
|
71
|
+
@symbols = disassembler.prog_binding.invert
|
|
72
|
+
@symbols_len = @symbols.keys.inject({}) { |h, s| h.update s => 1 }
|
|
73
|
+
@modulemap = {}
|
|
74
|
+
@breakpoint = {}
|
|
75
|
+
@breakpoint_memory = {}
|
|
76
|
+
@breakpoint_thread = {}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def detach
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def initialize_disassembler
|
|
83
|
+
end
|
|
84
|
+
def initialize_cpu
|
|
85
|
+
end
|
|
86
|
+
def initialize_memory
|
|
87
|
+
end
|
|
88
|
+
def invalidate
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def memory_get_page(addr, len)
|
|
92
|
+
@memory[addr, len]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_reg_value(r)
|
|
96
|
+
if r.to_s =~ /flags?_(.+)/i
|
|
97
|
+
f = $1.downcase.to_sym
|
|
98
|
+
get_flag_value(f)
|
|
99
|
+
else
|
|
100
|
+
@ctx[r] || 0
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def set_reg_value(r, v)
|
|
105
|
+
if r.to_s =~ /flags?_(.+)/i
|
|
106
|
+
f = $1.downcase.to_sym
|
|
107
|
+
set_flag_value(f, v)
|
|
108
|
+
else
|
|
109
|
+
@ctx[r] = v
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def do_check_target
|
|
114
|
+
true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def do_wait_target
|
|
118
|
+
true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def do_continue
|
|
122
|
+
while not @breakpoint[pc] and do_singlestep # TODO check bp#enabled
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def do_enable_bp(b) # no need to actually patch code in memory
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def do_disable_bp(b)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def do_singlestep
|
|
133
|
+
di = @disassembler.di_at(pc)
|
|
134
|
+
if not di
|
|
135
|
+
@disassembler.disassemble_fast(pc)
|
|
136
|
+
di = @disassembler.di_at(pc)
|
|
137
|
+
end
|
|
138
|
+
if not di
|
|
139
|
+
if callback_unknown_pc and callback_unknown_pc.call()
|
|
140
|
+
return true
|
|
141
|
+
end
|
|
142
|
+
return
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
if callback_emulate_di
|
|
146
|
+
ret = callback_emulate_di.call(di)
|
|
147
|
+
return true if ret
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
return if di.opcode.props[:stopexec] and not di.opcode.props[:setip]
|
|
151
|
+
|
|
152
|
+
# 2-pass to respect binding atomicity
|
|
153
|
+
fbd = @disassembler.get_fwdemu_binding(di, register_pc, self)
|
|
154
|
+
|
|
155
|
+
fbd.map { |k, v|
|
|
156
|
+
if k.kind_of?(Indirection)
|
|
157
|
+
k = Indirection.new(resolve(k.pointer), k.len, k.origin)
|
|
158
|
+
end
|
|
159
|
+
[k, resolve(v)]
|
|
160
|
+
}.each { |k, v|
|
|
161
|
+
case k
|
|
162
|
+
when Indirection
|
|
163
|
+
v = v & ((1 << (k.len*8)) - 1)
|
|
164
|
+
memory_write_int(k.pointer, v, k.len)
|
|
165
|
+
when Symbol
|
|
166
|
+
set_reg_value(k, v)
|
|
167
|
+
when /^dummy_metasm_/
|
|
168
|
+
else
|
|
169
|
+
puts "singlestep: badkey #{k.inspect} = #{v}"
|
|
170
|
+
end
|
|
171
|
+
}
|
|
172
|
+
true
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
data/metasm/os/main.rb
CHANGED
|
@@ -246,14 +246,14 @@ class VirtualString
|
|
|
246
246
|
def read_range(from, len)
|
|
247
247
|
from += @addr_start
|
|
248
248
|
if not len
|
|
249
|
-
base, page = cache_get_page(from)
|
|
250
|
-
page[from - base]
|
|
249
|
+
base, page, inval = cache_get_page(from)
|
|
250
|
+
page[from - base] if not inval
|
|
251
251
|
elsif len <= @pagelength
|
|
252
|
-
base, page = cache_get_page(from)
|
|
253
|
-
s = page[from - base, len]
|
|
252
|
+
base, page, inval = cache_get_page(from)
|
|
253
|
+
s = page[from - base, len] if not inval
|
|
254
254
|
if from+len-base > @pagelength # request crosses a page boundary
|
|
255
|
-
base, page = cache_get_page(from+len)
|
|
256
|
-
s << page[0, from+len-base]
|
|
255
|
+
base, page, inval = cache_get_page(from+len)
|
|
256
|
+
s << page[0, from+len-base] if s and not inval
|
|
257
257
|
end
|
|
258
258
|
s
|
|
259
259
|
else
|
|
@@ -272,6 +272,11 @@ class VirtualString
|
|
|
272
272
|
# overwrites a section of the original data
|
|
273
273
|
#def rewrite_at(addr, content)
|
|
274
274
|
#end
|
|
275
|
+
|
|
276
|
+
# decode an integer
|
|
277
|
+
def decode_imm(addr, len, cpu)
|
|
278
|
+
Expression.decode_imm(self, len, cpu, addr)
|
|
279
|
+
end
|
|
275
280
|
end
|
|
276
281
|
|
|
277
282
|
# on-demand reading of a file
|
data/metasm/parse.rb
CHANGED
|
@@ -26,18 +26,10 @@ class CPU
|
|
|
26
26
|
while tok = lexer.readtok and parse_prefix(i, tok.raw)
|
|
27
27
|
lexer.skip_space_eol
|
|
28
28
|
end
|
|
29
|
-
return if not tok
|
|
30
|
-
|
|
31
|
-
# allow '.' in opcode name
|
|
32
|
-
tok = tok.dup
|
|
33
|
-
while ntok = lexer.nexttok and ntok.type == :punct and ntok.raw == '.'
|
|
34
|
-
tok.raw << lexer.readtok.raw
|
|
35
|
-
ntok = lexer.readtok
|
|
36
|
-
raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
|
|
37
|
-
tok.raw << ntok.raw
|
|
38
|
-
end
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
lexer.unreadtok(tok)
|
|
31
|
+
tok = parse_instruction_mnemonic(lexer)
|
|
32
|
+
return if not tok
|
|
41
33
|
|
|
42
34
|
i.opname = tok.raw
|
|
43
35
|
i.backtrace = tok.backtrace
|
|
@@ -63,6 +55,23 @@ class CPU
|
|
|
63
55
|
i
|
|
64
56
|
end
|
|
65
57
|
|
|
58
|
+
# return a lexer token with an instruction mnemonic in #raw
|
|
59
|
+
# allows '.' in opcode name
|
|
60
|
+
# return nil at eof
|
|
61
|
+
def parse_instruction_mnemonic(lexer)
|
|
62
|
+
return if not tok = lexer.readtok
|
|
63
|
+
tok = tok.dup
|
|
64
|
+
while ntok = lexer.nexttok and ntok.type == :punct and ntok.raw == '.'
|
|
65
|
+
tok.raw << lexer.readtok.raw
|
|
66
|
+
ntok = lexer.readtok
|
|
67
|
+
raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
|
|
68
|
+
tok.raw << ntok.raw
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
raise tok, 'invalid opcode' if not opcode_list_byname[tok.raw]
|
|
72
|
+
tok
|
|
73
|
+
end
|
|
74
|
+
|
|
66
75
|
def parse_instruction_checkproto(i)
|
|
67
76
|
opcode_list_byname[i.opname].to_a.find { |o|
|
|
68
77
|
o.args.length == i.args.length and o.args.zip(i.args).all? { |f, a| parse_arg_valid?(o, f, a) }
|
|
@@ -421,7 +430,7 @@ class ExeFormat
|
|
|
421
430
|
@cursource << Padding.new(fillwith, tok.backtrace) << Offset.new(e, tok.backtrace)
|
|
422
431
|
|
|
423
432
|
else
|
|
424
|
-
@cpu.parse_parser_instruction(
|
|
433
|
+
@cpu.parse_parser_instruction(@lexer, tok)
|
|
425
434
|
end
|
|
426
435
|
end
|
|
427
436
|
|
|
@@ -746,6 +755,8 @@ class Expression
|
|
|
746
755
|
|
|
747
756
|
# for boolean operators, true is 1 (or anything != 0), false is 0
|
|
748
757
|
def parse(lexer)
|
|
758
|
+
lexer = Preprocessor.new(lexer) if lexer.kind_of?(::String)
|
|
759
|
+
|
|
749
760
|
opstack = []
|
|
750
761
|
stack = []
|
|
751
762
|
|
data/metasm/parse_c.rb
CHANGED
|
@@ -22,7 +22,17 @@ module C
|
|
|
22
22
|
__builtin_offsetof
|
|
23
23
|
].inject({}) { |h, w| h.update w => true }
|
|
24
24
|
|
|
25
|
+
module Misc
|
|
26
|
+
attr_accessor :misc
|
|
27
|
+
|
|
28
|
+
def with_misc(m)
|
|
29
|
+
@misc = m if m or misc
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
25
34
|
class Statement
|
|
35
|
+
include Misc
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
module Typed # allows quick testing whether an object is an CExpr or a Variable
|
|
@@ -114,6 +124,7 @@ module C
|
|
|
114
124
|
|
|
115
125
|
class Type
|
|
116
126
|
include Attributes
|
|
127
|
+
include Misc
|
|
117
128
|
attr_accessor :qualifier # const volatile
|
|
118
129
|
|
|
119
130
|
def pointer? ; false end
|
|
@@ -758,6 +769,7 @@ module C
|
|
|
758
769
|
class Variable
|
|
759
770
|
include Attributes
|
|
760
771
|
include Typed
|
|
772
|
+
include Misc
|
|
761
773
|
|
|
762
774
|
attr_accessor :type
|
|
763
775
|
attr_accessor :initializer # CExpr / Block (for Functions)
|
|
@@ -773,6 +785,8 @@ module C
|
|
|
773
785
|
# found in a block's Statements, used to know the initialization order
|
|
774
786
|
# eg { int i; i = 4; struct foo { int k; } toto = {i}; }
|
|
775
787
|
class Declaration
|
|
788
|
+
include Misc
|
|
789
|
+
|
|
776
790
|
attr_accessor :var
|
|
777
791
|
def initialize(var)
|
|
778
792
|
@var = var
|
|
@@ -946,8 +960,8 @@ module C
|
|
|
946
960
|
raise ftok, 'unterminated asm block' if not tok = parser.lexer.readtok
|
|
947
961
|
break if tok.type == :punct and tok.raw == '}'
|
|
948
962
|
case tok.type
|
|
949
|
-
when :space; body << ' '
|
|
950
|
-
when :eol; body << "\n"
|
|
963
|
+
when :space; body << ' ' unless body.empty?
|
|
964
|
+
when :eol; body << "\n" unless body.empty?
|
|
951
965
|
when :punct; body << tok.raw
|
|
952
966
|
when :quoted; body << CExpression.string_inspect(tok.value) # concat adjacent c strings
|
|
953
967
|
when :string
|
|
@@ -1056,12 +1070,15 @@ module C
|
|
|
1056
1070
|
class CExpression < Statement
|
|
1057
1071
|
include Typed
|
|
1058
1072
|
|
|
1073
|
+
AssignOp = [:'=', :'+=', :'-=', :'*=', :'/=', :'%=', :'^=', :'&=', :'|=', :'>>=', :'<<=', :'++', :'--']
|
|
1074
|
+
|
|
1059
1075
|
# may be :,, :., :'->', :funcall (function, [arglist]), :[] (array indexing), nil (cast)
|
|
1060
1076
|
attr_accessor :op
|
|
1061
1077
|
# nil/CExpr/Variable/Label/::String( = :quoted/struct member name)/::Integer/::Float/Block
|
|
1062
1078
|
attr_accessor :lexpr, :rexpr
|
|
1063
1079
|
# a Type
|
|
1064
1080
|
attr_accessor :type
|
|
1081
|
+
|
|
1065
1082
|
def initialize(l, o, r, t)
|
|
1066
1083
|
raise "invalid CExpr #{[l, o, r, t].inspect}" if (o and not o.kind_of? ::Symbol) or not t.kind_of? Type
|
|
1067
1084
|
@lexpr, @op, @rexpr, @type = l, o, r, t
|
|
@@ -1092,7 +1109,7 @@ module C
|
|
|
1092
1109
|
# sub-arrays in args are to be passed to self.[] recursively (syntaxic sugar)
|
|
1093
1110
|
splat = lambda { |e| e.kind_of?(::Array) ? self[*e] : e }
|
|
1094
1111
|
|
|
1095
|
-
args.shift while args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
|
|
1112
|
+
args.shift while args.length > 0 and args.first == nil # CExpr[nil, :&, bla] => CExpr[:&, bla]
|
|
1096
1113
|
|
|
1097
1114
|
case args.length
|
|
1098
1115
|
when 4
|
|
@@ -1114,9 +1131,9 @@ module C
|
|
|
1114
1131
|
|
|
1115
1132
|
case op
|
|
1116
1133
|
when :funcall
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1134
|
+
rt = x1.type.untypedef
|
|
1135
|
+
rt = rt.type.untypedef if rt.pointer?
|
|
1136
|
+
new(x1, op, x2, rt.type)
|
|
1120
1137
|
when :[]; new(x1, op, x2, x1.type.untypedef.type)
|
|
1121
1138
|
when :+; new(x1, op, x2, (x2.type.pointer? ? x2.type : x1.type))
|
|
1122
1139
|
when :-; new(x1, op, x2, ((x1.type.pointer? and x2.type.pointer?) ? BaseType.new(:int) : x2.type.pointer? ? x2.type : x1.type))
|
|
@@ -3176,7 +3193,7 @@ EOH
|
|
|
3176
3193
|
end
|
|
3177
3194
|
|
|
3178
3195
|
# parse a given String as an AllocCStruct
|
|
3179
|
-
# offset is an
|
|
3196
|
+
# offset is an optional offset from the string start
|
|
3180
3197
|
# modification to the structure will modify the underlying string
|
|
3181
3198
|
def decode_c_struct(structname, str, offset=0)
|
|
3182
3199
|
struct = find_c_struct(structname)
|
|
@@ -3321,19 +3338,49 @@ EOH
|
|
|
3321
3338
|
end
|
|
3322
3339
|
end
|
|
3323
3340
|
|
|
3341
|
+
# used to render a C to a source string, while keeping the information of which each character comes from which C object
|
|
3342
|
+
class CRenderString < ::String
|
|
3343
|
+
attr_accessor :my_c # default C obj with which raw characters are associated
|
|
3344
|
+
# hash offset => C::Statement, means bytes from this offset to the next entry comes from rendering this C object
|
|
3345
|
+
def c_at_offset
|
|
3346
|
+
@c_at_offset ||= {}
|
|
3347
|
+
end
|
|
3348
|
+
|
|
3349
|
+
# concatenate another CRenderString: merge @c_at_offset
|
|
3350
|
+
def <<(o)
|
|
3351
|
+
if o.kind_of?(self.class)
|
|
3352
|
+
o.c_at_offset.each { |k, v|
|
|
3353
|
+
c_at_offset[length+k] ||= v
|
|
3354
|
+
}
|
|
3355
|
+
elsif my_c
|
|
3356
|
+
c_at_offset[length] ||= my_c
|
|
3357
|
+
end
|
|
3358
|
+
super(o)
|
|
3359
|
+
end
|
|
3360
|
+
|
|
3361
|
+
def initialize(*a)
|
|
3362
|
+
if cs = a.grep(Statement).first
|
|
3363
|
+
a -= [cs]
|
|
3364
|
+
@my_c = cs
|
|
3365
|
+
c_at_offset[0] = cs
|
|
3366
|
+
end
|
|
3367
|
+
super(*a)
|
|
3368
|
+
end
|
|
3369
|
+
end
|
|
3370
|
+
|
|
3324
3371
|
class Statement
|
|
3325
|
-
def self.dump(e, scope, r=[
|
|
3372
|
+
def self.dump(e, scope, r=[CRenderString.new], dep=[])
|
|
3326
3373
|
case e
|
|
3327
3374
|
when nil; r.last << ';'
|
|
3328
3375
|
when Block
|
|
3329
3376
|
r.last << ' ' if not r.last.empty?
|
|
3330
3377
|
r.last << '{'
|
|
3331
|
-
tr, dep = e.dump(scope, [
|
|
3378
|
+
tr, dep = e.dump(scope, [CRenderString.new], dep)
|
|
3332
3379
|
tr.pop if tr.last.empty?
|
|
3333
3380
|
r.concat tr.map { |s| Case.dump_indent(s) }
|
|
3334
|
-
(r.last[-1] == ?{ ? r.last : r) << '}'
|
|
3381
|
+
(r.last[-1] == ?{ ? r.last : r) << CRenderString.new('}')
|
|
3335
3382
|
else
|
|
3336
|
-
tr, dep = e.dump(scope, [
|
|
3383
|
+
tr, dep = e.dump(scope, [CRenderString.new], dep)
|
|
3337
3384
|
r.concat tr.map { |s| Case.dump_indent(s) }
|
|
3338
3385
|
end
|
|
3339
3386
|
[r, dep]
|
|
@@ -3348,7 +3395,7 @@ EOH
|
|
|
3348
3395
|
def to_s() dump(nil)[0].join("\n") end
|
|
3349
3396
|
|
|
3350
3397
|
# return array of c source lines and array of dependencies (objects)
|
|
3351
|
-
def dump(scp, r=[
|
|
3398
|
+
def dump(scp, r=[CRenderString.new], dep=[])
|
|
3352
3399
|
mydefs = @symbol.values.grep(TypeDef) + @struct.values + anonymous_enums.to_a
|
|
3353
3400
|
todo_rndr = {}
|
|
3354
3401
|
todo_deps = {}
|
|
@@ -3360,7 +3407,7 @@ EOH
|
|
|
3360
3407
|
[r, dep]
|
|
3361
3408
|
end
|
|
3362
3409
|
|
|
3363
|
-
def dump_reorder(mydefs, todo_rndr, todo_deps, r=[
|
|
3410
|
+
def dump_reorder(mydefs, todo_rndr, todo_deps, r=[CRenderString.new], dep=[])
|
|
3364
3411
|
val = todo_deps.values.flatten.uniq
|
|
3365
3412
|
dep |= val
|
|
3366
3413
|
dep -= mydefs | todo_deps.keys
|
|
@@ -3375,6 +3422,7 @@ EOH
|
|
|
3375
3422
|
# predeclare structs involved in cyclic dependencies
|
|
3376
3423
|
dep_cycle = lambda { |ary|
|
|
3377
3424
|
# sexyness inside (c)
|
|
3425
|
+
# XXX 5 years later, i have no idea whats going on here
|
|
3378
3426
|
deps = todo_deps[ary.last]
|
|
3379
3427
|
if deps.include? ary.first; ary
|
|
3380
3428
|
elsif (deps-ary).find { |d| deps = dep_cycle[ary + [d]] }; deps
|
|
@@ -3384,7 +3432,7 @@ EOH
|
|
|
3384
3432
|
oldc = nil
|
|
3385
3433
|
while c = dep_cycle[[t]]
|
|
3386
3434
|
break if oldc == c
|
|
3387
|
-
r << "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};" if not oldc
|
|
3435
|
+
r << CRenderString.new(t, "#{t.kind_of?(Struct) ? 'struct' : 'union'} #{t.name};") if not oldc
|
|
3388
3436
|
oldc = c
|
|
3389
3437
|
c.each { |s|
|
|
3390
3438
|
# XXX struct z { struct a* }; struct a { void (*foo)(struct z); };
|
|
@@ -3403,7 +3451,7 @@ EOH
|
|
|
3403
3451
|
end
|
|
3404
3452
|
todo_now.sort_by { |k| k.name || '0' }.each { |k|
|
|
3405
3453
|
if k.kind_of? Variable and k.type.kind_of? Function and k.initializer
|
|
3406
|
-
r <<
|
|
3454
|
+
r << CRenderString.new
|
|
3407
3455
|
r.concat todo_rndr.delete(k)
|
|
3408
3456
|
else
|
|
3409
3457
|
r.pop if r.last == ''
|
|
@@ -3413,12 +3461,12 @@ EOH
|
|
|
3413
3461
|
todo_deps.delete k
|
|
3414
3462
|
}
|
|
3415
3463
|
todo_deps.each_key { |k| todo_deps[k] -= todo_now }
|
|
3416
|
-
r <<
|
|
3464
|
+
r << CRenderString.new << CRenderString.new << CRenderString.new
|
|
3417
3465
|
end
|
|
3418
3466
|
|
|
3419
3467
|
@statements.each { |s|
|
|
3420
|
-
r <<
|
|
3421
|
-
if s.kind_of?
|
|
3468
|
+
r << CRenderString.new if not r.last.empty?
|
|
3469
|
+
if s.kind_of?(Block)
|
|
3422
3470
|
r, dep = Statement.dump(s, self, r, dep)
|
|
3423
3471
|
else
|
|
3424
3472
|
r, dep = s.dump(self, r, dep)
|
|
@@ -3429,10 +3477,10 @@ EOH
|
|
|
3429
3477
|
end
|
|
3430
3478
|
end
|
|
3431
3479
|
class Declaration
|
|
3432
|
-
def dump(scope, r=[
|
|
3433
|
-
tr, dep = @var.dump_def(scope, [
|
|
3434
|
-
if @var.kind_of?
|
|
3435
|
-
r <<
|
|
3480
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3481
|
+
tr, dep = @var.dump_def(scope, [CRenderString.new], dep)
|
|
3482
|
+
if @var.kind_of?(Variable) and @var.type.kind_of?(Function) and @var.initializer
|
|
3483
|
+
r << CRenderString.new
|
|
3436
3484
|
r.concat tr
|
|
3437
3485
|
else
|
|
3438
3486
|
r.pop if r.last == ''
|
|
@@ -3461,14 +3509,14 @@ EOH
|
|
|
3461
3509
|
end
|
|
3462
3510
|
end
|
|
3463
3511
|
class Variable
|
|
3464
|
-
def dump(scope, r=[
|
|
3512
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3465
3513
|
if name
|
|
3466
3514
|
dep |= [scope.symbol_ancestors[@name]]
|
|
3467
3515
|
r.last << @name
|
|
3468
3516
|
end
|
|
3469
3517
|
[r, dep]
|
|
3470
3518
|
end
|
|
3471
|
-
def dump_def(scope, r=[
|
|
3519
|
+
def dump_def(scope, r=[CRenderString.new], dep=[], skiptype=false)
|
|
3472
3520
|
# int a=1, b=2;
|
|
3473
3521
|
r.last << dump_attributes_pre
|
|
3474
3522
|
if not skiptype
|
|
@@ -3476,7 +3524,7 @@ EOH
|
|
|
3476
3524
|
r, dep = @type.base.dump(scope, r, dep)
|
|
3477
3525
|
r.last << ' ' if name
|
|
3478
3526
|
end
|
|
3479
|
-
r, dep = @type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
|
3527
|
+
r, dep = @type.dump_declarator([CRenderString.new(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
|
3480
3528
|
|
|
3481
3529
|
if initializer
|
|
3482
3530
|
r.last << ' = ' if not @type.kind_of?(Function)
|
|
@@ -3490,7 +3538,7 @@ EOH
|
|
|
3490
3538
|
end
|
|
3491
3539
|
end
|
|
3492
3540
|
class Type
|
|
3493
|
-
def dump_initializer(init, scope, r=[
|
|
3541
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
|
3494
3542
|
case init
|
|
3495
3543
|
when ::Numeric
|
|
3496
3544
|
r.last << init.to_s
|
|
@@ -3502,9 +3550,9 @@ EOH
|
|
|
3502
3550
|
end
|
|
3503
3551
|
end
|
|
3504
3552
|
|
|
3505
|
-
def dump_declarator(decl, scope, r=[
|
|
3553
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
|
3506
3554
|
r.last << decl.shift
|
|
3507
|
-
r.concat decl
|
|
3555
|
+
r.concat decl.map { |d| CRenderString.new << d }
|
|
3508
3556
|
[r, dep]
|
|
3509
3557
|
end
|
|
3510
3558
|
|
|
@@ -3512,11 +3560,11 @@ EOH
|
|
|
3512
3560
|
dump(*a)
|
|
3513
3561
|
end
|
|
3514
3562
|
|
|
3515
|
-
def dump_cast(scope, r=[
|
|
3563
|
+
def dump_cast(scope, r=[CRenderString.new], dep=[])
|
|
3516
3564
|
r.last << '('
|
|
3517
3565
|
r.last << dump_attributes_pre if not kind_of? TypeDef
|
|
3518
3566
|
r, dep = base.dump(scope, r, dep)
|
|
3519
|
-
r, dep = dump_declarator([kind_of?(TypeDef) ? '' : dump_attributes], scope, r, dep)
|
|
3567
|
+
r, dep = dump_declarator([CRenderString.new(kind_of?(TypeDef) ? '' : dump_attributes)], scope, r, dep)
|
|
3520
3568
|
r.last << ')'
|
|
3521
3569
|
[r, dep]
|
|
3522
3570
|
end
|
|
@@ -3526,28 +3574,29 @@ EOH
|
|
|
3526
3574
|
end
|
|
3527
3575
|
end
|
|
3528
3576
|
class Pointer
|
|
3529
|
-
def dump_declarator(decl, scope, r=[
|
|
3577
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
|
3530
3578
|
d = decl[0]
|
|
3531
|
-
decl[0] =
|
|
3579
|
+
decl[0] = CRenderString.new
|
|
3580
|
+
decl[0] << '*'
|
|
3532
3581
|
decl[0] << ' ' << @qualifier.map { |q| q.to_s }.join(' ') << ' ' if qualifier
|
|
3533
3582
|
decl[0] << d
|
|
3534
|
-
if @type.kind_of?
|
|
3535
|
-
decl[0] = '(' << decl[0]
|
|
3583
|
+
if @type.kind_of?(Function) or @type.kind_of?(Array)
|
|
3584
|
+
decl[0] = CRenderString.new << '(' << decl[0]
|
|
3536
3585
|
decl.last << ')'
|
|
3537
3586
|
end
|
|
3538
3587
|
@type.dump_declarator(decl, scope, r, dep)
|
|
3539
3588
|
end
|
|
3540
3589
|
end
|
|
3541
3590
|
class Array
|
|
3542
|
-
def dump_declarator(decl, scope, r=[
|
|
3591
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
|
3543
3592
|
decl.last << '()' if decl.last.empty?
|
|
3544
3593
|
decl.last << '['
|
|
3545
3594
|
decl, dep = CExpression.dump(@length, scope, decl, dep) if length
|
|
3546
3595
|
decl.last << ']'
|
|
3547
3596
|
@type.dump_declarator(decl, scope, r, dep)
|
|
3548
3597
|
end
|
|
3549
|
-
def dump_initializer(init, scope, r=[
|
|
3550
|
-
return super(init, scope, r, dep) if not init.kind_of?
|
|
3598
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
|
3599
|
+
return super(init, scope, r, dep) if not init.kind_of?(::Array)
|
|
3551
3600
|
r.last << '{ '
|
|
3552
3601
|
showname = false
|
|
3553
3602
|
init.each_with_index { |v, i|
|
|
@@ -3556,21 +3605,21 @@ EOH
|
|
|
3556
3605
|
next
|
|
3557
3606
|
end
|
|
3558
3607
|
r.last << ', ' if r.last[-2, 2] != '{ '
|
|
3559
|
-
rt = [
|
|
3608
|
+
rt = [CRenderString.new]
|
|
3560
3609
|
if showname
|
|
3561
3610
|
showname = false
|
|
3562
|
-
rt << "[#{i}] = "
|
|
3611
|
+
rt << CRenderString.new("[#{i}] = ")
|
|
3563
3612
|
end
|
|
3564
3613
|
rt, dep = @type.dump_initializer(v, scope, rt, dep)
|
|
3565
3614
|
r.last << rt.shift
|
|
3566
|
-
r.concat rt.map { |s| "\t" << s }
|
|
3615
|
+
r.concat rt.map { |s| CRenderString.new << "\t" << s }
|
|
3567
3616
|
}
|
|
3568
3617
|
r.last << ' }'
|
|
3569
3618
|
[r, dep]
|
|
3570
3619
|
end
|
|
3571
3620
|
end
|
|
3572
3621
|
class Function
|
|
3573
|
-
def dump_declarator(decl, scope, r=[
|
|
3622
|
+
def dump_declarator(decl, scope, r=[CRenderString.new], dep=[])
|
|
3574
3623
|
decl.last << '()' if decl.last.empty?
|
|
3575
3624
|
decl.last << '('
|
|
3576
3625
|
if args
|
|
@@ -3589,12 +3638,12 @@ EOH
|
|
|
3589
3638
|
@type.dump_declarator(decl, scope, r, dep)
|
|
3590
3639
|
end
|
|
3591
3640
|
|
|
3592
|
-
def dump_initializer(init, scope, r=[
|
|
3593
|
-
Statement.dump(init, scope, r <<
|
|
3641
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
|
3642
|
+
Statement.dump(init, scope, r << CRenderString.new, dep)
|
|
3594
3643
|
end
|
|
3595
3644
|
end
|
|
3596
3645
|
class BaseType
|
|
3597
|
-
def dump(scope, r=[
|
|
3646
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3598
3647
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
|
3599
3648
|
r.last << @specifier.to_s << ' ' if specifier and @name != :ptr
|
|
3600
3649
|
r.last << case @name
|
|
@@ -3607,27 +3656,27 @@ EOH
|
|
|
3607
3656
|
end
|
|
3608
3657
|
end
|
|
3609
3658
|
class TypeDef
|
|
3610
|
-
def dump(scope, r=[
|
|
3659
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3611
3660
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
|
3612
3661
|
r.last << @name
|
|
3613
3662
|
dep |= [scope.symbol_ancestors[@name]]
|
|
3614
3663
|
[r, dep]
|
|
3615
3664
|
end
|
|
3616
3665
|
|
|
3617
|
-
def dump_def(scope, r=[
|
|
3666
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
|
3618
3667
|
r.last << 'typedef '
|
|
3619
3668
|
r.last << dump_attributes_pre
|
|
3620
3669
|
r, dep = @type.base.dump(scope, r, dep)
|
|
3621
3670
|
r.last << ' '
|
|
3622
|
-
@type.dump_declarator([(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
|
3671
|
+
@type.dump_declarator([CRenderString.new(name ? @name.dup : '') << dump_attributes], scope, r, dep)
|
|
3623
3672
|
end
|
|
3624
3673
|
|
|
3625
|
-
def dump_initializer(init, scope, r=[
|
|
3674
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
|
3626
3675
|
@type.dump_initializer(init, scope, r, dep)
|
|
3627
3676
|
end
|
|
3628
3677
|
end
|
|
3629
3678
|
class Union
|
|
3630
|
-
def dump(scope, r=[
|
|
3679
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3631
3680
|
if name
|
|
3632
3681
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
|
3633
3682
|
r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1] << ' ' << @name
|
|
@@ -3638,26 +3687,26 @@ EOH
|
|
|
3638
3687
|
end
|
|
3639
3688
|
end
|
|
3640
3689
|
|
|
3641
|
-
def dump_def(scope, r=[
|
|
3642
|
-
r <<
|
|
3690
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
|
3691
|
+
r << CRenderString.new
|
|
3643
3692
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
|
3644
3693
|
r.last << self.class.name.downcase[/(?:.*::)?(.*)/, 1]
|
|
3645
3694
|
r.last << ' ' << @name if name
|
|
3646
3695
|
if members
|
|
3647
3696
|
r.last << ' {'
|
|
3648
3697
|
@members.each_with_index { |m,i|
|
|
3649
|
-
tr, dep = m.dump_def(scope, [
|
|
3698
|
+
tr, dep = m.dump_def(scope, [CRenderString.new], dep)
|
|
3650
3699
|
tr.last << ':' << @bits[i].to_s if bits and @bits[i]
|
|
3651
3700
|
tr.last << ';'
|
|
3652
|
-
r.concat tr.map { |s| "\t" << s }
|
|
3701
|
+
r.concat tr.map { |s| CRenderString.new << "\t" << s }
|
|
3653
3702
|
}
|
|
3654
|
-
r << '}'
|
|
3703
|
+
r << CRenderString.new('}')
|
|
3655
3704
|
end
|
|
3656
3705
|
r.last << dump_attributes
|
|
3657
3706
|
[r, dep]
|
|
3658
3707
|
end
|
|
3659
3708
|
|
|
3660
|
-
def dump_initializer(init, scope, r=[
|
|
3709
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
|
3661
3710
|
return super(init, scope, r, dep) if not init.kind_of? ::Array
|
|
3662
3711
|
r.last << '{ '
|
|
3663
3712
|
showname = false
|
|
@@ -3667,21 +3716,21 @@ EOH
|
|
|
3667
3716
|
next
|
|
3668
3717
|
end
|
|
3669
3718
|
r.last << ', ' if r.last[-2, 2] != '{ '
|
|
3670
|
-
rt = [
|
|
3719
|
+
rt = [CRenderString.new]
|
|
3671
3720
|
if showname
|
|
3672
3721
|
showname = false
|
|
3673
3722
|
rt << ".#{m.name} = "
|
|
3674
3723
|
end
|
|
3675
3724
|
rt, dep = m.type.dump_initializer(i, scope, rt, dep)
|
|
3676
3725
|
r.last << rt.shift
|
|
3677
|
-
r.concat rt.map { |s| "\t" << s }
|
|
3726
|
+
r.concat rt.map { |s| CRenderString.new << "\t" << s }
|
|
3678
3727
|
}
|
|
3679
3728
|
r.last << ' }'
|
|
3680
3729
|
[r, dep]
|
|
3681
3730
|
end
|
|
3682
3731
|
end
|
|
3683
3732
|
class Struct
|
|
3684
|
-
def dump_def(scope, r=[
|
|
3733
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
|
3685
3734
|
if pack
|
|
3686
3735
|
r, dep = super(scope, r, dep)
|
|
3687
3736
|
r.last <<
|
|
@@ -3695,7 +3744,7 @@ EOH
|
|
|
3695
3744
|
end
|
|
3696
3745
|
end
|
|
3697
3746
|
class Enum
|
|
3698
|
-
def dump(scope, r=[
|
|
3747
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3699
3748
|
if name
|
|
3700
3749
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
|
3701
3750
|
r.last << 'enum ' << @name
|
|
@@ -3706,7 +3755,7 @@ EOH
|
|
|
3706
3755
|
end
|
|
3707
3756
|
end
|
|
3708
3757
|
|
|
3709
|
-
def dump_def(scope, r=[
|
|
3758
|
+
def dump_def(scope, r=[CRenderString.new], dep=[])
|
|
3710
3759
|
r.last << @qualifier.map { |q| q.to_s << ' ' }.join if qualifier
|
|
3711
3760
|
r.last << 'enum'
|
|
3712
3761
|
r.last << ' ' << @name if name
|
|
@@ -3726,7 +3775,7 @@ EOH
|
|
|
3726
3775
|
[r, dep]
|
|
3727
3776
|
end
|
|
3728
3777
|
|
|
3729
|
-
def dump_initializer(init, scope, r=[
|
|
3778
|
+
def dump_initializer(init, scope, r=[CRenderString.new], dep=[])
|
|
3730
3779
|
if members and (
|
|
3731
3780
|
k = @members.index(init) or
|
|
3732
3781
|
(init.kind_of? CExpression and not init.op and k = @members.index(init.rexpr))
|
|
@@ -3739,14 +3788,14 @@ EOH
|
|
|
3739
3788
|
end
|
|
3740
3789
|
end
|
|
3741
3790
|
class If
|
|
3742
|
-
def dump(scope, r=[
|
|
3743
|
-
r.last << 'if ('
|
|
3791
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3792
|
+
r.last << CRenderString.new(self, 'if (')
|
|
3744
3793
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
|
3745
3794
|
r.last << ')'
|
|
3746
3795
|
r, dep = Statement.dump(@bthen, scope, r, dep)
|
|
3747
3796
|
if belse
|
|
3748
|
-
@bthen.kind_of?(Block) ? (r.last << ' else') : (r << 'else')
|
|
3749
|
-
if @belse.kind_of?
|
|
3797
|
+
@bthen.kind_of?(Block) ? (r.last << CRenderString.new(' else')) : (r << CRenderString.new(self, 'else'))
|
|
3798
|
+
if @belse.kind_of?(If)
|
|
3750
3799
|
# skip indent
|
|
3751
3800
|
r.last << ' '
|
|
3752
3801
|
r, dep = @belse.dump(scope, r, dep)
|
|
@@ -3758,9 +3807,9 @@ EOH
|
|
|
3758
3807
|
end
|
|
3759
3808
|
end
|
|
3760
3809
|
class For
|
|
3761
|
-
def dump(scope, r=[
|
|
3762
|
-
r.last << 'for ('
|
|
3763
|
-
if @init.kind_of?
|
|
3810
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3811
|
+
r.last << CRenderString.new(self, 'for (')
|
|
3812
|
+
if @init.kind_of?(Block)
|
|
3764
3813
|
scope = @init
|
|
3765
3814
|
skiptype = false
|
|
3766
3815
|
@init.symbol.each_value { |s|
|
|
@@ -3784,56 +3833,57 @@ EOH
|
|
|
3784
3833
|
end
|
|
3785
3834
|
end
|
|
3786
3835
|
class While
|
|
3787
|
-
def dump(scope, r=[
|
|
3788
|
-
r.last << 'while ('
|
|
3836
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3837
|
+
r.last << CRenderString.new(self, 'while (')
|
|
3789
3838
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
|
3790
3839
|
r.last << ')'
|
|
3791
3840
|
Statement.dump(@body, scope, r, dep)
|
|
3792
3841
|
end
|
|
3793
3842
|
end
|
|
3794
3843
|
class DoWhile
|
|
3795
|
-
def dump(scope, r=[
|
|
3796
|
-
r.last << 'do'
|
|
3844
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3845
|
+
r.last << CRenderString.new(self, 'do')
|
|
3797
3846
|
r, dep = Statement.dump(@body, scope, r, dep)
|
|
3798
|
-
|
|
3847
|
+
r << CRenderString.new if not @body.kind_of?(Block)
|
|
3848
|
+
r.last << CRenderString.new(self, ' while (')
|
|
3799
3849
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
|
3800
3850
|
r.last << ');'
|
|
3801
3851
|
[r, dep]
|
|
3802
3852
|
end
|
|
3803
3853
|
end
|
|
3804
3854
|
class Switch
|
|
3805
|
-
def dump(scope, r=[
|
|
3806
|
-
r.last << 'switch ('
|
|
3855
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3856
|
+
r.last << CRenderString.new(self, 'switch (')
|
|
3807
3857
|
r, dep = CExpression.dump(@test, scope, r, dep)
|
|
3808
3858
|
r.last << ')'
|
|
3809
|
-
r.last << ' {' if @body.kind_of?
|
|
3810
|
-
tr, dep = @body.dump(scope, [
|
|
3859
|
+
r.last << ' {' if @body.kind_of?(Block)
|
|
3860
|
+
tr, dep = @body.dump(scope, [CRenderString.new], dep)
|
|
3811
3861
|
r.concat tr.map { |s| Case.dump_indent(s, true) }
|
|
3812
|
-
r << '}' if @body.kind_of? Block
|
|
3862
|
+
r << CRenderString.new('}') if @body.kind_of? Block
|
|
3813
3863
|
[r, dep]
|
|
3814
3864
|
end
|
|
3815
3865
|
end
|
|
3816
3866
|
class Continue
|
|
3817
|
-
def dump(scope, r=[
|
|
3818
|
-
r.last << 'continue;'
|
|
3867
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3868
|
+
r.last << CRenderString.new(self, 'continue;')
|
|
3819
3869
|
[r, dep]
|
|
3820
3870
|
end
|
|
3821
3871
|
end
|
|
3822
3872
|
class Break
|
|
3823
|
-
def dump(scope, r=[
|
|
3824
|
-
r.last << 'break;'
|
|
3873
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3874
|
+
r.last << CRenderString.new(self, 'break;')
|
|
3825
3875
|
[r, dep]
|
|
3826
3876
|
end
|
|
3827
3877
|
end
|
|
3828
3878
|
class Goto
|
|
3829
|
-
def dump(scope, r=[
|
|
3830
|
-
r.last << "goto #@target;"
|
|
3879
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3880
|
+
r.last << CRenderString.new(self, "goto #@target;")
|
|
3831
3881
|
[r, dep]
|
|
3832
3882
|
end
|
|
3833
3883
|
end
|
|
3834
3884
|
class Return
|
|
3835
|
-
def dump(scope, r=[
|
|
3836
|
-
r.last << 'return '
|
|
3885
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3886
|
+
r.last << CRenderString.new(self, 'return ')
|
|
3837
3887
|
r, dep = CExpression.dump(@value, scope, r, dep)
|
|
3838
3888
|
r.last.chop! if r.last[-1] == ?\ # the space character
|
|
3839
3889
|
r.last << ';'
|
|
@@ -3841,12 +3891,12 @@ EOH
|
|
|
3841
3891
|
end
|
|
3842
3892
|
end
|
|
3843
3893
|
class Case
|
|
3844
|
-
def dump(scope, r=[
|
|
3894
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3845
3895
|
case @expr
|
|
3846
3896
|
when 'default'
|
|
3847
3897
|
r.last << @expr
|
|
3848
3898
|
else
|
|
3849
|
-
r.last << 'case '
|
|
3899
|
+
r.last << CRenderString.new(self, 'case ')
|
|
3850
3900
|
r, dep = CExpression.dump(@expr, scope, r, dep)
|
|
3851
3901
|
if exprup
|
|
3852
3902
|
r.last << ' ... '
|
|
@@ -3859,35 +3909,35 @@ EOH
|
|
|
3859
3909
|
|
|
3860
3910
|
def self.dump_indent(s, short=false)
|
|
3861
3911
|
case s
|
|
3862
|
-
when /^(case|default)\W/; (short ? ' ' : "\t") << s
|
|
3863
|
-
when /^\s+(case|default)\W/; "\t" << s
|
|
3912
|
+
when /^(case|default)\W/; CRenderString.new(short ? ' ' : "\t") << s
|
|
3913
|
+
when /^\s+(case|default)\W/; CRenderString.new("\t") << s
|
|
3864
3914
|
when /:$/; s
|
|
3865
|
-
else "\t" << s
|
|
3915
|
+
else CRenderString.new("\t") << s
|
|
3866
3916
|
end
|
|
3867
3917
|
end
|
|
3868
3918
|
end
|
|
3869
3919
|
class Label
|
|
3870
|
-
def dump(scope, r=[
|
|
3871
|
-
r.last << @name << ':'
|
|
3920
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3921
|
+
r.last << CRenderString.new(self, @name) << ':'
|
|
3872
3922
|
dump_inner(scope, r, dep)
|
|
3873
3923
|
end
|
|
3874
|
-
def dump_inner(scope, r=[
|
|
3924
|
+
def dump_inner(scope, r=[CRenderString.new], dep=[])
|
|
3875
3925
|
if not @statement; [r, dep]
|
|
3876
|
-
elsif @statement.kind_of?
|
|
3877
|
-
else @statement.dump(scope, r <<
|
|
3926
|
+
elsif @statement.kind_of?(Block); Statement.dump(@statement, scope, r, dep)
|
|
3927
|
+
else @statement.dump(scope, r << CRenderString.new, dep)
|
|
3878
3928
|
end
|
|
3879
3929
|
end
|
|
3880
3930
|
end
|
|
3881
3931
|
class Asm
|
|
3882
|
-
def dump(scope, r=[
|
|
3883
|
-
r.last << 'asm '
|
|
3932
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3933
|
+
r.last << CRenderString.new(self, 'asm ')
|
|
3884
3934
|
r.last << 'volatile ' if @volatile
|
|
3885
3935
|
r.last << '('
|
|
3886
|
-
r.last << CExpression.string_inspect(@body)
|
|
3936
|
+
r.last << CRenderString.new(self, CExpression.string_inspect(@body))
|
|
3887
3937
|
if @output or @input or @clobber
|
|
3888
3938
|
if @output and @output != []
|
|
3889
3939
|
# TODO
|
|
3890
|
-
r << ': /* todo */'
|
|
3940
|
+
r << CRenderString.new(': /* todo */')
|
|
3891
3941
|
elsif (@input and @input != []) or (@clobber and @clobber != [])
|
|
3892
3942
|
r.last << ' :'
|
|
3893
3943
|
end
|
|
@@ -3895,13 +3945,13 @@ EOH
|
|
|
3895
3945
|
if @input or @clobber
|
|
3896
3946
|
if @input and @input != []
|
|
3897
3947
|
# TODO
|
|
3898
|
-
r << ': /* todo */'
|
|
3948
|
+
r << CRenderString.new(': /* todo */')
|
|
3899
3949
|
elsif @clobber and @clobber != []
|
|
3900
3950
|
r.last << ' :'
|
|
3901
3951
|
end
|
|
3902
3952
|
end
|
|
3903
3953
|
if @clobber and @clobber != []
|
|
3904
|
-
r << (': ' << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
|
|
3954
|
+
r << (CRenderString.new(': ') << @clobber.map { |c| CExpression.string_inspect(c) }.join(', '))
|
|
3905
3955
|
end
|
|
3906
3956
|
r.last << ');'
|
|
3907
3957
|
[r, dep]
|
|
@@ -3910,18 +3960,20 @@ EOH
|
|
|
3910
3960
|
class CExpression
|
|
3911
3961
|
def self.string_inspect(s)
|
|
3912
3962
|
# keep all ascii printable except \ and "
|
|
3913
|
-
'"' + s.gsub(/[^ !\x23-\x5b\x5d-\x7e]/) { |o|
|
|
3963
|
+
'"' + s.gsub(/[^ !\x23-\x5b\x5d-\x7e]/) { |o|
|
|
3964
|
+
case hex = o.unpack('H*').first.downcase
|
|
3965
|
+
when '00'; '\\0'
|
|
3966
|
+
when '0a'; '\\n'
|
|
3967
|
+
when '0d'; '\\r'
|
|
3968
|
+
when '1b'; '\\e'
|
|
3969
|
+
when '22'; '\\"'
|
|
3970
|
+
when '5c'; '\\\\'
|
|
3971
|
+
else "\\x#{hex}"
|
|
3972
|
+
end
|
|
3973
|
+
} + '"'
|
|
3914
3974
|
end
|
|
3915
3975
|
|
|
3916
|
-
def self.dump(e, scope, r=[
|
|
3917
|
-
if $DEBUG
|
|
3918
|
-
brace = false
|
|
3919
|
-
case e
|
|
3920
|
-
when CExpression, Variable
|
|
3921
|
-
r, dep = e.type.dump_cast(scope, r, dep)
|
|
3922
|
-
end
|
|
3923
|
-
r.last << '('
|
|
3924
|
-
end
|
|
3976
|
+
def self.dump(e, scope, r=[CRenderString.new], dep=[], brace = false)
|
|
3925
3977
|
r, dep = \
|
|
3926
3978
|
case e
|
|
3927
3979
|
when ::Numeric; r.last << e.to_s ; [r, dep]
|
|
@@ -3931,20 +3983,22 @@ EOH
|
|
|
3931
3983
|
when nil; [r, dep]
|
|
3932
3984
|
else raise 'wtf?' + e.inspect
|
|
3933
3985
|
end
|
|
3934
|
-
if $DEBUG
|
|
3935
|
-
r.last << ')'
|
|
3936
|
-
end
|
|
3937
3986
|
[r, dep]
|
|
3938
3987
|
end
|
|
3939
3988
|
|
|
3940
|
-
def dump(scope, r=[
|
|
3989
|
+
def dump(scope, r=[CRenderString.new], dep=[])
|
|
3941
3990
|
r, dep = dump_inner(scope, r, dep)
|
|
3942
|
-
r.last << ';'
|
|
3991
|
+
r.last << CRenderString.new(self, ';')
|
|
3943
3992
|
[r, dep]
|
|
3944
3993
|
end
|
|
3945
3994
|
|
|
3946
|
-
def dump_inner(scope, r=[
|
|
3947
|
-
r.last <<
|
|
3995
|
+
def dump_inner(scope, r=[CRenderString.new], dep=[], brace = false)
|
|
3996
|
+
r.last << CRenderString.new(self)
|
|
3997
|
+
if misc and misc[:custom_display]
|
|
3998
|
+
r.last << misc[:custom_display]
|
|
3999
|
+
return [r, dep]
|
|
4000
|
+
end
|
|
4001
|
+
r.last << '(' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?(CExpression))
|
|
3948
4002
|
if not @lexpr
|
|
3949
4003
|
if not @op
|
|
3950
4004
|
case @rexpr
|
|
@@ -3960,7 +4014,7 @@ EOH
|
|
|
3960
4014
|
else
|
|
3961
4015
|
r.last << re.to_s
|
|
3962
4016
|
end
|
|
3963
|
-
if @type.kind_of?
|
|
4017
|
+
if @type.kind_of?(BaseType)
|
|
3964
4018
|
r.last << 'U' if @type.specifier == :unsigned
|
|
3965
4019
|
case @type.name
|
|
3966
4020
|
when :longlong, :__int64; r.last << 'LL'
|
|
@@ -3969,7 +4023,7 @@ EOH
|
|
|
3969
4023
|
end
|
|
3970
4024
|
end
|
|
3971
4025
|
when ::String
|
|
3972
|
-
r.last << 'L' if @type.kind_of?
|
|
4026
|
+
r.last << 'L' if @type.kind_of?(Pointer) and @type.type.kind_of?(BaseType) and @type.type.name == :short
|
|
3973
4027
|
r.last << CExpression.string_inspect(@rexpr)
|
|
3974
4028
|
when CExpression # cast
|
|
3975
4029
|
r, dep = @type.dump_cast(scope, r, dep)
|
|
@@ -3982,11 +4036,11 @@ EOH
|
|
|
3982
4036
|
r.last << ' )'
|
|
3983
4037
|
when Label
|
|
3984
4038
|
r.last << '&&' << @rexpr.name
|
|
3985
|
-
else raise "wtf? #{inspect}"
|
|
4039
|
+
else raise "(wtf? #{inspect})"
|
|
3986
4040
|
end
|
|
3987
4041
|
else
|
|
3988
4042
|
r.last << @op.to_s
|
|
3989
|
-
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?
|
|
4043
|
+
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?(C::CExpression) and @rexpr.lexpr))
|
|
3990
4044
|
end
|
|
3991
4045
|
elsif not @rexpr
|
|
3992
4046
|
r, dep = CExpression.dump(@lexpr, scope, r, dep)
|
|
@@ -3995,15 +4049,15 @@ EOH
|
|
|
3995
4049
|
case @op
|
|
3996
4050
|
when :'->', :'.'
|
|
3997
4051
|
r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
|
|
3998
|
-
r.last << @op.to_s << @rexpr
|
|
4052
|
+
r.last << CRenderString.new(self, @op.to_s) << @rexpr
|
|
3999
4053
|
when :'[]'
|
|
4000
4054
|
r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
|
|
4001
4055
|
r.last << '['
|
|
4002
|
-
l = lexpr if lexpr.kind_of?
|
|
4003
|
-
l = lexpr.lexpr.type.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?
|
|
4004
|
-
l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?
|
|
4056
|
+
l = lexpr if lexpr.kind_of?(Variable)
|
|
4057
|
+
l = lexpr.lexpr.type.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?(CExpression) and lexpr.op == :'.'
|
|
4058
|
+
l = lexpr.lexpr.type.pointed.untypedef.findmember(lexpr.rexpr) if lexpr.kind_of?(CExpression) and lexpr.op == :'->'
|
|
4005
4059
|
# honor __attribute__((indexenum(enumname)))
|
|
4006
|
-
if l and l.attributes and rexpr.kind_of?
|
|
4060
|
+
if l and l.attributes and rexpr.kind_of?(CExpression) and not rexpr.op and rexpr.rexpr.kind_of?(::Integer) and
|
|
4007
4061
|
n = l.has_attribute_var('indexenum') and enum = scope.struct_ancestors[n] and i = enum.members.index(rexpr.rexpr)
|
|
4008
4062
|
r.last << i
|
|
4009
4063
|
dep |= [enum]
|
|
@@ -4016,22 +4070,22 @@ EOH
|
|
|
4016
4070
|
r.last << '('
|
|
4017
4071
|
@rexpr.each { |arg|
|
|
4018
4072
|
r.last << ', ' if r.last[-1] != ?(
|
|
4019
|
-
r, dep = CExpression.dump(arg, scope, r, dep)
|
|
4073
|
+
r, dep = CExpression.dump(arg, scope, r, dep, (arg.kind_of?(CExpression) and arg.op == :','))
|
|
4020
4074
|
}
|
|
4021
4075
|
r.last << ')'
|
|
4022
4076
|
when :'?:'
|
|
4023
4077
|
r, dep = CExpression.dump(@lexpr, scope, r, dep, true)
|
|
4024
|
-
r.last << ' ? '
|
|
4078
|
+
r.last << CRenderString.new(self, ' ? ')
|
|
4025
4079
|
r, dep = CExpression.dump(@rexpr[0], scope, r, dep, true)
|
|
4026
|
-
r.last << ' : '
|
|
4080
|
+
r.last << CRenderString.new(self, ' : ')
|
|
4027
4081
|
r, dep = CExpression.dump(@rexpr[1], scope, r, dep, true)
|
|
4028
4082
|
else
|
|
4029
|
-
r, dep = CExpression.dump(@lexpr, scope, r, dep, (@lexpr.kind_of?
|
|
4030
|
-
r.last << ' ' << @op.to_s << ' '
|
|
4031
|
-
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?
|
|
4083
|
+
r, dep = CExpression.dump(@lexpr, scope, r, dep, (@lexpr.kind_of?(CExpression) and @lexpr.lexpr and @lexpr.op != @op and @lexpr.op != :funcall))
|
|
4084
|
+
r.last << CRenderString.new(self, ' ' << @op.to_s << ' ')
|
|
4085
|
+
r, dep = CExpression.dump(@rexpr, scope, r, dep, (@rexpr.kind_of?(CExpression) and @rexpr.lexpr and @rexpr.op != @op and @rexpr.op != :funcall and @op != :'='))
|
|
4032
4086
|
end
|
|
4033
4087
|
end
|
|
4034
|
-
r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?
|
|
4088
|
+
r.last << ')' if brace and @op != :'->' and @op != :'.' and @op != :'[]' and (@op or @rexpr.kind_of?(CExpression))
|
|
4035
4089
|
[r, dep]
|
|
4036
4090
|
end
|
|
4037
4091
|
|