Class: Elf::Dynamic

Inherits:
Section show all
Defined in:
lib/elf/dynamic.rb

Defined Under Namespace

Modules: Features1, Flags, Flags1, PosFlags1 Classes: Entry, SectionLink, StringEntry, TimestampEntry, Type

Constant Summary collapse

ClassMap =
{
  Type::Needed       => StringEntry,
  Type::Hash         => SectionLink,
  Type::StrTab       => SectionLink,
  Type::SymTab       => SectionLink,
  Type::Init         => SectionLink,
  Type::Fini         => SectionLink,
  Type::SoName       => StringEntry,
  Type::RPath        => StringEntry,
  Type::RunPath      => StringEntry,
  Type::GNUPrelinked => TimestampEntry,
  Type::GNUHash      => SectionLink,
  Type::Auxiliary    => StringEntry
}

Constants inherited from Section

Section::Abs, Section::Common, Section::FlagsToChars, Section::OsSpecific, Section::ProcSpecific, Section::Reserved, Section::SunW, Section::SunWIgnore, Section::Undef, Section::XIndex

Instance Attribute Summary

Attributes inherited from Section

#addr, #addralign, #entsize, #file, #index, #info, #offset, #size, #type

Instance Method Summary collapse

Methods inherited from Section

#==, #flags, #flags_i, #flags_s, #initialize, #link, #load, #name, read, #summary

Constructor Details

This class inherits a constructor from Elf::Section

Instance Method Details

#auxiliary_library_path(type) ⇒ Object

Returns the auxiliary path specified by the given type

Please never use this function because it does not caches its values, use Dynamic#rpath or Dynamic#runpath instead.



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/elf/dynamic.rb', line 279

def auxiliary_library_path(type)
  retval = Array.new

  each_entry do |entry|
    next unless entry.type == type
    retval.concat entry.parsed.split(":")
  end

  return retval.uniq.collect do |path|
    if path == "$ORIGIN" or path == "${ORIGIN}"
      Pathname.new(@file.path).dirname
    else
      begin
        Pathname.new(path).realpath
      rescue Errno::ENOENT
        path
      end
    end.to_s
  end
end

#complete_library_pathObject

Returns the complete library path for the current ELF file.

Since the ELF loaders have somewhat complex rules to identify the path to load dependencies from, we evalute it on a per-file basis.



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/elf/dynamic.rb', line 305

def complete_library_path
  if @complete_library_path.nil?
    @complete_library_path = Array.new

    # If there is no DT_RUNPATH. RPATH wins over the LD_LIBRARY_PATH
    @complete_library_path.concat rpath unless runpath.empty?

    @complete_library_path.concat Elf::Utilities.environment_library_path

    # If there is a DT_RUNPATH it wins over the system library path
    @complete_library_path.concat runpath

    @complete_library_path.concat Elf::Utilities.system_library_path

    @complete_library_path.uniq!
  end

  return @complete_library_path
end

#countObject

Return the amount of entries in the .dynamic section.



251
252
253
254
255
# File 'lib/elf/dynamic.rb', line 251

def count
  load unless @entries

  @entries.size
end

#each_entry(&block) ⇒ Object

Iterate over all the entries in the .dynamic section.



244
245
246
247
248
# File 'lib/elf/dynamic.rb', line 244

def each_entry(&block)
  load unless @entries

  @entries.each(&block)
end

#find_library(soname) ⇒ Object

Return the ELF library corresponding to the given soname.

This function gets the system library paths and eventually adds the rpaths as expressed by the file itself, then look them up to find the proper library, just like the loader would.



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/elf/dynamic.rb', line 330

def find_library(soname)
  complete_library_path.each do |path|
    # For the ELF linker an empty entry in the library path is the
    # same as "." and means the current working directory, so
    # replace it.
    path = "." if path == ""

    if FileTest.exist? "#{path}/#{soname}"
      begin
        possible_library = Elf::Utilities::FilePool["#{path}/#{soname}"]

        return possible_library if @file.is_compatible(possible_library)
      rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR, Elf::File::NotAnELF
        # we don't care if the file does not exist and similar.
      end
    end
  end

  return nil
end

#load_internalObject



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/elf/dynamic.rb', line 225

def load_internal
  elf32 = @file.elf_class == Class::Elf32

  @entries = []

  for i in 1..@numentries
    type = Type[elf32 ? @file.read_sword : @file.read_sxword]

    @entries << if ClassMap.has_key? type
                  ClassMap[type].new(type, @file)
                else
                  Entry.new(type, @file)
                end

    break if type == Type::Null
  end
end

#needed_librariesObject

Returns an hash representing the dependencies of the ELF file.

This function reads the .dynamic section of the file for DT_NEEDED entries, then looks for them and add them to an hash.

Note that nil values in the hash means that the library couldn’t be found on either the runpath of the file or the system library path.



377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/elf/dynamic.rb', line 377

def needed_libraries
  # Make sure to cache the thing, we don't want to have to parse
  # this multiple times since we might access it over and over to
  # check the dependencies.
  if @needed_libraries.nil?
    @needed_libraries = Hash.new

    needed_sonames.each do |soname|
      @needed_libraries[soname] = find_library(soname)
    end
  end

  return @needed_libraries
end

#needed_sonamesObject

Returns an array of needed sonames from .dynamic section

This function reads the .dynamic section of the file for DT_NEEDED entries, and fills an array with them.



355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/elf/dynamic.rb', line 355

def needed_sonames
  if @needed_sonames.nil?
    @needed_sonames = Array.new

    each_entry do |entry|
      next unless entry.type == Elf::Dynamic::Type::Needed

      @needed_sonames << entry.parsed
    end
  end

  return @needed_sonames
end

#rpathObject

Returns the value of DT_RPATH entries in the file



266
267
268
# File 'lib/elf/dynamic.rb', line 266

def rpath
  @rpath ||= auxiliary_library_path(Type::RPath)
end

#runpathObject

Returns the value of DT_RUNPATH entries in the file



271
272
273
# File 'lib/elf/dynamic.rb', line 271

def runpath
  @runpath ||= auxiliary_library_path(Type::RunPath)
end

#sonameObject



257
258
259
260
261
262
263
# File 'lib/elf/dynamic.rb', line 257

def soname
  each_entry do |entry|
    return entry.parsed if entry.type == Type::SoName
  end

  return nil
end