elftools 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elftools/relative_relocations'
4
+ require 'elftools/sections/section'
5
+
6
+ module ELFTools
7
+ module Sections
8
+ # Class of the section packing the relocations that only add the load bias.
9
+ #
10
+ # This section is usually named .relr.dyn, and records the very relocations
11
+ # the +DT_RELR+ tag points at.
12
+ class RelativeRelocationSection < Section
13
+ # Instantiate a {RelativeRelocationSection} object.
14
+ # @param [ELFTools::Structs::ELF_Shdr] header
15
+ # See {Section#initialize} for more information.
16
+ # @param [#pos=, #read] stream
17
+ # See {Section#initialize} for more information.
18
+ # @param [Integer] machine
19
+ # The machine of the ELF file, which decides what these relocations
20
+ # are of. This should be +e_machine+ of the ELF header.
21
+ def initialize(header, stream, machine: nil, **_kwargs)
22
+ @machine = machine
23
+ super
24
+ end
25
+
26
+ # The relocations the section packs.
27
+ # @return [Array<ELFTools::Relocation>]
28
+ # The relocations, in the ascending order the section records them.
29
+ # @example
30
+ # section.relocations.map(&:type_name).uniq
31
+ # #=> ['R_X86_64_RELATIVE']
32
+ def relocations
33
+ @relocations ||= RelativeRelocations.new(
34
+ stream, header.sh_offset.to_i...(header.sh_offset.to_i + header.sh_size.to_i),
35
+ elf_class: header.elf_class, endian: header.class.self_endian, machine: @machine
36
+ ).to_a
37
+ end
38
+
39
+ # How many relocations the section packs.
40
+ # @return [Integer] The number.
41
+ def num_relocations
42
+ relocations.size
43
+ end
44
+ end
45
+ end
46
+ end
@@ -46,6 +46,37 @@ module ELFTools
46
46
  stream.read(header.sh_size)
47
47
  end
48
48
 
49
+ # Is this section written to while the file runs?
50
+ # @return [Boolean] True or false.
51
+ # @example
52
+ # elf.section_by_name('.data').writable?
53
+ # #=> true
54
+ def writable?
55
+ header.sh_flags.allbits?(Constants::SHF_WRITE)
56
+ end
57
+
58
+ # Is this section executed?
59
+ # @return [Boolean] True or false.
60
+ # @example
61
+ # elf.section_by_name('.text').executable?
62
+ # #=> true
63
+ def executable?
64
+ header.sh_flags.allbits?(Constants::SHF_EXECINSTR)
65
+ end
66
+
67
+ # Does this section take memory while the file runs?
68
+ #
69
+ # The ones that do are what a file is loaded by, the rest being what is
70
+ # recorded about it, its symbol names and its debugging information
71
+ # among them.
72
+ # @return [Boolean] True or false.
73
+ # @example
74
+ # elf.section_by_name('.symtab').allocated?
75
+ # #=> false
76
+ def allocated?
77
+ header.sh_flags.allbits?(Constants::SHF_ALLOC)
78
+ end
79
+
49
80
  # Is this a null section?
50
81
  # @return [Boolean] No it's not.
51
82
  def null?
@@ -7,9 +7,13 @@ require 'elftools/sections/section'
7
7
  require 'elftools/sections/dynamic_section'
8
8
  require 'elftools/sections/note_section'
9
9
  require 'elftools/sections/null_section'
10
+ require 'elftools/sections/relative_relocation_section'
10
11
  require 'elftools/sections/relocation_section'
11
12
  require 'elftools/sections/str_tab_section'
12
13
  require 'elftools/sections/sym_tab_section'
14
+ require 'elftools/sections/version_definition_section'
15
+ require 'elftools/sections/version_need_section'
16
+ require 'elftools/sections/version_section'
13
17
 
14
18
  module ELFTools
15
19
  # Defines different types of sections in this module.
@@ -27,6 +31,10 @@ module ELFTools
27
31
  when Constants::SHT_NULL then NullSection
28
32
  when Constants::SHT_NOTE then NoteSection
29
33
  when Constants::SHT_RELA, Constants::SHT_REL then RelocationSection
