metasm 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -64,7 +64,13 @@ class DecodedInstruction
64
64
  ret = []
65
65
  ret << Expression[address] << ' ' if address
66
66
  ret << @instruction
67
- ret << ' ; ' << @comment if comment
67
+ if comment
68
+ ret << ' ; '
69
+ @comment.each { |c|
70
+ ret << c << ' '
71
+ }
72
+ ret.pop
73
+ end
68
74
  ret
69
75
  end
70
76
 
@@ -102,11 +108,11 @@ class BacktraceTrace
102
108
  attr_accessor :detached
103
109
  # maxdepth at the point of the object creation
104
110
  attr_accessor :maxdepth
111
+ # disassembler cpu_context
112
+ attr_accessor :cpu_context
105
113
 
106
- def initialize(expr, origin, orig_expr, type, len=nil, maxdepth=nil)
107
- @expr, @origin, @orig_expr, @type = expr, origin, orig_expr, type
108
- @len = len if len
109
- @maxdepth = maxdepth if maxdepth
114
+ def initialize(expr, origin, orig_expr, type, len=nil, maxdepth=nil, cpu_context=nil)
115
+ @expr, @origin, @orig_expr, @type, @len, @maxdepth, @cpu_context = expr, origin, orig_expr, type, len, maxdepth, cpu_context
110
116
  end
111
117
 
112
118
  def hash ; [origin, expr].hash ; end
@@ -246,10 +252,10 @@ class DecodedFunction
246
252
  # if btbind_callback is defined, calls it with args [dasm, binding, funcaddr, calladdr, expr, origin, maxdepth]
247
253
  # else update lazily the binding from expr.externals, and return backtrace_binding
248
254
  def get_backtrace_binding(dasm, funcaddr, calladdr, expr, origin, maxdepth)
249
- if btbind_callback
250
- @btbind_callback[dasm, @backtrace_binding, funcaddr, calladdr, expr, origin, maxdepth]
251
- elsif backtrace_binding and dest = @backtrace_binding[:thunk] and target = dasm.function[dest]
255
+ if backtrace_binding and dest = @backtrace_binding[:thunk] and target = dasm.function[dest]
252
256
  target.get_backtrace_binding(dasm, funcaddr, calladdr, expr, origin, maxdepth)
257
+ elsif btbind_callback
258
+ @btbind_callback[dasm, @backtrace_binding, funcaddr, calladdr, expr, origin, maxdepth]
253
259
  else
254
260
  unk_regs = expr.externals.grep(Symbol).uniq - @backtrace_binding.keys - [:unknown]
255
261
  dasm.cpu.backtrace_update_function_binding(dasm, funcaddr, self, return_address, *unk_regs) if not unk_regs.empty?
@@ -260,10 +266,10 @@ class DecodedFunction
260
266
  # if btfor_callback is defined, calls it with args [dasm, bt_for, funcaddr, calladdr]
261
267
  # else return backtracked_for
262
268
  def get_backtracked_for(dasm, funcaddr, calladdr)
263
- if btfor_callback
264
- @btfor_callback[dasm, @backtracked_for, funcaddr, calladdr]
265
- elsif backtrace_binding and dest = @backtrace_binding[:thunk] and target = dasm.function[dest]
269
+ if backtrace_binding and dest = @backtrace_binding[:thunk] and target = dasm.function[dest]
266
270
  target.get_backtracked_for(dasm, funcaddr, calladdr)
271
+ elsif btfor_callback
272
+ @btfor_callback[dasm, @backtracked_for, funcaddr, calladdr]
267
273
  else
268
274
  @backtracked_for
269
275
  end
@@ -286,6 +292,17 @@ class DecodedFunction
286
292
  end
287
293
 
288
294
  class CPU
295
+ # decode an instruction with a dasm context
296
+ # context is a hash, should be modified inplace by the CPU
297
+ # will be passed to the next instruction(s) in the code flow
298
+ def decode_instruction_context(dasm, edata, di_addr, context)
299
+ decode_instruction(edata, di_addr)
300
+ end
301
+
302
+ # return the initial context for the disassembler, starts disassembling from addr
303
+ def disassemble_init_context(dasm, addr)
304
+ end
305
+
289
306
  # return the thing to backtrace to find +value+ before the execution of this instruction
290
307
  # eg backtrace_emu('inc eax', Expression[:eax]) => Expression[:eax + 1]
291
308
  # (the value of :eax after 'inc eax' is the value of :eax before plus 1)
@@ -294,8 +311,10 @@ class CPU
294
311
  Expression[Expression[value].bind(di.backtrace_binding ||= get_backtrace_binding(di)).reduce]
295
312
  end
296
313
 
297
- # returns a list of Expressions/Integer to backtrace to find an execution target
314
+ # return the list of jump targets for insturctions modifying the control flow
298
315
  def get_xrefs_x(dasm, di)
316
+ return [] if not di.opcode.props[:setip]
317
+ [symbolic(di.instruction.args.last, di)]
299
318
  end
300
319
 
301
320
  # returns a list of [type, address, len]
@@ -338,7 +357,7 @@ class CPU
338
357
  def replace_instr_arg_immediate(i, old, new)
339
358
  i.args.map! { |a|
340
359
  case a
341
- when Expression; Expression[a.bind(old => new).reduce]
360
+ when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
342
361
  else a
343
362
  end
344
363
  }
@@ -396,6 +415,8 @@ class Disassembler
396
415
  attr_accessor :disassemble_maxblocklength
397
416
  # a cparser that parsed some C header files, prototypes are converted to DecodedFunction when jumped to
398
417
  attr_accessor :c_parser
418
+ # if false, disassembler skips internal functions with a prototype defined in a C header (eg static libraries)
419
+ attr_accessor :disassemble_known_functions
399
420
  # hash address => array of strings
400
421
  # default dasm dump will only show comments at beginning of code blocks
401
422
  attr_accessor :comment
@@ -418,6 +439,8 @@ class Disassembler
418
439
  attr_accessor :callback_finished
419
440
  # pointer to the gui widget we're displayed in
420
441
  attr_accessor :gui
442
+ # arbitrary data stored by other objects
443
+ attr_accessor :misc
421
444
 
422
445
  @@backtrace_maxblocks = 50
423
446
 
@@ -452,7 +475,7 @@ class Disassembler
452
475
  # adds a section, updates prog_binding
453
476
  # base addr is an Integer or a String (label name for offset 0)
454
477
  def add_section(encoded, base)
455
- encoded, base = base, encoded if base.kind_of? EncodedData
478
+ encoded, base = base, encoded if base.kind_of?(EncodedData)
456
479
  case base
457
480
  when ::Integer
458
481
  when ::String
@@ -491,7 +514,7 @@ class Disassembler
491
514
  end
492
515
  end
493
516
 
494
- # yields each xref to a given address, optionnaly restricted to a type
517
+ # yields each xref to a given address, optionaly restricted to a type
495
518
  def each_xref(addr, type=nil)
496
519
  addr = normalize addr
497
520
 
