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:



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

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.

Nothing a file is loaded by 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. Only DT_HASH records the number outright.

This is therefore 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.



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

def num_symbols
  @num_symbols ||= (hash_tables.map(&:num_symbols) + [count_from_relocations]).compact.max || 0
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
38
39
# File 'lib/elftools/dynamic/symbols.rb', line 28

def symbol_at(n)
  return if n.negative?

  @symbol_at_map ||= {}
  @symbol_at_map[n] ||= begin
    klass = Structs::ELF_sym[header.elf_class]
    # An entry takes what its structure takes, which is also what
    # DT_SYMENT records and what a file has no way of disagreeing with.
    sym = read_struct(klass, sym_offset + (n * struct(klass).num_bytes))
    Sections::Symbol.new(sym, stream, symstr: method(:string_table), machine: @machine)
  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. They do not index every symbol, and a file need not record one at all, so a name they do not lead to is searched for among the symbols #symbols reaches.

Examples:

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

Parameters:

  • name (String)

    The name of symbol.

Returns:



103
104
105
106
107
108
109
110
# File 'lib/elftools/dynamic/symbols.rb', line 103

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

  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:



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

def symbols
  each_symbol.to_a
end