34
+ when Constants::SHT_RELR then RelativeRelocationSection
35
+ when Constants::SHT_GNU_versym then VersionSection
36
+ when Constants::SHT_GNU_verneed then VersionNeedSection
37
+ when Constants::SHT_GNU_verdef then VersionDefinitionSection
30
38
  when Constants::SHT_STRTAB then StrTabSection
31
39
  when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection
32
40
  else Section
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'elftools/sections/section'
4
4
  require 'elftools/sections/symbol'
5
+ require 'elftools/version_tables'
5
6
 
6
7
  module ELFTools
7
8
  module Sections
@@ -16,14 +17,15 @@ module ELFTools
16
17
  # See {Section#initialize} for more information.
17
18
  # @param [#pos=, #read] stream
18
19
  # See {Section#initialize} for more information.
19
- # @param [Proc] section_at
20
- # The method for fetching other sections by index.
21
- # This lambda should be {ELFTools::ELFFile#section_at}.
20
+ # @param [Proc] sections
21
+ # The method for fetching the sections, which is where the names and
22
+ # the versions of these symbols are recorded. This lambda should be
23
+ # {ELFTools::ELFFile#sections}.
22
24
  # @param [Integer] machine
23
25
  # The machine of the ELF file, which decides what the fields of a
24
26
  # symbol mean. This should be +e_machine+ of the ELF header.
25
- def initialize(header, stream, section_at: nil, machine: nil, **_kwargs)
26
- @section_at = section_at
27
+ def initialize(header, stream, sections: nil, machine: nil, **_kwargs)
28
+ @sections = sections
27
29
  @machine = machine
28
30
  # For faster #symbol_by_name
29
31
  super
@@ -91,7 +93,7 @@ module ELFTools
91
93
  # Lazy loaded.
92
94
  # @return [ELFTools::Sections::StrTabSection] The string table section.
93
95
  def symstr
94
- @symstr ||= @section_at.call(header.sh_link)
96
+ @symstr ||= @sections.call[header.sh_link]
95
97
  end
96
98
 
97
99
  private
@@ -100,7 +102,37 @@ module ELFTools
100
102
  stream.pos = header.sh_offset + n * header.sh_entsize
101
103
  sym = Structs::ELF_sym[header.elf_class].new(endian: header.class.self_endian, offset: stream.pos)
102
104
  sym.read(stream)
103
- Symbol.new(sym, stream, symstr: method(:symstr), machine: @machine)
105
+ Symbol.new(sym, stream, symstr: method(:symstr), machine: @machine, version: -> { version_at(n) })
106
+ end
107
+
108
+ # The version the +n+-th symbol binds to.
109
+ # @return [ELFTools::VersionTables::Version, nil]
110
+ # The version, +nil+ unless this is the table a file is loaded by and
111
+ # the file records versions at all.
112
+ def version_at(n)
113
+ return if versions.nil?
114
+
115
+ VersionTables.version(versions.version_at(n), versions_by_index)
116
+ end
117
+
118
+ # The section recording which version each of these symbols binds to,
119
+ # which is the one naming this table.
120
+ # @return [ELFTools::Sections::VersionSection, nil] The section.
121
+ def versions
122
+ return @versions if defined?(@versions)
123
+
124
+ @versions = @sections&.call&.find do |sec|
125
+ sec.is_a?(VersionSection) && @sections.call[sec.header.sh_link].equal?(self)
126
+ end
127
+ end
128
+
129
+ # The name each index the symbols record names.
130
+ # @return [Hash{Integer => String}] The names.
131
+ def versions_by_index
132
+ @versions_by_index ||= VersionTables.names(
133
+ @sections.call.grep(VersionNeedSection).flat_map(&:requirements),
134
+ @sections.call.grep(VersionDefinitionSection).flat_map(&:definitions)
135
+ )
104
136
  end
105
137
  end
106
138
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'elftools/constants'
4
+ require 'elftools/util'
4
5
 
5
6
  module ELFTools
6
7
  module Sections
@@ -19,11 +20,15 @@ module ELFTools
19
20
  # access {Symbol#name}.
20
21
  # @param [Integer] machine
21
22
  # The machine of the ELF file, which a name of a value depends on.
