indis-core 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/indis-core.rb +1 -0
- data/lib/indis-core/section.rb +4 -1
- data/lib/indis-core/symbol.rb +4 -0
- data/lib/indis-core/target.rb +70 -2
- data/lib/indis-core/version.rb +1 -1
- data/lib/indis-core/vmmap.rb +1 -1
- data/spec/indis-core/section_spec.rb +2 -2
- data/spec/indis-core/target_spec.rb +46 -1
- metadata +2 -2
data/lib/indis-core.rb
CHANGED
data/lib/indis-core/section.rb
CHANGED
@@ -21,13 +21,16 @@ module Indis
|
|
21
21
|
class Section
|
22
22
|
attr_reader :name, :segment
|
23
23
|
attr_reader :vmaddr, :vmsize, :bytes
|
24
|
+
attr_reader :type, :attributes
|
24
25
|
|
25
|
-
def initialize(seg, name, vmaddr, vmsize, iooff)
|
26
|
+
def initialize(seg, name, vmaddr, vmsize, iooff, type, attrs)
|
26
27
|
@segment = seg
|
27
28
|
@name = name
|
28
29
|
@vmaddr = vmaddr
|
29
30
|
@vmsize = vmsize
|
30
31
|
@iooff = iooff
|
32
|
+
@type = type
|
33
|
+
@attributes = attrs
|
31
34
|
end
|
32
35
|
|
33
36
|
def to_vmrange
|
data/lib/indis-core/symbol.rb
CHANGED
data/lib/indis-core/target.rb
CHANGED
@@ -38,7 +38,7 @@ module Indis
|
|
38
38
|
# @raise [AttributeError] if the file does not exist
|
39
39
|
# @raise [RuntimeError] if there is no known format for magic or there are several matching formats
|
40
40
|
def initialize(filename)
|
41
|
-
raise
|
41
|
+
raise ArgumentError, "File does not exist" unless FileTest.file?(filename)
|
42
42
|
@filename = filename
|
43
43
|
@io = StringIO.new(File.open(filename).read().force_encoding('BINARY'))
|
44
44
|
|
@@ -50,9 +50,23 @@ module Indis
|
|
50
50
|
raise RuntimeError, "Unknown format for magic #{magic.to_s(16)}" if fmts.length == 0
|
51
51
|
raise RuntimeError, "Several possible formats: #{fmts}" if fmts.length > 1
|
52
52
|
|
53
|
-
@
|
53
|
+
@format_class = fmts.first
|
54
|
+
@format_load_complete = false
|
55
|
+
end
|
56
|
+
|
57
|
+
# Perform format load and set up a vm map
|
58
|
+
def load
|
59
|
+
raise RuntimeError, "Already loaded" unless @format_class
|
60
|
+
@format = @format_class.new(self, @io)
|
61
|
+
@format_class = nil
|
54
62
|
|
55
63
|
@vmmap = VMMap.new(self)
|
64
|
+
|
65
|
+
@format_load_complete = true
|
66
|
+
replay_queue
|
67
|
+
publish_event :target_load_complete
|
68
|
+
|
69
|
+
self
|
56
70
|
end
|
57
71
|
|
58
72
|
# A target can consist of several other targets (e.g. fat mach-o). In such
|
@@ -63,6 +77,60 @@ module Indis
|
|
63
77
|
def meta?
|
64
78
|
@subtargets && @subtargets.length > 0
|
65
79
|
end
|
80
|
+
|
81
|
+
# External class can subscribe for events happening with target
|
82
|
+
#
|
83
|
+
# @param [Symbol] event event name
|
84
|
+
# @param listener event listener
|
85
|
+
def subscribe_for_event(event, listener)
|
86
|
+
subscriptions_array(event) << listener
|
87
|
+
end
|
88
|
+
|
89
|
+
# Post an event with optional payload. All events queue up until #load ends
|
90
|
+
#
|
91
|
+
# @param [Symbol] event event name
|
92
|
+
def publish_event(event, *args)
|
93
|
+
if @format_load_complete == true
|
94
|
+
subscriptions_array(event).each { |s| s.send(event, *args) }
|
95
|
+
else
|
96
|
+
enqueue_event(event, args)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Resolves a symbol at given virtual address. Targe does so by first checking
|
101
|
+
# the locally available symbols, and falls back to format specific resolver
|
102
|
+
# if nothing found
|
103
|
+
#
|
104
|
+
# @param [Fixnum] vmaddr virtual address
|
105
|
+
# @return [Indis::Symbol, nil] resolved symbol or nil if none found
|
106
|
+
def resolve_symbol_at_address(vmaddr)
|
107
|
+
s = @symbols.find { |sym| sym.vmaddr == vmaddr }
|
108
|
+
return s if s
|
109
|
+
return @format.resolve_symbol_at_address(vmaddr) if @format.respond_to?(:resolve_symbol_at_address)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
def enqueue_event(event, args)
|
114
|
+
@event_queue ||= []
|
115
|
+
@event_queue << [event, args]
|
116
|
+
end
|
117
|
+
|
118
|
+
def replay_queue
|
119
|
+
return unless @event_queue
|
120
|
+
@event_queue.each { |(e, args)| publish_event(e, *args) }
|
121
|
+
@event_queue = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
def subscriptions_array(event)
|
125
|
+
@subscriptions ||= {}
|
126
|
+
|
127
|
+
a = @subscriptions[event]
|
128
|
+
unless a
|
129
|
+
a = []
|
130
|
+
@subscriptions[event] = a
|
131
|
+
end
|
132
|
+
a
|
133
|
+
end
|
66
134
|
end
|
67
135
|
|
68
136
|
end
|
data/lib/indis-core/version.rb
CHANGED
data/lib/indis-core/vmmap.rb
CHANGED
@@ -81,7 +81,7 @@ module Indis
|
|
81
81
|
# Maps an {Indis::Entity entity} (based on its offset).
|
82
82
|
# @raise [ArgumentError] if the range is occupied by another entity
|
83
83
|
def map(e)
|
84
|
-
raise ArgumentError unless has_unmapped(e.vmaddr, e.size)
|
84
|
+
raise ArgumentError, "Tried to map #{e} at #{e.vmaddr}+#{e.size} on top of #{self[e.vmaddr...(e.vmaddr+e.size)]}" unless has_unmapped(e.vmaddr, e.size)
|
85
85
|
@blocks[e.vmaddr] = e
|
86
86
|
end
|
87
87
|
|
@@ -2,13 +2,13 @@ require 'indis-core/section'
|
|
2
2
|
|
3
3
|
describe Indis::Section do
|
4
4
|
it "should provide a correct range for its vm region" do
|
5
|
-
sect = Indis::Section.new(double('Segment'), '__text', 0x4096, 120, 0)
|
5
|
+
sect = Indis::Section.new(double('Segment'), '__text', 0x4096, 120, 0, :undef, [])
|
6
6
|
sect.to_vmrange.should == (0x4096..0x410e)
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should provide bytes value from segment based on io offset" do
|
10
10
|
seg = double('Segment', bytes: 'qwertyuiop', iooff: 100)
|
11
|
-
sect = Indis::Section.new(seg, '__text', 0x4096, 4, 102)
|
11
|
+
sect = Indis::Section.new(seg, '__text', 0x4096, 4, 102, :undef, [])
|
12
12
|
sect.bytes.should == 'erty'
|
13
13
|
end
|
14
14
|
end
|
@@ -6,13 +6,58 @@ describe Indis::Target do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
it "should load file for known format" do
|
9
|
-
fmt = double('MachO', magic: 0xfeedface, name: 'Mach-O', new:
|
9
|
+
fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
|
10
10
|
Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
|
11
11
|
t = Indis::Target.new("spec/fixtures/single-object.o")
|
12
|
+
t.load
|
12
13
|
t.io.length.should_not == 0
|
14
|
+
t.format.should_not be_nil
|
13
15
|
end
|
14
16
|
|
15
17
|
it "should raise if there is no known format to process binary" do
|
16
18
|
expect { Indis::Target.new("spec/fixtures/single-object.o") }.to raise_error(RuntimeError)
|
17
19
|
end
|
20
|
+
|
21
|
+
it "should trigger load event" do
|
22
|
+
fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
|
23
|
+
Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
|
24
|
+
t = Indis::Target.new("spec/fixtures/single-object.o")
|
25
|
+
|
26
|
+
lis = double('Listener')
|
27
|
+
lis.should_receive(:target_load_complete)
|
28
|
+
|
29
|
+
t.subscribe_for_event(:target_load_complete, lis)
|
30
|
+
|
31
|
+
t.load
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should queue up events that happen before load" do
|
35
|
+
fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
|
36
|
+
Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
|
37
|
+
t = Indis::Target.new("spec/fixtures/single-object.o")
|
38
|
+
|
39
|
+
lis = double('Listener')
|
40
|
+
lis.should_receive(:early_event).twice
|
41
|
+
|
42
|
+
t.subscribe_for_event(:early_event, lis)
|
43
|
+
|
44
|
+
t.publish_event(:early_event)
|
45
|
+
t.publish_event(:early_event)
|
46
|
+
|
47
|
+
t.load
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should pass arguments to event subscriptions" do
|
51
|
+
fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
|
52
|
+
Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
|
53
|
+
t = Indis::Target.new("spec/fixtures/single-object.o")
|
54
|
+
t.load
|
55
|
+
|
56
|
+
lis = double('Listener')
|
57
|
+
lis.should_receive(:event_with_args).with(1, 2).once
|
58
|
+
|
59
|
+
t.subscribe_for_event(:event_with_args, lis)
|
60
|
+
|
61
|
+
t.publish_event(:event_with_args, 1, 2)
|
62
|
+
end
|
18
63
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: indis-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|