elftools 1.0.1 → 1.1.3
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.
- checksums.yaml +5 -5
- data/lib/elftools.rb +2 -0
- data/lib/elftools/constants.rb +142 -79
- data/lib/elftools/dynamic.rb +20 -2
- data/lib/elftools/elf_file.rb +17 -10
- data/lib/elftools/exceptions.rb +11 -0
- data/lib/elftools/lazy_array.rb +4 -1
- data/lib/elftools/note.rb +7 -2
- data/lib/elftools/sections/dynamic_section.rb +2 -0
- data/lib/elftools/sections/note_section.rb +2 -0
- data/lib/elftools/sections/null_section.rb +2 -0
- data/lib/elftools/sections/relocation_section.rb +3 -0
- data/lib/elftools/sections/section.rb +2 -0
- data/lib/elftools/sections/sections.rb +4 -2
- data/lib/elftools/sections/str_tab_section.rb +2 -0
- data/lib/elftools/sections/sym_tab_section.rb +3 -0
- data/lib/elftools/segments/dynamic_segment.rb +2 -0
- data/lib/elftools/segments/interp_segment.rb +2 -0
- data/lib/elftools/segments/load_segment.rb +91 -0
- data/lib/elftools/segments/note_segment.rb +2 -0
- data/lib/elftools/segments/segment.rb +2 -0
- data/lib/elftools/segments/segments.rb +6 -2
- data/lib/elftools/structs.rb +22 -13
- data/lib/elftools/util.rb +6 -0
- data/lib/elftools/version.rb +3 -1
- metadata +13 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ef6779875e27077da47848a95cef46ee26be52e56e763c0850dbd2e22e7e100b
|
4
|
+
data.tar.gz: a9b422a4fb0a11a08036e222475110f9a9f6f788ce8c775d6e67d0e6f1b5a9c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13f82b3b243a09531408986b1acef31556089bca5927077c9e4d490632229f77cef97f9fdd1eb4343be8dc9bbb9f55e57b3ee51f5da5651009bd4b4ac3724eb5
|
7
|
+
data.tar.gz: 276ad11bcc135f067046694da526da5078cfdc0b24137cadeb7d8c52b0ddb462b23ee7d47c97bc08611160d436240c559ff1b4d18b51ed78a0b607c0973dc913
|
data/lib/elftools.rb
CHANGED
data/lib/elftools/constants.rb
CHANGED
@@ -1,54 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ELFTools
|
2
4
|
# Define constants from elf.h.
|
3
5
|
# Mostly refer from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h
|
4
6
|
# and binutils/elfcpp/elfcpp.h.
|
5
7
|
module Constants
|
6
8
|
# ELF magic header
|
7
|
-
ELFMAG = "\x7FELF"
|
9
|
+
ELFMAG = "\x7FELF"
|
8
10
|
|
9
|
-
#
|
10
|
-
module
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
SHT_HASH = 5 # symbol hash table
|
17
|
-
SHT_DYNAMIC = 6 # information of dynamic linking
|
18
|
-
SHT_NOTE = 7 # note section
|
19
|
-
SHT_NOBITS = 8 # section occupies no space
|
20
|
-
SHT_REL = 9 # relocation
|
21
|
-
SHT_SHLIB = 10 # reserved
|
22
|
-
SHT_DYNSYM = 11 # symbols for dynamic
|
23
|
-
# Values between {SHT_LOPROC} and {SHT_HIPROC} are reserved for processor-specific semantics.
|
24
|
-
SHT_LOPROC = 0x70000000
|
25
|
-
SHT_HIPROC = 0x7fffffff # see {SHT_LOPROC}
|
26
|
-
# Values between {SHT_LOUSER} and {SHT_HIUSER} are reserved for application programs.
|
27
|
-
SHT_LOUSER = 0x80000000
|
28
|
-
SHT_HIUSER = 0xffffffff # see {SHT_LOUSER}
|
29
|
-
end
|
30
|
-
include SHT
|
11
|
+
# Values of `d_un.d_val' in the DT_FLAGS and DT_FLAGS_1 entry.
|
12
|
+
module DF
|
13
|
+
DF_ORIGIN = 0x00000001 # Object may use DF_ORIGIN
|
14
|
+
DF_SYMBOLIC = 0x00000002 # Symbol resolutions starts here
|
15
|
+
DF_TEXTREL = 0x00000004 # Object contains text relocations
|
16
|
+
DF_BIND_NOW = 0x00000008 # No lazy binding for this object
|
17
|
+
DF_STATIC_TLS = 0x00000010 # Module uses the static TLS model
|
31
18
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
19
|
+
DF_1_NOW = 0x00000001 # Set RTLD_NOW for this object.
|
20
|
+
DF_1_GLOBAL = 0x00000002 # Set RTLD_GLOBAL for this object.
|
21
|
+
DF_1_GROUP = 0x00000004 # Set RTLD_GROUP for this object.
|
22
|
+
DF_1_NODELETE = 0x00000008 # Set RTLD_NODELETE for this object.
|
23
|
+
DF_1_LOADFLTR = 0x00000010 # Trigger filtee loading at runtime.
|
24
|
+
DF_1_INITFIRST = 0x00000020 # Set RTLD_INITFIRST for this object
|
25
|
+
DF_1_NOOPEN = 0x00000040 # Set RTLD_NOOPEN for this object.
|
26
|
+
DF_1_ORIGIN = 0x00000080 # $ORIGIN must be handled.
|
27
|
+
DF_1_DIRECT = 0x00000100 # Direct binding enabled.
|
28
|
+
DF_1_TRANS = 0x00000200 # :nodoc:
|
29
|
+
DF_1_INTERPOSE = 0x00000400 # Object is used to interpose.
|
30
|
+
DF_1_NODEFLIB = 0x00000800 # Ignore default lib search path.
|
31
|
+
DF_1_NODUMP = 0x00001000 # Object can't be dldump'ed.
|
32
|
+
DF_1_CONFALT = 0x00002000 # Configuration alternative created.
|
33
|
+
DF_1_ENDFILTEE = 0x00004000 # Filtee terminates filters search.
|
34
|
+
DF_1_DISPRELDNE = 0x00008000 # Disp reloc applied at build time.
|
35
|
+
DF_1_DISPRELPND = 0x00010000 # Disp reloc applied at run-time.
|
36
|
+
DF_1_NODIRECT = 0x00020000 # Object has no-direct binding.
|
37
|
+
DF_1_IGNMULDEF = 0x00040000 # :nodoc:
|
38
|
+
DF_1_NOKSYMS = 0x00080000 # :nodoc:
|
39
|
+
DF_1_NOHDR = 0x00100000 # :nodoc:
|
40
|
+
DF_1_EDITED = 0x00200000 # Object is modified after built.
|
41
|
+
DF_1_NORELOC = 0x00400000 # :nodoc:
|
42
|
+
DF_1_SYMINTPOSE = 0x00800000 # Object has individual interposers.
|
43
|
+
DF_1_GLOBAUDIT = 0x01000000 # Global auditing required.
|
44
|
+
DF_1_SINGLETON = 0x02000000 # Singleton symbols are used.
|
50
45
|
end
|
51
|
-
include
|
46
|
+
include DF
|
52
47
|
|
53
48
|
# Dynamic table types, records in +d_tag+.
|
54
49
|
module DT
|
@@ -100,6 +95,7 @@ module ELFTools
|
|
100
95
|
DT_VERDEF = 0x6ffffffc # address of version definition table
|
101
96
|
DT_VERDEFNUM = 0x6ffffffd # number of entries in {DT_VERDEF}
|
102
97
|
DT_VERNEED = 0x6ffffffe # address of version dependency table
|
98
|
+
DT_VERSYM = 0x6ffffff0 # section address of .gnu.version
|
103
99
|
DT_VERNEEDNUM = 0x6fffffff # number of entries in {DT_VERNEED}
|
104
100
|
# Values between {DT_LOPROC} and {DT_HIPROC} are reserved for processor-specific semantics.
|
105
101
|
DT_LOPROC = 0x70000000
|
@@ -107,43 +103,6 @@ module ELFTools
|
|
107
103
|
end
|
108
104
|
include DT
|
109
105
|
|
110
|
-
# Values of `d_un.d_val' in the DT_FLAGS and DT_FLAGS_1 entry.
|
111
|
-
module DF
|
112
|
-
DF_ORIGIN = 0x00000001 # Object may use DF_ORIGIN
|
113
|
-
DF_SYMBOLIC = 0x00000002 # Symbol resolutions starts here
|
114
|
-
DF_TEXTREL = 0x00000004 # Object contains text relocations
|
115
|
-
DF_BIND_NOW = 0x00000008 # No lazy binding for this object
|
116
|
-
DF_STATIC_TLS = 0x00000010 # Module uses the static TLS model
|
117
|
-
|
118
|
-
DF_1_NOW = 0x00000001 # Set RTLD_NOW for this object.
|
119
|
-
DF_1_GLOBAL = 0x00000002 # Set RTLD_GLOBAL for this object.
|
120
|
-
DF_1_GROUP = 0x00000004 # Set RTLD_GROUP for this object.
|
121
|
-
DF_1_NODELETE = 0x00000008 # Set RTLD_NODELETE for this object.
|
122
|
-
DF_1_LOADFLTR = 0x00000010 # Trigger filtee loading at runtime.
|
123
|
-
DF_1_INITFIRST = 0x00000020 # Set RTLD_INITFIRST for this object
|
124
|
-
DF_1_NOOPEN = 0x00000040 # Set RTLD_NOOPEN for this object.
|
125
|
-
DF_1_ORIGIN = 0x00000080 # $ORIGIN must be handled.
|
126
|
-
DF_1_DIRECT = 0x00000100 # Direct binding enabled.
|
127
|
-
DF_1_TRANS = 0x00000200 # :nodoc:
|
128
|
-
DF_1_INTERPOSE = 0x00000400 # Object is used to interpose.
|
129
|
-
DF_1_NODEFLIB = 0x00000800 # Ignore default lib search path.
|
130
|
-
DF_1_NODUMP = 0x00001000 # Object can't be dldump'ed.
|
131
|
-
DF_1_CONFALT = 0x00002000 # Configuration alternative created.
|
132
|
-
DF_1_ENDFILTEE = 0x00004000 # Filtee terminates filters search.
|
133
|
-
DF_1_DISPRELDNE = 0x00008000 # Disp reloc applied at build time.
|
134
|
-
DF_1_DISPRELPND = 0x00010000 # Disp reloc applied at run-time.
|
135
|
-
DF_1_NODIRECT = 0x00020000 # Object has no-direct binding.
|
136
|
-
DF_1_IGNMULDEF = 0x00040000 # :nodoc:
|
137
|
-
DF_1_NOKSYMS = 0x00080000 # :nodoc:
|
138
|
-
DF_1_NOHDR = 0x00100000 # :nodoc:
|
139
|
-
DF_1_EDITED = 0x00200000 # Object is modified after built.
|
140
|
-
DF_1_NORELOC = 0x00400000 # :nodoc:
|
141
|
-
DF_1_SYMINTPOSE = 0x00800000 # Object has individual interposers.
|
142
|
-
DF_1_GLOBAUDIT = 0x01000000 # Global auditing required.
|
143
|
-
DF_1_SINGLETON = 0x02000000 # Singleton symbols are used.
|
144
|
-
end
|
145
|
-
include DF
|
146
|
-
|
147
106
|
# These constants define the various ELF target machines.
|
148
107
|
module EM
|
149
108
|
EM_NONE = 0 # none
|
@@ -253,5 +212,109 @@ module ELFTools
|
|
253
212
|
end
|
254
213
|
end
|
255
214
|
include ET
|
215
|
+
|
216
|
+
# Program header permission flags, records bitwise OR value in +p_flags+.
|
217
|
+
module PF
|
218
|
+
PF_X = 1
|
219
|
+
PF_W = 2
|
220
|
+
PF_R = 4
|
221
|
+
end
|
222
|
+
include PF
|
223
|
+
|
224
|
+
# Program header types, records in +p_type+.
|
225
|
+
module PT
|
226
|
+
PT_NULL = 0 # null segment
|
227
|
+
PT_LOAD = 1 # segment to be load
|
228
|
+
PT_DYNAMIC = 2 # dynamic tags
|
229
|
+
PT_INTERP = 3 # interpreter, same as .interp section
|
230
|
+
PT_NOTE = 4 # same as .note* section
|
231
|
+
PT_SHLIB = 5 # reserved
|
232
|
+
PT_PHDR = 6 # where program header starts
|
233
|
+
PT_TLS = 7 # thread local storage segment
|
234
|
+
PT_LOOS = 0x60000000 # OS-specific
|
235
|
+
PT_HIOS = 0x6fffffff # OS-specific
|
236
|
+
# Values between {PT_LOPROC} and {PT_HIPROC} are reserved for processor-specific semantics.
|
237
|
+
PT_LOPROC = 0x70000000
|
238
|
+
PT_HIPROC = 0x7fffffff # see {PT_LOPROC}
|
239
|
+
PT_GNU_EH_FRAME = 0x6474e550 # for exception handler
|
240
|
+
PT_GNU_STACK = 0x6474e551 # permission of stack
|
241
|
+
PT_GNU_RELRO = 0x6474e552 # read only after relocation
|
242
|
+
end
|
243
|
+
include PT
|
244
|
+
|
245
|
+
# Special indices to section. These are used when there is no valid index to section header.
|
246
|
+
# The meaning of these values is left upto the embedding header.
|
247
|
+
module SHN
|
248
|
+
SHN_UNDEF = 0 # undefined section
|
249
|
+
SHN_LORESERVE = 0xff00 # start of reserved indices
|
250
|
+
end
|
251
|
+
include SHN
|
252
|
+
|
253
|
+
# Section header types, records in +sh_type+.
|
254
|
+
module SHT
|
255
|
+
SHT_NULL = 0 # null section
|
256
|
+
SHT_PROGBITS = 1 # information defined by program itself
|
257
|
+
SHT_SYMTAB = 2 # symbol table section
|
258
|
+
SHT_STRTAB = 3 # string table section
|
259
|
+
SHT_RELA = 4 # relocation with addends
|
260
|
+
SHT_HASH = 5 # symbol hash table
|
261
|
+
SHT_DYNAMIC = 6 # information of dynamic linking
|
262
|
+
SHT_NOTE = 7 # note section
|
263
|
+
SHT_NOBITS = 8 # section occupies no space
|
264
|
+
SHT_REL = 9 # relocation
|
265
|
+
SHT_SHLIB = 10 # reserved
|
266
|
+
SHT_DYNSYM = 11 # symbols for dynamic
|
267
|
+
# Values between {SHT_LOPROC} and {SHT_HIPROC} are reserved for processor-specific semantics.
|
268
|
+
SHT_LOPROC = 0x70000000
|
269
|
+
SHT_HIPROC = 0x7fffffff # see {SHT_LOPROC}
|
270
|
+
# Values between {SHT_LOUSER} and {SHT_HIUSER} are reserved for application programs.
|
271
|
+
SHT_LOUSER = 0x80000000
|
272
|
+
SHT_HIUSER = 0xffffffff # see {SHT_LOUSER}
|
273
|
+
end
|
274
|
+
include SHT
|
275
|
+
|
276
|
+
# Symbol binding from Sym st_info field.
|
277
|
+
module STB
|
278
|
+
STB_LOCAL = 0 # Local symbol
|
279
|
+
STB_GLOBAL = 1 # Global symbol
|
280
|
+
STB_WEAK = 2 # Weak symbol
|
281
|
+
STB_NUM = 3 # Number of defined types.
|
282
|
+
STB_LOOS = 10 # Start of OS-specific
|
283
|
+
STB_GNU_UNIQUE = 10 # Unique symbol.
|
284
|
+
STB_HIOS = 12 # End of OS-specific
|
285
|
+
STB_LOPROC = 13 # Start of processor-specific
|
286
|
+
STB_HIPROC = 15 # End of processor-specific
|
287
|
+
end
|
288
|
+
include STB
|
289
|
+
|
290
|
+
# Symbol types from Sym st_info field.
|
291
|
+
module STT
|
292
|
+
STT_NOTYPE = 0 # Symbol type is unspecified
|
293
|
+
STT_OBJECT = 1 # Symbol is a data object
|
294
|
+
STT_FUNC = 2 # Symbol is a code object
|
295
|
+
STT_SECTION = 3 # Symbol associated with a section
|
296
|
+
STT_FILE = 4 # Symbol's name is file name
|
297
|
+
STT_COMMON = 5 # Symbol is a common data object
|
298
|
+
STT_TLS = 6 # Symbol is thread-local data object
|
299
|
+
STT_NUM = 7 # Number of defined types.
|
300
|
+
|
301
|
+
# GNU extension: symbol value points to a function which is called
|
302
|
+
# at runtime to determine the final value of the symbol.
|
303
|
+
STT_GNU_IFUNC = 10
|
304
|
+
|
305
|
+
STT_LOOS = 10 # Start of OS-specific
|
306
|
+
STT_HIOS = 12 # End of OS-specific
|
307
|
+
STT_LOPROC = 13 # Start of processor-specific
|
308
|
+
STT_HIPROC = 15 # End of processor-specific
|
309
|
+
|
310
|
+
# The section type that must be used for register symbols on
|
311
|
+
# Sparc. These symbols initialize a global register.
|
312
|
+
STT_SPARC_REGISTER = 13
|
313
|
+
|
314
|
+
# ARM: a THUMB function. This is not defined in ARM ELF Specification but
|
315
|
+
# used by the GNU tool-chain.
|
316
|
+
STT_ARM_TFUNC = 13
|
317
|
+
end
|
318
|
+
include STT
|
256
319
|
end
|
257
320
|
end
|
data/lib/elftools/dynamic.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ELFTools
|
2
4
|
# Define common methods for dynamic sections and dynamic segments.
|
3
5
|
#
|
@@ -18,6 +20,7 @@ module ELFTools
|
|
18
20
|
# Otherwise, return array of tags.
|
19
21
|
def each_tags(&block)
|
20
22
|
return enum_for(:each_tags) unless block_given?
|
23
|
+
|
21
24
|
arr = []
|
22
25
|
0.step do |i|
|
23
26
|
tag = tag_at(i).tap(&block)
|
@@ -31,7 +34,7 @@ module ELFTools
|
|
31
34
|
# @return [Array<ELFTools::Dynamic::Tag>]
|
32
35
|
# Array of tags.
|
33
36
|
def tags
|
34
|
-
each_tags.to_a
|
37
|
+
@tags ||= each_tags.to_a
|
35
38
|
end
|
36
39
|
|
37
40
|
# Get a tag of specific type.
|
@@ -63,6 +66,18 @@ module ELFTools
|
|
63
66
|
each_tags.find { |tag| tag.header.d_tag == type }
|
64
67
|
end
|
65
68
|
|
69
|
+
# Get tags of specific type.
|
70
|
+
# @param [Integer, Symbol, String] type
|
71
|
+
# Constant value, symbol, or string of type
|
72
|
+
# is acceptable. See examples for more information.
|
73
|
+
# @return [Array<ELFTools::Dynamic::Tag>] The desired tags.
|
74
|
+
#
|
75
|
+
# @see #tag_by_type
|
76
|
+
def tags_by_type(type)
|
77
|
+
type = Util.to_constant(Constants::DT, type)
|
78
|
+
each_tags.select { |tag| tag.header.d_tag == type }
|
79
|
+
end
|
80
|
+
|
66
81
|
# Get the +n+-th tag.
|
67
82
|
#
|
68
83
|
# Tags are lazy loaded.
|
@@ -76,9 +91,11 @@ module ELFTools
|
|
76
91
|
# @param [Integer] n The index.
|
77
92
|
# @return [ELFTools::Dynamic::Tag] The desired tag.
|
78
93
|
def tag_at(n)
|
79
|
-
return if n
|
94
|
+
return if n.negative?
|
95
|
+
|
80
96
|
@tag_at_map ||= {}
|
81
97
|
return @tag_at_map[n] if @tag_at_map[n]
|
98
|
+
|
82
99
|
dyn = Structs::ELF_Dyn.new(endian: endian)
|
83
100
|
dyn.elf_class = header.elf_class
|
84
101
|
stream.pos = tag_start + n * dyn.num_bytes
|
@@ -153,6 +170,7 @@ module ELFTools
|
|
153
170
|
# @return [String, nil] The name.
|
154
171
|
def name
|
155
172
|
return nil unless name?
|
173
|
+
|
156
174
|
Util.cstring(stream, @str_offset.call + header.d_val.to_i)
|
157
175
|
end
|
158
176
|
end
|
data/lib/elftools/elf_file.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'elftools/constants'
|
2
4
|
require 'elftools/exceptions'
|
3
5
|
require 'elftools/lazy_array'
|
@@ -32,6 +34,7 @@ module ELFTools
|
|
32
34
|
# @return [ELFTools::Structs::ELF_Ehdr] The header.
|
33
35
|
def header
|
34
36
|
return @header if defined?(@header)
|
37
|
+
|
35
38
|
stream.pos = 0
|
36
39
|
@header = Structs::ELF_Ehdr.new(endian: endian, offset: stream.pos)
|
37
40
|
@header.elf_class = elf_class
|
@@ -49,9 +52,11 @@ module ELFTools
|
|
49
52
|
def build_id
|
50
53
|
section = section_by_name('.note.gnu.build-id')
|
51
54
|
return nil if section.nil?
|
55
|
+
|
52
56
|
note = section.notes.first
|
53
57
|
return nil if note.nil?
|
54
|
-
|
58
|
+
|
59
|
+
note.desc.unpack1('H*')
|
55
60
|
end
|
56
61
|
|
57
62
|
# Get machine architecture.
|
@@ -116,6 +121,7 @@ module ELFTools
|
|
116
121
|
# otherwise, the whole sections will be returned.
|
117
122
|
def each_sections(&block)
|
118
123
|
return enum_for(:each_sections) unless block_given?
|
124
|
+
|
119
125
|
Array.new(num_sections) do |i|
|
120
126
|
section_at(i).tap(&block)
|
121
127
|
end
|
@@ -188,6 +194,7 @@ module ELFTools
|
|
188
194
|
# Whole segments will be returned.
|
189
195
|
def each_segments(&block)
|
190
196
|
return enum_for(:each_segments) unless block_given?
|
197
|
+
|
191
198
|
Array.new(num_segments) do |i|
|
192
199
|
segment_at(i).tap(&block)
|
193
200
|
end
|
@@ -277,18 +284,15 @@ module ELFTools
|
|
277
284
|
#
|
278
285
|
# This method should work no matter ELF is a PIE or not.
|
279
286
|
# This method refers from (actually equals to) binutils/readelf.c#offset_from_vma.
|
280
|
-
# @param [Integer] vma The address
|
281
|
-
# @return [Integer]
|
287
|
+
# @param [Integer] vma The virtual address to be queried.
|
288
|
+
# @return [Integer] Related file offset.
|
282
289
|
# @example
|
283
290
|
# elf = ELFTools::ELFFile.new(File.open('/bin/cat'))
|
284
291
|
# elf.offset_from_vma(0x401337)
|
285
292
|
# #=> 4919 # 0x1337
|
286
293
|
def offset_from_vma(vma, size = 0)
|
287
294
|
segments_by_type(:load) do |seg|
|
288
|
-
|
289
|
-
vma + size <= seg.header.p_vaddr + seg.header.p_filesz
|
290
|
-
return vma - seg.header.p_vaddr + seg.header.p_offset
|
291
|
-
end
|
295
|
+
return seg.vma_to_offset(vma) if seg.vma_in?(vma, size)
|
292
296
|
end
|
293
297
|
end
|
294
298
|
|
@@ -324,6 +328,7 @@ module ELFTools
|
|
324
328
|
explore = lambda do |obj|
|
325
329
|
return obj if obj.is_a?(::ELFTools::Structs::ELFStruct)
|
326
330
|
return obj.map(&explore) if obj.is_a?(Array)
|
331
|
+
|
327
332
|
obj.instance_variables.map do |s|
|
328
333
|
explore.call(obj.instance_variable_get(s))
|
329
334
|
end
|
@@ -334,19 +339,21 @@ module ELFTools
|
|
334
339
|
def identify
|
335
340
|
stream.pos = 0
|
336
341
|
magic = stream.read(4)
|
337
|
-
raise
|
342
|
+
raise ELFMagicError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG
|
343
|
+
|
338
344
|
ei_class = stream.read(1).ord
|
339
345
|
@elf_class = {
|
340
346
|
1 => 32,
|
341
347
|
2 => 64
|
342
348
|
}[ei_class]
|
343
|
-
raise
|
349
|
+
raise ELFClassError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil?
|
350
|
+
|
344
351
|
ei_data = stream.read(1).ord
|
345
352
|
@endian = {
|
346
353
|
1 => :little,
|
347
354
|
2 => :big
|
348
355
|
}[ei_data]
|
349
|
-
raise
|
356
|
+
raise ELFDataError, format('Invalid EI_DATA "\x%02x"', ei_data) if endian.nil?
|
350
357
|
end
|
351
358
|
|
352
359
|
def create_section(n)
|
data/lib/elftools/exceptions.rb
CHANGED
@@ -1,4 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ELFTools
|
2
4
|
# Being raised when parsing error.
|
3
5
|
class ELFError < StandardError; end
|
6
|
+
|
7
|
+
# Raised on invalid ELF magic.
|
8
|
+
class ELFMagicError < ELFError; end
|
9
|
+
|
10
|
+
# Raised on invalid ELF class (EI_CLASS).
|
11
|
+
class ELFClassError < ELFError; end
|
12
|
+
|
13
|
+
# Raised on invalid ELF data encoding (EI_DATA).
|
14
|
+
class ELFDataError < ELFError; end
|
4
15
|
end
|
data/lib/elftools/lazy_array.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ELFTools
|
2
4
|
# A helper class for {ELFTools} easy to implement
|
3
5
|
# 'lazy loading' objects.
|
@@ -37,7 +39,8 @@ module ELFTools
|
|
37
39
|
# return type of block given in {#initialize}.
|
38
40
|
def [](i)
|
39
41
|
# XXX: support negative index?
|
40
|
-
return nil
|
42
|
+
return nil unless i.between?(0, @internal.size - 1)
|
43
|
+
|
41
44
|
@internal[i] ||= @block.call(i)
|
42
45
|
end
|
43
46
|
end
|
data/lib/elftools/note.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'elftools/structs'
|
2
4
|
require 'elftools/util'
|
3
5
|
|
@@ -41,6 +43,7 @@ module ELFTools
|
|
41
43
|
# Otherwise, return the array of notes.
|
42
44
|
def each_notes
|
43
45
|
return enum_for(:each_notes) unless block_given?
|
46
|
+
|
44
47
|
@notes_offset_map ||= {}
|
45
48
|
cur = note_start
|
46
49
|
notes = []
|
@@ -100,7 +103,8 @@ module ELFTools
|
|
100
103
|
# Name of this note.
|
101
104
|
# @return [String] The name.
|
102
105
|
def name
|
103
|
-
return @name if @name
|
106
|
+
return @name if defined?(@name)
|
107
|
+
|
104
108
|
stream.pos = @offset + SIZE_OF_NHDR
|
105
109
|
@name = stream.read(header.n_namesz)[0..-2]
|
106
110
|
end
|
@@ -108,7 +112,8 @@ module ELFTools
|
|
108
112
|
# Description of this note.
|
109
113
|
# @return [String] The description.
|
110
114
|
def desc
|
111
|
-
return @desc if
|
115
|
+
return @desc if instance_variable_defined?(:@desc)
|
116
|
+
|
112
117
|
stream.pos = @offset + SIZE_OF_NHDR + Util.align(header.n_namesz, 2)
|
113
118
|
@desc = stream.read(header.n_descsz)
|
114
119
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'elftools/constants'
|
2
4
|
require 'elftools/sections/section'
|
3
5
|
require 'elftools/structs'
|
@@ -42,6 +44,7 @@ module ELFTools
|
|
42
44
|
# Otherwise, the whole relocations will be returned.
|
43
45
|
def each_relocations(&block)
|
44
46
|
return enum_for(:each_relocations) unless block_given?
|
47
|
+
|
45
48
|
Array.new(num_relocations) do |i|
|
46
49
|
relocation_at(i).tap(&block)
|
47
50
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Require this file to load all sections classes.
|
2
4
|
|
3
5
|
require 'elftools/sections/section'
|
@@ -19,7 +21,7 @@ module ELFTools
|
|
19
21
|
# @param [#pos=, #read] stream Streaming object.
|
20
22
|
# @return [ELFTools::Sections::Section]
|
21
23
|
# Return object dependes on +header.sh_type+.
|
22
|
-
def create(header, stream, *args)
|
24
|
+
def create(header, stream, *args, **kwargs)
|
23
25
|
klass = case header.sh_type
|
24
26
|
when Constants::SHT_DYNAMIC then DynamicSection
|
25
27
|
when Constants::SHT_NULL then NullSection
|
@@ -29,7 +31,7 @@ module ELFTools
|
|
29
31
|
when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection
|
30
32
|
else Section
|
31
33
|
end
|
32
|
-
klass.new(header, stream, *args)
|
34
|
+
klass.new(header, stream, *args, **kwargs)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'elftools/sections/section'
|
2
4
|
|
3
5
|
module ELFTools
|
@@ -56,6 +58,7 @@ module ELFTools
|
|
56
58
|
# Otherwise return array of symbols.
|
57
59
|
def each_symbols(&block)
|
58
60
|
return enum_for(:each_symbols) unless block_given?
|
61
|
+
|
59
62
|
Array.new(num_symbols) do |i|
|
60
63
|
symbol_at(i).tap(&block)
|
61
64
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'elftools/segments/segment'
|
4
|
+
|
5
|
+
module ELFTools
|
6
|
+
module Segments
|
7
|
+
# For DT_LOAD segment.
|
8
|
+
# Able to query between file offset and virtual memory address.
|
9
|
+
class LoadSegment < Segment
|
10
|
+
# Returns the start of this segment.
|
11
|
+
# @return [Integer]
|
12
|
+
# The file offset.
|
13
|
+
def file_head
|
14
|
+
header.p_offset.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns size in file.
|
18
|
+
# @return [Integer]
|
19
|
+
# The size.
|
20
|
+
def size
|
21
|
+
header.p_filesz.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the end of this segment.
|
25
|
+
# @return [Integer]
|
26
|
+
# The file offset.
|
27
|
+
def file_tail
|
28
|
+
file_head + size
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the start virtual address of this segment.
|
32
|
+
# @return [Integer]
|
33
|
+
# The vma.
|
34
|
+
def mem_head
|
35
|
+
header.p_vaddr.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns size in memory.
|
39
|
+
# @return [Integer]
|
40
|
+
# The size.
|
41
|
+
def mem_size
|
42
|
+
header.p_memsz.to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the end virtual address of this segment.
|
46
|
+
# @return [Integer]
|
47
|
+
# The vma.
|
48
|
+
def mem_tail
|
49
|
+
mem_head + mem_size
|
50
|
+
end
|
51
|
+
|
52
|
+
# Query if the given file offset located in this segment.
|
53
|
+
# @param [Integer] offset
|
54
|
+
# File offset.
|
55
|
+
# @param [Integer] size
|
56
|
+
# Size.
|
57
|
+
# @return [Boolean]
|
58
|
+
def offset_in?(offset, size = 0)
|
59
|
+
file_head <= offset && offset + size < file_tail
|
60
|
+
end
|
61
|
+
|
62
|
+
# Convert file offset into virtual memory address.
|
63
|
+
# @param [Integer] offset
|
64
|
+
# File offset.
|
65
|
+
# @return [Integer]
|
66
|
+
def offset_to_vma(offset)
|
67
|
+
# XXX: What if file_head is not aligned with p_vaddr (which is invalid according to ELF spec)?
|
68
|
+
offset - file_head + header.p_vaddr
|
69
|
+
end
|
70
|
+
|
71
|
+
# Query if the given virtual memory address located in this segment.
|
72
|
+
# @param [Integer] vma
|
73
|
+
# Virtual memory address.
|
74
|
+
# @param [Integer] size
|
75
|
+
# Size.
|
76
|
+
# @return [Boolean]
|
77
|
+
def vma_in?(vma, size = 0)
|
78
|
+
vma >= (header.p_vaddr & -header.p_align) &&
|
79
|
+
vma + size <= mem_tail
|
80
|
+
end
|
81
|
+
|
82
|
+
# Convert virtual memory address into file offset.
|
83
|
+
# @param [Integer] vma
|
84
|
+
# Virtual memory address.
|
85
|
+
# @return [Integer]
|
86
|
+
def vma_to_offset(vma)
|
87
|
+
vma - header.p_vaddr + header.p_offset
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Require this file to load all segment classes.
|
2
4
|
|
3
5
|
require 'elftools/segments/segment'
|
4
6
|
|
5
7
|
require 'elftools/segments/dynamic_segment'
|
6
8
|
require 'elftools/segments/interp_segment'
|
9
|
+
require 'elftools/segments/load_segment'
|
7
10
|
require 'elftools/segments/note_segment'
|
8
11
|
|
9
12
|
module ELFTools
|
@@ -16,14 +19,15 @@ module ELFTools
|
|
16
19
|
# @param [#pos=, #read] stream Streaming object.
|
17
20
|
# @return [ELFTools::Segments::Segment]
|
18
21
|
# Return object dependes on +header.p_type+.
|
19
|
-
def create(header, stream, *args)
|
22
|
+
def create(header, stream, *args, **kwargs)
|
20
23
|
klass = case header.p_type
|
21
24
|
when Constants::PT_DYNAMIC then DynamicSegment
|
22
25
|
when Constants::PT_INTERP then InterpSegment
|
26
|
+
when Constants::PT_LOAD then LoadSegment
|
23
27
|
when Constants::PT_NOTE then NoteSegment
|
24
28
|
else Segment
|
25
29
|
end
|
26
|
-
klass.new(header, stream, *args)
|
30
|
+
klass.new(header, stream, *args, **kwargs)
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
data/lib/elftools/structs.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bindata'
|
4
|
+
|
2
5
|
module ELFTools
|
3
6
|
# Define ELF related structures in this module.
|
4
7
|
#
|
5
8
|
# Structures are fetched from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h.
|
6
|
-
#
|
7
|
-
# little/big endian simultaneously.
|
9
|
+
# Use gem +bindata+ to have these structures support 32/64 bits and little/big endian simultaneously.
|
8
10
|
module Structs
|
9
11
|
# The base structure to define common methods.
|
10
12
|
class ELFStruct < BinData::Record
|
@@ -23,9 +25,13 @@ module ELFTools
|
|
23
25
|
end
|
24
26
|
|
25
27
|
class << self
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
28
|
+
# Hooks the constructor.
|
29
|
+
#
|
30
|
+
# +BinData::Record+ doesn't allow us to override +#initialize+, so we hack +new+ here.
|
31
|
+
def new(*args)
|
32
|
+
# XXX: The better implementation is +new(*args, **kwargs)+, but we can't do this unless bindata changed
|
33
|
+
# lib/bindata/dsl.rb#override_new_in_class to invoke +new+ with both +args+ and +kwargs+.
|
34
|
+
kwargs = args.last.is_a?(Hash) ? args.last : {}
|
29
35
|
offset = kwargs.delete(:offset)
|
30
36
|
super.tap do |obj|
|
31
37
|
obj.offset = offset
|
@@ -42,18 +48,19 @@ module ELFTools
|
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
45
|
-
#
|
46
|
-
# @return [
|
51
|
+
# Gets the endianness of current class.
|
52
|
+
# @return [:little, :big] The endianness.
|
47
53
|
def self_endian
|
48
54
|
bindata_name[-2..-1] == 'be' ? :big : :little
|
49
55
|
end
|
50
56
|
|
51
|
-
#
|
57
|
+
# Packs an integer to string.
|
52
58
|
# @param [Integer] val
|
53
59
|
# @param [Integer] bytes
|
54
60
|
# @return [String]
|
55
61
|
def pack(val, bytes)
|
56
62
|
raise ArgumentError, "Not supported assign type #{val.class}" unless val.is_a?(Integer)
|
63
|
+
|
57
64
|
number = val & ((1 << (8 * bytes)) - 1)
|
58
65
|
out = []
|
59
66
|
bytes.times do
|
@@ -109,7 +116,7 @@ module ELFTools
|
|
109
116
|
choice :sh_entsize, **CHOICE_SIZE_T
|
110
117
|
end
|
111
118
|
|
112
|
-
# Program header structure for
|
119
|
+
# Program header structure for 32-bit.
|
113
120
|
class ELF32_Phdr < ELFStruct
|
114
121
|
endian :big_and_little
|
115
122
|
uint32 :p_type
|
@@ -122,7 +129,7 @@ module ELFTools
|
|
122
129
|
uint32 :p_align
|
123
130
|
end
|
124
131
|
|
125
|
-
# Program header structure for
|
132
|
+
# Program header structure for 64-bit.
|
126
133
|
class ELF64_Phdr < ELFStruct
|
127
134
|
endian :big_and_little
|
128
135
|
uint32 :p_type
|
@@ -134,13 +141,14 @@ module ELFTools
|
|
134
141
|
uint64 :p_memsz
|
135
142
|
uint64 :p_align
|
136
143
|
end
|
137
|
-
|
144
|
+
|
145
|
+
# Gets the class of program header according to bits.
|
138
146
|
ELF_Phdr = {
|
139
147
|
32 => ELF32_Phdr,
|
140
148
|
64 => ELF64_Phdr
|
141
149
|
}.freeze
|
142
150
|
|
143
|
-
# Symbol structure for
|
151
|
+
# Symbol structure for 32-bit.
|
144
152
|
class ELF32_sym < ELFStruct
|
145
153
|
endian :big_and_little
|
146
154
|
uint32 :st_name
|
@@ -151,7 +159,7 @@ module ELFTools
|
|
151
159
|
uint16 :st_shndx
|
152
160
|
end
|
153
161
|
|
154
|
-
# Symbol structure for
|
162
|
+
# Symbol structure for 64-bit.
|
155
163
|
class ELF64_sym < ELFStruct
|
156
164
|
endian :big_and_little
|
157
165
|
uint32 :st_name # Symbol name, index in string tbl
|
@@ -161,6 +169,7 @@ module ELFTools
|
|
161
169
|
uint64 :st_value # Value of the symbol
|
162
170
|
uint64 :st_size # Associated symbol size
|
163
171
|
end
|
172
|
+
|
164
173
|
# Get symbol header class according to bits.
|
165
174
|
ELF_sym = {
|
166
175
|
32 => ELF32_sym,
|
data/lib/elftools/util.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ELFTools
|
2
4
|
# Define some util methods.
|
3
5
|
module Util
|
@@ -17,6 +19,7 @@ module ELFTools
|
|
17
19
|
def align(num, bit)
|
18
20
|
n = 2**bit
|
19
21
|
return num if (num % n).zero?
|
22
|
+
|
20
23
|
(num + n) & ~(n - 1)
|
21
24
|
end
|
22
25
|
|
@@ -36,6 +39,7 @@ module ELFTools
|
|
36
39
|
# if val is an integer, check if exists in mod
|
37
40
|
if val.is_a?(Integer)
|
38
41
|
return val if mod.constants.any? { |c| mod.const_get(c) == val }
|
42
|
+
|
39
43
|
raise ArgumentError, "No constants in #{module_name} is #{val}"
|
40
44
|
end
|
41
45
|
val = val.to_s.upcase
|
@@ -43,6 +47,7 @@ module ELFTools
|
|
43
47
|
val = prefix + '_' + val unless val.start_with?(prefix)
|
44
48
|
val = val.to_sym
|
45
49
|
raise ArgumentError, "No constants in #{module_name} named \"#{val}\"" unless mod.const_defined?(val)
|
50
|
+
|
46
51
|
mod.const_get(val)
|
47
52
|
end
|
48
53
|
|
@@ -61,6 +66,7 @@ module ELFTools
|
|
61
66
|
c = stream.read(1)
|
62
67
|
return nil if c.nil? # reach EOF
|
63
68
|
break if c == "\x00"
|
69
|
+
|
64
70
|
ret += c
|
65
71
|
end
|
66
72
|
ret
|
data/lib/elftools/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elftools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- david942j
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bindata
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: codeclimate-test-reporter
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0.6'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0.6'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: pry
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,56 +44,56 @@ dependencies:
|
|
58
44
|
requirements:
|
59
45
|
- - "~>"
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
47
|
+
version: '13.0'
|
62
48
|
type: :development
|
63
49
|
prerelease: false
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
65
51
|
requirements:
|
66
52
|
- - "~>"
|
67
53
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
54
|
+
version: '13.0'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: rspec
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
59
|
- - "~>"
|
74
60
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
61
|
+
version: '3.7'
|
76
62
|
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
66
|
- - "~>"
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version: '3.
|
68
|
+
version: '3.7'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: rubocop
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - "~>"
|
88
74
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0.
|
75
|
+
version: '0.59'
|
90
76
|
type: :development
|
91
77
|
prerelease: false
|
92
78
|
version_requirements: !ruby/object:Gem::Requirement
|
93
79
|
requirements:
|
94
80
|
- - "~>"
|
95
81
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0.
|
82
|
+
version: '0.59'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: simplecov
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
87
|
- - "~>"
|
102
88
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
89
|
+
version: '0.17'
|
104
90
|
type: :development
|
105
91
|
prerelease: false
|
106
92
|
version_requirements: !ruby/object:Gem::Requirement
|
107
93
|
requirements:
|
108
94
|
- - "~>"
|
109
95
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
96
|
+
version: '0.17'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
98
|
name: yard
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,6 +135,7 @@ files:
|
|
149
135
|
- lib/elftools/sections/sym_tab_section.rb
|
150
136
|
- lib/elftools/segments/dynamic_segment.rb
|
151
137
|
- lib/elftools/segments/interp_segment.rb
|
138
|
+
- lib/elftools/segments/load_segment.rb
|
152
139
|
- lib/elftools/segments/note_segment.rb
|
153
140
|
- lib/elftools/segments/segment.rb
|
154
141
|
- lib/elftools/segments/segments.rb
|
@@ -167,15 +154,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
167
154
|
requirements:
|
168
155
|
- - ">="
|
169
156
|
- !ruby/object:Gem::Version
|
170
|
-
version: 2.
|
157
|
+
version: '2.3'
|
171
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
159
|
requirements:
|
173
160
|
- - ">="
|
174
161
|
- !ruby/object:Gem::Version
|
175
162
|
version: '0'
|
176
163
|
requirements: []
|
177
|
-
|
178
|
-
rubygems_version: 2.5.2
|
164
|
+
rubygems_version: 3.1.2
|
179
165
|
signing_key:
|
180
166
|
specification_version: 4
|
181
167
|
summary: ELFTools - Pure ruby library for parsing and patching ELF files
|