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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +3 -2
  5. data/metasm.gemspec +3 -2
  6. data/metasm.rb +4 -1
  7. data/metasm/compile_c.rb +2 -2
  8. data/metasm/cpu/arc/decode.rb +0 -21
  9. data/metasm/cpu/arc/main.rb +4 -4
  10. data/metasm/cpu/arm/decode.rb +1 -5
  11. data/metasm/cpu/arm/main.rb +3 -3
  12. data/metasm/cpu/arm64/decode.rb +2 -6
  13. data/metasm/cpu/arm64/main.rb +5 -5
  14. data/metasm/cpu/bpf/decode.rb +3 -35
  15. data/metasm/cpu/bpf/main.rb +5 -5
  16. data/metasm/cpu/bpf/render.rb +1 -12
  17. data/metasm/cpu/cy16/decode.rb +0 -6
  18. data/metasm/cpu/cy16/main.rb +3 -3
  19. data/metasm/cpu/cy16/render.rb +0 -11
  20. data/metasm/cpu/dalvik/decode.rb +4 -26
  21. data/metasm/cpu/dalvik/main.rb +20 -2
  22. data/metasm/cpu/dalvik/opcodes.rb +3 -2
  23. data/metasm/cpu/{mips/compile_c.rb → ebpf.rb} +5 -2
  24. data/metasm/cpu/ebpf/debug.rb +61 -0
  25. data/metasm/cpu/ebpf/decode.rb +142 -0
  26. data/metasm/cpu/ebpf/main.rb +58 -0
  27. data/metasm/cpu/ebpf/opcodes.rb +97 -0
  28. data/metasm/cpu/ebpf/render.rb +36 -0
  29. data/metasm/cpu/ia32/debug.rb +39 -1
  30. data/metasm/cpu/ia32/decode.rb +111 -90
  31. data/metasm/cpu/ia32/decompile.rb +45 -37
  32. data/metasm/cpu/ia32/main.rb +10 -0
  33. data/metasm/cpu/ia32/parse.rb +6 -0
  34. data/metasm/cpu/mcs51/decode.rb +1 -1
  35. data/metasm/cpu/mcs51/main.rb +11 -0
  36. data/metasm/cpu/mips/decode.rb +8 -18
  37. data/metasm/cpu/mips/main.rb +3 -3
  38. data/metasm/cpu/mips/opcodes.rb +1 -1
  39. data/metasm/cpu/msp430/decode.rb +2 -6
  40. data/metasm/cpu/msp430/main.rb +3 -3
  41. data/metasm/cpu/openrisc.rb +11 -0
  42. data/metasm/cpu/openrisc/debug.rb +106 -0
  43. data/metasm/cpu/openrisc/decode.rb +182 -0
  44. data/metasm/cpu/openrisc/decompile.rb +350 -0
  45. data/metasm/cpu/openrisc/main.rb +70 -0
  46. data/metasm/cpu/openrisc/opcodes.rb +109 -0
  47. data/metasm/cpu/openrisc/render.rb +37 -0
  48. data/metasm/cpu/ppc/decode.rb +0 -25
  49. data/metasm/cpu/ppc/main.rb +6 -6
  50. data/metasm/cpu/ppc/opcodes.rb +3 -4
  51. data/metasm/cpu/python/decode.rb +0 -20
  52. data/metasm/cpu/python/main.rb +1 -1
  53. data/metasm/cpu/sh4/decode.rb +2 -6
  54. data/metasm/cpu/sh4/main.rb +25 -23
  55. data/metasm/cpu/st20/decode.rb +0 -7
  56. data/metasm/cpu/webasm.rb +11 -0
  57. data/metasm/cpu/webasm/debug.rb +31 -0
  58. data/metasm/cpu/webasm/decode.rb +321 -0
  59. data/metasm/cpu/webasm/decompile.rb +386 -0
  60. data/metasm/cpu/webasm/encode.rb +104 -0
  61. data/metasm/cpu/webasm/main.rb +81 -0
  62. data/metasm/cpu/webasm/opcodes.rb +214 -0
  63. data/metasm/cpu/x86_64/compile_c.rb +13 -9
  64. data/metasm/cpu/x86_64/parse.rb +1 -1
  65. data/metasm/cpu/z80/decode.rb +0 -27
  66. data/metasm/cpu/z80/main.rb +3 -3
  67. data/metasm/cpu/z80/render.rb +0 -11
  68. data/metasm/debug.rb +43 -8
  69. data/metasm/decode.rb +62 -14
  70. data/metasm/decompile.rb +793 -466
  71. data/metasm/disassemble.rb +188 -131
  72. data/metasm/disassemble_api.rb +30 -17
  73. data/metasm/dynldr.rb +2 -2
  74. data/metasm/encode.rb +8 -2
  75. data/metasm/exe_format/autoexe.rb +2 -0
  76. data/metasm/exe_format/coff.rb +21 -3
  77. data/metasm/exe_format/coff_decode.rb +12 -0
  78. data/metasm/exe_format/coff_encode.rb +6 -3
  79. data/metasm/exe_format/dex.rb +13 -3
  80. data/metasm/exe_format/elf.rb +12 -2
  81. data/metasm/exe_format/elf_decode.rb +59 -1
  82. data/metasm/exe_format/main.rb +2 -0
  83. data/metasm/exe_format/mz.rb +1 -0
  84. data/metasm/exe_format/pe.rb +25 -3
  85. data/metasm/exe_format/wasm.rb +402 -0
  86. data/metasm/gui/dasm_decomp.rb +171 -95
  87. data/metasm/gui/dasm_graph.rb +61 -2
  88. data/metasm/gui/dasm_hex.rb +2 -2
  89. data/metasm/gui/dasm_main.rb +45 -19
  90. data/metasm/gui/debug.rb +13 -4
  91. data/metasm/gui/gtk.rb +12 -4
  92. data/metasm/main.rb +108 -103
  93. data/metasm/os/emulator.rb +175 -0
  94. data/metasm/os/main.rb +11 -6
  95. data/metasm/parse.rb +23 -12
  96. data/metasm/parse_c.rb +189 -135
  97. data/metasm/preprocessor.rb +16 -1
  98. data/misc/openrisc-parser.rb +79 -0
  99. data/samples/dasm-plugins/scanxrefs.rb +6 -4
  100. data/samples/dasm-plugins/selfmodify.rb +8 -8
  101. data/samples/dbg-plugins/trace_func.rb +1 -1
  102. data/samples/disassemble-gui.rb +14 -3
  103. data/samples/emubios.rb +251 -0
  104. data/samples/emudbg.rb +127 -0
  105. data/samples/lindebug.rb +79 -78
  106. data/samples/metasm-shell.rb +8 -8
  107. data/tests/all.rb +1 -1
  108. data/tests/expression.rb +2 -0
  109. data/tests/graph_layout.rb +1 -1
  110. data/tests/ia32.rb +1 -0
  111. data/tests/mips.rb +1 -1
  112. data/tests/preprocessor.rb +18 -0
  113. metadata +124 -6
  114. metadata.gz.sig +0 -0
@@ -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])
@@ -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
@@ -87,7 +87,7 @@ class MCS51
87
87
  di
88
88
  end
89
89
 
90
- def backtrace_binding(b)
90
+ def init_backtrace_binding
91
91
  @backtrace_binding ||= {}
92
92
  end
93
93
 
@@ -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
@@ -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.address)
175
+ when Memref; arg.symbolic(di)
181
176
  when Reg; arg.symbolic
182
177
  else arg
183
178
  end
184
179
  }
185
180
 
186
- binding = if binding = backtrace_binding[di.instruction.opname]
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
- if di.instruction.opname[0] == ?b and di.opcode.props[:setip]
190
- else
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)
@@ -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(orig)
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, orig]
55
+ Indirection[p.reduce, @sz/8, (di.address if di)]
56
56
  end
57
57
  end
58
58
 
@@ -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 => unconditionnal
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
 
@@ -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.address)
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.address)
191
+ when Memref; val = val.symbolic(di)
196
192
  end
197
193
 
198
194
  [Expression[val]]
@@ -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(orig=nil)
38
+ def symbolic(di=nil)
39
39
  r = @base.symbolic if @base
40
40
  e = Expression[r, :+, @offset].reduce
41
- Indirection[e, (@size || 1), orig]
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