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
data/metasm/cpu/ia32/main.rb
CHANGED
|
@@ -73,26 +73,31 @@ class Ia32 < CPU
|
|
|
73
73
|
# segment register: es, cs, ss, ds, fs, gs and the theoretical segr6/7
|
|
74
74
|
class SegReg < Argument
|
|
75
75
|
simple_map((0..7).zip(%w(es cs ss ds fs gs segr6 segr7)))
|
|
76
|
+
def symbolic(di=nil) ; to_s.to_sym end
|
|
76
77
|
end
|
|
77
78
|
|
|
78
79
|
# debug register (dr0..dr3, dr6, dr7), and theoretical dr4/5
|
|
79
80
|
class DbgReg < Argument
|
|
80
81
|
simple_map((0..7).map { |i| [i, "dr#{i}"] })
|
|
82
|
+
def symbolic(di=nil) ; to_s.to_sym end
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
# control register (cr0, cr2, cr3, cr4) and theoretical cr1/5/6/7
|
|
84
86
|
class CtrlReg < Argument
|
|
85
87
|
simple_map((0..7).map { |i| [i, "cr#{i}"] })
|
|
88
|
+
def symbolic(di=nil) ; to_s.to_sym end
|
|
86
89
|
end
|
|
87
90
|
|
|
88
91
|
# test registers (tr0..tr7) (undocumented)
|
|
89
92
|
class TstReg < Argument
|
|
90
93
|
simple_map((0..7).map { |i| [i, "tr#{i}"] })
|
|
94
|
+
def symbolic(di=nil) ; to_s.to_sym end
|
|
91
95
|
end
|
|
92
96
|
|
|
93
97
|
# floating point registers
|
|
94
98
|
class FpReg < Argument
|
|
95
99
|
simple_map((0..7).map { |i| [i, "ST(#{i})"] } << [nil, 'ST'])
|
|
100
|
+
def symbolic(di=nil) ; to_s.tr('()', '').to_sym end
|
|
96
101
|
end
|
|
97
102
|
|
|
98
103
|
# Single Instr Multiple Data register (mm0..mm7, xmm0..xmm7, ymm0..ymm7)
|
|
@@ -145,6 +150,11 @@ class Ia32 < CPU
|
|
|
145
150
|
def ==(o)
|
|
146
151
|
self.class == o.class and seg == o.seg and addr == o.addr
|
|
147
152
|
end
|
|
153
|
+
|
|
154
|
+
def symbolic(di=nil)
|
|
155
|
+
# XXX realmode only
|
|
156
|
+
Expression[[@seg, :<<, 4], :|, @addr]
|
|
157
|
+
end
|
|
148
158
|
end
|
|
149
159
|
|
|
150
160
|
# ModRM represents indirections in x86 (eg dword ptr [eax+4*ebx+12h])
|
data/metasm/cpu/ia32/parse.rb
CHANGED
|
@@ -133,6 +133,8 @@ class ModRM
|
|
|
133
133
|
|
|
134
134
|
raise otok, 'mrm: bad reg size' if b.kind_of?(Reg) and i.kind_of?(Reg) and b.sz != i.sz
|
|
135
135
|
|
|
136
|
+
raise otok, 'mrm: cannot encode [rip+reg], only [rip+imm]' if (b and b.val == 16 and i) or (i and i.val == 16 and (b or s != 1))
|
|
137
|
+
|
|
136
138
|
# find default address size
|
|
137
139
|
adsz = b ? b.sz : i ? i.sz : nil
|
|
138
140
|
# ptsz may be nil now, will be fixed up later (in parse_instr_fixup) to match another instruction argument's size
|
|
@@ -355,5 +357,9 @@ end
|
|
|
355
357
|
def instr_uncond_jump_to(target)
|
|
356
358
|
parse_instruction("jmp #{target}")
|
|
357
359
|
end
|
|
360
|
+
|
|
361
|
+
def instr_jump_stop
|
|
362
|
+
parse_instruction("hlt")
|
|
363
|
+
end
|
|
358
364
|
end
|
|
359
365
|
end
|
data/metasm/cpu/mcs51/decode.rb
CHANGED
data/metasm/cpu/mcs51/main.rb
CHANGED
|
@@ -37,6 +37,9 @@ class MCS51 < CPU
|
|
|
37
37
|
new(S_TO_I[s])
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
def symbolic(di=nil)
|
|
41
|
+
to_s.to_sym
|
|
42
|
+
end
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
class Immediate
|
|
@@ -47,6 +50,10 @@ class MCS51 < CPU
|
|
|
47
50
|
def to_s
|
|
48
51
|
"#" + @value.to_s
|
|
49
52
|
end
|
|
53
|
+
|
|
54
|
+
def symbolic(di=nil)
|
|
55
|
+
Expression[@value]
|
|
56
|
+
end
|
|
50
57
|
end
|
|
51
58
|
|
|
52
59
|
class Memref
|
|
@@ -59,6 +66,10 @@ class MCS51 < CPU
|
|
|
59
66
|
def to_s
|
|
60
67
|
@base ? "@" + @base.to_s : @offset.to_s
|
|
61
68
|
end
|
|
69
|
+
|
|
70
|
+
def symbolic(di=nil)
|
|
71
|
+
Indirection[(@base || @offset), 1, (di.address if di)]
|
|
72
|
+
end
|
|
62
73
|
end
|
|
63
74
|
|
|
64
75
|
def initialize
|
data/metasm/cpu/mips/decode.rb
CHANGED
|
@@ -126,12 +126,6 @@ class MIPS
|
|
|
126
126
|
di
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
# hash opname => lambda { |di, *sym_args| binding }
|
|
130
|
-
def backtrace_binding
|
|
131
|
-
@backtrace_binding ||= init_backtrace_binding
|
|
132
|
-
end
|
|
133
|
-
def backtrace_binding=(b) @backtrace_binding = b end
|
|
134
|
-
|
|
135
129
|
def init_backtrace_binding
|
|
136
130
|
@backtrace_binding ||= {}
|
|
137
131
|
opcode_list.map { |ol| ol.name }.uniq.each { |op|
|
|
@@ -167,6 +161,7 @@ class MIPS
|
|
|
167
161
|
when 'jal', 'jalr'; lambda { |di, a0| { :$ra => Expression[Expression[di.address, :+, 2*di.bin_length].reduce] } }
|
|
168
162
|
when 'li', 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
169
163
|
when 'syscall'; lambda { |di, *a| { :$v0 => Expression::Unknown } }
|
|
164
|
+
when /^b/; lambda { |di, *a| {} }
|
|
170
165
|
end
|
|
171
166
|
|
|
172
167
|
@backtrace_binding[op] ||= binding if binding
|
|
@@ -177,25 +172,20 @@ class MIPS
|
|
|
177
172
|
def get_backtrace_binding(di)
|
|
178
173
|
a = di.instruction.args.map { |arg|
|
|
179
174
|
case arg
|
|
180
|
-
when Memref; arg.symbolic(di
|
|
175
|
+
when Memref; arg.symbolic(di)
|
|
181
176
|
when Reg; arg.symbolic
|
|
182
177
|
else arg
|
|
183
178
|
end
|
|
184
179
|
}
|
|
185
180
|
|
|
186
|
-
|
|
187
|
-
binding[di, *a]
|
|
181
|
+
if binding = backtrace_binding[di.instruction.opname]
|
|
182
|
+
bd = binding[di, *a]
|
|
183
|
+
bd.delete 0 # allow add $zero, 42 => nop
|
|
184
|
+
bd
|
|
188
185
|
else
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
puts "unknown instruction to emu #{di}" if $VERBOSE
|
|
192
|
-
end
|
|
193
|
-
{}
|
|
186
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
|
187
|
+
{:incomplete_binding => Expression[1]}
|
|
194
188
|
end
|
|
195
|
-
|
|
196
|
-
binding.delete 0 # allow add $zero, 42 => nop
|
|
197
|
-
|
|
198
|
-
binding
|
|
199
189
|
end
|
|
200
190
|
|
|
201
191
|
def get_xrefs_x(dasm, di)
|
data/metasm/cpu/mips/main.rb
CHANGED
|
@@ -26,7 +26,7 @@ class MIPS < CPU
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
Sym = @i_to_s.sort.map { |k, v| v.to_sym }
|
|
29
|
-
def symbolic ; @i == 0 ? 0 : Sym[@i] end
|
|
29
|
+
def symbolic(di=nil) ; @i == 0 ? 0 : Sym[@i] end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
class FpReg
|
|
@@ -48,11 +48,11 @@ class MIPS < CPU
|
|
|
48
48
|
@base, @offset, @sz = base, offset, sz
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def symbolic(
|
|
51
|
+
def symbolic(di=nil)
|
|
52
52
|
p = nil
|
|
53
53
|
p = Expression[p, :+, @base.symbolic] if base
|
|
54
54
|
p = Expression[p, :+, @offset] if offset
|
|
55
|
-
Indirection[p.reduce, @sz/8,
|
|
55
|
+
Indirection[p.reduce, @sz/8, (di.address if di)]
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
data/metasm/cpu/mips/opcodes.rb
CHANGED
|
@@ -181,7 +181,7 @@ class MIPS
|
|
|
181
181
|
addop 'teqi', (1<<26) | (0b01100<<16), :rs, :i16, :setip
|
|
182
182
|
addop 'tnei', (1<<26) | (0b01110<<16), :rs, :i16, :setip
|
|
183
183
|
addop 'bltzal', (1<<26) | (0b10000<<16), :rs, :i16, :setip, :saveip
|
|
184
|
-
addop 'bgezal', (1<<26) | (0b10001<<16), :i16, :setip, :stopexec, :saveip # bgezal $zero =>
|
|
184
|
+
addop 'bgezal', (1<<26) | (0b10001<<16), :i16, :setip, :stopexec, :saveip # bgezal $zero => unconditional
|
|
185
185
|
addop 'bgezal', (1<<26) | (0b10001<<16), :rs, :i16, :setip, :saveip
|
|
186
186
|
|
|
187
187
|
|
data/metasm/cpu/msp430/decode.rb
CHANGED
|
@@ -124,10 +124,6 @@ class MSP430
|
|
|
124
124
|
di
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
def backtrace_binding
|
|
128
|
-
@backtrace_binding ||= init_backtrace_binding
|
|
129
|
-
end
|
|
130
|
-
|
|
131
127
|
def init_backtrace_binding
|
|
132
128
|
@backtrace_binding ||= {}
|
|
133
129
|
|
|
@@ -159,7 +155,7 @@ class MSP430
|
|
|
159
155
|
a = di.instruction.args.map { |arg|
|
|
160
156
|
case arg
|
|
161
157
|
when Reg; arg.symbolic
|
|
162
|
-
when Memref; arg.symbolic(di
|
|
158
|
+
when Memref; arg.symbolic(di)
|
|
163
159
|
else arg
|
|
164
160
|
end
|
|
165
161
|
}
|
|
@@ -192,7 +188,7 @@ class MSP430
|
|
|
192
188
|
val = di.instruction.args[0]
|
|
193
189
|
case val
|
|
194
190
|
when Reg; val = val.symbolic
|
|
195
|
-
when Memref; val = val.symbolic(di
|
|
191
|
+
when Memref; val = val.symbolic(di)
|
|
196
192
|
end
|
|
197
193
|
|
|
198
194
|
[Expression[val]]
|
data/metasm/cpu/msp430/main.rb
CHANGED
|
@@ -20,7 +20,7 @@ class MSP430 < CPU
|
|
|
20
20
|
|
|
21
21
|
attr_accessor :i
|
|
22
22
|
def initialize(i) ; @i = i end
|
|
23
|
-
def symbolic ; Sym[@i] end
|
|
23
|
+
def symbolic(di=nil) ; Sym[@i] end
|
|
24
24
|
def render ; [Sym[@i].to_s] end
|
|
25
25
|
def ==(o) ; o.class == self.class and o.i == @i end
|
|
26
26
|
end
|
|
@@ -35,10 +35,10 @@ class MSP430 < CPU
|
|
|
35
35
|
@postincr = postincr
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def symbolic(
|
|
38
|
+
def symbolic(di=nil)
|
|
39
39
|
r = @base.symbolic if @base
|
|
40
40
|
e = Expression[r, :+, @offset].reduce
|
|
41
|
-
Indirection[e, (@size || 1),
|
|
41
|
+
Indirection[e, (@size || 1), (di.address if di)]
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
include Renderable
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
require 'metasm/cpu/openrisc/decode'
|
|
9
|
+
require 'metasm/cpu/openrisc/render'
|
|
10
|
+
require 'metasm/cpu/openrisc/debug'
|
|
11
|
+
require 'metasm/cpu/openrisc/decompile'
|
|
@@ -0,0 +1,106 @@
|
|
|
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/opcodes'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class OpenRisc
|
|
11
|
+
def dbg_register_pc
|
|
12
|
+
@dbg_register_pc ||= :pc
|
|
13
|
+
end
|
|
14
|
+
def dbg_register_sp
|
|
15
|
+
@dbg_register_sp ||= :r1
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def dbg_register_list
|
|
19
|
+
@dbg_register_list ||= (1..31).to_a.map { |i| "r#{i}".to_sym } + [:pc, :nextpc, :flag]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def dbg_flag_list
|
|
23
|
+
@dbg_flag_list ||= []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def dbg_register_size
|
|
27
|
+
@dbg_register_size ||= Hash.new(32)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get_fwdemu_binding(di, pc_reg=nil, dbg_ctx=nil)
|
|
31
|
+
fbd = di.backtrace_binding ||= get_backtrace_binding(di)
|
|
32
|
+
fbd = fix_fwdemu_binding(di, fbd)
|
|
33
|
+
if pc_reg
|
|
34
|
+
if @delay_slot == 0
|
|
35
|
+
n_a = Expression[pc_reg, :+, 4]
|
|
36
|
+
else
|
|
37
|
+
n_a = Expression[:nextpc, :+, 4]
|
|
38
|
+
end
|
|
39
|
+
if di.opcode.props[:setip]
|
|
40
|
+
xr = get_xrefs_x(nil, di).to_a
|
|
41
|
+
xr |= [n_a] if not di.opcode.props[:stopexec]
|
|
42
|
+
if xr.length == 1
|
|
43
|
+
if @delay_slot == 0
|
|
44
|
+
fbd[pc_reg] = xr[0]
|
|
45
|
+
else
|
|
46
|
+
fbd[pc_reg] = Expression[:nextpc]
|
|
47
|
+
fbd[:nextpc] = xr[0]
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
|
|
51
|
+
end
|
|
52
|
+
else
|
|
53
|
+
if @delay_slot == 0
|
|
54
|
+
fbd[pc_reg] = n_a
|
|
55
|
+
else
|
|
56
|
+
fbd[pc_reg] = Expression[:nextpc]
|
|
57
|
+
fbd[:nextpc] = n_a
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
fbd
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
|
|
65
|
+
a = di.instruction.args.map { |aa| symbolic(aa) }
|
|
66
|
+
|
|
67
|
+
cond = case di.opcode.name
|
|
68
|
+
when 'bf'; dbg_ctx.get_reg_value(:flag) != 0
|
|
69
|
+
when 'bnf'; dbg_ctx.get_reg_value(:flag) == 0
|
|
70
|
+
else return super(di, fbd, pc_reg, dbg_ctx)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if cond
|
|
74
|
+
n_a = a.last
|
|
75
|
+
else
|
|
76
|
+
if @delay_slot == 0
|
|
77
|
+
n_a = di.next_addr + 4
|
|
78
|
+
else
|
|
79
|
+
n_a = Expression[:nextpc, :+, 4]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if @delay_slot == 0
|
|
84
|
+
fbd[pc_reg] = n_a
|
|
85
|
+
else
|
|
86
|
+
fbd[pc_reg] = Expression[:nextpc]
|
|
87
|
+
fbd[:nextpc] = n_a
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def dbg_enable_bp(dbg, bp)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def dbg_disable_bp(dbg, bp)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def dbg_need_stepover(dbg, addr, di)
|
|
98
|
+
if @delay_slot == 0
|
|
99
|
+
di.opcode.props[:saveip]
|
|
100
|
+
else
|
|
101
|
+
ddi = dbg.disassembler.di_at(addr-4)
|
|
102
|
+
ddi and ddi.opcode.props[:saveip]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
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/opcodes'
|
|
8
|
+
require 'metasm/decode'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class OpenRisc
|
|
12
|
+
def build_bin_lookaside
|
|
13
|
+
bl = Array.new(255) { [] }
|
|
14
|
+
opcode_list.each { |op|
|
|
15
|
+
((op.bin >> 24) .. ((op.bin | op.bin_mask) >> 24)).each { |b|
|
|
16
|
+
if (b | (op.bin_mask >> 24)) == ((op.bin | op.bin_mask) >> 24)
|
|
17
|
+
bl[b] << op
|
|
18
|
+
end
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
bl
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# tries to find the opcode encoded at edata.ptr
|
|
25
|
+
def decode_findopcode(edata)
|
|
26
|
+
return if edata.ptr > edata.data.length-4
|
|
27
|
+
di = DecodedInstruction.new self
|
|
28
|
+
val = edata.decode_imm(:u32, @endianness)
|
|
29
|
+
di.misc = val
|
|
30
|
+
return di if di.opcode = @bin_lookaside[val >> 24].find { |op|
|
|
31
|
+
(op.bin | op.bin_mask) == (val | op.bin_mask)
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def decode_instr_op(edata, di)
|
|
36
|
+
op = di.opcode
|
|
37
|
+
di.instruction.opname = op.name
|
|
38
|
+
di.bin_length = 4
|
|
39
|
+
val = di.misc
|
|
40
|
+
fld = lambda { |f|
|
|
41
|
+
(val >> @fields_off[f]) & @fields_mask[f]
|
|
42
|
+
}
|
|
43
|
+
sign_fld = lambda { |f, sz|
|
|
44
|
+
Expression.make_signed(Expression[fld[f]], sz).reduce
|
|
45
|
+
}
|
|
46
|
+
fld_smoo = lambda {
|
|
47
|
+
Expression[Expression.make_signed((val & 0x7ff) | ((val >> 10) & 0xF800), 16)]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
op.args.each { |a|
|
|
51
|
+
di.instruction.args << case a
|
|
52
|
+
when :rA, :rB, :rD; Reg.new(fld[a])
|
|
53
|
+
when :fA; FpReg.new(fld[:rA])
|
|
54
|
+
when :fB; FpReg.new(fld[:rB])
|
|
55
|
+
when :fD; FpReg.new(fld[:rD])
|
|
56
|
+
when :disp26; Expression[sign_fld[a, 26]]
|
|
57
|
+
when :uimm5, :uimm16; Expression[fld[a]]
|
|
58
|
+
when :simm16; Expression[sign_fld[a, 16]]
|
|
59
|
+
when :rA_simm16; Memref.new(Reg.new(fld[:rA]), Expression[sign_fld[:simm16, 16]], di.opcode.props[:memsz])
|
|
60
|
+
when :rA_smoo; Memref.new(Reg.new(fld[:rA]), fld_smoo[], di.opcode.props[:memsz])
|
|
61
|
+
else raise "unhandled arg #{a}"
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
di
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def decode_instr_interpret(di, addr)
|
|
69
|
+
if di.opcode.props[:setip]
|
|
70
|
+
case di.opcode.name
|
|
71
|
+
when 'j', 'jal', 'bf', 'bnf'
|
|
72
|
+
# abs26 is not absolute, duh
|
|
73
|
+
arg = Expression[addr, :+, [di.instruction.args[-1], :<<, 2]].reduce
|
|
74
|
+
di.instruction.args[-1] = Expression[arg]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
di
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# populate the @backtrace_binding hash with default values
|
|
82
|
+
def init_backtrace_binding
|
|
83
|
+
@backtrace_binding ||= {}
|
|
84
|
+
|
|
85
|
+
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
|
86
|
+
binding = case op
|
|
87
|
+
when 'movhi'; lambda { |di, a0, a1| { a0 => Expression[a1, :<<, 16] } }
|
|
88
|
+
when 'add'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :+, a2] } }
|
|
89
|
+
when 'sub'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :-, a2] } }
|
|
90
|
+
when 'mul'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :*, a2] } }
|
|
91
|
+
when 'div'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :/, a2] } }
|
|
92
|
+
when 'and'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :&, a2] } }
|
|
93
|
+
when 'or'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :|, a2] } }
|
|
94
|
+
when 'xor'; lambda { |di, a0, a1, a2| { a0 => Expression[a1, :^, a2] } }
|
|
95
|
+
when 'shl'; lambda { |di, a0, a1, a2| { a0 => Expression[[a1, :<<, a2], :&, 0xffff_ffff] } }
|
|
96
|
+
when 'shr'; lambda { |di, a0, a1, a2| { a0 => Expression[[a1, :>>, a2], :&, 0xffff_ffff] } }
|
|
97
|
+
when 'sar'; lambda { |di, a0, a1, a2| { a0 => Expression[[[a1, :>>, a2], :|, [[0xffff_ffff, :<<, a2], :*, [a1, :>>, 31]]], :&, 0xffff_ffff] } }
|
|
98
|
+
when 'ror'; lambda { |di, a0, a1, a2| { a0 => Expression[[[a1, :>>, a2], :|, [a1, :<<, [32, :-, a2]]], :&, 0xffff_ffff] } }
|
|
99
|
+
when 'lwz', 'lbz', 'lhz'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
100
|
+
when 'lbs'; lambda { |di, a0, a1| { a0 => Expression[Expression.make_signed(a1, 8)] } }
|
|
101
|
+
when 'lhs'; lambda { |di, a0, a1| { a0 => Expression[Expression.make_signed(a1, 16)] } }
|
|
102
|
+
when 'sw', 'sh', 'sb'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
103
|
+
when 'jal', 'jalr'; lambda { |di, a0| { :r9 => Expression[di.next_addr + delay_slot(di)*4] } }
|
|
104
|
+
when 'jr', 'j', 'bf', 'bnf', 'nop'; lambda { |di, *a| {} }
|
|
105
|
+
when 'sfeq'; lambda { |di, a0, a1| { :flag => Expression[a0, :==, a1] } }
|
|
106
|
+
when 'sfne'; lambda { |di, a0, a1| { :flag => Expression[a0, :!=, a1] } }
|
|
107
|
+
when 'sfgtu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :>, [a1, :&, 0xffff_ffff]] } }
|
|
108
|
+
when 'sfgeu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :>=, [a1, :&, 0xffff_ffff]] } }
|
|
109
|
+
when 'sfltu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :<, [a1, :&, 0xffff_ffff]] } }
|
|
110
|
+
when 'sfleu'; lambda { |di, a0, a1| { :flag => Expression[[a0, :&, 0xffff_ffff], :<=, [a1, :&, 0xffff_ffff]] } }
|
|
111
|
+
when 'sfgts'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :>, Expression.make_signed(a1, 32)] } }
|
|
112
|
+
when 'sfges'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :>=, Expression.make_signed(a1, 32)] } }
|
|
113
|
+
when 'sflts'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :<, Expression.make_signed(a1, 32)] } }
|
|
114
|
+
when 'sfles'; lambda { |di, a0, a1| { :flag => Expression[Expression.make_signed(a0, 32), :<=, Expression.make_signed(a1, 32)] } }
|
|
115
|
+
end
|
|
116
|
+
@backtrace_binding[op] ||= binding if binding
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@backtrace_binding
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# returns a DecodedFunction from a parsed C function prototype
|
|
123
|
+
def decode_c_function_prototype(cp, sym, orig=nil)
|
|
124
|
+
sym = cp.toplevel.symbol[sym] if sym.kind_of?(::String)
|
|
125
|
+
df = DecodedFunction.new
|
|
126
|
+
orig ||= Expression[sym.name]
|
|
127
|
+
|
|
128
|
+
new_bt = lambda { |expr, rlen|
|
|
129
|
+
df.backtracked_for << BacktraceTrace.new(expr, orig, expr, rlen ? :r : :x, rlen)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# return instr emulation
|
|
133
|
+
if sym.has_attribute 'noreturn' or sym.has_attribute '__noreturn__'
|
|
134
|
+
df.noreturn = true
|
|
135
|
+
else
|
|
136
|
+
new_bt[:r9, nil]
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
[3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].each { |r|
|
|
140
|
+
# dirty regs according to ABI
|
|
141
|
+
df.backtrace_binding.update "r#{r}".to_sym => Expression::Unknown
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# scan args for function pointers
|
|
145
|
+
reg_args = [:r3, :r4, :r5, :r6, :r7, :r8]
|
|
146
|
+
sym.type.args.to_a.zip(reg_args).each { |a, ra|
|
|
147
|
+
break if not a or not ra
|
|
148
|
+
if a.type.untypedef.kind_of?(C::Pointer)
|
|
149
|
+
pt = a.type.untypedef.type.untypedef
|
|
150
|
+
if pt.kind_of?(C::Function)
|
|
151
|
+
new_bt[ra, nil]
|
|
152
|
+
df.backtracked_for.last.detached = true
|
|
153
|
+
elsif pt.kind_of?(C::Struct)
|
|
154
|
+
new_bt[ra, cp.typesize[:ptr]]
|
|
155
|
+
else
|
|
156
|
+
new_bt[ra, cp.sizeof(nil, pt)]
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
df
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def disassembler_default_func
|
|
165
|
+
df = DecodedFunction.new
|
|
166
|
+
df.backtrace_binding = (1..32).inject({}) { |h, r| h.update "r#{r}".to_sym => Expression["r#{r}".to_sym] }
|
|
167
|
+
[3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31].each { |r|
|
|
168
|
+
df.backtrace_binding["r#{r}".to_sym] = Expression::Unknown
|
|
169
|
+
}
|
|
170
|
+
df.backtracked_for = [BacktraceTrace.new(Expression[:r9], :default, Expression[:r9], :x)]
|
|
171
|
+
df
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def backtrace_is_function_return(expr, di=nil)
|
|
175
|
+
Expression[expr].reduce_rec == :r9
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def backtrace_is_stack_address(expr)
|
|
179
|
+
Expression[expr].expr_externals.include? :r1
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|