22
- def initialize(header, stream, symstr: nil, machine: nil)
23
+ # @param [Proc] version
24
+ # Call this to get the version this symbol binds to, which only the
25
+ # symbols a file is loaded by have.
26
+ def initialize(header, stream, symstr: nil, machine: nil, version: nil)
23
27
  @header = header
24
28
  @stream = stream
25
29
  @symstr = symstr
26
30
  @machine = machine
31
+ @version = version
27
32
  end
28
33
 
29
34
  # Return the symbol name.
@@ -32,6 +37,51 @@ module ELFTools
32
37
  @name ||= @symstr.call.name_at(header.st_name)
33
38
  end
34
39
 
40
+ # The version this symbol binds to.
41
+ #
42
+ # Only the symbols a file is loaded by have one, and only where the file
43
+ # records the versions at all. {#name} is left as the file records it,
44
+ # without the version appended.
45
+ # @return [String, nil] The name of the version.
46
+ # @example
47
+ # elf.dynamic.symbol_by_name('printf').version
48
+ # #=> 'GLIBC_2.2.5'
49
+ def version
50
+ binding_version&.name
51
+ end
52
+
53
+ # Whether {#version} is one the symbol asks for by name rather than the
54
+ # default one of its name.
55
+ # @return [Boolean] The answer.
56
+ def version_hidden?
57
+ binding_version&.hidden? || false
58
+ end
59
+
60
+ # What this symbol is worth, which for most of them is the address of
61
+ # what they name.
62
+ #
63
+ # A symbol of a file that is not loaded anywhere records an offset into
64
+ # the section holding it instead, and one the linker is still to place,
65
+ # which {ELFTools::Constants::SHN_COMMON} marks, records the alignment it
66
+ # needs. The ABI leaves the field to the kind of symbol for that reason,
67
+ # and this answers with what is recorded either way.
68
+ # @return [Integer] The value.
69
+ # @example
70
+ # elf.section_by_name('.symtab').symbol_by_name('main').value
71
+ # #=> 4196061 # 0x4006dd
72
+ def value
73
+ header.st_value.to_i
74
+ end
75
+
76
+ # How many bytes what this symbol names takes.
77
+ # @return [Integer] The number, zero where the file records none.
78
+ # @example
79
+ # elf.section_by_name('.symtab').symbol_by_name('main').size
80
+ # #=> 142
81
+ def size
82
+ header.st_size.to_i
83
+ end
84
+
35
85
  # What kind of entity this symbol refers to.
36
86
  #
37
87
  # The available types are listed in {ELFTools::Constants::STT}.
@@ -43,6 +93,15 @@ module ELFTools
43
93
  header.st_info & 0xf
44
94
  end
45
95
 
96
+ # Sets what kind of entity this symbol refers to.
97
+ # @param [Integer] type The type.
98
+ # @raise [ArgumentError] If the four bits recording it cannot hold it.
99
+ # @example
100
+ # symbol.type = ELFTools::Constants::STT_FUNC
101
+ def type=(type)
102
+ header.st_info = (bind << 4) | Util.fits!(type, 4, 'Symbol type')
103
+ end
104
+
46
105
  # The name of {#type}.
47
106
  #
48
107
  # A machine names types of its own, so the name is only known when the
@@ -66,6 +125,15 @@ module ELFTools
66
125
  header.st_info >> 4
67
126
  end
68
127
 
128
+ # Sets how this symbol is linked against others with the same name.
129
+ # @param [Integer] bind The binding.
130
+ # @raise [ArgumentError] If the four bits recording it cannot hold it.
131
+ # @example
132
+ # symbol.bind = ELFTools::Constants::STB_WEAK
133
+ def bind=(bind)
134
+ header.st_info = (Util.fits!(bind, 4, 'Symbol binding') << 4) | type
135
+ end
136
+
69
137
  # The name of {#bind}.
70
138
  # @return [String] The name.
71
139
  # @example
@@ -87,6 +155,19 @@ module ELFTools
87
155
  header.st_other & 0x3
88
156
  end
89
157
 
