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
@@ -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