elftools 1.3.1 → 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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +193 -7
  3. data/lib/elftools/constants/machine.rb +248 -0
  4. data/lib/elftools/constants/machine_names.rb +246 -0
  5. data/lib/elftools/constants/relocation/aarch64.rb +213 -0
  6. data/lib/elftools/constants/relocation/alpha.rb +47 -0
  7. data/lib/elftools/constants/relocation/amdgpu.rb +28 -0
  8. data/lib/elftools/constants/relocation/arm.rb +150 -0
  9. data/lib/elftools/constants/relocation/avr.rb +51 -0
  10. data/lib/elftools/constants/relocation/bfin.rb +72 -0
  11. data/lib/elftools/constants/relocation/bpf.rb +21 -0
  12. data/lib/elftools/constants/relocation/cr16.rb +46 -0
  13. data/lib/elftools/constants/relocation/cris.rb +46 -0
  14. data/lib/elftools/constants/relocation/crx.rb +35 -0
  15. data/lib/elftools/constants/relocation/csky.rb +79 -0
  16. data/lib/elftools/constants/relocation/d10v.rb +23 -0
  17. data/lib/elftools/constants/relocation/d30v.rb +27 -0
  18. data/lib/elftools/constants/relocation/dlx.rb +24 -0
  19. data/lib/elftools/constants/relocation/epiphany.rb +28 -0
  20. data/lib/elftools/constants/relocation/fr30.rb +27 -0
  21. data/lib/elftools/constants/relocation/frv.rb +57 -0
  22. data/lib/elftools/constants/relocation/ft32.rb +27 -0
  23. data/lib/elftools/constants/relocation/h8.rb +69 -0
  24. data/lib/elftools/constants/relocation/hppa.rb +135 -0
  25. data/lib/elftools/constants/relocation/i370.rb +26 -0
  26. data/lib/elftools/constants/relocation/i386.rb +59 -0
  27. data/lib/elftools/constants/relocation/i860.rb +48 -0
  28. data/lib/elftools/constants/relocation/i960.rb +22 -0
  29. data/lib/elftools/constants/relocation/ia64.rb +117 -0
  30. data/lib/elftools/constants/relocation/ip2k.rb +29 -0
  31. data/lib/elftools/constants/relocation/iq2000.rb +27 -0
  32. data/lib/elftools/constants/relocation/kvx.rb +97 -0
  33. data/lib/elftools/constants/relocation/lm32.rb +32 -0
  34. data/lib/elftools/constants/relocation/loongarch.rb +144 -0
  35. data/lib/elftools/constants/relocation/m32c.rb +27 -0
  36. data/lib/elftools/constants/relocation/m32r.rb +57 -0
  37. data/lib/elftools/constants/relocation/m68hc11.rb +35 -0
  38. data/lib/elftools/constants/relocation/m68k.rb +57 -0
  39. data/lib/elftools/constants/relocation/mcore.rb +27 -0
  40. data/lib/elftools/constants/relocation/mep.rb +36 -0
  41. data/lib/elftools/constants/relocation/metag.rb +63 -0
  42. data/lib/elftools/constants/relocation/microblaze.rb +48 -0
  43. data/lib/elftools/constants/relocation/mips.rb +125 -0
  44. data/lib/elftools/constants/relocation/mmix.rb +51 -0
  45. data/lib/elftools/constants/relocation/mn10200.rb +22 -0
  46. data/lib/elftools/constants/relocation/mn10300.rb +49 -0
  47. data/lib/elftools/constants/relocation/moxie.rb +17 -0
  48. data/lib/elftools/constants/relocation/msp430.rb +27 -0
  49. data/lib/elftools/constants/relocation/msp430x.rb +37 -0
  50. data/lib/elftools/constants/relocation/mt.rb +21 -0
  51. data/lib/elftools/constants/relocation/nds32.rb +167 -0
  52. data/lib/elftools/constants/relocation/nfp.rb +41 -0
  53. data/lib/elftools/constants/relocation/nfp3200.rb +46 -0
  54. data/lib/elftools/constants/relocation/nios2.rb +74 -0
  55. data/lib/elftools/constants/relocation/or1k.rb +69 -0
  56. data/lib/elftools/constants/relocation/pj.rb +24 -0
  57. data/lib/elftools/constants/relocation/ppc.rb +131 -0
  58. data/lib/elftools/constants/relocation/ppc64.rb +177 -0
  59. data/lib/elftools/constants/relocation/pru.rb +31 -0
  60. data/lib/elftools/constants/relocation/riscv.rb +74 -0
  61. data/lib/elftools/constants/relocation/rl78.rb +70 -0
  62. data/lib/elftools/constants/relocation/rx.rb +81 -0
  63. data/lib/elftools/constants/relocation/s12z.rb +22 -0
  64. data/lib/elftools/constants/relocation/s390.rb +82 -0
  65. data/lib/elftools/constants/relocation/score.rb +36 -0
  66. data/lib/elftools/constants/relocation/sh.rb +124 -0
  67. data/lib/elftools/constants/relocation/sparc.rb +108 -0
  68. data/lib/elftools/constants/relocation/spu.rb +32 -0
  69. data/lib/elftools/constants/relocation/tic6x.rb +48 -0
  70. data/lib/elftools/constants/relocation/tilegx.rb +134 -0
  71. data/lib/elftools/constants/relocation/tilepro.rb +105 -0
  72. data/lib/elftools/constants/relocation/v800.rb +101 -0
  73. data/lib/elftools/constants/relocation/v850.rb +66 -0
  74. data/lib/elftools/constants/relocation/vax.rb +29 -0
  75. data/lib/elftools/constants/relocation/visium.rb +30 -0
  76. data/lib/elftools/constants/relocation/wasm32.rb +16 -0
  77. data/lib/elftools/constants/relocation/x86_64.rb +68 -0
  78. data/lib/elftools/constants/relocation/xgate.rb +34 -0
  79. data/lib/elftools/constants/relocation/xstormy16.rb +29 -0
  80. data/lib/elftools/constants/relocation/xtensa.rb +75 -0
  81. data/lib/elftools/constants/relocation/z80.rb +28 -0
  82. data/lib/elftools/constants/relocation.rb +181 -0
  83. data/lib/elftools/constants.rb +168 -231
  84. data/lib/elftools/dynamic/hash_table.rb +232 -0
  85. data/lib/elftools/dynamic/string_table.rb +30 -0
  86. data/lib/elftools/dynamic/symbols.rb +174 -0
  87. data/lib/elftools/dynamic/tag.rb +66 -0
  88. data/lib/elftools/dynamic/versions.rb +87 -0
  89. data/lib/elftools/dynamic.rb +119 -62
  90. data/lib/elftools/elf_file.rb +74 -22
  91. data/lib/elftools/lazy_array.rb +42 -4
  92. data/lib/elftools/note.rb +6 -3
  93. data/lib/elftools/relative_relocations.rb +88 -0
  94. data/lib/elftools/relocation.rb +144 -0
  95. data/lib/elftools/sections/dynamic_section.rb +13 -0
  96. data/lib/elftools/sections/relative_relocation_section.rb +46 -0
  97. data/lib/elftools/sections/relocation_section.rb +24 -43
  98. data/lib/elftools/sections/section.rb +35 -4
  99. data/lib/elftools/sections/sections.rb +8 -0
  100. data/lib/elftools/sections/sym_tab_section.rb +47 -35
  101. data/lib/elftools/sections/symbol.rb +202 -0
  102. data/lib/elftools/sections/version_definition_section.rb +40 -0
  103. data/lib/elftools/sections/version_need_section.rb +40 -0
  104. data/lib/elftools/sections/version_section.rb +44 -0
  105. data/lib/elftools/segments/dynamic_segment.rb +1 -0
  106. data/lib/elftools/segments/load_segment.rb +33 -5
  107. data/lib/elftools/segments/segment.rb +8 -4
  108. data/lib/elftools/structs.rb +132 -18
  109. data/lib/elftools/util.rb +69 -12
  110. data/lib/elftools/version.rb +1 -1
  111. data/lib/elftools/version_tables.rb +155 -0
  112. metadata +108 -11
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elftools/constants'
4
+ require 'elftools/util'
5
+
6
+ module ELFTools
7
+ # A relocation entry.
8
+ #
9
+ # Can be either a REL or RELA relocation.
10
+ class Relocation
11
+ attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header.
12
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
13
+
14
+ # Instantiate a {Relocation} object.
15
+ # @param [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] header
16
+ # The relocation header.
17
+ # @param [#pos=, #read] stream The streaming object.
18
+ # @param [Integer] machine
19
+ # The machine of the ELF file, which decides what {#type} means and how
20
+ # {#header} records it.
21
+ def initialize(header, stream, machine: nil)
22
+ @header = header
23
+ @stream = stream
24
+ @machine = machine
25
+ end
26
+
27
+ # Which symbol this relocation is against, as an index into the symbol
28
+ # table.
29
+ # @return [Integer] The symbol index.
30
+ def symbol_index
31
+ sym_and_type.first
32
+ end
33
+
34
+ # What this relocation does, which only means something together with the
35
+ # machine of the file. {#type_name} names it.
36
+ # @return [Integer] The relocation type.
37
+ def type
38
+ sym_and_type.last
39
+ end
40
+
41
+ # Sets which symbol this relocation is against.
42
+ # @param [Integer] index The symbol index.
43
+ # @raise [ArgumentError] If the bits recording it cannot hold it.
44
+ # @example
45
+ # relocation.symbol_index = 3
46
+ def symbol_index=(index)
47
+ header.r_info = info_of(Util.fits!(index, index_bits, 'Symbol index'), type)
48
+ end
49
+
50
+ # Sets what this relocation does.
51
+ # @param [Integer] type The relocation type.
52
+ # @raise [ArgumentError] If the bits recording it cannot hold it.
53
+ # @example
54
+ # relocation.type = ELFTools::Constants::R::X86_64::R_X86_64_JUMP_SLOT
55
+ def type=(type)
56
+ header.r_info = info_of(symbol_index, Util.fits!(type, type_bits, 'Relocation type'))
57
+ end
58
+
59
+ # The name of {#type}.
60
+ #
61
+ # Every architecture numbers relocation types on its own, so the name is
62
+ # only known when the machine of the file is.
63
+ # @return [String] The name.
64
+ # @example
65
+ # relocation.type_name
66
+ # #=> 'R_X86_64_JUMP_SLOT'
67
+ def type_name
68
+ Constants::R.mapping(@machine, type)
69
+ end
70
+
71
+ private
72
+
73
+ # The +r_info+ recording a symbol index and a type, laid out the way this
74
+ # file lays it out. The inverse of {#sym_and_type}.
75
+ # @return [Integer] The +r_info+.
76
+ def info_of(index, type)
77
+ return mips64_info_of(index, type) if mips64?
78
+
79
+ (index << mask_bit) | type
80
+ end
81
+
82
+ # The +r_info+ as the 64-bit MIPS ABI records it, leaving the bytes the
83
+ # ABI keeps for itself as they were.
84
+ # @return [Integer] The +r_info+.
85
+ def mips64_info_of(index, type)
86
+ info = header.r_info.to_i
87
+ return (index << 32) | (info & 0xffff_ff00) | type if header.class.self_endian == :big
88
+
89
+ (info & 0x00ff_ffff_0000_0000) | (type << 56) | index
90
+ end
91
+
92
+ # How many bits record a symbol index.
93
+ # @return [Integer] The number.
94
+ def index_bits
95
+ mips64? ? 32 : (header.elf_class - mask_bit)
96
+ end
97
+
98
+ # How many bits record a relocation type.
99
+ # @return [Integer] The number.
100
+ def type_bits
101
+ mips64? ? 8 : mask_bit
102
+ end
103
+
104
+ # What +r_info+ records, i.e. a symbol index and a relocation type. Most
105
+ # machines split the field in half between the two, one lays it out its
106
+ # own way.
107
+ # @return [Array(Integer, Integer)] The symbol index and the type.
108
+ def sym_and_type
109
+ return mips64_sym_and_type if mips64?
110
+
111
+ [header.r_info >> mask_bit, header.r_info & ((1 << mask_bit) - 1)]
112
+ end
113
+
114
+ # Whether the file records relocations the way the 64-bit MIPS ABI does,
115
+ # which is the one layout that departs from halving +r_info+.
116
+ # @return [Boolean] The answer.
117
+ def mips64?
118
+ @machine == Constants::EM_MIPS && header.elf_class == 64
119
+ end
120
+
121
+ # Reads +r_info+ as the 64-bit MIPS ABI records it, i.e. a symbol index of
122
+ # four bytes followed by four bytes the ABI keeps for itself, the last of
123
+ # which is the type reported here. Those bytes are ordered as the rest of
124
+ # the file is, which is why the two ends of the field swap places.
125
+ # @example
126
+ # # A big endian file records the symbol index first,
127
+ # # 00 00 00 08 | 00 05 18 07
128
+ # # sym | ssym type3 type2 type
129
+ # 0x0000000800051807 #=> [8, 7]
130
+ # # a little endian one records the very same relocation as
131
+ # 0x0718050000000008 #=> [8, 7]
132
+ # @return [Array(Integer, Integer)] The symbol index and the type.
133
+ def mips64_sym_and_type
134
+ info = header.r_info.to_i
135
+ return [info >> 32, info & 0xff] if header.class.self_endian == :big
136
+
137
+ [info & 0xffff_ffff, info >> 56]
138
+ end
139
+
140
+ def mask_bit
141
+ header.elf_class == 32 ? 8 : 32
142
+ end
143
+ end
144
+ end
@@ -12,6 +12,19 @@ module ELFTools
12
12
  class DynamicSection < Section