158
+ # Sets how this symbol is accessed once it becomes part of an executable
159
+ # or shared object.
160
+ #
161
+ # The rest of +st_other+ is left alone, which some machines record their
162
+ # own thing in.
163
+ # @param [Integer] visibility The visibility.
164
+ # @raise [ArgumentError] If the two bits recording it cannot hold it.
165
+ # @example
166
+ # symbol.visibility = ELFTools::Constants::STV_HIDDEN
167
+ def visibility=(visibility)
168
+ header.st_other = (header.st_other.to_i & 0xfc) | Util.fits!(visibility, 2, 'Symbol visibility')
169
+ end
170
+
90
171
  # The name of {#visibility}.
91
172
  # @return [String] The name.
92
173
  # @example
@@ -96,6 +177,15 @@ module ELFTools
96
177
  Constants::STV.mapping(@machine, visibility)
97
178
  end
98
179
 
180
+ # The version this symbol binds to, whatever is asked of it.
181
+ # @return [ELFTools::Dynamic::Versions::Version, nil] The version.
182
+ def binding_version
183
+ return @binding_version if defined?(@binding_version)
184
+
185
+ @binding_version = @version&.call
186
+ end
187
+ private :binding_version
188
+
99
189
  # The index of the section this symbol is defined in.
100
190
  #
101
191
  # Values in {ELFTools::Constants::SHN} have special meanings instead of
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elftools/sections/section'
4
+ require 'elftools/version_tables'
5
+
6
+ module ELFTools
7
+ module Sections
8
+ # Class of the section recording the versions a file defines for what it
9
+ # exports.
10
+ #
11
+ # This section is usually named .gnu.version_d, and records the very
12
+ # versions the +DT_VERDEF+ tag points at.
13
+ class VersionDefinitionSection < Section
14
+ # Instantiate a {VersionDefinitionSection} object.
15
+ # @param [ELFTools::Structs::ELF_Shdr] header
16
+ # See {Section#initialize} for more information.
17
+ # @param [#pos=, #read] stream
18
+ # See {Section#initialize} for more information.
19
+ # @param [Proc] section_at
20
+ # The method for fetching other sections by index, which is where the
21
+ # names are recorded.
22
+ def initialize(header, stream, section_at: nil, **_kwargs)
23
+ @section_at = section_at
24
+ super
25
+ end
26
+
27
+ # The versions this file defines for what it exports.
28
+ # @return [Array<ELFTools::VersionTables::Definition>]
29
+ # The definitions, in the order the section records them.
30
+ # @example
31
+ # section.definitions.map(&:name).first(3)
32
+ # #=> ['libc.so.6', 'GLIBC_2.2.5', 'GLIBC_2.2.6']
33
+ def definitions
34
+ @definitions ||= VersionTables.new(stream, @section_at.call(header.sh_link),
35
+ endian: header.class.self_endian)
36
+ .definitions(header.sh_offset.to_i, header.sh_info.to_i)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elftools/sections/section'
4
+ require 'elftools/version_tables'
5
+
6
+ module ELFTools
7
+ module Sections
8
+ # Class of the section recording the versions a file needs of the files it
9
+ # is loaded with.
10
+ #
11
+ # This section is usually named .gnu.version_r, and records the very
12
+ # versions the +DT_VERNEED+ tag points at.
13
+ class VersionNeedSection < Section
14
+ # Instantiate a {VersionNeedSection} object.
15
+ # @param [ELFTools::Structs::ELF_Shdr] header
16
+ # See {Section#initialize} for more information.
17
+ # @param [#pos=, #read] stream
18
+ # See {Section#initialize} for more information.
19
+ # @param [Proc] section_at
20
+ # The method for fetching other sections by index, which is where the
21
+ # names are recorded.
22
+ def initialize(header, stream, section_at: nil, **_kwargs)
23
+ @section_at = section_at
24
+ super
25
+ end
26
+
27
+ # The versions this file needs of the files it is loaded with.
28
+ # @return [Array<ELFTools::VersionTables::Requirement>]
29
+ # The requirements, in the order the section records them.
30
+ # @example
31
+ # section.requirements.map { |need| [need.file, need.versions.map(&:name)] }
32
+ # #=> [['libc.so.6', ['GLIBC_2.4', 'GLIBC_2.2.5']]]
33
+ def requirements
34
+ @requirements ||= VersionTables.new(stream, @section_at.call(header.sh_link),
35
+ endian: header.class.self_endian)
36
+ .requirements(header.sh_offset.to_i, header.sh_info.to_i)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elftools/sections/section'
4
+
5
+ module ELFTools
6
+ module Sections
7
+ # Class of the section recording which version each symbol binds to.
8
+ #
9
+ # This section is usually named .gnu.version, and holds an index per symbol
10
+ # of the table its +sh_link+ names, the very indices the +DT_VERSYM+ tag
11
+ # points at.
12
+ class VersionSection < Section
13
+ # How many symbols the section records a version for.
14
+ # @return [Integer] The number.
15
+ def num_versions
16
+ header.sh_size.to_i / entry_size
17
+ end
18
+
19
+ # What the +n+-th symbol records as its version, which is an index into
20
+ # the versions a file needs or defines, with the highest bit marking a
21
+ # version the symbol asks for by name rather than the default one.
22
+ # @param [Integer] n The symbol index.
23
+ # @return [Integer, nil] The index, +nil+ if the section records none for it.
24
+ # @example
25
+ # section.version_at(1)
26
+ # #=> 2
27
+ def version_at(n)
28
+ return if n.negative? || n >= num_versions
29
+
30
+ stream.pos = header.sh_offset.to_i + (n * entry_size)
31
+ stream.read(entry_size).unpack1(header.class.self_endian == :big ? 'S>' : 'S<')
32
+ end
33
+
34
+ private
35
+
36
+ # What an entry takes, which the section records and the format fixes at
37
+ # two bytes either way.
38
+ # @return [Integer] The number of bytes.
39
+ def entry_size
40
+ 2
41
+ end
42
+ end
43
+ end
44
+ end
@@ -18,15 +18,73 @@ module ELFTools
18
18
  attr_accessor :elf_class # @return [Integer] 32 or 64.
