indis-core 0.1.1 → 0.1.2
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/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
|