@@ -545,7 +568,7 @@ class Disassembler
545
568
  # returns the canonical form of addr (absolute address integer or label of start of section + section offset)
546
569
  def normalize(addr)
547
570
  return addr if not addr or addr == :default
548
- addr = Expression[addr].bind(@old_prog_binding).reduce if not addr.kind_of? Integer
571
+ addr = Expression[addr].bind(@old_prog_binding).reduce if not addr.kind_of?(Integer)
549
572
  addr
550
573
  end
551
574
 
@@ -554,18 +577,18 @@ class Disassembler
554
577
  def get_section_at(addr, memcheck=true)
555
578
  case addr = normalize(addr)
556
579
  when ::Integer
557
- if s = @sections.find { |b, e| b.kind_of? ::Integer and addr >= b and addr < b + e.length } ||
558
- @sections.find { |b, e| b.kind_of? ::Integer and addr == b + e.length } # end label
580
+ if s = @sections.find { |b, e| b.kind_of?(::Integer) and addr >= b and addr < b + e.length } ||
581
+ @sections.find { |b, e| b.kind_of?(::Integer) and addr == b + e.length } # end label
559
582
  s[1].ptr = addr - s[0]
560
583
  return if memcheck and s[1].data.respond_to?(:page_invalid?) and s[1].data.page_invalid?(s[1].ptr)
561
584
  [s[1], s[0]]
562
585
  end
563
586
  when Expression
564
- if addr.op == :+ and addr.rexpr.kind_of? ::Integer and addr.rexpr >= 0 and addr.lexpr.kind_of? ::String and e = @sections[addr.lexpr]
587
+ if addr.op == :+ and addr.rexpr.kind_of?(::Integer) and addr.rexpr >= 0 and addr.lexpr.kind_of?(::String) and e = @sections[addr.lexpr]
565
588
  e.ptr = addr.rexpr
566
589
  return if memcheck and e.data.respond_to?(:page_invalid?) and e.data.page_invalid?(e.ptr)
567
590
  [e, Expression[addr.lexpr]]
568
- elsif addr.op == :+ and addr.rexpr.kind_of? ::String and not addr.lexpr and e = @sections[addr.rexpr]
591
+ elsif addr.op == :+ and addr.rexpr.kind_of?(::String) and not addr.lexpr and e = @sections[addr.rexpr]
569
592
  e.ptr = 0
570
593
  return if memcheck and e.data.respond_to?(:page_invalid?) and e.data.page_invalid?(e.ptr)
571
594
  [e, addr.rexpr]
@@ -582,12 +605,14 @@ class Disassembler
582
605
  return if addrstr !~ /^\w+$/
583
606
  e, b = get_section_at(addr)
584
607
  if not e
585
- l = Expression[addr].reduce_rec if Expression[addr].reduce_rec.kind_of? ::String
586
- l ||= addrstr if addr.kind_of? Expression and addr.externals.grep(::Symbol).empty?
608
+ l = Expression[addr].reduce_rec if Expression[addr].reduce_rec.kind_of?(::String)
609
+ l ||= addrstr if addr.kind_of?(Expression) and addr.externals.grep(::Symbol).empty?
587
610
  elsif not l = e.inv_export[e.ptr]
588
611
  l = @program.new_label(addrstr)
589
612
  e.add_export l, e.ptr
590
- @label_alias_cache = nil
613
+ if @label_alias_cache ||= nil
614
+ (@label_alias_cache[b + e.ptr] ||= []) << l
615
+ end
591
616
  @old_prog_binding[l] = @prog_binding[l] = b + e.ptr
592
617
  elsif rewritepfx.find { |p| base != p and addrstr.sub(base, p) == l }
593
618
  newl = addrstr
@@ -629,19 +654,24 @@ class Disassembler
629
654
  return false
630
655
  elsif @addrs_todo.empty?
631
656
  ep = entrypoints.shift
632
- l = auto_label_at(normalize(ep), 'entrypoint')
657
+ cpu_context = get_initial_cpu_context(ep)
658
+ l = auto_label_at(normalize(ep), 'entrypoint') || normalize(ep)
633
659
  puts "start disassemble from #{l} (#{entrypoints.length})" if $VERBOSE and not entrypoints.empty?
634
660
  @entrypoints << l
635
- @addrs_todo << [ep]
661
+ @addrs_todo << { :addr => ep, :cpu_context => cpu_context }
636
662
  else
637
663
  disassemble_step
638
664
  end
639
665
  true
640
666
  end
641
667
 
668
+ def get_initial_cpu_context(addr)
669
+ @cpu.disassemble_init_context(self, addr)
670
+ end
671
+
642
672
  def post_disassemble