19
19
  attr_accessor :offset # @return [Integer] The file offset of this header.
20
20
 
21
- # Records which fields have been patched.
22
- # @return [Hash{Integer => Integer}] Patches.
21
+ # Reads the structure, remembering the bytes it was read from.
22
+ #
23
+ # They are taken back off the stream. A stream that cannot be seeked is
24
+ # serialized instead.
25
+ # @param [#pos=, #read] io The streaming object.
26
+ # @return [ELFTools::Structs::ELFStruct] Itself.
27
+ def read(io)
28
+ start = io.pos if io.respond_to?(:pos)
29
+ super.tap { @source = start.nil? ? to_binary_s : bytes_read(io, start) }
30
+ end
31
+
32
+ # Which bytes of this structure have been changed since it was read.
33
+ #
34
+ # Every field answers alike, however deeply it is nested, because what is
35
+ # compared is the bytes the structure occupies rather than the
36
+ # assignments that were made to it. A field assigned the value it
37
+ # already held leaves nothing behind.
38
+ # @return [Hash{Integer => String}]
39
+ # Where each run of changed bytes starts, as an offset into the
40
+ # structure, and the bytes it is to be replaced with.
41
+ # @example
42
+ # header.e_ident.ei_abiversion = 41
43
+ # header.patches
44
+ # #=> { 8 => "\x29" }
23
45
  def patches
24
- @patches ||= {}
46
+ return {} if @source.nil?
47
+
48
+ changed_runs(@source, to_binary_s)
25
49
  end
26
50
 
27
51
  # BinData hash(Snapshot) that behaves like HashWithIndifferentAccess
28
52
  alias to_h snapshot
29
53
 
54
+ private
55
+
56
+ # The bytes a read has just taken from a stream, leaving it where the
57
+ # read left it.
58
+ # @param [#pos=, #read] io The streaming object.
59
+ # @param [Integer] start Where the read began.
60
+ # @return [String] The bytes.
61
+ def bytes_read(io, start)
62
+ here = io.pos
63
+ io.pos = start
64
+ io.read(here - start).tap { io.pos = here }
65
+ end
66
+
67
+ # Where two strings of bytes differ, as the runs of bytes that differ.
68
+ #
69
+ # Only as far as +before+ reaches, so that a patch never covers more of
70
+ # the file than the structure it came from.
71
+ # @param [String] before The bytes as they were.
72
+ # @param [String] after The bytes as they are.
73
+ # @return [Hash{Integer => String}] Where each run starts, and its bytes.
74
+ def changed_runs(before, after)
75
+ runs = {}
76
+ start = nil
77
+ (0..before.bytesize).each do |i|
78
+ if i < before.bytesize && before.getbyte(i) != after.getbyte(i)
79
+ start ||= i
80
+ elsif start
81
+ runs[start] = after.byteslice(start, i - start)
82
+ start = nil
83
+ end
84
+ end
85
+ runs
86
+ end
87
+
30
88
  class << self