13
13
  include ELFTools::Dynamic
14
14
 
15
+ # Instantiate a {DynamicSection} object.
16
+ # @param [ELFTools::Structs::ELF_Shdr] header
17
+ # See {Section#initialize} for more information.
18
+ # @param [#pos=, #read] stream
19
+ # See {Section#initialize} for more information.
20
+ # @param [Integer] machine
21
+ # The machine of the ELF file, which decides what the entries a tag
22
+ # points at mean. This should be +e_machine+ of the ELF header.
23
+ def initialize(header, stream, machine: nil, **_kwargs)
24
+ @machine = machine
25
+ super
26
+ end
27
+
15
28
  # Get the start address of tags.
16
29
  # @return [Integer] Start address of tags.
17
30
  def tag_start
@@ -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
@@ -1,14 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'elftools/constants'
4
+ require 'elftools/relocation'
4
5
  require 'elftools/sections/section'
5
6
  require 'elftools/structs'
6
7
 
7
8
  module ELFTools
8
9
  module Sections
9
- # Class of note section.
10
- # Note section records notes
10
+ # Class of relocation section.
11
+ # Usually for sections .rel.* and .rela.*,
12
+ # which record relocations in ELF file.
11
13
  class RelocationSection < Section
14
+ # Instantiate a {RelocationSection} 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 [Integer] machine
20
+ # The machine of the ELF file, which decides what a relocation type
21
+ # means. This should be +e_machine+ of the ELF header.
22
+ def initialize(header, stream, machine: nil, **_kwargs)
23
+ @machine = machine
24
+ super
25
+ end
26
+
12
27
  # Is this relocation a RELA or REL type.