643
673
  @decoded.each_value { |di|
644
- next if not di.kind_of? DecodedInstruction
674
+ next if not di.kind_of?(DecodedInstruction)
645
675
  next if not di.opcode or not di.opcode.props[:saveip]
646
676
  if not di.block.to_subfuncret
647
677
  di.add_comment 'noreturn'
@@ -671,19 +701,20 @@ puts " finalize subfunc #{Expression[addr]}" if debug_backtrace
671
701
  # adds next addresses to handle to addrs_todo
672
702
  # if @function[:default] exists, jumps to unknows locations are interpreted as to @function[:default]
673
703
  def disassemble_step
674
- return if not todo = @addrs_todo.pop or @addrs_done.include? todo
675
- @addrs_done << todo if todo[1]
704
+ return if not x = @addrs_todo.pop or @addrs_done.include?(x)
705
+ @addrs_done << x if x[:from]
676
706
 
677
- # from_sfret is true if from is the address of a function call that returns to addr
678
- addr, from, from_subfuncret = todo
707
+ addr = x[:addr]
708
+ from = x[:from]
709
+ # from_subfuncret is true if from is the address of a function call that returns to addr
679
710
 
680
711
  return if from == Expression::Unknown
681
712
 
682
- puts "disassemble_step #{Expression[addr]} #{Expression[from] if from} #{from_subfuncret} (/#{@addrs_todo.length})" if $DEBUG
713
+ puts "disassemble_step #{Expression[addr]} #{Expression[from] if from} #{x[:from_subfuncret]} (/#{@addrs_todo.length})" if $DEBUG
683
714
 
684
715
  addr = normalize(addr)
685
716
 
686
- if from and from_subfuncret and di_at(from)
717
+ if from and x[:from_subfuncret] and di_at(from)
687
718
  @decoded[from].block.each_to_normal { |subfunc|
688
719
  subfunc = normalize(subfunc)
689
720
  next if not f = @function[subfunc] or f.finalized
@@ -697,27 +728,36 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
697
728
  end
698
729
 
699
730
  if di = @decoded[addr]
700
- if di.kind_of? DecodedInstruction
731
+ if di.kind_of?(DecodedInstruction)
701
732
  split_block(di.block, di.address, true) if not di.block_head? # this updates di.block
702
- di.block.add_from(from, from_subfuncret ? :subfuncret : :normal) if from and from != :default
733
+ di.block.add_from(from, x[:from_subfuncret] ? :subfuncret : :normal) if from and from != :default
703
734
  bf = di.block
704
735
  elsif di == true
705
736
  bf = @function[addr]
706
737
  end
707
- elsif bf = @function[addr]
738
+ elsif from and bf = @function[addr]
708
739
  detect_function_thunk_noreturn(from) if bf.noreturn
709
740
  elsif s = get_section_at(addr)
710
- block = InstructionBlock.new(normalize(addr), s[0])
711
- block.add_from(from, from_subfuncret ? :subfuncret : :normal) if from and from != :default
712
- disassemble_block(block)
713
- elsif from and c_parser and name = Expression[addr].reduce_rec and name.kind_of? ::String and
714
- s = c_parser.toplevel.symbol[name] and s.type.untypedef.kind_of? C::Function
715
- bf = @function[addr] = @cpu.decode_c_function_prototype(@c_parser, s)
741
+ if from and c_parser and not disassemble_known_functions and name = get_all_labels_at(addr).find { |n|
742
+ cs = c_parser.toplevel.symbol[n] and cs.type.untypedef.kind_of?(C::Function) }
743
+ # do not disassemble internal function for which we have a prototype (eg static library)
744
+ puts "found known function #{name} at #{Expression[addr]}" if $VERBOSE
745
+ bf = @function[addr] = @cpu.decode_c_function_prototype(@c_parser, c_parser.toplevel.symbol[name])
746
+ detect_function_thunk_noreturn(from) if bf.noreturn
747
+ else
748
+ block = InstructionBlock.new(normalize(addr), s[0])
749
+ block.add_from(from, x[:from_subfuncret] ? :subfuncret : :normal) if from and from != :default
750
+ disassemble_block(block, x[:cpu_context])
751
+ end
752
+ elsif from and c_parser and name = Expression[addr].reduce_rec and name.kind_of?(::String) and
753
+ cs = c_parser.toplevel.symbol[name] and cs.type.untypedef.kind_of?(C::Function)
754
+ # use C header prototype for external functions if available
755
+ bf = @function[addr] = @cpu.decode_c_function_prototype(@c_parser, cs)
716
756
  detect_function_thunk_noreturn(from) if bf.noreturn
717
- elsif from
757
+ elsif from and not @function[addr]
718
758
  if bf = @function[:default]
719
759
  puts "using default function for #{Expression[addr]} from #{Expression[from]}" if $DEBUG
720
- if name = Expression[addr].reduce_rec and name.kind_of? ::String
760
+ if name = Expression[addr].reduce_rec and name.kind_of?(::String)
721
761
  @function[addr] = @function[:default].dup
722
762
  else
723
763
  addr = :default
@@ -737,7 +777,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
737
777
  end
738
778
 
739
779
  if bf and from and from != :default
740
- if bf.kind_of? DecodedFunction
780
+ if bf.kind_of?(DecodedFunction)
741
781
  bff = bf.get_backtracked_for(self, addr, from)
742
782
  else
743
783
  bff = bf.backtracked_for
@@ -745,21 +785,21 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
745
785
  end
746
786
  bff.each { |btt|
747
787
  next if btt.address
748
- if @decoded[from].kind_of? DecodedInstruction and @decoded[from].opcode.props[:saveip] and not from_subfuncret and not @function[addr]
749
- backtrace_check_found(btt.expr, @decoded[addr], btt.origin, btt.type, btt.len, btt.maxdepth, btt.detached)
788
+ if @decoded[from].kind_of?(DecodedInstruction) and @decoded[from].opcode.props[:saveip] and not x[:from_subfuncret] and not @function[addr]
789
+ backtrace_check_found(btt.expr, @decoded[addr], btt.origin, btt.type, btt.len, btt.maxdepth, btt.detached, btt.cpu_context)
750
790
  end
751
791
  next if backtrace_check_funcret(btt, addr, from)
752
792
  backtrace(btt.expr, from,
753
- :include_start => true, :from_subfuncret => from_subfuncret,
793
+ :include_start => true, :from_subfuncret => x[:from_subfuncret],
754
794
  :origin => btt.origin, :orig_expr => btt.orig_expr, :type => btt.type,
755
- :len => btt.len, :detached => btt.detached, :maxdepth => btt.maxdepth)
795
+ :len => btt.len, :detached => btt.detached, :maxdepth => btt.maxdepth, :cpu_context => btt.cpu_context)
756
796
  } if bff
757
797
  end
758
798
 
759
799
  # splits an InstructionBlock, updates the blocks backtracked_for
760
800
  def split_block(block, address=nil, rebacktrace=false)
761
801
  if not address # invoked as split_block(0x401012)
762
- return if not @decoded[block].kind_of? DecodedInstruction
802
+ return if not @decoded[block].kind_of?(DecodedInstruction)
763
803
  block, address = @decoded[block].block, block
764
804
  end
765
805
  return block if address == block.address
@@ -770,14 +810,14 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
770
810
  :only_upto => block.list.last.address,
771
811
  :include_start => !btt.exclude_instr, :from_subfuncret => btt.from_subfuncret,
772
812
  :origin => btt.origin, :orig_expr => btt.orig_expr, :type => btt.type, :len => btt.len,
773
- :detached => btt.detached, :maxdepth => btt.maxdepth)
813
+ :detached => btt.detached, :maxdepth => btt.maxdepth, :cpu_context => btt.cpu_context)
774
814
  }
775
815
  end
776
816
  new_b
777
817
  end
778
818
 
779
819
  # disassembles a new instruction block at block.address (must be normalized)
780
- def disassemble_block(block)
820
+ def disassemble_block(block, cpu_context)
781
821
  raise if not block.list.empty?
782
822
  di_addr = block.address
783
823
  delay_slot = nil
@@ -805,7 +845,8 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
805
845
 
806
846
  # decode instruction
807
847
  block.edata.ptr = di_addr - block.address + block.edata_ptr
808
- if not di = @cpu.decode_instruction(block.edata, di_addr)
848
+ cpu_context = cpu_context.dup if cpu_context
849
+ if not di = @cpu.decode_instruction_context(self, block.edata, di_addr, cpu_context)
809
850
  ed = block.edata
810
851
  break if ed.ptr >= ed.length and get_section_at(di_addr) and di = block.list.last
811
852
  puts "#{ed.ptr >= ed.length ? "end of section reached" : "unknown instruction #{ed.data[di_addr-block.address+block.edata_ptr, 4].to_s.unpack('H*').first}"} at #{Expression[di_addr]}" if $VERBOSE
@@ -845,18 +886,23 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
845
886
  if delay_slot
846
887
  di, delay = delay_slot
847
888
  if delay == 0 or not di_addr
848
- backtrace_xrefs_di_x(di)
889
+ backtrace_xrefs_di_x(di, cpu_context)
849
890
  if di.opcode.props[:stopexec] or not di_addr; return
850
891
  else break
851
892
  end
852
893
  end
853
894
  delay_slot[1] = delay - 1
854
895
  end
896
+
897
+ if block.edata.inv_export[di_addr - block.address + block.edata_ptr]
898
+ # ensure there is a block split if we have a label defined
899
+ break
900
+ end
855
901
  }