31
89
  # Hooks the constructor.
32
90
  #
@@ -41,19 +99,7 @@ module ELFTools
41
99
  def new(*args)
42
100
  kwargs = args.last.is_a?(Hash) ? args.last : {}
43
101
  offset = kwargs.delete(:offset)
44
- super.tap do |obj|
45
- obj.offset = offset
46
- obj.field_names.each do |f|
47
- m = :"#{f}="
48
- old_method = obj.singleton_method(m)
49
- obj.singleton_class.send(:undef_method, m)
50
- obj.define_singleton_method(m) do |val|
51
- org = obj.send(f)
52
- obj.patches[org.abs_offset] = ELFStruct.pack(val, org.num_bytes)
53
- old_method.call(val)
54
- end
55
- end
56
- end
102
+ super.tap { |obj| obj.offset = offset }
57
103
  end
58
104
 
59
105
  # Gets the endianness of current class.
@@ -63,6 +109,10 @@ module ELFTools
63
109
  end
64
110
 
65
111
  # Packs an integer to string.
112
+ #
113
+ # @deprecated
114
+ # Nothing here packs a patch by hand anymore, see {ELFStruct#patches}.
115
+ # This is kept for anyone who called it and goes in the next major.
66
116
  # @param [Integer] val
67
117
  # @param [Integer] bytes
68
118
  # @return [String]
@@ -200,6 +250,49 @@ module ELFTools
200
250
  uint32 :shift2 # The second shift the bloom filter is built with
201
251
  end
202
252
 
253
+ # An entry of the table of versions a file needs of another, which the
254
+ # +vn_next+ of the one before it points at.
255
+ class ELF_Verneed < ELFStruct
256
+ endian :big_and_little
257
+ uint16 :vn_version # Revision of this structure
258
+ uint16 :vn_cnt # How many versions of the file are needed
259
+ uint32 :vn_file # Name of the file, as an offset into the string table
260
+ uint32 :vn_aux # Where the versions start, as an offset from here
261
+ uint32 :vn_next # Where the next entry is, as an offset from here
262
+ end
263
+
264
+ # A version an {ELF_Verneed} needs, which the +vna_next+ of the one before
265
+ # it points at.
266
+ class ELF_Vernaux < ELFStruct
267
+ endian :big_and_little
268
+ uint32 :vna_hash # Hash of the name
269
+ uint16 :vna_flags # Flags
270
+ uint16 :vna_other # The index the symbols name this version with
271
+ uint32 :vna_name # The name, as an offset into the string table
272
+ uint32 :vna_next # Where the next version is, as an offset from here
273
+ end
274
+
275
+ # An entry of the table of versions a file defines, which the +vd_next+ of
276
+ # the one before it points at.
277
+ class ELF_Verdef < ELFStruct
278
+ endian :big_and_little
279
+ uint16 :vd_version # Revision of this structure
280
+ uint16 :vd_flags # Flags
281
+ uint16 :vd_ndx # The index the symbols name this version with
282
+ uint16 :vd_cnt # How many names follow, the version and its ancestors
283
+ uint32 :vd_hash # Hash of the name
284
+ uint32 :vd_aux # Where the names start, as an offset from here
285
+ uint32 :vd_next # Where the next entry is, as an offset from here
286
+ end
287
+
288
+ # A name an {ELF_Verdef} records, its own or an ancestor's, which the
289
+ # +vda_next+ of the one before it points at.
290
+ class ELF_Verdaux < ELFStruct
291
+ endian :big_and_little
292
+ uint32 :vda_name # The name, as an offset into the string table
293
+ uint32 :vda_next # Where the next name is, as an offset from here
294
+ end
295
+
203
296
  # Note header.
204
297
  class ELF_Nhdr < ELFStruct
205
298
  endian :big_and_little