13
28
  # @return [Boolean] If is RELA.
14
29
  def rela?
@@ -42,19 +57,22 @@ module ELFTools
42
57
  # @return [Enumerator<ELFTools::Relocation>, Array<ELFTools::Relocation>]
43
58
  # If block is not given, an enumerator will be returned.
44
59
  # Otherwise, the whole relocations will be returned.
45
- def each_relocations(&block)
46
- return enum_for(:each_relocations) unless block_given?
60
+ def each_relocation(&block)
61
+ return enum_for(:each_relocation) unless block_given?
47
62
 
48
63
  Array.new(num_relocations) do |i|
49
64
  relocation_at(i).tap(&block)
50
65
  end
51
66
  end
52
67
 
68
+ # The name this used to go by, kept so that it keeps working.
69
+ alias each_relocations each_relocation
70
+
53
71
  # Simply use {#relocations} to get all relocations.
54
72
  # @return [Array<ELFTools::Relocation>]
55
73
  # Whole relocations.
56
74
  def relocations
57
- each_relocations.to_a
75
+ each_relocation.to_a
58
76
  end
59
77
 
60
78
  private
@@ -65,45 +83,8 @@ module ELFTools
65
83
  rel = klass.new(endian: header.class.self_endian, offset: stream.pos)
66
84
  rel.elf_class = header.elf_class