856
902
 
857
903
  ar = [di_addr]
858
904
  ar = @callback_newaddr[block.list.last.address, ar] || ar if callback_newaddr
859
- ar.each { |di_addr_| backtrace(di_addr_, di.address, :origin => di.address, :type => :x) }
905
+ ar.each { |di_addr_| backtrace(di_addr_, di.address, :origin => di.address, :type => :x, :cpu_context => cpu_context) }
860
906
 
861
907
  block
862
908
  end
@@ -878,53 +924,60 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
878
924
  @entrypoints ||= []
879
925
  @entrypoints |= entrypoints
880
926
 
881
- entrypoints.each { |ep| do_disassemble_fast_deep(normalize(ep)) }
927
+ entrypoints.each { |ep| do_disassemble_fast_deep(:addr => normalize(ep)) }
882
928
 
883
929
  @callback_finished[] if callback_finished
884
930
  end
885
931
 
886
932
  def do_disassemble_fast_deep(ep)
887
933
  disassemble_fast(ep) { |fa, di|
888
- fa = normalize(fa)
889
- do_disassemble_fast_deep(fa)
890
- if di and ndi = di_at(fa)
891
- ndi.block.add_from_normal(di.address)
892
- end
934
+ do_disassemble_fast_deep(:addr => normalize(fa), :from => di.address)
893
935
  }
894
936
  end
895
937
 
896
938
  # disassembles fast from a list of entrypoints
897
939
  # see disassemble_fast_step
898
940
  def disassemble_fast(entrypoint, maxdepth=-1, &b)
899
- ep = [entrypoint]
900
- until ep.empty?
901
- disassemble_fast_step(ep, &b)
941
+ td = entrypoint
942
+ td = { :addr => entrypoint } unless td.kind_of?(::Hash)
943
+ td[:cpu_context] ||= get_initial_cpu_context(td[:addr])
944
+ todo = [td]
945
+ until todo.empty?
946
+ disassemble_fast_step(todo, &b)
902
947
  maxdepth -= 1
903
- ep.delete_if { |a| not @decoded[normalize(a[0])] } if maxdepth == 0
948
+ todo.delete_if { |a| not @decoded[normalize(a[:addr])] } if maxdepth == 0
904
949
  end
905
- check_noreturn_function(entrypoint)
950
+ check_noreturn_function(td[:addr])
906
951
  end
907
952
 
908
953
  # disassembles one block from the ary, see disassemble_fast_block
909
954
  def disassemble_fast_step(todo, &b)
910
955
  return if not x = todo.pop
911
- addr, from, from_subfuncret = x
912
956
 
913
- addr = normalize(addr)
957
+ addr = normalize(x[:addr])
914
958
 
915
959
  if di = @decoded[addr]
916
- if di.kind_of? DecodedInstruction
960
+ if di.kind_of?(DecodedInstruction)
917
961
  split_block(di.block, di.address) if not di.block_head?
918
- di.block.add_from(from, from_subfuncret ? :subfuncret : :normal) if from and from != :default
962
+ di.block.add_from(x[:from], x[:from_subfuncret] ? :subfuncret : :normal) if x[:from] and x[:from] != :default
919
963
  end
964
+ elsif @function[addr] and x[:from]
920
965
  elsif s = get_section_at(addr)
921
- block = InstructionBlock.new(normalize(addr), s[0])
922
- block.add_from(from, from_subfuncret ? :subfuncret : :normal) if from and from != :default
923
- todo.concat disassemble_fast_block(block, &b)
924
- elsif name = Expression[addr].reduce_rec and name.kind_of? ::String and not @function[addr]
925
- if c_parser and s = c_parser.toplevel.symbol[name] and s.type.untypedef.kind_of? C::Function
926
- @function[addr] = @cpu.decode_c_function_prototype(@c_parser, s)
927
- detect_function_thunk_noreturn(from) if @function[addr].noreturn
966
+ if x[:from] and c_parser and not disassemble_known_functions and name = get_all_labels_at(addr).find { |n|
967
+ cs = c_parser.toplevel.symbol[n] and cs.type.untypedef.kind_of?(C::Function) }
968
+ # do not disassemble internal function for which we have a prototype (eg static library)
969
+ puts "found known function #{name} at #{Expression[addr]}" if $VERBOSE
970
+ @function[addr] = @cpu.decode_c_function_prototype(@c_parser, c_parser.toplevel.symbol[name])
971
+ detect_function_thunk_noreturn(x[:from]) if @function[addr].noreturn
972
+ else
973
+ block = InstructionBlock.new(addr, s[0])
974
+ block.add_from(x[:from], x[:from_subfuncret] ? :subfuncret : :normal) if x[:from] and x[:from] != :default
975
+ todo.concat disassemble_fast_block(block, x[:cpu_context], &b)
976
+ end
977
+ elsif name = Expression[addr].reduce_rec and name.kind_of?(::String) and not @function[addr]
978
+ if c_parser and cs = c_parser.toplevel.symbol[name] and cs.type.untypedef.kind_of?(C::Function)
979
+ @function[addr] = @cpu.decode_c_function_prototype(@c_parser, cs)
980
+ detect_function_thunk_noreturn(x[:from]) if @function[addr].noreturn
928
981
  elsif @function[:default]
929
982
  @function[addr] = @function[:default].dup
930
983
  end
@@ -935,7 +988,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
935
988
 
936
989
  # check if an addr has an xref :x from a :saveip, if so mark as Function
937
990
  def disassemble_fast_checkfunc(addr)
938
- if @decoded[addr].kind_of? DecodedInstruction and not @function[addr]
991
+ if @decoded[addr].kind_of?(DecodedInstruction) and not @function[addr]
939
992
  func = false
