ruby-elf 1.0.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,49 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Simple ELF parser for Ruby
3
+ #
4
+ # Copyright © 2007-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
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
+
26
+ module Elf
27
+ class StringTable < Section
28
+ def load_internal
29
+ @rawtable = @file.readexactly(@size)
30
+ end
31
+
32
+ class InvalidIndex < Exception
33
+ def initialize(idx, max_idx)
34
+ super("Invalid index #{idx} (maximum index: #{max_idx})")
35
+ end
36
+ end
37
+
38
+ def [](idx)
39
+ load unless @rawtable
40
+
41
+ raise InvalidIndex.new(idx, @rawtable.size) if
42
+ idx >= @rawtable.size
43
+
44
+ endidx = @rawtable.index("\x00", idx)
45
+
46
+ return @rawtable[idx..endidx].chomp("\x00")
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,158 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Simple ELF parser for Ruby
3
+ #
4
+ # Copyright © 2008-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
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
@@ -0,0 +1,368 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Simple ELF parser for Ruby
3
+ #
4
+ # Copyright © 2007-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
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/symbol/demangler_gcc3'
25
+
26
+ module Elf
27
+ class Symbol
28
+ class Binding < Value
29
+ fill(
30
+ 0 => [ :Local, 'Local symbol' ],
31
+ 1 => [ :Global, 'Global symbol' ],
32
+ 2 => [ :Weak, 'Weak symbol' ],
33
+ # This one is inferred out of libpam.so
34
+ 3 => [ :Number, 'Number of defined type' ]
35
+ )
36
+
37
+ class GNU < Value
38
+ fill(
39
+ 10 => [ :Unique, 'Unique symbol' ]
40
+ )
41
+ end
42
+
43
+ OsSpecific = 10..12
44
+ ProcSpecific = 13..15
45
+
46
+ SpecialRanges = {
47
+ "STB_LOOS" => OsSpecific,
48
+ "STB_LOPROC" => ProcSpecific
49
+ }
50
+ end
51
+
52
+ class Type < Value
53
+ fill(
54
+ 0 => [ :None, 'Unspecified' ],
55
+ 1 => [ :Object, 'Data object' ],
56
+ 2 => [ :Func, 'Code object' ],
57
+ 3 => [ :Section, 'Associated with a section' ],
58
+ 4 => [ :File, 'File name' ],
59
+ 5 => [ :Common, 'Common data object' ],
60
+ 6 => [ :TLS, 'Thread-local data object' ]
61
+ )
62
+
63
+ class GNU < Value
64
+ fill(
65
+ 10 => [ :IFunc, 'Indirect function' ]
66
+ )
67
+ end
68
+
69
+ OsSpecific = 10..12
70
+ ProcSpecific = 13..15
71
+ SpecialRanges = {
72
+ "STT_LOOS" => OsSpecific,
73
+ "STT_LOPROC" => ProcSpecific
74
+ }
75
+ end
76
+
77
+ class Visibility < Value
78
+ fill(
79
+ 0 => [ :Default, 'Default visibility' ],
80
+ 1 => [ :Internal, 'Processor-specific hidden visibility' ],
81
+ 2 => [ :Hidden, 'Hidden visibility' ],
82
+ 3 => [ :Protected, 'Protected visibility' ],
83
+ 4 => [ :Exported, 'Exported symbol' ],
84
+ 5 => [ :Singleton, 'Singleton symbol' ],
85
+ 6 => [ :Eliminate, 'Symbol to be eliminated' ]
86
+ )
87
+ end
88
+
89
+ attr_reader :value, :size, :other, :bind, :type, :idx, :visibility, :file
90
+
91
+ # Create a new Symbol object reading the symbol structure from the file.
92
+ # This function assumes that the elf file is aligned ad the
93
+ # start of a symbol structure, and returns the file moved at the
94
+ # start of the symbol.
95
+ def initialize(elf, symsect, idx)
96
+ @symsect = symsect
97
+ @idx = idx
98
+
99
+ case elf.elf_class
100
+ when Class::Elf32
101
+ @name = elf.read_word
102
+ @value = elf.read_addr
103
+ @size = elf.read_word
104
+ info = elf.read_u8
105
+ @other = elf.read_u8
106
+ @section = elf.read_section
107
+ when Class::Elf64
108
+ @name = elf.read_word
109
+ info = elf.read_u8
110
+ @other = elf.read_u8
111
+ @section = elf.read_section
112
+ @value = elf.read_addr
113
+ @size = elf.read_xword
114
+ end
115
+
116
+ begin
117
+ type_value = info & 0xF
118
+ @type = case
119
+ when Type::OsSpecific.include?(type_value)
120
+ # Assume always GNU for now, but it's wrong
121
+ Type::GNU[type_value]
122
+ else
123
+ Type[type_value]
124
+ end
125
+
126
+ binding_value = info >> 4
127
+ @bind = case
128
+ when Binding::OsSpecific.include?(binding_value)
129
+ # Assume always GNU for now, but it's wrong
130
+ Binding::GNU[binding_value]
131
+ else
132
+ Binding[binding_value]
133
+ end
134
+
135
+ rescue Elf::Value::OutOfBound => e
136
+ e.append_message("While processing symbol #{@idx}. Symbol info: 0x#{info.hex}")
137
+ raise e
138
+ end
139
+
140
+ begin
141
+ @visibility = Visibility[@other & 0x03]
142
+ rescue Elf::Value::OutOfBound => e
143
+ e.append_message("While procesing symbol #{@idx}. Symbol other info: 0x#{@other.hex}")
144
+ raise e
145
+ end
146
+
147
+ @file = elf
148
+ end
149
+
150
+ class InvalidName < Exception
151
+ def initialize(name_idx, sym, symsect)
152
+ super("Invalid name index in #{symsect.link.name} #{name_idx} for symbol #{sym.idx}")
153
+ end
154
+ end
155
+
156
+ def name
157
+ # We didn't read the name in form of string yet;
158
+ if @name.is_a? Integer and @symsect.link
159
+ begin
160
+ name = @symsect.link[@name]
161
+ rescue StringTable::InvalidIndex
162
+ raise InvalidName.new(@name, self, @symsect)
163
+ end
164
+ @name = name if name
165
+ end
166
+
167
+ @name
168
+ end
169
+
170
+ # Alias to_s to name so that using this in a string will report the name
171
+ alias :to_s :name
172
+
173
+ def section
174
+ # We didn't read the section yet.
175
+ @section = nil if @section.is_a? Integer and @section == 0
176
+
177
+ if @section.is_a? Integer and
178
+ not Section::Reserved.include?(@section) and
179
+ @file.has_section?(@section)
180
+
181
+ @section = @file[@section]
182
+ end
183
+
184
+ @section
185
+ end
186
+
187
+ def version
188
+ # bit 15 is meant to say that this symbol is _not_ the default
189
+ # version to link to; we don't care about that here so we simply
190
+ # ignore its presence.
191
+ version_idx = version_index & ~(1 << 15)
192
+
193
+ return nil unless version_idx && version_idx >= 1
194
+
195
+ return '' if version_idx == 1
196
+
197
+ if section.nil? or @file['.gnu.version_d'][version_idx].nil?
198
+ return @file['.gnu.version_r'][version_idx][:name]
199
+ else
200
+ return @file['.gnu.version_d'][version_idx][:names][0]
201
+ end
202
+ end
203
+
204
+ # the default symbol version is the one that the link editor will
205
+ # use when linking against the library; any symbol is the default
206
+ # symbol unless bit 15 of its version index is set.
207
+ #
208
+ # An undefined symbol cannot be the default symbol
209
+ def version_default?
210
+ !section.nil? and (version_index & (1 << 15) == 0)
211
+ end
212
+
213
+ def defined?
214
+ return false if section.nil?
215
+ return false if section.is_a?(Integer)
216
+ return false if bind == Binding::Weak and value == 0
217
+ return true
218
+ end
219
+
220
+ # Exception raised when the NM code for a given symbol is unknown.
221
+ class UnknownNMCode < Exception
222
+ def initialize(symbol)
223
+ section = if symbol.section.nil?
224
+ nil
225
+ elsif symbol.section.is_a?(Integer)
226
+ symbol.section.hex
227
+ else
228
+ symbol.section.name
229
+ end
230
+
231
+ super("Unknown NM code for symbol #{symbol.name} in section #{section}")
232
+ end
233
+ end
234
+
235
+ # Show the letter code as compatible with GNU nm
236
+ #
237
+ # This function has been moved inside the library since multiple
238
+ # tools based on ruby-elf would be using these code to report
239
+ # symbols, and since the code is complex it's easier to have it
240
+ # here.
241
+ #
242
+ # The resturned value is a one-letter string. The function may
243
+ # raise an UnknownNMCode exception.
244
+ def nm_code
245
+ @nmflag ||= nm_code_internal
246
+ end
247
+
248
+ # Convenience function for the first tile the nm code is requested.
249
+ def nm_code_internal
250
+ nmflag = nil
251
+
252
+ case
253
+ when idx == 0
254
+ return " "
255
+
256
+ # When the section is nil, it means it goes into the Undef
257
+ # section, and the symbol is not defined.
258
+ when section.nil?
259
+ nmflag = "U"
260
+
261
+ when bind == Binding::Weak
262
+ nmflag = case type
263
+ when Type::Object then "V"
264
+ else "W"
265
+ end
266
+
267
+ nmflag.downcase! if value == 0
268
+
269
+ when section.is_a?(Integer)
270
+ nmflag = case section
271
+ when Elf::Section::Abs then "A"
272
+ when Elf::Section::Common then "C"
273
+ else nil
274
+ end
275
+
276
+ else
277
+ # Find the nm(1) code for the section.
278
+ nmflag = section.nm_code
279
+ end
280
+
281
+ # If we haven't found the flag with the above code, we don't
282
+ # know what to use, so raise exception.
283
+ raise UnknownNMCode.new(self) if nmflag.nil?
284
+
285
+ nmflag = nmflag.dup
286
+
287
+ nmflag.downcase! if bind == Binding::Local
288
+
289
+ return nmflag
290
+ end
291
+
292
+ # Reports the symbol's address as a string, if any is provided
293
+ #
294
+ # Reports a string full of whitespace if the symbols is not
295
+ # defined (as there is no address)
296
+ def address_string
297
+ addrsize = (@file.elf_class == Elf::Class::Elf32 ? 8 : 16)
298
+
299
+ if section
300
+ sprintf("%0#{addrsize}x", value)
301
+ else
302
+ ' ' * addrsize
303
+ end
304
+ end
305
+
306
+ # Check whether two symbols are the same
307
+ #
308
+ # This function compares the name, version and section of two
309
+ # symbols to tell if they are the same symbol.
310
+ def ==(other)
311
+ return false unless other.is_a? Symbol
312
+
313
+ return false unless name == other.name
314
+ return false unless version == other.version
315
+
316
+ return false if section == nil and other.section != nil
317
+ return false if section != nil and other.section == nil
318
+
319
+ return true
320
+ end
321
+
322
+ def eql?(other)
323
+ return self == other
324
+ end
325
+
326
+ # Check whether one symbol is compatible with the other
327
+ #
328
+ # This function compares the name and version of two symbols, and
329
+ # ensures that only one of them is undefined; this allows to
330
+ # establish whether one symbol might be satisfied by another.
331
+ def =~(other)
332
+ return false unless other.is_a? Symbol
333
+
334
+ return false unless name == other.name
335
+ return false unless version == other.version
336
+
337
+ return false if section == nil and other.section == nil
338
+ return false if section != nil and other.section != nil
339
+
340
+ return true
341
+ end
342
+
343
+ Demanglers = [ Elf::Symbol::Demangler::GCC3 ]
344
+ def demangle
345
+ return @demangled if @demangled
346
+
347
+ Demanglers.each do |demangler|
348
+ break if (@demangled ||= demangler.demangle(name))
349
+ end
350
+
351
+ # We're going to remove top-namespace specifications as we don't
352
+ # need them, but it's easier for the demangler to still emit
353
+ # them.
354
+ @demangled.gsub!(/(^| |\()::/, '\1') if @demangled
355
+
356
+ return @demangled ||= name
357
+ end
358
+
359
+ private
360
+ def version_index
361
+ return nil if (!@file.has_section?('.gnu.version')) or
362
+ ( section.is_a?(Integer) and section == Elf::Section::Abs ) or
363
+ ( section.is_a? Elf::Section and section.name == ".bss" )
364
+
365
+ @file['.gnu.version'][@idx]
366
+ end
367
+ end
368
+ end