67
85
  rel.read(stream)
68
- Relocation.new(rel, stream)
86
+ Relocation.new(rel, stream, machine: @machine)
69
87
  end
70
88
  end
71
89
  end
72
-
73
- # A relocation entry.
74
- #
75
- # Can be either a REL or RELA relocation.
76
- # XXX: move this to an independent file?
77
- class Relocation
78
- attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header.
79
- attr_reader :stream # @return [#pos=, #read] Streaming object.
80
-
81
- # Instantiate a {Relocation} object.
82
- def initialize(header, stream)
83
- @header = header
84
- @stream = stream
85
- end
86
-
87
- # +r_info+ contains sym and type, use two methods
88
- # to access them easier.
89
- # @return [Integer] sym infor.
90
- def r_info_sym
91
- header.r_info >> mask_bit
92
- end
93
- alias symbol_index r_info_sym
94
-
95
- # +r_info+ contains sym and type, use two methods
96
- # to access them easier.
97
- # @return [Integer] type infor.
98
- def r_info_type
99
- header.r_info & ((1 << mask_bit) - 1)
100
- end
101
- alias type r_info_type
102
-
103
- private
104
-
105
- def mask_bit
106
- header.elf_class == 32 ? 8 : 32
107
- end
108
- end
109
90
  end
