Class: Elf::Symbol

Inherits:
Object
  • Object
show all
Defined in:
lib/elf/symbol.rb

Defined Under Namespace

Classes: Binding, InvalidName, Type, UnknownNMCode, Visibility

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(elf, symsect, idx) ⇒ Symbol

Create a new Symbol object reading the symbol structure from the file. This function assumes that the elf file is aligned ad the start of a symbol structure, and returns the file moved at the start of the symbol.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/elf/symbol.rb', line 93

def initialize(elf, symsect, idx)
  @symsect = symsect
  @idx = idx

  case elf.elf_class
  when Class::Elf32
    @name = elf.read_word
    @value = elf.read_addr
    @size = elf.read_word
    info = elf.read_u8
    @other = elf.read_u8
    @section = elf.read_section
  when Class::Elf64
    @name = elf.read_word
    info = elf.read_u8
    @other = elf.read_u8
    @section = elf.read_section
    @value = elf.read_addr
    @size = elf.read_xword
  end

  begin
    type_value = info & 0xF
    @type = case
            when Type::OsSpecific.include?(type_value)
              # Assume always GNU for now, but it's wrong
              Type::GNU[type_value]
            else
              Type[type_value]
            end

    binding_value = info >> 4
    @bind = case
            when Binding::OsSpecific.include?(binding_value)
              # Assume always GNU for now, but it's wrong
              Binding::GNU[binding_value]
            else
              Binding[binding_value]
            end

  rescue Elf::Value::OutOfBound => e
    e.append_message(sprintf("While processing symbol %d. Symbol 'info' value: 0x%x",
                             @idx,
                             info))
    raise e
  end

  begin
    @visibility = Visibility[@other & 0x03]
  rescue Elf::Value::OutOfBound => e
    e.append_message(sprintf("While procesing symbol %d. Symbol 'other' value: 0x%x",
                             @idx,
                             other))
    raise e
  end

  @file = elf
end

Instance Attribute Details

#bindObject (readonly)

Returns the value of attribute bind.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def bind
  @bind
end

#fileObject (readonly)

Returns the value of attribute file.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def file
  @file
end

#idxObject (readonly)

Returns the value of attribute idx.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def idx
  @idx
end

#otherObject (readonly)

Returns the value of attribute other.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def other
  @other
end

#sizeObject (readonly)

Returns the value of attribute size.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def size
  @size
end

#typeObject (readonly)

Returns the value of attribute type.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def type
  @type
end

#valueObject (readonly)

Returns the value of attribute value.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def value
  @value
end

#visibilityObject (readonly)

Returns the value of attribute visibility.



87
88
89
# File 'lib/elf/symbol.rb', line 87

def visibility
  @visibility
end

Instance Method Details

#==(other) ⇒ Object

Check whether two symbols are the same

This function compares the name, version and section of two symbols to tell if they are the same symbol.



342
343
344
345
346
347
348
349
350
351
352
# File 'lib/elf/symbol.rb', line 342

def ==(other)
  return false unless other.is_a? Symbol

  return false unless name == other.name
  return false unless version == other.version

  return false if section == nil and other.section != nil
  return false if section != nil and other.section == nil

  return true
end

#=~(other) ⇒ Object

Check whether one symbol is compatible with the other

This function compares the name and version of two symbols, and ensures that only one of them is undefined; this allows to establish whether one symbol might be satisfied by another.



363
364
365
366
367
368
369
370
371
372
373
# File 'lib/elf/symbol.rb', line 363

def =~(other)
  return false unless other.is_a? Symbol

  return false unless name == other.name
  return false unless version == other.version

  return false if section == nil and other.section == nil
  return false if section != nil and other.section != nil

  return true
end

#address_stringObject

Reports the symbol’s address as a string, if any is provided

Reports a string full of whitespace if the symbols is not defined (as there is no address)



334
335
336
# File 'lib/elf/symbol.rb', line 334

def address_string
  section ? sprintf("%0#{@file.address_print_size}x", value) : ''
end

#defined?Boolean

Returns:

  • (Boolean)


219
220
221
222
223
224
# File 'lib/elf/symbol.rb', line 219

def defined?
  return false if section.nil?
  return false if section.is_a?(Integer)
  return false if bind == Binding::Weak and value == 0
  return true
end

#demangleObject

