ruby-elf 1.0.3 → 1.0.4
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.
- data/bin/cowstats +217 -215
- data/bin/elfgrep +165 -144
- data/bin/missingstatic +74 -73
- data/bin/rbelf-read +111 -0
- data/bin/rbelf-size +144 -107
- data/bin/verify-lfs +92 -87
- data/lib/elf.rb +1 -1
- data/lib/elf/dynamic.rb +1 -1
- data/lib/elf/file.rb +30 -3
- data/lib/elf/gnu.rb +3 -3
- data/lib/elf/section.rb +85 -40
- data/lib/elf/symbol.rb +19 -13
- data/lib/elf/symboltable.rb +1 -1
- data/lib/elf/tools.rb +198 -164
- data/manpages/cowstats.1 +1 -4
- data/manpages/elfgrep.1 +10 -9
- data/manpages/elfgrep.1.xml +9 -7
- data/manpages/missingstatic.1 +1 -4
- data/manpages/rbelf-size.1 +13 -15
- data/manpages/rbelf-size.1.xml +25 -14
- data/manpages/verify-lfs.1 +1 -4
- data/tools/link-collisions/harvest.rb +262 -297
- data/tools/link-collisions/multimplementations +17 -3
- data/tools/link-collisions/suppressions +30 -26
- metadata +6 -6
- data/tools/link-collisions/analyse.rb +0 -57
- data/tools/readelf-d.rb +0 -79
data/bin/cowstats
CHANGED
@@ -20,245 +20,247 @@
|
|
20
20
|
|
21
21
|
require 'elf/tools'
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
["--statistics", "-s", GetoptLong::NO_ARGUMENT],
|
26
|
-
# Show the total size of COW pages
|
27
|
-
["--total", "-t", GetoptLong::NO_ARGUMENT],
|
28
|
-
# Ignore C++ "false positives" (vtables and typeinfo)
|
29
|
-
["--ignore-cxx", "-x", GetoptLong::NO_ARGUMENT ],
|
30
|
-
# Ignore Profiling false positives
|
31
|
-
["--ignore-profiling", "-p", GetoptLong::NO_ARGUMENT ],
|
32
|
-
# Ignore .data.rel.ro relocated constants
|
33
|
-
["--ignore-data-rel-ro", "-r", GetoptLong::NO_ARGUMENT ],
|
34
|
-
# Decide sorting column
|
35
|
-
["--sort-by", "-S", GetoptLong::REQUIRED_ARGUMENT ]
|
36
|
-
]
|
23
|
+
module Elf::Tools
|
24
|
+
class CoWStats < Elf::Tool
|
37
25
|
|
38
|
-
def self.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
26
|
+
def self.initialize
|
27
|
+
super
|
28
|
+
@options |= [
|
29
|
+
# Only show statistics for the various files
|
30
|
+
["--statistics", "-s", GetoptLong::NO_ARGUMENT],
|
31
|
+
# Show the total size of COW pages
|
32
|
+
["--total", "-t", GetoptLong::NO_ARGUMENT],
|
33
|
+
# Ignore C++ "false positives" (vtables and typeinfo)
|
34
|
+
["--ignore-cxx", "-x", GetoptLong::NO_ARGUMENT ],
|
35
|
+
# Ignore Profiling false positives
|
36
|
+
["--ignore-profiling", "-p", GetoptLong::NO_ARGUMENT ],
|
37
|
+
# Ignore .data.rel.ro relocated constants
|
38
|
+
["--ignore-data-rel-ro", "-r", GetoptLong::NO_ARGUMENT ],
|
39
|
+
# Decide sorting column
|
40
|
+
["--sort-by", "-S", GetoptLong::REQUIRED_ARGUMENT ]
|
41
|
+
]
|
44
42
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@files_info = {}
|
51
|
-
end
|
43
|
+
@statistics = false
|
44
|
+
@total = false
|
45
|
+
@ignore_cxx = false
|
46
|
+
@ignore_profiling = false
|
47
|
+
@ignore_data_rel_ro = false
|
52
48
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
x[1][:bss_size] <=> y[1][:bss_size]
|
58
|
-
end
|
59
|
-
when '.data'
|
60
|
-
@results_sorter = Proc.new do |x, y|
|
61
|
-
x[1][:data_size] <=> y[1][:data_size]
|
62
|
-
end
|
63
|
-
when '.data.rel'
|
64
|
-
@results_sorter = Proc.new do |x, y|
|
65
|
-
x[1][:rel_size] <=> y[1][:rel_size]
|
66
|
-
end
|
67
|
-
when '.data.rel.ro'
|
68
|
-
@results_sorter = Proc.new do |x, y|
|
69
|
-
x[1][:relro_size] <=> y[1][:relro_size]
|
70
|
-
end
|
71
|
-
else
|
72
|
-
puterror "invalid sort column: #{column}"
|
73
|
-
exit -1
|
74
|
-
end
|
75
|
-
end
|
49
|
+
@results_sorter = Proc.new do |x, y|
|
50
|
+
# 0 is the filename
|
51
|
+
x[0] <=> y[0]
|
52
|
+
end
|
76
53
|
|
77
|
-
|
78
|
-
if @total
|
79
|
-
@data_total = 0
|
80
|
-
@bss_total = 0
|
81
|
-
@rel_total = 0
|
82
|
-
@relro_total = 0
|
83
|
-
end
|
84
|
-
end
|
54
|
+
@files_info = {}
|
85
55
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
bss_size = 0
|
91
|
-
rel_vars = []
|
92
|
-
rel_size = 0
|
93
|
-
relro_vars = []
|
94
|
-
relro_size = 0
|
95
|
-
|
96
|
-
Elf::File.open(file) do |elf|
|
97
|
-
if elf.type != Elf::File::Type::Rel
|
98
|
-
putnotice "#{file}: not an object file"
|
99
|
-
next
|
56
|
+
@data_total = 0
|
57
|
+
@bss_total = 0
|
58
|
+
@rel_total = 0
|
59
|
+
@relro_total = 0
|
100
60
|
end
|
101
|
-
if not elf.has_section?(".symtab")
|
102
|
-
putnotice "#{file}: no .symtab section found"
|
103
|
-
next
|
104
|
-
end
|
105
|
-
|
106
|
-
elf['.symtab'].each do |symbol|
|
107
|
-
# Ignore undefined, absolute and common symbols.
|
108
|
-
next unless symbol.section.is_a? Elf::Section
|
109
|
-
# When the symbol name is empty, it refers to the
|
110
|
-
# section itself.
|
111
|
-
next if symbol.name == ""
|
112
61
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
# Ignore non-allocated sections (all data sections are allocated)
|
131
|
-
next unless symbol.section.flags.include? Elf::Section::Flags::Alloc
|
132
|
-
|
133
|
-
# Until I can find a way to distinguish between relocated and
|
134
|
-
# non-relocated sections, still use the name to choose between
|
135
|
-
# them. If the name is not in this list, at least warn now
|
136
|
-
# about it.
|
137
|
-
#
|
138
|
-
# The “l” prefix is used by Sun's compiler for x64-specific
|
139
|
-
# sections that can hold over 2GiB of data. They don't change
|
140
|
-
# for what we're concerned.
|
141
|
-
case symbol.section.name
|
142
|
-
when /^\.l?data\.rel\.ro(\..*)?/
|
143
|
-
unless @inore_data_rel_ro
|
144
|
-
relro_vars << symbol unless @statistics
|
145
|
-
relro_size += symbol.size
|
62
|
+
def self.sort_by_cb(column)
|
63
|
+
case column
|
64
|
+
when '.bss'
|
65
|
+
@results_sorter = Proc.new do |x, y|
|
66
|
+
x[1][:bss_size] <=> y[1][:bss_size]
|
67
|
+
end
|
68
|
+
when '.data'
|
69
|
+
@results_sorter = Proc.new do |x, y|
|
70
|
+
x[1][:data_size] <=> y[1][:data_size]
|
71
|
+
end
|
72
|
+
when '.data.rel'
|
73
|
+
@results_sorter = Proc.new do |x, y|
|
74
|
+
x[1][:rel_size] <=> y[1][:rel_size]
|
75
|
+
end
|
76
|
+
when '.data.rel.ro'
|
77
|
+
@results_sorter = Proc.new do |x, y|
|
78
|
+
x[1][:relro_size] <=> y[1][:relro_size]
|
146
79
|
end
|
147
|
-
when /^\.l?data\.rel(\..*)?/, /^\.picdata/
|
148
|
-
rel_vars << symbol unless @statistics
|
149
|
-
rel_size += symbol.size
|
150
|
-
when /^\.l?t?data(\.local)?(\..*)?/
|
151
|
-
data_vars << symbol unless @statistics
|
152
|
-
data_size += symbol.size
|
153
80
|
else
|
154
|
-
puterror "
|
81
|
+
puterror "invalid sort column: #{column}"
|
82
|
+
exit -1
|
155
83
|
end
|
156
84
|
end
|
157
|
-
|
158
|
-
end
|
159
85
|
|
160
|
-
|
86
|
+
def self.analysis(file)
|
87
|
+
data_vars = []
|
88
|
+
data_size = 0
|
89
|
+
bss_vars = []
|
90
|
+
bss_size = 0
|
91
|
+
rel_vars = []
|
92
|
+
rel_size = 0
|
93
|
+
relro_vars = []
|
94
|
+
relro_size = 0
|
95
|
+
|
96
|
+
Elf::File.open(file) do |elf|
|
97
|
+
if elf.type != Elf::File::Type::Rel
|
98
|
+
putnotice "#{file}: not an object file"
|
99
|
+
next
|
100
|
+
end
|
101
|
+
if not elf.has_section?(".symtab")
|
102
|
+
putnotice "#{file}: no .symtab section found"
|
103
|
+
next
|
104
|
+
end
|
161
105
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
if @statistics
|
170
|
-
@files_info[file] = {
|
171
|
-
:data_size => data_size,
|
172
|
-
:bss_size => bss_size,
|
173
|
-
:rel_size => rel_size,
|
174
|
-
:relro_size => relro_size
|
175
|
-
}
|
176
|
-
return
|
177
|
-
end
|
106
|
+
elf['.symtab'].each do |symbol|
|
107
|
+
# Ignore undefined, absolute and common symbols.
|
108
|
+
next unless symbol.section.is_a? Elf::Section
|
109
|
+
# When the symbol name is empty, it refers to the
|
110
|
+
# section itself.
|
111
|
+
next if symbol.name == ""
|
178
112
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
113
|
+
# Ignore C++ vtables and other symbols when requested
|
114
|
+
next if @ignore_cxx and symbol.name =~ /^_ZT[VI](N[0-9]+[A-Z_].*)*[0-9]+[A-Z_].*/
|
115
|
+
# Ignore profiling symbols when requested by user
|
116
|
+
next if @ignore_profiling and symbol.name =~ /^__gcov_/
|
117
|
+
|
118
|
+
# If the section is NoBits, then it's .bss or equivalent, handle
|
119
|
+
# and skip right away.
|
120
|
+
if symbol.section.type == Elf::Section::Type::NoBits
|
121
|
+
bss_vars << symbol unless @statistics
|
122
|
+
bss_size += symbol.size
|
123
|
+
next
|
124
|
+
end
|
125
|
+
|
126
|
+
# Ignore executable code (.text, .init, .fini)
|
127
|
+
next if symbol.section.flags.include? Elf::Section::Flags::ExecInstr
|
128
|
+
# Ignore read-only sections (.rodata)
|
129
|
+
next unless symbol.section.flags.include? Elf::Section::Flags::Write
|
130
|
+
# Ignore non-allocated sections (all data sections are allocated)
|
131
|
+
next unless symbol.section.flags.include? Elf::Section::Flags::Alloc
|
132
|
+
|
133
|
+
# Until I can find a way to distinguish between relocated and
|
134
|
+
# non-relocated sections, still use the name to choose between
|
135
|
+
# them. If the name is not in this list, at least warn now
|
136
|
+
# about it.
|
137
|
+
#
|
138
|
+
# The “l” prefix is used by Sun's compiler for x64-specific
|
139
|
+
# sections that can hold over 2GiB of data. They don't change
|
140
|
+
# for what we're concerned.
|
141
|
+
case symbol.section.name
|
142
|
+
when /^\.l?data\.rel\.ro(\..*)?/
|
143
|
+
unless @inore_data_rel_ro
|
144
|
+
relro_vars << symbol unless @statistics
|
145
|
+
relro_size += symbol.size
|
146
|
+
end
|
147
|
+
when /^\.l?data\.rel(\..*)?/, /^\.picdata/
|
148
|
+
rel_vars << symbol unless @statistics
|
149
|
+
rel_size += symbol.size
|
150
|
+
when /^\.l?t?data(\.local)?(\..*)?/
|
151
|
+
data_vars << symbol unless @statistics
|
152
|
+
data_size += symbol.size
|
153
|
+
else
|
154
|
+
puterror "symbol #{symbol.name} in unknown section #{symbol.section.name}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
193
158
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
159
|
+
|
160
|
+
return unless (data_size + bss_size + rel_size + relro_size ) > 0
|
161
|
+
|
162
|
+
if @total
|
163
|
+
@data_total += data_size
|
164
|
+
@bss_total += bss_size
|
165
|
+
@rel_total += rel_size
|
166
|
+
@relro_total += relro_size
|
200
167
|
end
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
168
|
+
|
169
|
+
if @statistics
|
170
|
+
@files_info[file] = {
|
171
|
+
:data_size => data_size,
|
172
|
+
:bss_size => bss_size,
|
173
|
+
:rel_size => rel_size,
|
174
|
+
:relro_size => relro_size
|
175
|
+
}
|
176
|
+
return
|
207
177
|
end
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
178
|
+
|
179
|
+
@output_mutex.synchronize do
|
180
|
+
puts "Processing file #{file}"
|
181
|
+
|
182
|
+
if bss_vars.length > 0
|
183
|
+
puts " The following variables aren't initialised (Copy-On-Write):"
|
184
|
+
bss_vars.each do |sym|
|
185
|
+
puts " #{sym} (size: #{sym.size})"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
if data_vars.length > 0
|
190
|
+
puts " The following variables are writable (Copy-On-Write):"
|
191
|
+
data_vars.each do |sym|
|
192
|
+
puts " #{sym} (size: #{sym.size})"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
if rel_vars.length > 0
|
197
|
+
puts " The following variables need runtime relocation (Copy-On-Write):"
|
198
|
+
rel_vars.each do |sym|
|
199
|
+
puts " #{sym} (size: #{sym.size})"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
if relro_vars.length > 0
|
204
|
+
puts " The following constants need runtime relocation (Prelinkable Copy-On-Write):"
|
205
|
+
relro_vars.each do |sym|
|
206
|
+
puts " #{sym} (size: #{sym.size})"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
if @total
|
211
|
+
puts " Total non-initialised variables size: #{bss_size}" unless bss_size == 0
|
212
|
+
puts " Total writable variables size: #{data_size}" unless data_size == 0
|
213
|
+
puts " Total variables needing runtime relocation size: #{rel_size}" unless rel_size == 0
|
214
|
+
unless @ignore_data_rel_ro
|
215
|
+
puts " Total constants needing runtime relocation size: #{relro_size}" unless relro_size == 0
|
216
|
+
end
|
217
|
+
end
|
216
218
|
end
|
217
219
|
end
|
218
|
-
end
|
219
|
-
end
|
220
220
|
|
221
|
-
def self.results
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
221
|
+
def self.results
|
222
|
+
if @statistics
|
223
|
+
file_lengths = ["File name".length]
|
224
|
+
bss_lengths = [".bss size".length]
|
225
|
+
data_lengths = [".data size".length]
|
226
|
+
rel_lengths = [".data.rel size".length]
|
227
|
+
relro_lengths = [".data.rel.ro size".length] unless @no_datalrero
|
228
|
+
@files_info.each_pair do |file, info|
|
229
|
+
file_lengths << file.length
|
230
|
+
bss_lengths << info[:bss_size] .to_s.length
|
231
|
+
data_lengths << info[:data_size].to_s.length
|
232
|
+
rel_lengths << info[:rel_size] .to_s.length
|
233
|
+
relro_lengths<< info[:relro_size] .to_s.length
|
234
|
+
end
|
235
235
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
236
|
+
maxlen = file_lengths.max
|
237
|
+
max_bss_len = bss_lengths .max
|
238
|
+
max_data_len = data_lengths.max
|
239
|
+
max_rel_len = rel_lengths .max
|
240
|
+
max_relro_len= relro_lengths .max
|
241
241
|
|
242
|
-
|
243
|
-
|
242
|
+
datarelro_header = @ignore_data_rel_ro ? "" : " | #{'.data.rel.ro size'.ljust max_relro_len}"
|
243
|
+
puts "#{'File name'.ljust maxlen} | #{'.bss size'.ljust max_data_len} | #{'.data size'.ljust max_data_len} | #{'.data.rel size'.ljust max_rel_len}#{datarelro_header}"
|
244
244
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
245
|
+
(@files_info.sort &@results_sorter).each do |file, info|
|
246
|
+
datarelro_line = @ignore_data_rel_ro ? "" : " #{info[:relro_size].to_s.rjust max_relro_len}"
|
247
|
+
puts "#{file.ljust maxlen} #{info[:bss_size].to_s.rjust max_bss_len} #{info[:data_size].to_s.rjust max_data_len} #{info[:rel_size].to_s.rjust max_rel_len}#{datarelro_line}"
|
248
|
+
end
|
249
|
+
end
|
250
250
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
251
|
+
if @total
|
252
|
+
data_total_real = @data_total > 0 ? ((@data_total/4096) + (@data_total % 4096 ? 1 : 0)) * 4096 : 0
|
253
|
+
bss_total_real = @bss_total > 0 ? ((@bss_total/4096) + (@bss_total % 4096 ? 1 : 0)) * 4096 : 0
|
254
|
+
rel_total_real = @rel_total > 0 ? ((@rel_total/4096) + (@rel_total % 4096 ? 1 : 0)) * 4096 : 0
|
255
|
+
relro_total_real = @relro_total > 0 ? ((@relro_total/4096) + (@relro_total % 4096 ? 1 : 0)) * 4096 : 0
|
256
256
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
257
|
+
puts "Totals:"
|
258
|
+
puts " #{@bss_total} (#{bss_total_real} \"real\") bytes of non-initialised variables."
|
259
|
+
puts " #{@data_total} (#{data_total_real} \"real\") bytes of writable variables."
|
260
|
+
puts " #{@rel_total} (#{rel_total_real} \"real\") bytes of variables needing runtime relocation."
|
261
|
+
puts " #{@relro_total} (#{relro_total_real} \"real\") bytes of constants needing runtime relocation." unless @no_datalrero
|
262
|
+
puts " Total #{@data_total+@bss_total+@rel_total+@relro_total} (#{data_total_real+bss_total_real+rel_total_real+relro_total_real} \"real\") bytes of variables in copy-on-write sections"
|
263
|
+
end
|
264
|
+
end
|
263
265
|
end
|
264
266
|
end
|