@@ -13,16 +13,16 @@ module ELFTools
13
13
  # The section header object.
14
14
  # @param [#pos=, #read] stream
15
15
  # The streaming object for further dump.
16
- # @param [ELFTools::Sections::StrTabSection, Proc] strtab
16
+ # @param [ELFTools::Sections::StrTabSection, Proc] section_name_table
17
17
  # The string table object. For fetching section names.
18
18
  # If +Proc+ if given, it will call at the first
19
19
  # time access +#name+.
20
20
  # @param [Method] offset_from_vma
21
21
  # The method to get offset of file, given virtual memory address.
22
- def initialize(header, stream, offset_from_vma: nil, strtab: nil, **_kwargs)
22
+ def initialize(header, stream, offset_from_vma: nil, section_name_table: nil, **_kwargs)
23
23
  @header = header
24
24
  @stream = stream
25
- @strtab = strtab
25
+ @section_name_table = section_name_table
26
26
  @offset_from_vma = offset_from_vma
27
27
  end
28
28
 
@@ -36,7 +36,7 @@ module ELFTools
36
36
  # Get name of this section.
37
37
  # @return [String] The name.
38
38
  def name
39
- @name ||= @strtab.call.name_at(header.sh_name)
39
+ @name ||= @section_name_table.call.name_at(header.sh_name)
40
40
  end
41
41
 
42
42
  # Fetch data of this section.
@@ -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
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'elftools/sections/section'
4
+ require 'elftools/sections/symbol'
5
+ require 'elftools/version_tables'
4
6
 
5
7
  module ELFTools
6
8
  module Sections
@@ -15,11 +17,16 @@ module ELFTools
15
17
  # See {Section#initialize} for more information.
16
18
  # @param [#pos=, #read] stream
17
19
  # See {Section#initialize} for more information.