940
993
  each_xref(addr, :x) { |x_|
941
994
  func = true if odi = di_at(x_.origin) and odi.opcode.props[:saveip]
@@ -957,8 +1010,8 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
957
1010
  # no backtrace for :x (change with backtrace_maxblocks_fast)
958
1011
  # returns a todo-style ary
959
1012
  # assumes @addrs_todo is empty
960
- def disassemble_fast_block(block, &b)
961
- block = InstructionBlock.new(normalize(block), get_section_at(block)[0]) if not block.kind_of? InstructionBlock
1013
+ def disassemble_fast_block(block, cpu_context, &b)
1014
+ block = InstructionBlock.new(normalize(block), get_section_at(block)[0]) if not block.kind_of?(InstructionBlock)
962
1015
  di_addr = block.address
963
1016
  delay_slot = nil
964
1017
  di = nil
@@ -971,7 +1024,8 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
971
1024
 
972
1025
  # decode instruction
973
1026
  block.edata.ptr = di_addr - block.address + block.edata_ptr
974
- if not di = @cpu.decode_instruction(block.edata, di_addr)
1027
+ cpu_context = cpu_context.dup if cpu_context
1028
+ if not di = @cpu.decode_instruction_context(self, block.edata, di_addr, cpu_context)
975
1029
  break if block.edata.ptr >= block.edata.length and get_section_at(di_addr) and di = block.list.last
976
1030
  return ret
977
1031
  end
@@ -1002,12 +1056,12 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1002
1056
  ar = @program.get_xrefs_x(self, di)
1003
1057
  ar = @callback_newaddr[di.address, ar] || ar if callback_newaddr
1004
1058
  ar.each { |expr|
1005
- backtrace(expr, di.address, :origin => di.address, :type => :x, :maxdepth => @backtrace_maxblocks_fast)
1059
+ backtrace(expr, di.address, :origin => di.address, :type => :x, :maxdepth => @backtrace_maxblocks_fast, :cpu_context => cpu_context)
1006
1060
  }
1007
1061
  end
1008
1062
  if di.opcode.props[:saveip]
1009
1063
  @addrs_todo = []
1010
- ret.concat disassemble_fast_block_subfunc(di, &b)
1064
+ ret.concat disassemble_fast_block_subfunc(di, cpu_context, &b)
1011
1065
  else
1012
1066
  ret.concat @addrs_todo
1013
1067
  @addrs_todo = []
@@ -1028,13 +1082,13 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1028
1082
  ar = @callback_newaddr[block.list.last.address, ar] || ar if callback_newaddr
1029
1083
  ar.each { |a|
1030
1084
  di.block.add_to_normal(a)
1031
- ret << [a, di.address]
1085
+ ret << { :addr => a, :from => di.address, :cpu_context => cpu_context }
1032
1086
  }
1033
1087
  ret
1034
1088
  end
1035
1089
 
1036
1090
  # handles when disassemble_fast encounters a call to a subfunction
1037
- def disassemble_fast_block_subfunc(di)
1091
+ def disassemble_fast_block_subfunc(di, cpu_context)
1038
1092
  funcs = di.block.to_normal.to_a
1039
1093
  do_ret = funcs.empty?
1040
1094
  ret = []
@@ -1047,10 +1101,10 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1047
1101
  # this includes retaddr unless f is noreturn
1048
1102
  bf.each { |btt|
1049
1103
  next if btt.type != :x
1050
- bt = backtrace(btt.expr, di.address, :include_start => true, :origin => btt.origin, :maxdepth => [@backtrace_maxblocks_fast, 1].max)
1104
+ bt = backtrace(btt.expr, di.address, :include_start => true, :origin => btt.origin, :maxdepth => [@backtrace_maxblocks_fast, 1].max, :cpu_context => cpu_context)
1051
1105
  if btt.detached
1052
- ret.concat bt # callback argument
1053
- elsif bt.find { |a| normalize(a) == na }
1106
+ ret.concat bt.map { |a| { :addr => a } } # callback argument
1107
+ elsif not f.noreturn and bt.find { |a| normalize(a) == na }
1054
1108
  do_ret = true
1055
1109
  end
1056
1110
  }
@@ -1060,9 +1114,10 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1060
1114
  }
1061
1115
  if do_ret
1062
1116
  di.block.add_to_subfuncret(na)
1063
- ret << [na, di.address, true]
1117
+ ret << { :addr => na, :from => di.address, :from_subfuncret => true, :cpu_context => cpu_context }
1064
1118
  di.block.add_to_normal :default if not di.block.to_normal and @function[:default]
1065
1119
  end
1120
+ di.add_comment 'noreturn' if ret.empty?
1066
1121
  ret
1067
1122
  end
1068
1123
 
@@ -1085,10 +1140,10 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1085
1140
  end
1086
1141
 
1087
1142
  # trace xrefs for execution
1088
- def backtrace_xrefs_di_x(di)
1143
+ def backtrace_xrefs_di_x(di, cpu_context)
1089
1144
  ar = @program.get_xrefs_x(self, di)
1090
1145
  ar = @callback_newaddr[di.address, ar] || ar if callback_newaddr
1091
- ar.each { |expr| backtrace(expr, di.address, :origin => di.address, :type => :x) }
1146
+ ar.each { |expr| backtrace(expr, di.address, :origin => di.address, :type => :x, :cpu_context => cpu_context) }
1092
1147
  end
1093
1148
 
1094
1149
  # checks if the function starting at funcaddr is an external function thunk (eg jmp [SomeExtFunc])
@@ -1096,7 +1151,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1096
1151
  # which must not have return_addresses
1097
1152
  # returns the new thunk name if it was changed
1098
1153
  def detect_function_thunk(funcaddr)
1099
- # check thunk linearity (no conditionnal branch etc)
1154
+ # check thunk linearity (no conditional branch etc)
1100
1155
  addr = funcaddr
1101
1156
  count = 0
1102
1157
  while b = block_at(addr)
@@ -1129,7 +1184,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1129
1184
  f.backtrace_binding = { :thunk => addr }
1130
1185
  f.noreturn = true if @function[addr] and @function[addr].noreturn
1131
1186
  end
1132
- return if not fname.kind_of? ::String
1187
+ return if not fname.kind_of?(::String)
1133
1188
  l = auto_label_at(funcaddr, 'sub', 'loc')
1134
1189
  return if l[0, 4] != 'sub_'
1135
1190
  puts "found thunk for #{fname} at #{Expression[funcaddr]}" if $DEBUG
@@ -1167,14 +1222,14 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1167
1222
  # should only be called with fa = target of a call
1168
1223
  def check_noreturn_function(fa)
1169
1224
  fb = function_blocks(fa, false, false)
1225
+ return if fb.empty?
1170
1226
  lasts = fb.keys.find_all { |k| fb[k] == [] }
1171
- return if lasts.empty?
1172
1227
  if lasts.all? { |la|
1173
1228
  b = block_at(la)
1174
1229
  next if not di = b.list.last
1175
1230
  (di.opcode.props[:saveip] and b.to_normal.to_a.all? { |tfa|
1176
1231
  tf = function_at(tfa) and tf.noreturn
1177
- }) or (di.opcode.props[:stopexec] and not di.opcode.props[:setip])
1232
+ }) or (di.opcode.props[:stopexec] and not (di.opcode.props[:setip] or not get_xrefs_x(di).empty?))
1178
1233
  }
1179
1234
  # yay
1180
1235
  @function[fa] ||= DecodedFunction.new
@@ -1229,7 +1284,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1229
1284
  # (defaults to dasm.backtrace_maxblocks, which defaults do Dasm.backtrace_maxblocks)
1230
1285
  def backtrace_walk(obj, addr, include_start, from_subfuncret, stopaddr, maxdepth)
1231
1286
  start_addr = normalize(addr)
1232
- stopaddr = [stopaddr] if stopaddr and not stopaddr.kind_of? ::Array
1287
+ stopaddr = [stopaddr] if stopaddr and not stopaddr.kind_of?(::Array)
1233
1288
 
1234
1289
  # array of [obj, addr, from_subfuncret, loopdetect]
1235
1290
  # loopdetect is an array of [obj, addr, from_type] of each end of block encountered
@@ -1256,7 +1311,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1256
1311
  next if f_type == :indirect
1257
1312
  hadsomething = true
