Module: ELFTools::Dynamic::Symbols

Included in:
ELFTools::Dynamic
Defined in:
lib/elftools/dynamic/symbols.rb

Overview

Note:

This module is included by ELFTools::Dynamic and reads through the methods there, so it cannot be included on its own.

The symbols a file is loaded by, which the tags point at.

Instance Method Summary collapse

Instance Method Details

#each_symbol {|symbol| ... } ⇒ Enumerator<ELFTools::Sections::Symbol>, Array<ELFTools::Sections::Symbol> Also known as: each_symbols

Iterate all symbols.

Symbols are lazy loaded, so #symbol_by_name only creates the symbols it has to look at.

Yield Parameters:

Yield Returns:

  • (void)

Returns:



72
73
74
75
76
# File 'lib/elftools/dynamic/symbols.rb', line 72

def each_symbol(&block)
  return enum_for(:each_symbol) unless block_given?

  Array.new(num_symbols) { |i| symbol_at(i).tap(&block) }
end

#num_symbolsInteger

How many symbols the tags reach.

A hash table that records the number outright is answered with, because nothing a file records can reach further than the table it counts.

Where the file records no such table, nothing records how large its symbol table is. The loader never enumerates it: it looks a name up through a hash table and jumps straight to an index, so where the table ends is none of its business. Two things bound it instead, the hash table that indexes the names a file exports and the relocations that name a symbol by index, and the answer is how far the further of the two reaches.

That answer is a lower bound. A symbol that is neither indexed by the hash table nor named by a relocation is invisible to both, and is missing from the count. #symbol_at is exact for any index.

Examples:

elf.dynamic.num_symbols
#=> 9

Returns:

  • (Integer)

    The number.



59
60
61
# File 'lib/elftools/dynamic/symbols.rb', line 59

def num_symbols
  @num_symbols ||= counted_num_symbols || bounded_num_symbols
end

#symbol_at(n) ⇒ ELFTools::Sections::Symbol

Note:

We cannot do bound checking of n here, because nothing records how many symbols there are. #num_symbols is a lower bound rather than a bound, so checking against it would hide symbols this method reads correctly.

Get the +n+-th symbol.

Symbols are lazy loaded.

Parameters:

  • n (Integer)

    The index.

Returns:

Raises:

  • (ELFTools::ELFError)

    If DT_SYMTAB is absent, or its address is not in any loadable segment.



28
29
30
31
32
33
34
35
36
37
# File 'lib/elftools/dynamic/symbols.rb', line 28

def symbol_at(n)
  return if n.negative?

  @symbol_at_map ||= {}
  @symbol_at_map[n] ||= begin
    sym = read_struct(Structs::ELF_sym[header.elf_class], sym_offset + (n * sym_entsize))
    Sections::Symbol.new(sym, stream, symstr: method(:string_table), machine: @machine,
                                      version: -> { version_at(n) })
  end
end

#symbol_by_name(name) ⇒ ELFTools::Sections::Symbol?

Get symbol by its name.

The hash tables answer first, which is the lookup the loader itself performs and takes no scanning. Where one of them is built over every symbol its answer is the whole answer, and a name it does not lead to is not one the file records. Otherwise the name is searched for among the symbols #symbols reaches, because a table need only index the names a file exports and a file need not record one at all.

Examples:

elf.dynamic.symbol_by_name('__libc_start_main').type_name
#=> 'STT_FUNC'

Parameters:

  • name (String)

    The name of symbol.

Returns:



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/elftools/dynamic/symbols.rb', line 106

def symbol_by_name(name)
  # Lazily, so that a table is only read when the ones before it have
  # not led anywhere.
  index = hash_tables.lazy.filter_map { |table| table.index_of(name) { |i| symbol_at(i).name == name } }.first
  return symbol_at(index) if index
  # A symbol with no name is the one thing such a table leaves out,
  # having nothing to be indexed by, so it is still searched for.
  return if !name.empty? && hash_tables.any?(&:covers_every_symbol?)

  each_symbol.find { |symbol| symbol.name == name }
end

#symbolsArray<ELFTools::Sections::Symbol>

The symbols the tags point at, which is where a file that has been stripped of its sections still records them.

As many of them as #num_symbols reaches.

Examples:

elf.dynamic.symbols.map(&:name)
#=> ['', 'puts', '__stack_chk_fail', 'printf', '__libc_start_main']

Returns:



89
90
91
# File 'lib/elftools/dynamic/symbols.rb', line 89

def symbols
  each_symbol.to_a
end