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,350 @@
|
|
|
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/cpu/openrisc/main'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class OpenRisc
|
|
11
|
+
# temporarily setup dasm.address_binding so that backtracking
|
|
12
|
+
# stack-related offsets resolve in :frameptr (relative to func start)
|
|
13
|
+
def decompile_makestackvars(dasm, funcstart, blocks)
|
|
14
|
+
oldfuncbd = dasm.address_binding[funcstart]
|
|
15
|
+
dasm.address_binding[funcstart] = { :r1 => :frameptr }
|
|
16
|
+
blocks.each { |block| yield block }
|
|
17
|
+
dasm.address_binding[funcstart] = oldfuncbd if oldfuncbd
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# add di-specific registry written/accessed
|
|
21
|
+
def decompile_func_finddeps_di(dcmp, func, di, a, w)
|
|
22
|
+
a << abi_funcall[:retval] if di.instruction.to_s == 'jr r9' and (not func.type.kind_of?(C::BaseType) or func.type.type.name != :void) # standard ABI
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# list of register symbols
|
|
26
|
+
def register_symbols
|
|
27
|
+
@dbg_register_list ||= (1..31).to_a.map { |i| "r#{i}".to_sym }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# returns a hash { :retval => r, :changed => [] }
|
|
31
|
+
def abi_funcall
|
|
32
|
+
{ :retval => :r11, :changed => [3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].map { |n| "r#{n}".to_sym }, :args => [:r3, :r4, :r5, :r6, :r7, :r8] }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# list variable dependency for each block, remove useless writes
|
|
36
|
+
# returns { blockaddr => [list of vars that are needed by a following block] }
|
|
37
|
+
def decompile_func_finddeps(dcmp, blocks, func)
|
|
38
|
+
deps_r = {} ; deps_w = {} ; deps_to = {}
|
|
39
|
+
deps_subfunc = {} # things read/written by subfuncs
|
|
40
|
+
|
|
41
|
+
# find read/writes by each block
|
|
42
|
+
blocks.each { |b, to|
|
|
43
|
+
deps_r[b] = [] ; deps_w[b] = [] ; deps_to[b] = to
|
|
44
|
+
deps_subfunc[b] = []
|
|
45
|
+
|
|
46
|
+
blk = dcmp.dasm.decoded[b].block
|
|
47
|
+
blk.list.each { |di|
|
|
48
|
+
a = di.backtrace_binding.values
|
|
49
|
+
w = []
|
|
50
|
+
di.backtrace_binding.keys.each { |k|
|
|
51
|
+
case k
|
|
52
|
+
when ::Symbol; w |= [k]
|
|
53
|
+
else a |= Expression[k].externals # if dword [eax] <- 42, eax is read
|
|
54
|
+
end
|
|
55
|
+
}
|
|
56
|
+
decompile_func_finddeps_di(dcmp, func, di, a, w)
|
|
57
|
+
|
|
58
|
+
deps_r[b] |= a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - deps_w[b]
|
|
59
|
+
deps_w[b] |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
|
|
60
|
+
}
|
|
61
|
+
subfunccall = false
|
|
62
|
+
blk.each_to_normal { |t|
|
|
63
|
+
t = dcmp.backtrace_target(t, blk.list.last.address)
|
|
64
|
+
next if not t = dcmp.c_parser.toplevel.symbol[t]
|
|
65
|
+
t.type = C::Function.new(C::BaseType.new(:int)) if not t.type.kind_of?(C::Function) # XXX this may seem a bit extreme, and yes, it is.
|
|
66
|
+
subfunccall = true
|
|
67
|
+
t.type.args.to_a.each { |arg|
|
|
68
|
+
if reg = arg.has_attribute('register')
|
|
69
|
+
deps_subfunc[b] |= [reg.to_sym]
|
|
70
|
+
end
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if subfunccall # last block instr == subfunction call
|
|
74
|
+
deps_r[b] |= deps_subfunc[b] - deps_w[b]
|
|
75
|
+
deps_w[b] |= abi_funcall[:changed]
|
|
76
|
+
end
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
bt = blocks.transpose
|
|
80
|
+
roots = bt[0] - bt[1].flatten # XXX jmp 1stblock ?
|
|
81
|
+
|
|
82
|
+
# find regs read and never written (must have been set by caller and are part of the func ABI)
|
|
83
|
+
uninitialized = lambda { |b, r, done|
|
|
84
|
+
if not deps_r[b]
|
|
85
|
+
elsif deps_r[b].include?(r)
|
|
86
|
+
blk = dcmp.dasm.decoded[b].block
|
|
87
|
+
bw = []
|
|
88
|
+
rdi = blk.list.find { |di|
|
|
89
|
+
a = di.backtrace_binding.values
|
|
90
|
+
w = []
|
|
91
|
+
di.backtrace_binding.keys.each { |k|
|
|
92
|
+
case k
|
|
93
|
+
when ::Symbol; w |= [k]
|
|
94
|
+
else a |= Expression[k].externals # if dword [eax] <- 42, eax is read
|
|
95
|
+
end
|
|
96
|
+
}
|
|
97
|
+
decompile_func_finddeps_di(dcmp, func, di, a, w)
|
|
98
|
+
|
|
99
|
+
next true if (a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - bw).include?(r)
|
|
100
|
+
bw |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
|
|
101
|
+
false
|
|
102
|
+
}
|
|
103
|
+
if decompile_func_abi_fcallret(r, rdi, blk)
|
|
104
|
+
func.type.type = C::BaseType.new(:void)
|
|
105
|
+
false
|
|
106
|
+
elsif rdi and rdi.backtrace_binding[r]
|
|
107
|
+
false # mov al, 42 ; ret -> don't regarg eax
|
|
108
|
+
else
|
|
109
|
+
true
|
|
110
|
+
end
|
|
111
|
+
elsif deps_w[b].include?(r)
|
|
112
|
+
else
|
|
113
|
+
done << b
|
|
114
|
+
(deps_to[b] - done).find { |tb| uninitialized[tb, r, done] }
|
|
115
|
+
end
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
regargs = []
|
|
119
|
+
register_symbols.each { |r|
|
|
120
|
+
if roots.find { |root| uninitialized[root, r, []] }
|
|
121
|
+
regargs << r
|
|
122
|
+
end
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# TODO honor user-defined prototype if available (eg no, really, eax is not read in this function returning al)
|
|
126
|
+
regargs.sort_by { |r| r.to_s }.each { |r|
|
|
127
|
+
a = C::Variable.new(r.to_s, C::BaseType.new(:int, :unsigned))
|
|
128
|
+
a.add_attribute("register(#{r})")
|
|
129
|
+
func.type.args << a
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# remove writes from a block if no following block read the value
|
|
133
|
+
dw = {}
|
|
134
|
+
deps_w.each { |b, deps|
|
|
135
|
+
dw[b] = deps.reject { |dep|
|
|
136
|
+
ret = true
|
|
137
|
+
done = []
|
|
138
|
+
todo = deps_to[b].dup
|
|
139
|
+
while a = todo.pop
|
|
140
|
+
next if done.include?(a)
|
|
141
|
+
done << a
|
|
142
|
+
if not deps_r[a] or deps_r[a].include?(dep)
|
|
143
|
+
ret = false
|
|
144
|
+
break
|
|
145
|
+
elsif not deps_w[a].include?(dep)
|
|
146
|
+
todo.concat deps_to[a]
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
ret
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
dw
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# return true if r is the implicit register read made by the subfunction return instruction to symbolize the return value ABI
|
|
157
|
+
def decompile_func_abi_fcallret(r, rdi, blk)
|
|
158
|
+
rdi ||= blk.list[-1-@delay_slot]
|
|
159
|
+
return if not rdi
|
|
160
|
+
r == abi_funcall[:retval] and rdi.instruction.to_s == 'jr r9'
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil)
|
|
164
|
+
scope = func.initializer
|
|
165
|
+
func.type.args.each { |a| scope.symbol[a.name] = a }
|
|
166
|
+
stmts = scope.statements
|
|
167
|
+
blocks_toclean = myblocks.dup
|
|
168
|
+
func_entry = myblocks.first[0]
|
|
169
|
+
until myblocks.empty?
|
|
170
|
+
b, to = myblocks.shift
|
|
171
|
+
if l = dcmp.dasm.get_label_at(b)
|
|
172
|
+
stmts << C::Label.new(l)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# list of assignments [[dest reg, expr assigned]]
|
|
176
|
+
ops = []
|
|
177
|
+
# reg binding (reg => value, values.externals = regs at block start)
|
|
178
|
+
binding = {}
|
|
179
|
+
# Expr => CExpr
|
|
180
|
+
ce = lambda { |*e| dcmp.decompile_cexpr(Expression[Expression[*e].reduce], scope) }
|
|
181
|
+
# Expr => Expr.bind(binding) => CExpr
|
|
182
|
+
ceb = lambda { |*e| ce[Expression[*e].bind(binding)] }
|
|
183
|
+
|
|
184
|
+
# dumps a CExprs that implements an assignment to a reg (uses ops[], patches op => [reg, nil])
|
|
185
|
+
commit = lambda {
|
|
186
|
+
deps[b].map { |k|
|
|
187
|
+
[k, ops.rindex(ops.reverse.find { |r, v| r == k })]
|
|
188
|
+
}.sort_by { |k, i| i.to_i }.each { |k, i|
|
|
189
|
+
next if not i or not binding[k]
|
|
190
|
+
e = k
|
|
191
|
+
final = []
|
|
192
|
+
ops[0..i].reverse_each { |r, v|
|
|
193
|
+
final << r if not v
|
|
194
|
+
e = Expression[e].bind(r => v).reduce if not final.include?(r)
|
|
195
|
+
}
|
|
196
|
+
ops[i][1] = nil
|
|
197
|
+
binding.delete k
|
|
198
|
+
stmts << ce[k, :'=', e] if k != e
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
# returns an array to use as funcall arguments
|
|
203
|
+
get_func_args = lambda { |di, f|
|
|
204
|
+
# XXX see remarks in #finddeps
|
|
205
|
+
args_todo = f.type.args.to_a.dup
|
|
206
|
+
args = []
|
|
207
|
+
args_abi = abi_funcall[:args].dup
|
|
208
|
+
args_todo.each { |a_|
|
|
209
|
+
if r = a_.has_attribute_var('register')
|
|
210
|
+
args << Expression[r.to_sym]
|
|
211
|
+
args_abi.delete r.to_sym
|
|
212
|
+
else
|
|
213
|
+
args << Expression[args_abi.shift]
|
|
214
|
+
end
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if f.type.varargs
|
|
218
|
+
nargs = 1
|
|
219
|
+
if f.type.args.last.type.pointer?
|
|
220
|
+
# check if last arg is a fmtstring
|
|
221
|
+
bt = dcmp.dasm.backtrace(args.last, di.block.list.last.address, :snapshot_addr => func_entry, :include_start => true)
|
|
222
|
+
if bt.length == 1 and s = dcmp.dasm.get_section_at(bt.first)
|
|
223
|
+
fmt = s[0].read(512)
|
|
224
|
+
fmt = fmt.unpack('v*').pack('C*') if dcmp.sizeof(f.type.args.last.type.untypedef.type) == 2
|
|
225
|
+
if fmt.index(?\0)
|
|
226
|
+
fmt = fmt[0...fmt.index(?\0)]
|
|
227
|
+
nargs = fmt.gsub('%%', '').count('%') # XXX %.*s etc..
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
bt = dcmp.dasm.backtrace(:r1, di.block.list.last.address, :snapshot_addr => func_entry, :include_start => true)
|
|
232
|
+
stackoff = Expression[bt, :-, :r1].bind(:r1 => :frameptr).reduce rescue nil
|
|
233
|
+
if stackoff and nargs > 0
|
|
234
|
+
nargs.times {
|
|
235
|
+
args << Indirection[[:frameptr, :+, stackoff], @size/8]
|
|
236
|
+
stackoff += @size/8
|
|
237
|
+
}
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
args.map { |e| ceb[e] }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
# go !
|
|
245
|
+
di_list = dcmp.dasm.decoded[b].block.list.dup
|
|
246
|
+
if di_list[-2] and di_list[-2].opcode.props[:setip] and @delay_slot > 0
|
|
247
|
+
di_list[-1], di_list[-2] = di_list[-2], di_list[-1]
|
|
248
|
+
end
|
|
249
|
+
di_list.each { |di|
|
|
250
|
+
if di.opcode.props[:setip] and not di.opcode.props[:stopexec]
|
|
251
|
+
# conditional jump
|
|
252
|
+
commit[]
|
|
253
|
+
n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
|
|
254
|
+
if di.opcode.name == /bfeq/
|
|
255
|
+
cc = ceb[:flag]
|
|
256
|
+
else
|
|
257
|
+
cc = ceb[:!, :flag]
|
|
258
|
+
end
|
|
259
|
+
# XXX switch/indirect/multiple jmp
|
|
260
|
+
stmts << C::If.new(C::CExpression[cc], C::Goto.new(n))
|
|
261
|
+
to.delete dcmp.dasm.normalize(n)
|
|
262
|
+
next
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
if di.instruction.to_s == 'jr r9'
|
|
266
|
+
commit[]
|
|
267
|
+
ret = C::CExpression[ceb[abi_funcall[:retval]]] unless func.type.type.kind_of?(C::BaseType) and func.type.type.name == :void
|
|
268
|
+
stmts << C::Return.new(ret)
|
|
269
|
+
elsif di.opcode.name == 'jal' or di.opcode.name == 'jalr'
|
|
270
|
+
n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
|
|
271
|
+
args = []
|
|
272
|
+
if f = dcmp.c_parser.toplevel.symbol[n] and f.type.kind_of?(C::Function) and f.type.args
|
|
273
|
+
args = get_func_args[di, f]
|
|
274
|
+
end
|
|
275
|
+
commit[]
|
|
276
|
+
#next if not di.block.to_subfuncret
|
|
277
|
+
|
|
278
|
+
if not n.kind_of?(::String) or (f and not f.type.kind_of?(C::Function))
|
|
279
|
+
# indirect funcall
|
|
280
|
+
fptr = ceb[n]
|
|
281
|
+
binding.delete n
|
|
282
|
+
proto = C::Function.new(C::BaseType.new(:int))
|
|
283
|
+
proto = f.type if f and f.type.kind_of?(C::Function)
|
|
284
|
+
f = C::CExpression[[fptr], C::Pointer.new(proto)]
|
|
285
|
+
elsif not f
|
|
286
|
+
# internal functions are predeclared, so this one is extern
|
|
287
|
+
f = C::Variable.new
|
|
288
|
+
f.name = n
|
|
289
|
+
f.type = C::Function.new(C::BaseType.new(:int))
|
|
290
|
+
if dcmp.recurse > 0
|
|
291
|
+
dcmp.c_parser.toplevel.symbol[n] = f
|
|
292
|
+
dcmp.c_parser.toplevel.statements << C::Declaration.new(f)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
commit[]
|
|
296
|
+
binding.delete abi_funcall[:retval]
|
|
297
|
+
e = C::CExpression[f, :funcall, args]
|
|
298
|
+
e = C::CExpression[ce[abi_funcall[:retval]], :'=', e, f.type.type] if deps[b].include?(abi_funcall[:retval]) and f.type.type != C::BaseType.new(:void)
|
|
299
|
+
stmts << e
|
|
300
|
+
else
|
|
301
|
+
bd = get_fwdemu_binding(di)
|
|
302
|
+
if di.backtrace_binding[:incomplete_binding]
|
|
303
|
+
commit[]
|
|
304
|
+
stmts << C::Asm.new(di.instruction.to_s, nil, nil, nil, nil, nil)
|
|
305
|
+
else
|
|
306
|
+
update = {}
|
|
307
|
+
bd.each { |k, v|
|
|
308
|
+
if k.kind_of?(::Symbol) and not deps[b].include?(k)
|
|
309
|
+
ops << [k, v]
|
|
310
|
+
update[k] = Expression[Expression[v].bind(binding).reduce]
|
|
311
|
+
else
|
|
312
|
+
stmts << ceb[k, :'=', v]
|
|
313
|
+
stmts.pop if stmts.last.kind_of?(C::Variable) # [:eflag_s, :=, :unknown].reduce
|
|
314
|
+
end
|
|
315
|
+
}
|
|
316
|
+
binding.update update
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
}
|
|
320
|
+
commit[]
|
|
321
|
+
|
|
322
|
+
case to.length
|
|
323
|
+
when 0
|
|
324
|
+
if not myblocks.empty? and (dcmp.dasm.decoded[b].block.list[-1-@delay_slot].instruction.to_s != 'jr r9' rescue true)
|
|
325
|
+
puts " block #{Expression[b]} has no to and don't end in ret"
|
|
326
|
+
end
|
|
327
|
+
when 1
|
|
328
|
+
if (myblocks.empty? ? nextaddr != to[0] : myblocks.first.first != to[0])
|
|
329
|
+
stmts << C::Goto.new(dcmp.dasm.auto_label_at(to[0], 'unknown_goto'))
|
|
330
|
+
end
|
|
331
|
+
else
|
|
332
|
+
puts " block #{Expression[b]} with multiple to"
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# cleanup di.bt_binding (we set :frameptr etc in those, this may confuse the dasm)
|
|
337
|
+
blocks_toclean.each { |b_, to_|
|
|
338
|
+
dcmp.dasm.decoded[b_].block.list.each { |di|
|
|
339
|
+
di.backtrace_binding = nil
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def decompile_check_abi(dcmp, entry, func)
|
|
345
|
+
a = func.type.args || []
|
|
346
|
+
# TODO check abi_funcall[:args], dont delete r4 __unused if r5 is used
|
|
347
|
+
a.delete_if { |arg| arg.has_attribute_var('register') and arg.has_attribute('unused') }
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
3
|
+
#
|
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
require 'metasm/main'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class OpenRisc < CPU
|
|
11
|
+
class Reg
|
|
12
|
+
attr_accessor :v
|
|
13
|
+
def initialize(v)
|
|
14
|
+
@v = v
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def symbolic(di=nil)
|
|
18
|
+
if @v != 0 or not di or di.instruction.args[0].object_id == self.object_id
|
|
19
|
+
"r#@v".to_sym
|
|
20
|
+
else
|
|
21
|
+
# r0 is always 0, but we still return :r0 when writing to it (ie its the 1st instr arg)
|
|
22
|
+
Expression[0]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class FpReg
|
|
28
|
+
attr_accessor :v
|
|
29
|
+
def initialize(v)
|
|
30
|
+
@v = v
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def symbolic(di=nil) ; "f#@v".to_sym ; end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Memref
|
|
37
|
+
attr_accessor :base, :offset, :msz
|
|
38
|
+
|
|
39
|
+
def initialize(base, offset, msz)
|
|
40
|
+
@base = base
|
|
41
|
+
@offset = offset
|
|
42
|
+
@msz = msz
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def symbolic(di)
|
|
46
|
+
p = Expression[@base.symbolic] if base
|
|
47
|
+
p = Expression[p, :+, @offset] if offset
|
|
48
|
+
Indirection[p.reduce, @msz, (di.address if di)]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def initialize(family = :latest, endianness = :big, delay_slot = 1)
|
|
53
|
+
super()
|
|
54
|
+
@endianness = endianness
|
|
55
|
+
@size = 32
|
|
56
|
+
@family = family
|
|
57
|
+
@delay_slot = delay_slot
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def init_opcode_list
|
|
61
|
+
send("init_#@family")
|
|
62
|
+
@opcode_list
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def delay_slot(di=nil)
|
|
66
|
+
@delay_slot
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
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/cpu/openrisc/main'
|
|
7
|
+
|
|
8
|
+
module Metasm
|
|
9
|
+
|
|
10
|
+
# https://github.com/s-macke/jor1k/blob/master/js/worker/or1k/safecpu.js
|
|
11
|
+
class OpenRisc
|
|
12
|
+
def addop(name, bin, *args)
|
|
13
|
+
o = Opcode.new name, bin
|
|
14
|
+
args.each { |a|
|
|
15
|
+
o.bin_mask = a if a.kind_of?(Integer)
|
|
16
|
+
o.args << a if @valid_args[a]
|
|
17
|
+
o.props.update a if a.kind_of?(::Hash)
|
|
18
|
+
}
|
|
19
|
+
@opcode_list << o
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def init_or1k
|
|
23
|
+
@opcode_list = []
|
|
24
|
+
@valid_args = [ :rA, :rB, :rD, :fA, :fB, :fD, :disp26, :uimm16, :simm16, :uimm5, :rA_simm16, :rA_smoo ].inject({}) { |h, a| h.update a => true }
|
|
25
|
+
@fields_off = { :rD => 21, :rA => 16, :rB => 11, :disp26 => 0, :uimm16 => 0, :simm16 => 0, :uimm5 => 0, :smoo => 0 }
|
|
26
|
+
@fields_mask = { :rD => 0x1F, :rA => 0x1F, :rB => 0x1F, :disp26 => 0x3FFFFFF, :simm16 => 0xFFFF, :uimm16 => 0xFFFF, :uimm5 => 0x1F, :smoo => 0x3E007FF }
|
|
27
|
+
|
|
28
|
+
addop 'j', 0x0000_0000, 0x03FF_FFFF, :disp26, :setip => true, :stopexec => true
|
|
29
|
+
addop 'jal', 0x0400_0000, 0x03FF_FFFF, :disp26, :setip => true, :stopexec => true, :saveip => true
|
|
30
|
+
addop 'bnf', 0x0C00_0000, 0x03FF_FFFF, :disp26, :setip => true # branch if not flag
|
|
31
|
+
addop 'bf', 0x1000_0000, 0x03FF_FFFF, :disp26, :setip => true
|
|
32
|
+
addop 'nop', 0x1400_0000, 0x03FF_FFFF
|
|
33
|
+
addop 'movhi', 0x1800_0000, 0x03FE_FFFF, :rD, :uimm16
|
|
34
|
+
addop 'macrc', 0x1801_0000, 0x03FE_FFFF
|
|
35
|
+
addop 'trap', 0x2100_0000, 0x0000_FFFF
|
|
36
|
+
addop 'sys', 0x2000_0000, 0x03FF_FFFF # args ?
|
|
37
|
+
addop 'rfe', 0x2400_0000, 0x03FF_FFFF
|
|
38
|
+
addop 'jr', 0x4400_0000, 0x03FF_FFFF, :rB, :setip => true, :stopexec => true
|
|
39
|
+
addop 'jalr', 0x4800_0000, 0x03FF_FFFF, :rB, :setip => true, :stopexec => true, :saveip => true
|
|
40
|
+
addop 'lwa', 0x6C00_0000, 0x03FF_FFFF, :rD, :rA_simm16
|
|
41
|
+
addop 'lwz', 0x8400_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 4
|
|
42
|
+
addop 'lbz', 0x8C00_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 1
|
|
43
|
+
addop 'lbs', 0x9000_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 1 # lbz + sign-expand byte
|
|
44
|
+
addop 'lhz', 0x9400_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 2
|
|
45
|
+
addop 'lhs', 0x9800_0000, 0x03FF_FFFF, :rD, :rA_simm16, :memsz => 2
|
|
46
|
+
addop 'add', 0x9C00_0000, 0x03FF_FFFF, :rD, :rA, :simm16
|
|
47
|
+
addop 'and', 0xA400_0000, 0x03FF_FFFF, :rD, :rA, :uimm16
|
|
48
|
+
addop 'or', 0xA800_0000, 0x03FF_FFFF, :rD, :rA, :uimm16
|
|
49
|
+
addop 'xor', 0xAC00_0000, 0x03FF_FFFF, :rD, :rA, :simm16
|
|
50
|
+
addop 'mfspr', 0xB400_0000, 0x03FF_FFFF, :rD, :rA, :simm16
|
|
51
|
+
addop 'shl', 0xB800_0000, 0x03FF_FF3F, :rD, :rA, :uimm5
|
|
52
|
+
addop 'ror', 0xB800_0040, 0x03FF_FF3F, :rD, :rA, :uimm5
|
|
53
|
+
addop 'sar', 0xB800_0080, 0x03FF_FF3F, :rD, :rA, :uimm5
|
|
54
|
+
addop 'sfeq', 0xBC00_0000, 0x001F_FFFF, :rA, :simm16
|
|
55
|
+
addop 'sfne', 0xBC20_0000, 0x001F_FFFF, :rA, :simm16
|
|
56
|
+
addop 'sfgtu', 0xBC40_0000, 0x001F_FFFF, :rA, :uimm16
|
|
57
|
+
addop 'sfgeu', 0xBC60_0000, 0x001F_FFFF, :rA, :uimm16
|
|
58
|
+
addop 'sfltu', 0xBC80_0000, 0x001F_FFFF, :rA, :uimm16
|
|
59
|
+
addop 'sfleu', 0xBCA0_0000, 0x001F_FFFF, :rA, :uimm16
|
|
60
|
+
addop 'sfgts', 0xBD40_0000, 0x001F_FFFF, :rA, :simm16
|
|
61
|
+
addop 'sfges', 0xBD60_0000, 0x001F_FFFF, :rA, :simm16
|
|
62
|
+
addop 'sflts', 0xBD80_0000, 0x001F_FFFF, :rA, :simm16
|
|
63
|
+
addop 'sfles', 0xBDA0_0000, 0x001F_FFFF, :rA, :simm16
|
|
64
|
+
addop 'mtspr', 0xC000_0000, 0x03FF_FFFF, :rA_smoo, :rB # smoo = (ins & 0x7ff) | ((ins >> 10) & 0xf800) ; setspr((rA|smoo), rB)
|
|
65
|
+
addop 'add', 0xC800_0000, 0x03FF_FF00, :fD, :fA, :fB # FPU
|
|
66
|
+
addop 'sub', 0xC800_0001, 0x03FF_FF00, :fD, :fA, :fB
|
|
67
|
+
addop 'mul', 0xC800_0002, 0x03FF_FF00, :fD, :fA, :fB
|
|
68
|
+
addop 'div', 0xC800_0003, 0x03FF_FF00, :fD, :fA, :fB
|
|
69
|
+
addop 'itof', 0xC800_0004, 0x03FF_FF00, :fD, :rA
|
|
70
|
+
addop 'ftoi', 0xC800_0005, 0x03FF_FF00, :rD, :fA
|
|
71
|
+
addop 'madd', 0xC800_0007, 0x03FF_FF00, :fD, :fA, :fB # fD += fA*fB
|
|
72
|
+
addop 'sfeq', 0xC800_0008, 0x03FF_FF00, :fA, :fB
|
|
73
|
+
addop 'sfne', 0xC800_0009, 0x03FF_FF00, :fA, :fB
|
|
74
|
+
addop 'sfgt', 0xC800_000A, 0x03FF_FF00, :fA, :fB
|
|
75
|
+
addop 'sfge', 0xC800_000B, 0x03FF_FF00, :fA, :fB
|
|
76
|
+
addop 'sflt', 0xC800_000C, 0x03FF_FF00, :fA, :fB
|
|
77
|
+
addop 'sfle', 0xC800_000D, 0x03FF_FF00, :fA, :fB
|
|
78
|
+
addop 'swa', 0xCC00_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 4 # sw + setf(ra_smoo == current_EA ?)
|
|
79
|
+
addop 'sw', 0xD400_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 4
|
|
80
|
+
addop 'sb', 0xD800_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 1
|
|
81
|
+
addop 'sh', 0xDC00_0000, 0x03FF_FFFF, :rA_smoo, :rB, :memsz => 2
|
|
82
|
+
addop 'add', 0xE000_0000, 0x03FF_FC30, :rD, :rA, :rB
|
|
83
|
+
addop 'sub', 0xE000_0002, 0x03FF_FC30, :rD, :rA, :rB
|
|
84
|
+
addop 'and', 0xE000_0003, 0x03FF_FC30, :rD, :rA, :rB
|
|
85
|
+
addop 'or', 0xE000_0004, 0x03FF_FC30, :rD, :rA, :rB
|
|
86
|
+
addop 'xor', 0xE000_0005, 0x03FF_FC30, :rD, :rA, :rB
|
|
87
|
+
addop 'shl', 0xE000_0008, 0x03FF_FC30, :rD, :rA, :rB
|
|
88
|
+
addop 'ff1', 0xE000_000F, 0x03FF_FC30, :rD, :rA, :rB # find first bit == 1
|
|
89
|
+
addop 'shr', 0xE000_0048, 0x03FF_FC30, :rD, :rA, :rB
|
|
90
|
+
addop 'sar', 0xE000_0088, 0x03FF_FC30, :rD, :rA, :rB
|
|
91
|
+
addop 'fl1', 0xE000_010F, 0x03FF_FC30, :rD, :rA, :rB # find last bit
|
|
92
|
+
addop 'mul', 0xE000_0306, 0x03FF_FC30, :rD, :rA, :rB # signed multiply ?
|
|
93
|
+
addop 'div', 0xE000_0309, 0x03FF_FC30, :rD, :rA, :rB
|
|
94
|
+
addop 'divu', 0xE000_030A, 0x03FF_FC30, :rD, :rA, :rB # rD = rA&0xffffffff / rB&0xffffffff
|
|
95
|
+
addop 'sfeq', 0xE400_0000, 0x001F_FFFF, :rA, :rB
|
|
96
|
+
addop 'sfne', 0xE420_0000, 0x001F_FFFF, :rA, :rB
|
|
97
|
+
addop 'sfgtu', 0xE440_0000, 0x001F_FFFF, :rA, :rB
|
|
98
|
+
addop 'sfgeu', 0xE460_0000, 0x001F_FFFF, :rA, :rB
|
|
99
|
+
addop 'sfltu', 0xE480_0000, 0x001F_FFFF, :rA, :rB
|
|
100
|
+
addop 'sfleu', 0xE4A0_0000, 0x001F_FFFF, :rA, :rB
|
|
101
|
+
addop 'sfgts', 0xE540_0000, 0x001F_FFFF, :rA, :rB
|
|
102
|
+
addop 'sfges', 0xE560_0000, 0x001F_FFFF, :rA, :rB
|
|
103
|
+
addop 'sflts', 0xE580_0000, 0x001F_FFFF, :rA, :rB
|
|
104
|
+
addop 'sfles', 0xE5A0_0000, 0x001F_FFFF, :rA, :rB
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
alias init_latest init_or1k
|
|
108
|
+
end
|
|
109
|
+
end
|