1258
1313
  o_f_addr = f_addr
1259
- f_addr = @decoded[f_addr].block.list.last.address if @decoded[f_addr].kind_of? DecodedInstruction # delay slot
1314
+ f_addr = @decoded[f_addr].block.list.last.address if @decoded[f_addr].kind_of?(DecodedInstruction) # delay slot
1260
1315
  if l = w_loopdetect.find { |l_obj, l_addr, l_type| l_addr == f_addr and l_type == f_type }
1261
1316
  f_obj = yield(:loop, w_obj, :looptrace => w_loopdetect[w_loopdetect.index(l)..-1], :loopdetect => w_loopdetect)
1262
1317
  if f_obj and f_obj != w_obj # should avoid infinite loops
@@ -1270,7 +1325,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1270
1325
  f_loopdetect ||= w_loopdetect
1271
1326
  # only count non-trivial paths in loopdetect (ignore linear links)
1272
1327
  add_detect = [[f_obj, f_addr, f_type]]
1273
- add_detect = [] if @decoded[f_addr].kind_of? DecodedInstruction and tmp = @decoded[f_addr].block and
1328
+ add_detect = [] if @decoded[f_addr].kind_of?(DecodedInstruction) and tmp = @decoded[f_addr].block and
1274
1329
  ((w_di.block.from_subfuncret.to_a == [] and w_di.block.from_normal == [f_addr] and
1275
1330
  tmp.to_normal == [w_di.address] and tmp.to_subfuncret.to_a == []) or
1276
1331
  (w_di.block.from_subfuncret == [f_addr] and tmp.to_subfuncret == [w_di.address]))
@@ -1283,7 +1338,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1283
1338
  each_xref(w_addr, :x) { |x|
1284
1339
  f_addr = x.origin
1285
1340
  o_f_addr = f_addr
1286
- f_addr = @decoded[f_addr].block.list.last.address if @decoded[f_addr].kind_of? DecodedInstruction # delay slot
1341
+ f_addr = @decoded[f_addr].block.list.last.address if @decoded[f_addr].kind_of?(DecodedInstruction) # delay slot
1287
1342
  if l = w_loopdetect.find { |l_obj, l_addr, l_type| l_addr == w_addr }
1288
1343
  f_obj = yield(:loop, w_obj, :looptrace => w_loopdetect[w_loopdetect.index(l)..-1], :loopdetect => w_loopdetect)
1289
1344
  if f_obj and f_obj != w_obj
@@ -1466,6 +1521,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1466
1521
  # :only_upto => backtrace only to update bt_for for current block & previous ending at only_upto
1467
1522
  # :no_check => don't use backtrace_check_found (will not backtrace indirection static values)
1468
1523
  # :terminals => array of symbols with constant value (stop backtracking if all symbols in the expr are terminals) (only supported with no_check)
1524
+ # :cpu_context => disassembler cpu_context
1469
1525
  def backtrace(expr, start_addr, nargs={})
1470
1526
  include_start = nargs.delete :include_start
1471
1527
  from_subfuncret = nargs.delete :from_subfuncret
@@ -1482,6 +1538,7 @@ puts " finalize subfunc #{Expression[subfunc]}" if debug_backtrace
1482
1538
  only_upto = nargs.delete :only_upto
1483
1539
  no_check = nargs.delete :no_check
1484
1540
  terminals = nargs.delete(:terminals) || []
1541
+ cpu_context = nargs.delete :cpu_context
1485
1542
  raise ArgumentError, "invalid argument to backtrace #{nargs.keys.inspect}" if not nargs.empty?
1486
1543
 
1487
1544
  expr = Expression[expr]
@@ -1502,7 +1559,7 @@ puts " not backtracking stack address #{expr}" if debug_backtrace
1502
1559
  end
1503
1560
 
1504
1561
  if vals = (no_check ? (!need_backtrace(expr, terminals) and [expr]) : backtrace_check_found(expr,
1505
- di, origin, type, len, maxdepth, detached, snapshot_addr))
1562
+ di, origin, type, len, maxdepth, detached, cpu_context, snapshot_addr))
1506
1563
  # no need to update backtracked_for
1507
1564
  return vals
1508
1565
  elsif maxdepth <= 0
@@ -1511,7 +1568,7 @@ puts " not backtracking stack address #{expr}" if debug_backtrace
1511
1568
 
1512
1569
  # create initial backtracked_for
1513
1570
  if type and origin == start_addr and di
1514
- btt = BacktraceTrace.new(expr, origin, origexpr, type, len, maxdepth-1)
1571
+ btt = BacktraceTrace.new(expr, origin, origexpr, type, len, maxdepth-1, cpu_context)
1515
1572
  btt.address = di.address
1516
1573
  btt.exclude_instr = true if not include_start
1517
1574
  btt.from_subfuncret = true if from_subfuncret and include_start
@@ -1532,9 +1589,9 @@ puts "backtracking #{type} #{expr} from #{di || Expression[start_addr || 0]} for
1532
1589
  when :unknown_addr, :maxdepth
1533
1590
  puts " backtrace end #{ev} #{expr}" if debug_backtrace
1534
1591
  result |= [expr] if not snapshot_addr
1535
- @addrs_todo << [expr, (detached ? nil : origin)] if not snapshot_addr and type == :x and origin
1592
+ @addrs_todo << { :addr => expr, :from => (detached ? nil : origin), :cpu_context => cpu_context } if not snapshot_addr and type == :x and origin
1536
1593
  when :end
1537
- if not expr.kind_of? StoppedExpr
1594
+ if not expr.kind_of?(StoppedExpr)
1538
1595
  oldexpr = expr
1539
1596
  expr = backtrace_emu_blockup(h[:addr], expr)
1540
1597
  puts " backtrace up #{Expression[h[:addr]]} #{oldexpr}#{" => #{expr}" if expr != oldexpr}" if debug_backtrace
@@ -1542,7 +1599,7 @@ puts " backtrace up #{Expression[h[:addr]]} #{oldexpr}#{" => #{expr}" if expr
1542
1599
  if expr != oldexpr and not snapshot_addr and vals = (no_check ?
1543
1600
  (!need_backtrace(expr, terminals) and [expr]) :
1544
1601
  backtrace_check_found(expr, nil, origin, type, len,
1545
- maxdepth-h[:loopdetect].length, detached, snapshot_addr))
1602
+ maxdepth-h[:loopdetect].length, detached, cpu_context, snapshot_addr))
1546
1603
  result |= vals
1547
1604
  next
1548
1605
  end
@@ -1551,14 +1608,14 @@ puts " backtrace end #{ev} #{expr}" if debug_backtrace
1551
1608
  if not snapshot_addr
1552
1609
  result |= [expr]
1553
1610
 
1554
- btt = BacktraceTrace.new(expr, origin, origexpr, type, len, maxdepth-h[:loopdetect].length-1)
1611
+ btt = BacktraceTrace.new(expr, origin, origexpr, type, len, maxdepth-h[:loopdetect].length-1, cpu_context)
1555
1612
  btt.detached = true if detached