begin

  Demanglers = [  ]
  def demangle
    return @demangled if @demangled

    Demanglers.each do |demangler|
      break if (@demangled ||= demangler.demangle(name))
    end

    # We're going to remove top-namespace specifications as we don't
    # need them, but it's easier for the demangler to still emit
    # them.
    @demangled.gsub!(/(^| |\()::/, '\1') if @demangled

    return @demangled ||= name
  end
rescue LoadError


392
393
394
# File 'lib/elf/symbol.rb', line 392

def demangle
  return name
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


354
355
356
# File 'lib/elf/symbol.rb', line 354

def eql?(other)
  return self == other
end

#nameObject Also known as: to_s



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/elf/symbol.rb', line 158

def name
  # We didn't read the name in form of string yet;
  if @name.is_a? Integer and @symsect.link
    begin
      name = @symsect.link[@name]
    rescue Utilities::OffsetTable::InvalidIndex
      raise InvalidName.new(@name, self, @symsect)
    end
    @name = name if name
  end

  @name
end

#nm_codeObject

Show the letter code as compatible with GNU nm

This function has been moved inside the library since multiple tools based on ruby-elf would be using these code to report symbols, and since the code is complex it’s easier to have it here.

The resturned value is a one-letter string. The function may raise an UnknownNMCode exception.



250
251
252
# File 'lib/elf/symbol.rb', line 250

def nm_code
  @nmflag ||= nm_code_internal
end

#nm_code_internalObject

Convenience function for the first tile the nm code is requested.

Raises:



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/elf/symbol.rb', line 255

def nm_code_internal
  nmflag = nil

  case
  when idx == 0
    return " "

    # When the section is nil, it means it goes into the Undef
    # section, and the symbol is not defined.
  when section.nil?
    nmflag = "U"

  when bind == Binding::Weak
    nmflag = case type
             when Type::Object then 'V'
               # we cannot use 'v' when value is zero, as for a
               # variable, a zero address is correct, it's just
               # functions that cannot be at zero address.
             when value == 0 then 'w'
             else 'W'
             end

  when bind == Binding::GNU::Unique
    nmflag = 'u'

  when section == Elf::Section::Abs
    nmflag = "A"
  when type == Type::Common, section == Elf::Section::Common
    # section check _should_ be limited to objects with
    # Type::Data, but turns out that ICC does not emit
    # uninitialised variables correctly, creating a Type::None
    # object defined in Section::Common. Handle that properly.
    nmflag = 'C'

  when type == Type::Object, type == Type::TLS
    # data object, distinguish between writable or read-only data,
    # as well as data in Section::Type::NoBits sections.
    nmflag = case
             when section.is_a?(Integer) then nil
             when !section.flags.include?(Elf::Section::Flags::Write) then "R"
             when section.type == Elf::Section::Type::NoBits then "B"
             else "D"
             end

  when type == Type::None
    # try being smarter than simply reporthing this as a none-type
    # symbol, as some compilers (namely pathCC) emit STT_NONE
    # symbols that are instead functions.
    nmflag = case
             when section.is_a?(Integer) then "N"
             when section.flags.include?(Elf::Section::Flags::ExecInstr) then "T"
             when section.type == Elf::Section::Type::NoBits then "B"
             else "N"
             end
  when type == Type::Func
    nmflag = 'T'
  when type == Type::Section
    nmflag = 'S'
  when type == Type::File
    nmflag = 'F'
  when type == Type::GNU::IFunc
    nmflag = 'i'
  end

  # If we haven't found the flag with the above code, we don't
  # know what to use, so raise exception.
  raise UnknownNMCode.new(self) if nmflag.nil?

  nmflag = nmflag.dup

  nmflag.downcase! if bind == Binding::Local

  return nmflag
end

#sectionObject



175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/elf/symbol.rb', line 175

def section
  # We didn't read the section yet.
  @section = nil if @section.is_a? Integer and @section == 0
  
  if @section.is_a? Integer and
      not Section::Reserved.include?(@section) and
      @file.has_section?(@section)

    @section = @file[@section]
  end

  @section
end

#versionObject



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/elf/symbol.rb', line 189

def version
  # bit 15 is meant to say that this symbol is _not_ the default
  # version to link to; we don't care about that here so we simply
  # ignore its presence.
  version_idx = version_index & ~(1 << 15)

  return nil unless version_idx && version_idx >= 1

  return '' if version_idx == 1

  begin
    if section.nil?
      return @file['.gnu.version_r'][version_idx][:name]
    else
      return @file['.gnu.version_d'][version_idx][:names][0]
    end
  rescue Elf::File::MissingSection
    return @file['.gnu.version_r'][version_idx][:name]
  end
end

#version_default?Boolean

the default symbol version is the one that the link editor will use when linking against the library; any symbol is the default symbol unless bit 15 of its version index is set.

An undefined symbol cannot be the default symbol

Returns:

  • (Boolean)


215
216
217
# File 'lib/elf/symbol.rb', line 215

def version_default?
  !section.nil? and (version_index & (1 << 15) == 0)
end