Class: ElfUtils::Symbol

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

Overview

Represents a symbol found in an ELF file.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, symbol, strtab = file.strtab) ⇒ Symbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Symbol.

Parameters:

  • file (ElfFile)

    ElfFile that declared this symbol

  • symbol (Integer)

    symbol index in symbol table

  • strtab (Section::Strtab) (defaults to: file.strtab)

    string table to lookup symbol name in



8
9
10
11
12
# File 'lib/elf_utils/symbol.rb', line 8

def initialize(file, symbol, strtab = file.strtab)
  @file = file
  @sym = symbol
  @strtab = strtab
end

Instance Attribute Details

#fileObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



15
16
17
# File 'lib/elf_utils/symbol.rb', line 15

def file
  @file
end

Instance Method Details

#addrInteger

get the address of the symbol

This method will return the address of the symbol in memory, taking into account any relocation performed on the section or load segment.

Returns:

  • (Integer)

    address of the symbol in memory

See Also:



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/elf_utils/symbol.rb', line 45

def addr
  if @sym.st_shndx == Types::SHN_COMMON
    nil
  elsif @sym.st_shndx == Types::SHN_ABS
    @sym.st_value
  elsif @file.relocatable?
    @sym.st_value + section.addr
  else
    @sym.st_value + section.relocation_offset
  end
end

#ctypeCType::Type

get the CType datatype instance for the variable declared in this symbol

Examples:

elf_file = ElfUtils.open("spec/data/complex_64be-dwarf64-v5")
symbol = elf_file.symbol("my_tlv")      # => #<ElfUtils::Symbol ...>
ctype = symbol.ctype                    # => #<CTypes::Struct ... >
tlv = ctype.unpack("\1\bhello world")   # => {  type: 1,
                                        # =>     len: 11,
                                        # =>   value: "hello world" }

Returns:

  • (CType::Type)

    datatype instance

See Also:



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/elf_utils/symbol.rb', line 87

def ctype
  return nil unless type == :object && (debug_info = @file.debug_info)

  name = self.name
  # use st_value because #addr may be relocated
  location = @sym.st_value
  die = debug_info.dies(top: true).find do |die|
    die.tag == :variable &&
      die[:name] == name &&
      die.location == location
  end or return nil
  die[:type]&.ctype
end

#inspectObject



138
139
140
141
142
143
# File 'lib/elf_utils/symbol.rb', line 138

def inspect
  "<%p %-7p %-18s %s, 0x%08x>" %
    [self.class, type, section&.name, name, addr]
rescue
  @sym.inspect
end

#nameString?

get the name of the symbol

Returns:

  • (String, nil)

    symbol name



19
20
21
# File 'lib/elf_utils/symbol.rb', line 19

def name
  @name ||= @strtab[@sym.st_name]
end

#sectionSection::Base

get the ELF section this symbol resides in

Returns:



25
26
27
# File 'lib/elf_utils/symbol.rb', line 25

def section
  @file.sections[@sym.st_shndx]
end

#section_offsetInteger

get the offset of this symbol within the ELF section

Returns:

  • (Integer)

    offset in bytes from the start of the ELF section



59
60
61
# File 'lib/elf_utils/symbol.rb', line 59

def section_offset
  addr - section.addr
end

#sizeInteger

get the size of this symbol in memory

Returns:

  • (Integer)

    size in bytes of this symbol



65
66
67
# File 'lib/elf_utils/symbol.rb', line 65

def size
  @sym.st_size
end

#source_locationHash<file, line>

get the source location for an :object or :func symbol

Examples:

elf_file = ElfUtils.open("spec/data/complex_64be-dwarf64-v5")
symbol = elf_file.symbol("main")    # => #<ElfUtils::Symbol ...>
symbol.source_location              # => { file: "test.c", line: 13 }

Returns:

  • (Hash<file, line>)


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
# File 'lib/elf_utils/symbol.rb', line 108

def source_location
  # look up the CU die, and the die for this object
  name = self.name
  addr = self.addr
  cu_die = nil
  die = @file.debug_info
    .dies(root: true, top: true)
    .find do |die|
      cu_die = die if die.tag == :compile_unit
      die[:name] == name && die.has_addr?(addr)
    end or return

  # get the line number program for the compilation unit
  lnp = @file
    .section(".debug_line")
    &.line_number_program(cu_die[:stmt_list]) or return

  # based on the type of symbol, we have different ways of looking up the
  # source location
  case type
  when :func
    lnp.source_location(addr)
  when :object
    {
      file: lnp.file_name(die[:decl_file]),
      line: die[:decl_line]
    }
  end
end

#to_rangeRange

get the range of memory addresses this symbol occupies in memory

Returns:

  • (Range)


71
72
73
74
# File 'lib/elf_utils/symbol.rb', line 71

def to_range
  addr = self.addr || 0
  (addr...addr + size)
end

#typeSymbol

get the symbol type

Returns:

See Also:



32
33
34
35
# File 'lib/elf_utils/symbol.rb', line 32

def type
  Types::Elf_Stt[@sym.st_info & 0xf] or
    raise Error, "invalid symbol table type: %p", @sym.st_info & 0xf
end