1556
1613
  @decoded[h[:addr]].block.backtracked_for |= [btt] if @decoded[h[:addr]]
1557
1614
  @function[h[:addr]].backtracked_for |= [btt] if @function[h[:addr]] and h[:addr] != :default
1558
- @addrs_todo << [expr, (detached ? nil : origin)] if type == :x and origin
1615
+ @addrs_todo << { :addr => expr, :from => (detached ? nil : origin), :cpu_context => cpu_context } if type == :x and origin
1559
1616
  end
1560
1617
  when :stopaddr
1561
- if not expr.kind_of? StoppedExpr
1618
+ if not expr.kind_of?(StoppedExpr)
1562
1619
  oldexpr = expr
1563
1620
  expr = backtrace_emu_blockup(h[:addr], expr)
1564
1621
  puts " backtrace up #{Expression[h[:addr]]} #{oldexpr}#{" => #{expr}" if expr != oldexpr}" if debug_backtrace
@@ -1567,7 +1624,7 @@ puts " backtrace up #{Expression[h[:addr]]} #{oldexpr}#{" => #{expr}" if expr
1567
1624
  puts " backtrace end #{ev} #{expr}" if debug_backtrace
1568
1625
  result |= ((expr.kind_of?(StoppedExpr)) ? expr.exprs : [expr])
1569
1626
  when :loop
1570
- next false if expr.kind_of? StoppedExpr
1627
+ next false if expr.kind_of?(StoppedExpr)
1571
1628
  t = h[:looptrace]
1572
1629
  oldexpr = t[0][0]
1573
1630
  next false if expr == oldexpr # unmodifying loop
@@ -1576,7 +1633,7 @@ puts " bt loop at #{Expression[t[0][1]]}: #{oldexpr} => #{expr} (#{t.map { |z|
1576
1633
  false
1577
1634
  when :up
1578
1635
  next false if only_upto and h[:to] != only_upto
1579
- next expr if expr.kind_of? StoppedExpr
1636
+ next expr if expr.kind_of?(StoppedExpr)
1580
1637
  oldexpr = expr
1581
1638
  expr = backtrace_emu_blockup(h[:from], expr)
1582
1639
  puts " backtrace up #{Expression[h[:from]]}->#{Expression[h[:to]]} #{oldexpr}#{" => #{expr}" if expr != oldexpr}" if debug_backtrace
@@ -1584,7 +1641,7 @@ puts " backtrace up #{Expression[h[:from]]}->#{Expression[h[:to]]} #{oldexpr}#
1584
1641
 
1585
1642
  if expr != oldexpr and vals = (no_check ? (!need_backtrace(expr, terminals) and [expr]) :
1586
1643
  backtrace_check_found(expr, @decoded[h[:from]], origin, type, len,
1587
- maxdepth-h[:loopdetect].length, detached, snapshot_addr))
1644
+ maxdepth-h[:loopdetect].length, detached, cpu_context, snapshot_addr))
1588
1645
  if snapshot_addr
1589
1646
  expr = StoppedExpr.new vals
1590
1647
  next expr
@@ -1606,7 +1663,7 @@ puts " backtrace up #{Expression[h[:from]]}->#{Expression[h[:to]]} #{oldexpr}#
1606
1663
  end
1607
1664
  }
1608
1665
 
1609
- btt = BacktraceTrace.new(expr, origin, origexpr, type, len, maxdepth-h[:loopdetect].length-1)
1666
+ btt = BacktraceTrace.new(expr, origin, origexpr, type, len, maxdepth-h[:loopdetect].length-1, cpu_context)
1610
1667
  btt.detached = true if detached
1611
1668
  if x = di_at(h[:from])
1612
1669
  update_btf[x.block.backtracked_for, btt]
@@ -1630,7 +1687,7 @@ puts " already backtraced" if debug_backtrace
1630
1687
  end
1631
1688
  expr
1632
1689
  when :di, :func
1633
- next if expr.kind_of? StoppedExpr
1690
+ next if expr.kind_of?(StoppedExpr)
1634
1691
  if not snapshot_addr and @cpu.backtrace_is_stack_address(expr)
1635
1692
  puts " not backtracking stack address #{expr}" if debug_backtrace
1636
1693
  next false
@@ -1653,7 +1710,7 @@ puts " backtrace: recursive function #{Expression[h[:funcaddr]]}" if debug_back
1653
1710
  end
1654
1711
  puts " backtrace #{h[:di] || Expression[h[:funcaddr]]} #{oldexpr} => #{expr}" if debug_backtrace and expr != oldexpr
1655
1712
  if vals = (no_check ? (!need_backtrace(expr, terminals) and [expr]) : backtrace_check_found(expr,
1656
- h[:di], origin, type, len, maxdepth-h[:loopdetect].length, detached, snapshot_addr))
1713
+ h[:di], origin, type, len, maxdepth-h[:loopdetect].length, detached, cpu_context, snapshot_addr))
1657
1714
  if snapshot_addr
1658
1715
  expr = StoppedExpr.new vals
1659
1716
  else
@@ -1685,7 +1742,7 @@ puts ' backtrace result: ' + result.map { |r| Expression[r] }.join(', ') if deb
1685
1742
  not need_backtrace(retaddr)
1686
1743
  puts " backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if debug_backtrace
1687
1744
  di.block.add_to_subfuncret normalize(retaddr)
1688
- if @decoded[funcaddr].kind_of? DecodedInstruction
1745
+ if @decoded[funcaddr].kind_of?(DecodedInstruction)
1689
1746
  # check that all callers :saveip returns (eg recursive call that was resolved
1690
1747
  # before we found funcaddr was a function)
