Opdis 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|