18
- # @param [Proc] section_at
19
- # The method for fetching other sections by index.
20
- # This lambda should be {ELFTools::ELFFile#section_at}.
21
- def initialize(header, stream, section_at: nil, **_kwargs)
22
- @section_at = 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}.
24
+ # @param [Integer] machine
25
+ # The machine of the ELF file, which decides what the fields of a
26
+ # symbol mean. This should be +e_machine+ of the ELF header.
27
+ def initialize(header, stream, sections: nil, machine: nil, **_kwargs)
28
+ @sections = sections
29
+ @machine = machine
23
30
  # For faster #symbol_by_name
24
31
  super
25
32
  end
@@ -56,19 +63,22 @@ module ELFTools
56
63
  # @return [Enumerator<ELFTools::Sections::Symbol>, Array<ELFTools::Sections::Symbol>]
57
64
  # If block is not given, an enumerator will be returned.
58
65
  # Otherwise return array of symbols.
59
- def each_symbols(&block)
60
- return enum_for(:each_symbols) unless block_given?
66
+ def each_symbol(&block)
67
+ return enum_for(:each_symbol) unless block_given?
61
68
 
62
69
  Array.new(num_symbols) do |i|
63
70
  symbol_at(i).tap(&block)
64
71
  end
65
72
  end
66
73
 
74
+ # The name this used to go by, kept so that it keeps working.
75
+ alias each_symbols each_symbol
76
+
67
77
  # Simply use {#symbols} to get all symbols.
68
78
  # @return [Array<ELFTools::Sections::Symbol>]
69
79
  # The whole symbols.
70
80
  def symbols
71
- each_symbols.to_a
81
+ each_symbol.to_a
72
82
  end
73
83
 
74
84
  # Get symbol by its name.
@@ -76,14 +86,14 @@ module ELFTools
76
86
  # The name of symbol.
77
87
  # @return [ELFTools::Sections::Symbol] Desired symbol.
78
88
  def symbol_by_name(name)
79
- each_symbols.find { |symbol| symbol.name == name }
89
+ each_symbol.find { |symbol| symbol.name == name }
80
90
  end
81
91
 
82
92
  # Return the symbol string section.
83
93
  # Lazy loaded.
84
94
  # @return [ELFTools::Sections::StrTabSection] The string table section.
85
95
  def symstr
86
- @symstr ||= @section_at.call(header.sh_link)
96
+ @symstr ||= @sections.call[header.sh_link]
87
97
  end
88
98
 
89
99
  private
@@ -92,35 +102,37 @@ module ELFTools
92
102
  stream.pos = header.sh_offset + n * header.sh_entsize
93
103
  sym = Structs::ELF_sym[header.elf_class].new(endian: header.class.self_endian, offset: stream.pos)
94
104
  sym.read(stream)
95
- Symbol.new(sym, stream, symstr: method(:symstr))
105
+ Symbol.new(sym, stream, symstr: method(:symstr), machine: @machine, version: -> { version_at(n) })
96
106
  end
97
- end
98
107
 
99
- # Class of symbol.
100
- #
101
- # XXX: Should this class be defined in an independent file?
102
- class Symbol
103
- attr_reader :header # @return [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] Section header.
104
- attr_reader :stream # @return [#pos=, #read] Streaming object.
105
-
106
- # Instantiate a {ELFTools::Sections::Symbol} object.
107
- # @param [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] header
108
- # The symbol header.
109
- # @param [#pos=, #read] stream The streaming object.
110
- # @param [ELFTools::Sections::StrTabSection, Proc] symstr
111
- # The symbol string section.
112
- # If +Proc+ is given, it will be called at the first time
113
- # access {Symbol#name}.
114
- def initialize(header, stream, symstr: nil)
115
- @header = header
116
- @stream = stream
117
- @symstr = symstr
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
118
127
  end
119
128
 
120
- # Return the symbol name.
121
- # @return [String] The name.
122
- def name
123
- @name ||= @symstr.call.name_at(header.st_name)
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
+ )
124
136
  end
125
137
  end
126
138
  end