1691
1748
  @decoded[funcaddr].block.each_from_normal { |fm|
@@ -1703,17 +1760,17 @@ puts " backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if
1703
1760
  todo = []
1704
1761
  di.block.each_to_normal { |t| todo << normalize(t) }
1705
1762
  while a = todo.pop
1706
- next if faddrlist.include? a or not get_section_at(a)
1763
+ next if faddrlist.include?(a) or not get_section_at(a)
1707
1764
  faddrlist << a
1708
- if @decoded[a].kind_of? DecodedInstruction
1765
+ if @decoded[a].kind_of?(DecodedInstruction)
1709
1766
  @decoded[a].block.each_to_samefunc(self) { |t| todo << normalize(t) }
1710
1767
  end
1711
1768
  end
1712
1769
 
1713
- idx = @addrs_todo.index(@addrs_todo.find { |r, i, sfr| faddrlist.include? normalize(r) }) || -1
1714
- @addrs_todo.insert(idx, [retaddr, instraddr, true])
1770
+ idx = @addrs_todo.index(@addrs_todo.find { |aa| faddrlist.include? normalize(aa[:addr]) }) || -1
1771
+ @addrs_todo.insert(idx, { :addr => retaddr, :from => instraddr, :from_subfuncret => true, :cpu_context => btt.cpu_context })
1715
1772
  else
1716
- @addrs_todo << [retaddr, instraddr, true]
1773
+ @addrs_todo << { :addr => retaddr, :from => instraddr, :from_subfuncret => true, :cpu_context => btt.cpu_context }
1717
1774
  end
1718
1775
  true
1719
1776
  end
@@ -1752,7 +1809,7 @@ puts " backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if
1752
1809
  # returns true if the expression needs more backtrace
1753
1810
  # it checks for the presence of a symbol (not :unknown), which means it depends on some register value
1754
1811
  def need_backtrace(expr, terminals=[])
1755
- return if expr.kind_of? ::Integer
1812
+ return if expr.kind_of?(::Integer)
1756
1813
  !(expr.externals.grep(::Symbol) - [:unknown] - terminals).empty?
1757
1814
  end
1758
1815
 
@@ -1770,7 +1827,7 @@ puts " backtrace addrs_todo << #{Expression[retaddr]} from #{di} (funcret)" if
1770
1827
  # TODO trace expr evolution through backtrace, to modify immediates to an expr involving label names
1771
1828
  # TODO mov [ptr], imm ; <...> ; jmp [ptr] => rename imm as loc_XX
1772
1829
  # eg. mov eax, 42 ; add eax, 4 ; jmp eax => mov eax, some_label-4
1773
- def backtrace_check_found(expr, di, origin, type, len, maxdepth, detached, snapshot_addr=nil)
1830
+ def backtrace_check_found(expr, di, origin, type, len, maxdepth, detached, cpu_context, snapshot_addr=nil)
1774
1831
  # only entrypoints or block starts called by a :saveip are checked for being a function
1775
1832
  # want to execute [esp] from a block start
1776
1833
  if type == :x and di and di == di.block.list.first and @cpu.backtrace_is_function_return(expr, @decoded[origin]) and (
@@ -1812,7 +1869,7 @@ puts "backtrace #{type} found #{expr} from #{di} orig #{@decoded[origin] || Expr
1812
1869
 
1813
1870
  # create xrefs/labels
1814
1871
  result.each { |e|
1815
- backtrace_found_result(e, di, type, origin, len, detached)
1872
+ backtrace_found_result(e, di, type, origin, len, detached, cpu_context)
1816
1873
  } if type and origin
1817
1874
 
1818
1875
  result
@@ -1941,7 +1998,7 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
1941
1998
  end
1942
1999
 
1943
2000
  # creates xrefs, updates addrs_todo, updates instr args
1944
- def backtrace_found_result(expr, di, type, origin, len, detached)
2001
+ def backtrace_found_result(expr, di, type, origin, len, detached, cpu_context)
1945
2002
  n = normalize(expr)
1946
2003
  fallthrough = true if type == :x and o = di_at(origin) and not o.opcode.props[:stopexec] and n == o.block.list.last.next_addr # delay_slot
1947
2004
  add_xref(n, Xref.new(type, origin, len)) if origin != :default and origin != Expression::Unknown and not fallthrough
@@ -2000,7 +2057,7 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2000
2057
  else
2001
2058
  @decoded[origin].block.add_to_normal(normalize(n)) if @decoded[origin] and not unk
2002
2059
  end
2003
- @addrs_todo << [n, origin]
2060
+ @addrs_todo << { :addr => n, :from => origin, :cpu_context => cpu_context }
2004
2061
  end
2005
2062
  end
2006
2063
 
@@ -2014,12 +2071,12 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2014
2071
  a
2015
2072
  end
2016
2073
 
2017
- # dumps the source, optionnally including data
2074
+ # dumps the source, optionally including data
2018
2075
  # yields (defaults puts) each line
2019
2076
  def dump(dump_data=true, &b)
2020
2077
  b ||= lambda { |l| puts l }
2021
2078
  @sections.sort_by { |addr, edata| addr.kind_of?(::Integer) ? addr : 0 }.each { |addr, edata|
2022
- addr = Expression[addr] if addr.kind_of? ::String
2079
+ addr = Expression[addr] if addr.kind_of?(::String)
2023
2080
  blockoffs = @decoded.values.grep(DecodedInstruction).map { |di| Expression[di.block.address, :-, addr].reduce if di.block_head? }.grep(::Integer).sort.reject { |o| o < 0 or o >= edata.length }
2024
2081
  b[@program.dump_section_header(addr, edata)]
2025
2082
  if not dump_data and edata.length > 16*1024 and blockoffs.empty?
@@ -2034,7 +2091,7 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2034
2091
  di = @decoded[addr+unk_off]
2035
2092
  if unk_off != di.block.edata_ptr
2036
2093
  b["\n// ------ overlap (#{unk_off-di.block.edata_ptr}) ------"]
2037
- elsif di.block.from_normal.kind_of? ::Array
2094
+ elsif di.block.from_normal.kind_of?(::Array)
2038
2095
  b["\n"]
2039
2096
  end
2040
2097
  dump_block(di.block, &b)
@@ -2079,7 +2136,7 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2079
2136
  label_alias[block.address].each { |name| b["#{name}:"] }
2080
2137
  end
2081
2138
  if c = @comment[block.address]
2082
- c = c.join("\n") if c.kind_of? ::Array
2139
+ c = c.join("\n") if c.kind_of?(::Array)
2083
2140
  c.each_line { |l| b["// #{l}"] }
2084
2141
  end
2085
2142
  end
@@ -2124,11 +2181,11 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2124
2181
  dups = edata.virtsize - off
2125
2182
  @prog_binding.each_value { |a|
2126
2183
  tmp = Expression[a, :-, addr].reduce
2127
- dups = tmp if tmp.kind_of? ::Integer and tmp > 0 and tmp < dups
2184
+ dups = tmp if tmp.kind_of?(::Integer) and tmp > 0 and tmp < dups
2128
2185
  }
2129
2186
  @xrefs.each_key { |a|
2130
2187
  tmp = Expression[a, :-, addr].reduce
2131
- dups = tmp if tmp.kind_of? ::Integer and tmp > 0 and tmp < dups
2188
+ dups = tmp if tmp.kind_of?(::Integer) and tmp > 0 and tmp < dups
2132
2189
  }
2133
2190
  dups /= elemlen
2134
2191
  dups = 1 if dups < 1
@@ -2174,7 +2231,7 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2174
2231
  if (elemlen == 1 or elemlen == 2)
2175
2232
  case value
2176
2233
  when 0x20..0x7e, 0x0a, 0x0d
2177
- if vals_.last.kind_of? ::String; vals_.last << value ; vals_
2234
+ if vals_.last.kind_of?(::String); vals_.last << value ; vals_
2178
2235
  else vals_ << value.chr
2179
2236
  end
2180
2237
  else vals_ << value
@@ -2184,7 +2241,7 @@ puts " backtrace_indirection for #{ind.target} failed: #{ev}" if debug_backtra
2184
2241
  }
2185
2242
 
2186
2243
  vals.map! { |value|
2187
- if value.kind_of? ::String
2244
+ if value.kind_of?(::String)
2188
2245
  if value.length > 2 # or value == vals.first or value == vals.last # if there is no xref, don't care
2189
2246
  value.inspect
2190
2247
  else