ony-ruby-elf 1.1.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.
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Simple ELF parser for Ruby
3
+ #
4
+ # Copyright © 2007-2010 Diego Elio Pettenò <flameeyes@flameeyes.eu>
5
+ # Portions inspired by elf.py
6
+ # Copyright © 2002 Netgraft Corporation
7
+ # Portions inspired by elf.h
8
+ # Copyright © 1995-2006 Free Software Foundation, Inc.
9
+ #
10
+ # This program is free software; you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation; either version 2 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this generator; if not, write to the Free Software
22
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
+
24
+ require 'elf/section'
25
+ require 'elf/utils/offsettable'
26
+
27
+ module Elf
28
+ class StringTable < Section
29
+ def load_internal
30
+ @rawtable = Utilities::OffsetTable.new(@file.readexactly(@size), "\x00")
31
+ end
32
+
33
+ def [](idx)
34
+ load unless @rawtable
35
+
36
+ @rawtable[idx]
37
+ end
38
+ end
39
+ end
data/lib/elf/sunw.rb ADDED
@@ -0,0 +1,158 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Simple ELF parser for Ruby
3
+ #
4
+ # Copyright © 2008-2010 Diego Elio Pettenò <flameeyes@flameeyes.eu>
5
+ # Portions inspired by elf.py
6
+ # Copyright © 2002 Netgraft Corporation
7
+ # Portions inspired by elf.h
8
+ # Copyright © 1995-2006 Free Software Foundation, Inc.
9
+ # Constants derived from OpenSolaris elf.h and documentation
10
+ # Copyright © 2007 Sun Microsystems, Inc.
11
+ #
12
+ # This program is free software; you can redistribute it and/or modify
13
+ # it under the terms of the GNU General Public License as published by
14
+ # the Free Software Foundation; either version 2 of the License, or
15
+ # (at your option) any later version.
16
+ #
17
+ # This program is distributed in the hope that it will be useful,
18
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ # GNU General Public License for more details.
21
+ #
22
+ # You should have received a copy of the GNU General Public License
23
+ # along with this generator; if not, write to the Free Software
24
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
+
26
+ module Elf
27
+ # Sun-specific sections parsing
28
+ module SunW
29
+
30
+ class Capabilities < Section
31
+ class Tag < Value
32
+ fill(
33
+ 0 => [ :Null, nil ],
34
+ 1 => [ :HW1, "Hardware capabilities" ],
35
+ 2 => [ :SF1, "Software capabilities" ]
36
+ )
37
+ end
38
+
39
+ class Software1 < Value
40
+ fill(
41
+ 0x0001 => [ :FramePointerKnown, "Frame pointer use is known" ],
42
+ 0x0002 => [ :FramePointerUsed, "Frame pointer is used" ]
43
+ )
44
+
45
+ # Known capabilities mask
46
+ KnownMask = 0x003
47
+ end
48
+
49
+ module Hardware1
50
+ class Sparc < Value
51
+ fill(
52
+ 0x0001 => [ :Mul32, "Uses 32x32-bit smul/umul" ],
53
+ 0x0002 => [ :Div32, "Uses 32x32-bit sdiv/udiv" ],
54
+ 0x0004 => [ :Fsmuld, "Uses fsmuld instruction" ],
55
+ 0x0008 => [ :V8Plus, "Uses V9 intructins in 32-bit apps" ],
56
+ 0x0010 => [ :Popc, "Uses popc instruction" ],
57
+ 0x0020 => [ :Vis, "Uses VIS instruction set" ],
58
+ 0x0040 => [ :Vis2, "Uses VIS2 instruction set" ],
59
+ 0x0080 => [ :AsiBlkInit, nil ],
60
+ 0x0100 => [ :Fmaf, "Uses Fused Multiply-Add" ],
61
+ 0x0200 => [ :FjFmau, "Uses Fujitsu Unfused Multiply-Add" ],
62
+ 0x0400 => [ :Ima, "Uses Integer Multiply-Add" ]
63
+ )
64
+ end
65
+
66
+ class I386 < Value
67
+ fill(
68
+ 0x00000001 => [ :FPU, "Uses x87-style floating point" ],
69
+ 0x00000002 => [ :TSC, "Uses rdtsc instruction" ],
70
+ 0x00000004 => [ :CX8, "Uses cmpxchg8b instruction" ],
71
+ 0x00000008 => [ :SEP, "Uses sysenter/sysexit instructions" ],
72
+ 0x00000010 => [ :AmdSycC, "Uses AMD's syscall/sysret instructions" ],
73
+ 0x00000020 => [ :CMov, "Uses conditional move instructions" ],
74
+ 0x00000040 => [ :MMX, "Uses MMX instruction set" ],
75
+ 0x00000080 => [ :AmdMMX, "Uses AMD's MMX instruction set" ],
76
+ 0x00000100 => [ :Amd3DNow, "Uses AMD's 3DNow! instruction set" ],
77
+ 0x00000200 => [ :Amd3DNowX, "Uses AMD's 3DNow! extended instruction set" ],
78
+ 0x00000400 => [ :FXSR, "Uses fxsave/fxrstor instructions" ],
79
+ 0x00000800 => [ :SSE, "Uses SSE instruction set and registers" ],
80
+ 0x00001000 => [ :SSE2, "Uses SSE2 instruction set and registers" ],
81
+ 0x00002000 => [ :Pause, "Uses pause instruction" ],
82
+ 0x00004000 => [ :SSE3, "Uses SSE3 instruction set and registers" ],
83
+ 0x00008000 => [ :Mon, "Uses monitor/mwait instructions" ],
84
+ 0x00010000 => [ :CX16, "Uses cmpxchg16b instruction" ],
85
+ 0x00020000 => [ :AHF, "Uses lahf/sahf instructions" ],
86
+ 0x00040000 => [ :TSCP, "Uses rdtscp instruction" ],
87
+ 0x00080000 => [ :AmdSSE4a, "Uses AMD's SSEA4a instructions" ],
88
+ 0x00100000 => [ :PopCnt, "Uses popcnt instruction" ],
89
+ 0x00200000 => [ :AmdLzcnt, "Uses AMD's lzcnt instructon" ],
90
+ 0x00400000 => [ :SSSE3, "Uses Intel's SSSE3 instruction set" ],
91
+ 0x00800000 => [ :SSE4_1, "Uses Intel's SSE4.1 instruction set" ],
92
+ 0x01000000 => [ :SSE4_2, "uses Intel's SSE4.2 instruction set" ]
93
+ )
94
+ end
95
+ end
96
+
97
+ def load_internal
98
+ elf32 = @file.elf_class == Class::Elf32
99
+
100
+ @entries = []
101
+ loop do
102
+ entry = {}
103
+ tag = elf32 ? @file.read_word : @file.read_xword
104
+ entry[:tag] = Tag[tag]
105
+
106
+ # This marks the end of the array.
107
+ break if entry[:tag] == Tag::Null
108
+
109
+ # Right now the only two types used make only use of c_val,
110
+ # but in the future there might be capabilities using c_ptr,
111
+ # so prepare for that.
112
+ case entry[:tag]
113
+ when Tag::SF1
114
+ val = elf32 ? @file.read_word : @file.read_xword
115
+ entry[:flags] = Set.new
116
+
117
+ Software1.each do |flag|
118
+ entry[:flags].add(flag) if (val & flag.val) == flag.val
119
+ end
120
+ when Tag::HW1
121
+ val = elf32 ? @file.read_word : @file.read_xword
122
+ entry[:flags] = Set.new
123
+
124
+ case @file.machine
125
+ when Machine::Sparc
126
+ Hardware1::Sparc.each do |flag|
127
+ entry[:flags].add(flag) if (val & flag.val) == flag.val
128
+ end
129
+ when Machine::I386
130
+ Hardware1::I386.each do |flag|
131
+ entry[:flags].add(flag) if (val & flag.val) == flag.val
132
+ end
133
+ else
134
+ raise "Sun-specific extensions only support i386/Sparc!"
135
+ end
136
+
137
+ else
138
+ entry[:ptr] = @file.read_addr
139
+ end
140
+
141
+ @entries << entry
142
+ end
143
+ end
144
+
145
+ def size
146
+ load unless @entries
147
+
148
+ @entries.size
149
+ end
150
+
151
+ def [](idx)
152
+ load unless @entries
153
+
154
+ @entries[idx]
155
+ end
156
+ end
157
+ end
158
+ end
data/lib/elf/symbol.rb ADDED
@@ -0,0 +1,406 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Simple ELF parser for Ruby
3
+ #
4
+ # Copyright © 2007-2010 Diego Elio Pettenò <flameeyes@flameeyes.eu>
5
+ # Portions inspired by elf.py
6
+ # Copyright © 2002 Netgraft Corporation
7
+ # Portions inspired by elf.h
8
+ # Copyright © 1995-2006 Free Software Foundation, Inc.
9
+ #
10
+ # This program is free software; you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation; either version 2 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this generator; if not, write to the Free Software
22
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
+
24
+ module Elf
25
+ class Symbol
26
+ class Binding < Value
27
+ fill(
28
+ 0 => [ :Local, 'Local symbol' ],
29
+ 1 => [ :Global, 'Global symbol' ],
30
+ 2 => [ :Weak, 'Weak symbol' ],
31
+ # This one is inferred out of libpam.so
32
+ 3 => [ :Number, 'Number of defined type' ]
33
+ )
34
+
35
+ class GNU < Value
36
+ fill(
37
+ 10 => [ :Unique, 'Unique symbol' ]
38
+ )
39
+ end
40
+
41
+ OsSpecific = 10..12
42
+ ProcSpecific = 13..15
43
+
44
+ SpecialRanges = {
45
+ "STB_LOOS" => OsSpecific,
46
+ "STB_LOPROC" => ProcSpecific
47
+ }
48
+ end
49
+
50
+ class Type < Value
51
+ fill(
52
+ 0 => [ :None, 'Unspecified' ],
53
+ 1 => [ :Object, 'Data object' ],
54
+ 2 => [ :Func, 'Code object' ],
55
+ 3 => [ :Section, 'Associated with a section' ],
56
+ 4 => [ :File, 'File name' ],
57
+ 5 => [ :Common, 'Common data object' ],
58
+ 6 => [ :TLS, 'Thread-local data object' ]
59
+ )
60
+
61
+ class GNU < Value
62
+ fill(
63
+ 10 => [ :IFunc, 'Indirect function' ]
64
+ )
65
+ end
66
+
67
+ OsSpecific = 10..12
68
+ ProcSpecific = 13..15
69
+ SpecialRanges = {
70
+ "STT_LOOS" => OsSpecific,
71
+ "STT_LOPROC" => ProcSpecific
72
+ }
73
+ end
74
+
75
+ class Visibility < Value
76
+ fill(
77
+ 0 => [ :Default, 'Default visibility' ],
78
+ 1 => [ :Internal, 'Processor-specific hidden visibility' ],
79
+ 2 => [ :Hidden, 'Hidden visibility' ],
80
+ 3 => [ :Protected, 'Protected visibility' ],
81
+ 4 => [ :Exported, 'Exported symbol' ],
82
+ 5 => [ :Singleton, 'Singleton symbol' ],
83
+ 6 => [ :Eliminate, 'Symbol to be eliminated' ]
84
+ )
85
+ end
86
+
87
+ attr_reader :value, :size, :other, :bind, :type, :idx, :visibility, :file
88
+
89
+ # Create a new Symbol object reading the symbol structure from the file.
90
+ # This function assumes that the elf file is aligned ad the
91
+ # start of a symbol structure, and returns the file moved at the
92
+ # start of the symbol.
93
+ def initialize(elf, symsect, idx)
94
+ @symsect = symsect
95
+ @idx = idx
96
+
97
+ case elf.elf_class
98
+ when Class::Elf32
99
+ @name = elf.read_word
100
+ @value = elf.read_addr
101
+ @size = elf.read_word
102
+ info = elf.read_u8
103
+ @other = elf.read_u8
104
+ @section = elf.read_section
105
+ when Class::Elf64
106
+ @name = elf.read_word
107
+ info = elf.read_u8
108
+ @other = elf.read_u8
109
+ @section = elf.read_section
110
+ @value = elf.read_addr
111
+ @size = elf.read_xword
112
+ end
113
+
114
+ begin
115
+ type_value = info & 0xF
116
+ @type = case
117
+ when Type::OsSpecific.include?(type_value)
118
+ # Assume always GNU for now, but it's wrong
119
+ Type::GNU[type_value]
120
+ else
121
+ Type[type_value]
122
+ end
123
+
124
+ binding_value = info >> 4
125
+ @bind = case
126
+ when Binding::OsSpecific.include?(binding_value)
127
+ # Assume always GNU for now, but it's wrong
128
+ Binding::GNU[binding_value]
129
+ else
130
+ Binding[binding_value]
131
+ end
132
+
133
+ rescue Elf::Value::OutOfBound => e
134
+ e.append_message(sprintf("While processing symbol %d. Symbol 'info' value: 0x%x",
135
+ @idx,
136
+ info))
137
+ raise e
138
+ end
139
+
140
+ begin
141
+ @visibility = Visibility[@other & 0x03]
142
+ rescue Elf::Value::OutOfBound => e
143
+ e.append_message(sprintf("While procesing symbol %d. Symbol 'other' value: 0x%x",
144
+ @idx,
145
+ other))
146
+ raise e
147
+ end
148
+
149
+ @file = elf
150
+ end
151
+
152
+ class InvalidName < Exception
153
+ def initialize(name_idx, sym, symsect)
154
+ super("Invalid name index in #{symsect.link.name} #{name_idx} for symbol #{sym.idx}")
155
+ end
156
+ end
157
+
158
+ def name
159
+ # We didn't read the name in form of string yet;
160
+ if @name.is_a? Integer and @symsect.link
161
+ begin
162
+ name = @symsect.link[@name]
163
+ rescue Utilities::OffsetTable::InvalidIndex
164
+ raise InvalidName.new(@name, self, @symsect)
165
+ end
166
+ @name = name if name
167
+ end
168
+
169
+ @name
170
+ end
171
+
172
+ # Alias to_s to name so that using this in a string will report the name
173
+ alias :to_s :name
174
+
175
+ def section
176
+ # We didn't read the section yet.
177
+ @section = nil if @section.is_a? Integer and @section == 0
178
+
179
+ if @section.is_a? Integer and
180
+ not Section::Reserved.include?(@section) and
181
+ @file.has_section?(@section)
182
+
183
+ @section = @file[@section]
184
+ end
185
+
186
+ @section
187
+ end
188
+
189
+ def version
190
+ # bit 15 is meant to say that this symbol is _not_ the default
191
+ # version to link to; we don't care about that here so we simply
192
+ # ignore its presence.
193
+ version_idx = version_index & ~(1 << 15)
194
+
195
+ return nil unless version_idx && version_idx >= 1
196
+
197
+ return '' if version_idx == 1
198
+
199
+ begin
200
+ if section.nil?
201
+ return @file['.gnu.version_r'][version_idx][:name]
202
+ else
203
+ return @file['.gnu.version_d'][version_idx][:names][0]
204
+ end
205
+ rescue Elf::File::MissingSection
206
+ return @file['.gnu.version_r'][version_idx][:name]
207
+ end
208
+ end
209
+
210
+ # the default symbol version is the one that the link editor will
211
+ # use when linking against the library; any symbol is the default
212
+ # symbol unless bit 15 of its version index is set.
213
+ #
214
+ # An undefined symbol cannot be the default symbol
215
+ def version_default?
216
+ !section.nil? and (version_index & (1 << 15) == 0)
217
+ end
218
+
219
+ def defined?
220
+ return false if section.nil?
221
+ return false if section.is_a?(Integer)
222
+ return false if bind == Binding::Weak and value == 0
223
+ return true
224
+ end
225
+
226
+ # Exception raised when the NM code for a given symbol is unknown.
227
+ class UnknownNMCode < Exception
228
+ def initialize(symbol)
229
+ section = if symbol.section.nil?
230
+ nil
231
+ elsif symbol.section.is_a?(Integer)
232
+ sprintf("%x", symbol.section)
233
+ else
234
+ symbol.section.name
235
+ end
236
+
237
+ super("Unknown NM code for symbol #{symbol.name} in section #{section}")
238
+ end
239
+ end
240
+
241
+ # Show the letter code as compatible with GNU nm
242
+ #
243
+ # This function has been moved inside the library since multiple
244
+ # tools based on ruby-elf would be using these code to report
245
+ # symbols, and since the code is complex it's easier to have it
246
+ # here.
247
+ #
248
+ # The resturned value is a one-letter string. The function may
249
+ # raise an UnknownNMCode exception.
250
+ def nm_code
251
+ @nmflag ||= nm_code_internal
252
+ end
253
+
254
+ # Convenience function for the first tile the nm code is requested.
255
+ def nm_code_internal
256
+ nmflag = nil
257
+
258
+ case
259
+ when idx == 0
260
+ return " "
261
+
262
+ # When the section is nil, it means it goes into the Undef
263
+ # section, and the symbol is not defined.
264
+ when section.nil?
265
+ nmflag = "U"
266
+
267
+ when bind == Binding::Weak
268
+ nmflag = case type
269
+ when Type::Object then 'V'
270
+ # we cannot use 'v' when value is zero, as for a
271
+ # variable, a zero address is correct, it's just
272
+ # functions that cannot be at zero address.
273
+ when value == 0 then 'w'
274
+ else 'W'
275
+ end
276
+
277
+ when bind == Binding::GNU::Unique
278
+ nmflag = 'u'
279
+
280
+ when section == Elf::Section::Abs
281
+ nmflag = "A"
282
+ when type == Type::Common, section == Elf::Section::Common
283
+ # section check _should_ be limited to objects with
284
+ # Type::Data, but turns out that ICC does not emit
285
+ # uninitialised variables correctly, creating a Type::None
286
+ # object defined in Section::Common. Handle that properly.
287
+ nmflag = 'C'
288
+
289
+ when type == Type::Object, type == Type::TLS
290
+ # data object, distinguish between writable or read-only data,
291
+ # as well as data in Section::Type::NoBits sections.
292
+ nmflag = case
293
+ when section.is_a?(Integer) then nil
294
+ when !section.flags.include?(Elf::Section::Flags::Write) then "R"
295
+ when section.type == Elf::Section::Type::NoBits then "B"
296
+ else "D"
297
+ end
298
+
299
+ when type == Type::None
300
+ # try being smarter than simply reporthing this as a none-type
301
+ # symbol, as some compilers (namely pathCC) emit STT_NONE
302
+ # symbols that are instead functions.
303
+ nmflag = case
304
+ when section.is_a?(Integer) then "N"
305
+ when section.flags.include?(Elf::Section::Flags::ExecInstr) then "T"
306
+ when section.type == Elf::Section::Type::NoBits then "B"
307
+ else "N"
308
+ end
309
+ when type == Type::Func
310
+ nmflag = 'T'
311
+ when type == Type::Section
312
+ nmflag = 'S'
313
+ when type == Type::File
314
+ nmflag = 'F'
315
+ when type == Type::GNU::IFunc
316
+ nmflag = 'i'
317
+ end
318
+
319
+ # If we haven't found the flag with the above code, we don't
320
+ # know what to use, so raise exception.
321
+ raise UnknownNMCode.new(self) if nmflag.nil?
322
+
323
+ nmflag = nmflag.dup
324
+
325
+ nmflag.downcase! if bind == Binding::Local
326
+
327
+ return nmflag
328
+ end
329
+
330
+ # Reports the symbol's address as a string, if any is provided
331
+ #
332
+ # Reports a string full of whitespace if the symbols is not
333
+ # defined (as there is no address)
334
+ def address_string
335
+ section ? sprintf("%0#{@file.address_print_size}x", value) : ''
336
+ end
337
+
338
+ # Check whether two symbols are the same
339
+ #
340
+ # This function compares the name, version and section of two
341
+ # symbols to tell if they are the same symbol.
342
+ def ==(other)
343
+ return false unless other.is_a? Symbol
344
+
345
+ return false unless name == other.name
346
+ return false unless version == other.version
347
+
348
+ return false if section == nil and other.section != nil
349
+ return false if section != nil and other.section == nil
350
+
351
+ return true
352
+ end
353
+
354
+ def eql?(other)
355
+ return self == other
356
+ end
357
+
358
+ # Check whether one symbol is compatible with the other
359
+ #
360
+ # This function compares the name and version of two symbols, and
361
+ # ensures that only one of them is undefined; this allows to
362
+ # establish whether one symbol might be satisfied by another.
363
+ def =~(other)
364
+ return false unless other.is_a? Symbol
365
+
366
+ return false unless name == other.name
367
+ return false unless version == other.version
368
+
369
+ return false if section == nil and other.section == nil
370
+ return false if section != nil and other.section != nil
371
+
372
+ return true
373
+ end
374
+
375
+ # begin
376
+ # Demanglers = [ ]
377
+ # def demangle
378
+ # return @demangled if @demangled
379
+ #
380
+ # Demanglers.each do |demangler|
381
+ # break if (@demangled ||= demangler.demangle(name))
382
+ # end
383
+ #
384
+ # # We're going to remove top-namespace specifications as we don't
385
+ # # need them, but it's easier for the demangler to still emit
386
+ # # them.
387
+ # @demangled.gsub!(/(^| |\()::/, '\1') if @demangled
388
+ #
389
+ # return @demangled ||= name
390
+ # end
391
+ # rescue LoadError
392
+ def demangle
393
+ return name
394
+ end
395
+ # end
396
+
397
+ private
398
+ def version_index
399
+ return nil if (!@file.has_section?('.gnu.version')) or
400
+ ( section.is_a?(Integer) and section == Elf::Section::Abs ) or
401
+ ( section.is_a? Elf::Section and section.name == ".bss" )
402
+
403
+ @file['.gnu.version'][@idx]
404
+ end
405
+ end
406
+ end