Opdis 1.3.0
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.
- data/ChangeLog +2 -0
- data/LICENSE +674 -0
- data/LICENSE.README +8 -0
- data/README +101 -0
- data/examples/array_linear.rb +23 -0
- data/examples/bfd_entry.rb +24 -0
- data/examples/bfd_section.rb +24 -0
- data/examples/bfd_symbol.rb +27 -0
- data/examples/buf_linear.rb +25 -0
- data/examples/decoder.rb +45 -0
- data/examples/file_linear.rb +31 -0
- data/examples/libopcodes_options.rb +11 -0
- data/examples/resolver.rb +191 -0
- data/examples/supported_architectures.rb +11 -0
- data/examples/visited_handler.rb +61 -0
- data/examples/x86_decoder.rb +46 -0
- data/lib/Opdis.rb +123 -0
- data/module/Arch.c +364 -0
- data/module/Arch.h +37 -0
- data/module/Callbacks.c +266 -0
- data/module/Callbacks.h +43 -0
- data/module/Model.c +1275 -0
- data/module/Model.h +230 -0
- data/module/Opdis.c +850 -0
- data/module/Opdis.h +89 -0
- data/module/extconf.rb +126 -0
- data/module/rdoc_input/Callbacks.rb +143 -0
- data/module/rdoc_input/Model.rb +636 -0
- data/module/rdoc_input/Opdis.rb +253 -0
- data/module/ruby_compat.c +72 -0
- data/module/ruby_compat.h +25 -0
- data/tests/ut_opdis.rb +30 -0
- data/tests/ut_opdis_bfd.rb +556 -0
- metadata +109 -0
data/LICENSE.README
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
The Opdis Ruby extension is released under the GNU Public License version 3.0,
|
2
|
+
distributed in this package as LICENSE.
|
3
|
+
|
4
|
+
The intent of this license choice is not to restrict distribution, but for
|
5
|
+
compatibility with the distribution terms of opdis and GNU binutils.
|
6
|
+
|
7
|
+
Contact community@thoughtgang.org for alternative licensing arrangements if
|
8
|
+
the GPLv3 is too restrictive.
|
data/README
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
Opdis
|
2
|
+
|
3
|
+
A Ruby C extension (and gem) for the opdis library, available from
|
4
|
+
http://freshmeat.net/projects/opdis .
|
5
|
+
|
6
|
+
BUILD
|
7
|
+
-----
|
8
|
+
|
9
|
+
The standard C extension build process is used:
|
10
|
+
|
11
|
+
bash# ruby1.9 extconf.rb
|
12
|
+
bash# make
|
13
|
+
|
14
|
+
Note that the Ruby headers must be installed. On Ubuntu, these are in the
|
15
|
+
ruby-dev or ruby1.9-dev package.
|
16
|
+
|
17
|
+
|
18
|
+
The gem is built using the standard gem build command:
|
19
|
+
|
20
|
+
bash# gem build Opdis.gemspec
|
21
|
+
|
22
|
+
|
23
|
+
The top-level Makefile supports each of these builds with the commands
|
24
|
+
'make' and 'make gem'.
|
25
|
+
|
26
|
+
bash# make
|
27
|
+
# builds C extension
|
28
|
+
bash# make gem
|
29
|
+
# builds the gem
|
30
|
+
|
31
|
+
|
32
|
+
BINUTILS AND SUPPORTED ARCHITECTURES
|
33
|
+
------------------------------------
|
34
|
+
|
35
|
+
The implementation of binutils (and libopcodes) does not provide a way to
|
36
|
+
determine the supported platforms at compile time, unless the config.h file
|
37
|
+
used to build the binutils package is present.
|
38
|
+
|
39
|
+
The extconf.rb file has been modified in order to detect the architectures
|
40
|
+
supported by the local copy of binutils, and to allow the user to specify
|
41
|
+
which architectures they want supported.
|
42
|
+
|
43
|
+
It does this using the following steps:
|
44
|
+
|
45
|
+
1. run objdump -i to get the supported architectures
|
46
|
+
2. each line that matches one of binutils' known architectures is
|
47
|
+
added as a #define to CPPFLAGS
|
48
|
+
3. if no architectures have been found, or if objdump failed to run,
|
49
|
+
default to the i386 architecture.
|
50
|
+
|
51
|
+
The binary used in step 1 can be specified by the user via the --with-objdump
|
52
|
+
flag. For example:
|
53
|
+
|
54
|
+
bash# cat /tmp/objdump.sh
|
55
|
+
#/bin/sh
|
56
|
+
echo 'arm'
|
57
|
+
echo 'sparc'
|
58
|
+
echo 'm68k'
|
59
|
+
bash# ruby1.9 extconf.rb --with-objdump=/tmp/objdump.sh
|
60
|
+
checking for init_disassemble_info() in -lopcodes... yes
|
61
|
+
Adding architecture 'arm'
|
62
|
+
Adding architecture 'sparc'
|
63
|
+
Adding architecture 'm68k'
|
64
|
+
creating Makefile
|
65
|
+
|
66
|
+
This makes it possible to force compilation of support for specific
|
67
|
+
architectures when there is no working objdump present. Note that libopcodes
|
68
|
+
must have been compiled with support for the architectures, or you will get
|
69
|
+
runtime errors.
|
70
|
+
|
71
|
+
|
72
|
+
EXAMPLES
|
73
|
+
|
74
|
+
Extended examples are provided in the 'examples' directory. The following
|
75
|
+
code snippets give a brief overview of using the BFD and Opdis extensions
|
76
|
+
together.
|
77
|
+
|
78
|
+
require 'BFD'
|
79
|
+
require 'Opdis'
|
80
|
+
|
81
|
+
Bfd::Target.new('/tmp/a.out') do |tgt|
|
82
|
+
Opdis::Disassembler.new do |dis|
|
83
|
+
dis.disasm_entry( tgt ) { |insn| puts insn }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
tgt = Bfd::Target.new('/tmp/a.out')
|
88
|
+
tgt.sections.values.each { |s| puts s.name } }
|
89
|
+
Opdis::Disassembler.new do |dis|
|
90
|
+
dis.disasm_section( tgt.sections['.text.] ) { |i| puts i }
|
91
|
+
end
|
92
|
+
|
93
|
+
Opdis::Disassembler.architectures.each { |arch| puts arch }
|
94
|
+
|
95
|
+
Opdis::Disassembler.new( arch: 'x86_64_intel' ) do |dis|
|
96
|
+
dis.disassemble( [0x90, 0xCC, 0x90] ) { |insn| puts insn }
|
97
|
+
end
|
98
|
+
|
99
|
+
Opdis::Disassembler.new( arch: 'x86_intel' ) do |dis|
|
100
|
+
dis.disassemble( "\x90\xCC\x90" ) { |insn| puts insn }
|
101
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: Array
|
3
|
+
# Linear disassembly of array of bytes
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'Opdis'
|
7
|
+
|
8
|
+
def disasm_bytes( arch, bytes )
|
9
|
+
Opdis::Disassembler.new( :arch => arch ) do |dis|
|
10
|
+
dis.disassemble( bytes ) { |i| puts i }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def hex_to_array( bytes )
|
15
|
+
bytes.collect { |b| b.hex }
|
16
|
+
end
|
17
|
+
|
18
|
+
if __FILE__ == $0
|
19
|
+
raise "Usage: #{$0} ARCH BYTE [BYTE...]" if ARGV.length < 2
|
20
|
+
|
21
|
+
arch = ARGV.shift
|
22
|
+
disasm_bytes( arch, hex_to_array(ARGV) )
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: BFD Entry Point
|
3
|
+
# Control-flow disassembly of a BFD object file from its entry point
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'BFD'
|
7
|
+
require 'Opdis'
|
8
|
+
|
9
|
+
def disasm_entry( tgt )
|
10
|
+
Opdis::Disassembler.new() do |dis|
|
11
|
+
# NOTE: This will print instructions as they are disassembled
|
12
|
+
# (i.e. not in order)
|
13
|
+
dis.disasm_entry( tgt ) { |i| puts i }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if __FILE__ == $0
|
18
|
+
raise "Usage: #{$0} FILE [FILE...]" if ARGV.length == 0
|
19
|
+
|
20
|
+
ARGV.each do |filename|
|
21
|
+
Bfd::Target.new(filename) { |f| disasm_entry( f ) }
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: BFD Section
|
3
|
+
# Linear disassembly of a section in a BFD object file
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'BFD'
|
7
|
+
require 'Opdis'
|
8
|
+
|
9
|
+
def disasm_section( sec )
|
10
|
+
puts "Section not found in BFD" if not sec
|
11
|
+
|
12
|
+
puts "#{sec.name}:"
|
13
|
+
Opdis::Disassembler.new() do |dis|
|
14
|
+
dis.disasm_section( sec ) { |i| puts "\t#{i}" }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if __FILE__ == $0
|
19
|
+
raise "Usage: #{$0} FILE SECTION [SECTION...]" if ARGV.length == 0
|
20
|
+
|
21
|
+
Bfd::Target.new(ARGV.shift) do |tgt|
|
22
|
+
ARGV.each { |name| disasm_section( tgt.sections[name] ) }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: BFD Symbol
|
3
|
+
# Disassembly of a BFD object file from named symbols
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'BFD'
|
7
|
+
require 'Opdis'
|
8
|
+
|
9
|
+
def disasm_symbol( sym )
|
10
|
+
raise "Symbol not found in BFD" if not sym
|
11
|
+
raise "Symbol #{sym.name} has no VMA!" if not sym.value
|
12
|
+
|
13
|
+
puts "#{sym.name}:"
|
14
|
+
Opdis::Disassembler.new() do |dis|
|
15
|
+
# NOTE: This will print instructions as they are disassembled
|
16
|
+
# i.e. not necessarily in order
|
17
|
+
dis.disasm_symbol( sym ) { |i| puts "\t#{i}" }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if __FILE__ == $0
|
22
|
+
raise "Usage: #{$0} FILE SYMBOL [SYMBOL...]" if ARGV.length == 0
|
23
|
+
|
24
|
+
Bfd::Target.new(ARGV.shift) do |tgt|
|
25
|
+
ARGV.each { |name| disasm_symbol( tgt.symbols[name] ) }
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: String
|
3
|
+
# Linear disassembly of string of bytes
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'Opdis'
|
7
|
+
|
8
|
+
def disasm_bytes( arch, bytes )
|
9
|
+
|
10
|
+
Opdis::Disassembler.new( :arch => arch ) do |dis|
|
11
|
+
dis.disassemble( bytes ) { |i| puts i }
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def hex_to_string( bytes )
|
17
|
+
bytes.collect { |b| b.hex }.pack( 'C' * bytes.length )
|
18
|
+
end
|
19
|
+
|
20
|
+
if __FILE__ == $0
|
21
|
+
raise "Usage: #{$0} ARCH BYTE [BYTE...]" if ARGV.length < 2
|
22
|
+
|
23
|
+
arch = ARGV.shift
|
24
|
+
disasm_bytes( arch, hex_to_string(ARGV) )
|
25
|
+
end
|
data/examples/decoder.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: Decoder
|
3
|
+
# Custom Instruction Decoder used in linear disassembly of array of bytes
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'BFD'
|
7
|
+
require 'Opdis'
|
8
|
+
|
9
|
+
# ----------------------------------------------------------------------
|
10
|
+
# Decoder that wraps Generic Decoder. This bypasses the X86Decoder processing.
|
11
|
+
class CustomDecoder < Opdis::InstructionDecoder
|
12
|
+
|
13
|
+
def decode(insn, hash)
|
14
|
+
# TODO
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# ----------------------------------------------------------------------
|
20
|
+
# print an instruction in the standard disasm listing format:
|
21
|
+
# VMA 8_hex_bytes instruction
|
22
|
+
def print_insn(insn)
|
23
|
+
hex_str = insn.bytes.collect { |b| "%02X" % b }.join(' ')
|
24
|
+
puts "%08X %-23.23s %s" % [ insn.vma, hex_str, insn.ascii ]
|
25
|
+
end
|
26
|
+
|
27
|
+
# ----------------------------------------------------------------------
|
28
|
+
def disasm_bytes( bytes )
|
29
|
+
# custom decoder to use in disassembler
|
30
|
+
decoder = CustomDecoder.new
|
31
|
+
|
32
|
+
Opdis::Disassembler.new( :insn_decoder => decoder ) do |dis|
|
33
|
+
|
34
|
+
dis.disasm_entry( bytes ) { |i| print_insn(i) }
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# ----------------------------------------------------------------------
|
40
|
+
if __FILE__ == $0
|
41
|
+
raise "Usage: #{$0} ARCH BYTE [BYTE...]" if ARGV.length < 2
|
42
|
+
|
43
|
+
arch = ARGV.shift
|
44
|
+
disasm_bytes( arch, ARGV.collect { |b| b.hex } )
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
3
|
+
# Linear disassembly of a section in a BFD object file
|
4
|
+
|
5
|
+
require 'Opdis'
|
6
|
+
|
7
|
+
def disasm_file( file, arch, offset, length )
|
8
|
+
if not length
|
9
|
+
file.seek( 0, IO::SEEK_END )
|
10
|
+
length = file.tell - offset
|
11
|
+
file.rewind
|
12
|
+
end
|
13
|
+
|
14
|
+
Opdis::Disassembler.new( :arch => arch ) do |dis|
|
15
|
+
opts = { :vma => offset, :buffer_vma => 0, :length=> length }
|
16
|
+
dis.disassemble( file, opts ) do |i|
|
17
|
+
puts "%08X\t%s" % [i.vma, i.to_s]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if __FILE__ == $0
|
23
|
+
raise "Usage: #{$0} FILE ARCH [OFFSET] [LENGTH]" if ARGV.length == 0
|
24
|
+
|
25
|
+
filename = ARGV.shift
|
26
|
+
arch = ARGV.shift
|
27
|
+
offset = ARGV.length > 0 ? ARGV.shift.to_i : 0
|
28
|
+
length = ARGV.length > 0 ? ARGV.shift.to_i : nil
|
29
|
+
|
30
|
+
File.open(filename, 'rb') { |f| disasm_file( f, arch, offset, length ) }
|
31
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Opdis Example: Resolver
|
3
|
+
# Custom Address Resolver used in control-flow disassembly of BFD entry point
|
4
|
+
# Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
|
5
|
+
|
6
|
+
require 'BFD'
|
7
|
+
require 'Opdis'
|
8
|
+
|
9
|
+
# ----------------------------------------------------------------------
|
10
|
+
class Opdis::ImmediateOperand
|
11
|
+
# return immediate operand value
|
12
|
+
def resolve( ign )
|
13
|
+
return @vma
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# ----------------------------------------------------------------------
|
18
|
+
class Opdis::AddressExpressionOperand
|
19
|
+
# attempt to resolve address expression [if stack-register only]
|
20
|
+
def resolve( vm )
|
21
|
+
# TODO: if base is stack or frame register, return item from vm.stack;
|
22
|
+
# otherwise, return nil (need to be able to deref mem addr for
|
23
|
+
# general addr expressions).
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# ----------------------------------------------------------------------
|
29
|
+
class Opdis::AbsoluteAddressOperand
|
30
|
+
# attempt to resolve absolute address [segment reg + addr]
|
31
|
+
def resolve( vm )
|
32
|
+
# TODO: lookup segment register in VM; return reg value + addr
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# ----------------------------------------------------------------------
|
38
|
+
class Opdis::RegisterOperand
|
39
|
+
# attempt to resolve register operand
|
40
|
+
def resolve( vm )
|
41
|
+
# TODO: lookup register name in vm.registers and return stored value
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# ----------------------------------------------------------------------
|
47
|
+
include Opdis
|
48
|
+
class CustomResolver < AddressResolver
|
49
|
+
attr_reader :registers # reg name -> value
|
50
|
+
attr_reader :stack # array of pushed values
|
51
|
+
attr_reader :stack_ptr # index (into @stack) of 'top' of stack
|
52
|
+
attr_reader :frame_ptr # index (into @stack) of start of frame
|
53
|
+
|
54
|
+
def initialize()
|
55
|
+
@registers = {}
|
56
|
+
@stack = []
|
57
|
+
@stack_ptr = @frame_ptr = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# return VMA for target operand or nil
|
61
|
+
def resolve(insn)
|
62
|
+
return insn.target ? insn.target.resolve(self) : nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# -- Stack Management --
|
66
|
+
def stack_push( val )
|
67
|
+
@stack.push val
|
68
|
+
@stack_ptr = @stack.length - 1
|
69
|
+
end
|
70
|
+
|
71
|
+
def stack_pop()
|
72
|
+
val = @stack.push
|
73
|
+
@stack_ptr = @stack.length - 1
|
74
|
+
return val
|
75
|
+
end
|
76
|
+
|
77
|
+
def stack_frame()
|
78
|
+
@frame_ptr = @stack_ptr
|
79
|
+
end
|
80
|
+
|
81
|
+
def stack_unframe()
|
82
|
+
@stack_ptr = @frame_ptr
|
83
|
+
end
|
84
|
+
|
85
|
+
def stack_adjust( val )
|
86
|
+
if val < 0
|
87
|
+
val.abs.times { @stack.push 0 }
|
88
|
+
else
|
89
|
+
val.abs.times { @stack.pop }
|
90
|
+
end
|
91
|
+
|
92
|
+
@stack_ptr = @stack.length - 1
|
93
|
+
end
|
94
|
+
|
95
|
+
# -- Register Management --
|
96
|
+
# -- Instruction Handlers --
|
97
|
+
# call insn
|
98
|
+
def call(insn, ign, ignn)
|
99
|
+
stack_push insn.vma + insn.size
|
100
|
+
end
|
101
|
+
|
102
|
+
# return insn
|
103
|
+
def ret(insn, ign, ignn)
|
104
|
+
stack_pop
|
105
|
+
end
|
106
|
+
|
107
|
+
# push insn
|
108
|
+
def push(ign, op, ignn)
|
109
|
+
# TODO: stack_push op.value
|
110
|
+
end
|
111
|
+
|
112
|
+
# pop insn
|
113
|
+
def pop(ign, op, ignn)
|
114
|
+
val = stack_pop
|
115
|
+
# TODO: if dest is reg, move val to reg, otherwise discard
|
116
|
+
end
|
117
|
+
|
118
|
+
# frame insn
|
119
|
+
def frame(ign, ignn, ignnn)
|
120
|
+
stack_frame
|
121
|
+
end
|
122
|
+
|
123
|
+
# unframe insn
|
124
|
+
def unframe(ign, ignn, ignnn)
|
125
|
+
stack_unframe
|
126
|
+
end
|
127
|
+
|
128
|
+
# load/store insn
|
129
|
+
def lost(ign, src, dest)
|
130
|
+
# TODO: if dest is addr_expr for stack, set stack item to reg.value
|
131
|
+
# if dest is reg, fill reg with src.value
|
132
|
+
end
|
133
|
+
|
134
|
+
INSN_HANDLERS = [
|
135
|
+
[Instruction::CAT_CFLOW, Instruction::FLG_CALL, :call],
|
136
|
+
[Instruction::CAT_CFLOW, Instruction::FLG_CALLCC, :call],
|
137
|
+
[Instruction::CAT_CFLOW, Instruction::FLG_RET, :ret],
|
138
|
+
[Instruction::CAT_STACK, Instruction::FLG_PUSH, :push],
|
139
|
+
[Instruction::CAT_STACK, Instruction::FLG_POP, :pop],
|
140
|
+
[Instruction::CAT_STACK, Instruction::FLG_FRAME, :frame],
|
141
|
+
[Instruction::CAT_STACK, Instruction::FLG_UNFRAME, :unframe],
|
142
|
+
#[Instruction::CAT_MATH, Instruction::FLG_ADD, :add],
|
143
|
+
#[Instruction::CAT_MATH, Instruction::FLG_SUB, :sub],
|
144
|
+
[Instruction::CAT_LOADSTORE, nil, :lost]
|
145
|
+
]
|
146
|
+
|
147
|
+
# Modify stack/insn contents based on insn
|
148
|
+
def process(insn)
|
149
|
+
INSN_HANDLERS.each do |hdlr|
|
150
|
+
if insn.category == hdlr[0] && (not hdlr[1] or insn.flags & hdlr[1])
|
151
|
+
# Invoke handler method with instruction and src, dest operands
|
152
|
+
self.send( hdlr[2], insn, insn.src, insn.dest )
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
# ----------------------------------------------------------------------
|
160
|
+
# print an instruction in the standard disasm listing format:
|
161
|
+
# VMA 8_hex_bytes instruction
|
162
|
+
def print_insn(insn)
|
163
|
+
hex_str = insn.bytes.bytes.collect { |b| "%02X" % b }.join(' ')
|
164
|
+
puts "%08X %-23.23s %s" % [ insn.vma, hex_str, insn.ascii ]
|
165
|
+
end
|
166
|
+
|
167
|
+
# ----------------------------------------------------------------------
|
168
|
+
def disasm_entry( tgt )
|
169
|
+
# custom resolver to use in disassembler
|
170
|
+
vm = CustomResolver.new
|
171
|
+
|
172
|
+
Disassembler.new( :resolver => vm ) do |dis|
|
173
|
+
|
174
|
+
dis.disasm_entry( tgt ) do |insn|
|
175
|
+
# Set register/stack contents based on insn
|
176
|
+
vm.process(insn)
|
177
|
+
|
178
|
+
# Print instructions in order of VMA
|
179
|
+
end.values.sort_by{ |i| i.vma }.each { |i| print_insn(i) }
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# ----------------------------------------------------------------------
|
184
|
+
if __FILE__ == $0
|
185
|
+
raise "Usage: #{$0} FILE [FILE...]" if ARGV.length == 0
|
186
|
+
|
187
|
+
ARGV.each do |filename|
|
188
|
+
Bfd::Target.new(filename) { |f| disasm_entry( f ) }
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|