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 CHANGED
@@ -20,245 +20,247 @@
20
20
 
21
21
  require 'elf/tools'
22
22
 
23
- Options = [
24
- # Only show statistics for the various files
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.before_options
39
- @statistics = false
40
- @total = false
41
- @ignore_cxx = false
42
- @ignore_profiling = false
43
- @ignore_data_rel_ro = false
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
- @results_sorter = Proc.new do |x, y|
46
- # 0 is the filename
47
- x[0] <=> y[0]
48
- end
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
- def self.sort_by_cb(column)
54
- case column
55
- when '.bss'
56
- @results_sorter = Proc.new do |x, y|
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
- def self.after_options
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
- 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
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
- # 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
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 "symbol #{symbol.name} in unknown section #{symbol.section.name}"
81
+ puterror "invalid sort column: #{column}"
82
+ exit -1
155
83
  end
156
84
  end
157
-
158
- end
159
85
 
160
- return unless (data_size + bss_size + rel_size + relro_size ) > 0
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
- if @total
163
- @data_total += data_size
164
- @bss_total += bss_size
165
- @rel_total += rel_size
166
- @relro_total += relro_size
167
- end
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
- @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})"
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
- 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})"
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
- 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})"
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
- 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
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
- 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
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
- 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
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
- 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}"
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
- (@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
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
- 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
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
- 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"
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