ruby-elf 1.0.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.
- data/COPYING +339 -0
- data/DONATING +42 -0
- data/bin/cowstats +264 -0
- data/bin/elfgrep +185 -0
- data/bin/missingstatic +112 -0
- data/bin/rbelf-size +123 -0
- data/bin/verify-lfs +120 -0
- data/extras/README.extras +5 -0
- data/extras/bindings-parsers.rb +157 -0
- data/lib/bytestream-reader.rb +271 -0
- data/lib/elf.rb +248 -0
- data/lib/elf/dynamic.rb +392 -0
- data/lib/elf/file.rb +366 -0
- data/lib/elf/gnu.rb +174 -0
- data/lib/elf/section.rb +321 -0
- data/lib/elf/stringtable.rb +49 -0
- data/lib/elf/sunw.rb +158 -0
- data/lib/elf/symbol.rb +368 -0
- data/lib/elf/symbol/demangler_gcc3.rb +1952 -0
- data/lib/elf/symboltable.rb +90 -0
- data/lib/elf/tools.rb +228 -0
- data/lib/elf/utils/loader.rb +112 -0
- data/lib/elf/utils/pool.rb +37 -0
- data/lib/elf/value.rb +128 -0
- data/manpages/cowstats.1 +180 -0
- data/manpages/elfgrep.1 +188 -0
- data/manpages/missingstatic.1 +176 -0
- data/manpages/rbelf-size.1 +186 -0
- data/manpages/verify-lfs.1 +95 -0
- data/tools/assess_duplicate_save.rb +105 -0
- data/tools/link-collisions/analyse.rb +57 -0
- data/tools/link-collisions/harvest.rb +367 -0
- data/tools/link-collisions/known-broken +165 -0
- data/tools/link-collisions/multimplementations +125 -0
- data/tools/link-collisions/suppress.rb +84 -0
- data/tools/link-collisions/suppressions +279 -0
- data/tools/nm.rb +78 -0
- data/tools/rbelf-lddtree.rb +49 -0
- data/tools/readelf-d.rb +76 -0
- metadata +114 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright © 2008-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; either version 2 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this generator; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
# Simple script to assess the amount of space saved by duplicate removal of
|
20
|
+
# entries in symbols' tables.
|
21
|
+
|
22
|
+
require 'elf'
|
23
|
+
|
24
|
+
file_list = nil
|
25
|
+
|
26
|
+
# If there are no arguments passed through the command line
|
27
|
+
# consider it like we're going to act on stdin.
|
28
|
+
if not file_list and ARGV.size == 0
|
29
|
+
file_list = $stdin
|
30
|
+
end
|
31
|
+
|
32
|
+
def assess_save(file)
|
33
|
+
begin
|
34
|
+
Elf::File.open(file) do |elf|
|
35
|
+
seenstr = Set.new
|
36
|
+
|
37
|
+
symsec = elf['.dynsym']
|
38
|
+
strsec = elf['.dynstr']
|
39
|
+
|
40
|
+
next unless symsec and strsec
|
41
|
+
|
42
|
+
# The NULL-entry can be aliased on the last string anyway by
|
43
|
+
# letting it point to sectionsize-1
|
44
|
+
fullsize = 0
|
45
|
+
|
46
|
+
symsec.each do |sym|
|
47
|
+
next if seenstr.include? sym.name
|
48
|
+
seenstr.add sym.name
|
49
|
+
fullsize += sym.name.length+1
|
50
|
+
end
|
51
|
+
|
52
|
+
# Dynamic executables and shared objects keep more data into the
|
53
|
+
# .dynstr than static executables, in particular they have symbols
|
54
|
+
# versions, their soname and their NEEDED sections strings.
|
55
|
+
versec = elf['.gnu.version_d']
|
56
|
+
if versec
|
57
|
+
versec.each do |veridx, ver|
|
58
|
+
ver[:names].each do |vername|
|
59
|
+
next if seenstr.include? vername
|
60
|
+
seenstr.add vername
|
61
|
+
fullsize += vername.length+1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
versec = elf['.gnu.version_r']
|
67
|
+
if versec
|
68
|
+
versec.each do |veridx, ver|
|
69
|
+
next if seenstr.include? ver[:name]
|
70
|
+
seenstr.add ver[:name]
|
71
|
+
fullsize += ver[:name].length+1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
elf['.dynamic'].each_entry do |entry|
|
76
|
+
case entry[:type]
|
77
|
+
when Elf::Dynamic::Type::Needed, Elf::Dynamic::Type::SoName,
|
78
|
+
Elf::Dynamic::Type::RPath, Elf::Dynamic::Type::RunPath
|
79
|
+
|
80
|
+
next if seenstr.include? entry[:parsed]
|
81
|
+
seenstr.add entry[:parsed]
|
82
|
+
fullsize += entry[:parsed].length+1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
puts "#{file}: current size #{strsec.size}, full size #{fullsize} difference #{fullsize-strsec.size}"
|
87
|
+
end
|
88
|
+
rescue Errno::ENOENT
|
89
|
+
$stderr.puts "assess_duplicate_save.rb: #{file}: no such file"
|
90
|
+
rescue Errno::EISDIR
|
91
|
+
$stderr.puts "assess_duplicate_save.rb: #{file}: is a directory"
|
92
|
+
rescue Elf::File::NotAnELF
|
93
|
+
$stderr.puts "assess_duplicate_save.rb: #{file}: not a valid ELF file."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if file_list
|
98
|
+
file_list.each_line do |file|
|
99
|
+
assess_save(file.rstrip)
|
100
|
+
end
|
101
|
+
else
|
102
|
+
ARGV.each do |file|
|
103
|
+
assess_save(file)
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright © 2007-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; either version 2 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this generator; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require 'getoptlong'
|
20
|
+
require 'pg'
|
21
|
+
|
22
|
+
opts = GetoptLong.new(
|
23
|
+
["--output", "-o", GetoptLong::REQUIRED_ARGUMENT],
|
24
|
+
["--postgres-username", "-U", GetoptLong::REQUIRED_ARGUMENT ],
|
25
|
+
["--postgres-password", "-P", GetoptLong::REQUIRED_ARGUMENT ],
|
26
|
+
["--postgres-hostname", "-H", GetoptLong::REQUIRED_ARGUMENT ],
|
27
|
+
["--postgres-port", "-T", GetoptLong::REQUIRED_ARGUMENT ],
|
28
|
+
["--postgres-database", "-D", GetoptLong::REQUIRED_ARGUMENT ]
|
29
|
+
)
|
30
|
+
|
31
|
+
outfile = $stdout
|
32
|
+
|
33
|
+
pg_params = {}
|
34
|
+
|
35
|
+
opts.each do |opt, arg|
|
36
|
+
case opt
|
37
|
+
when '--output'
|
38
|
+
outfile = File.new(arg, "w")
|
39
|
+
when '--postgres-username' then pg_params[:user] = arg
|
40
|
+
when '--postgres-password' then pg_params[:password] = arg
|
41
|
+
when '--postgres-hostname' then pg_params[:host] = arg
|
42
|
+
when '--postgres-port' then pg_params[:port] = arg
|
43
|
+
when '--postgres-database' then pg_params[:dbname] = arg
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
db = PGconn.open(pg_params)
|
48
|
+
|
49
|
+
db.exec("PREPARE getinstances (text, text) AS
|
50
|
+
SELECT name FROM symbols INNER JOIN objects ON symbols.object = objects.id WHERE symbol = $1 AND abi = $2 ORDER BY name")
|
51
|
+
|
52
|
+
db.exec("SELECT * FROM duplicate_symbols").each do |row|
|
53
|
+
outfile.puts "Symbol #{row['symbol']} (#{row['abi']}) present #{row['occurrences']} times"
|
54
|
+
db.exec( "EXECUTE getinstances ('#{row['symbol']}', '#{row['abi']}')" ).each do |path|
|
55
|
+
outfile.puts " #{path['name']}"
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,367 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright © 2007-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation; either version 2 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this generator; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
# This script is used to harvest the symbols defined in the shared
|
20
|
+
# objects of the whole system.
|
21
|
+
|
22
|
+
require 'getoptlong'
|
23
|
+
require 'set'
|
24
|
+
require 'pathname'
|
25
|
+
require 'pg'
|
26
|
+
|
27
|
+
require 'elf'
|
28
|
+
require 'elf/utils/loader'
|
29
|
+
|
30
|
+
opts = GetoptLong.new(
|
31
|
+
["--no-scan-ldpath", "-L", GetoptLong::NO_ARGUMENT ],
|
32
|
+
["--scan-path", "-p", GetoptLong::NO_ARGUMENT ],
|
33
|
+
["--suppressions", "-s", GetoptLong::REQUIRED_ARGUMENT ],
|
34
|
+
["--multiplementations", "-m", GetoptLong::REQUIRED_ARGUMENT ],
|
35
|
+
["--scan-directory", "-d", GetoptLong::REQUIRED_ARGUMENT ],
|
36
|
+
["--recursive-scan", "-r", GetoptLong::NO_ARGUMENT ],
|
37
|
+
["--elf-machine", "-M", GetoptLong::REQUIRED_ARGUMENT ],
|
38
|
+
["--postgres-username", "-U", GetoptLong::REQUIRED_ARGUMENT ],
|
39
|
+
["--postgres-password", "-P", GetoptLong::REQUIRED_ARGUMENT ],
|
40
|
+
["--postgres-hostname", "-H", GetoptLong::REQUIRED_ARGUMENT ],
|
41
|
+
["--postgres-port", "-T", GetoptLong::REQUIRED_ARGUMENT ],
|
42
|
+
["--postgres-database", "-D", GetoptLong::REQUIRED_ARGUMENT ]
|
43
|
+
)
|
44
|
+
|
45
|
+
suppression_files = File.exist?('suppressions') ? [ 'suppressions' ] : []
|
46
|
+
multimplementation_files = File.exist?('multimplementations') ? [ 'multimplementations' ] : []
|
47
|
+
scan_path = false
|
48
|
+
scan_ldpath = true
|
49
|
+
recursive_scan = false
|
50
|
+
scan_directories = []
|
51
|
+
$machines = []
|
52
|
+
|
53
|
+
pg_params = {}
|
54
|
+
|
55
|
+
opts.each do |opt, arg|
|
56
|
+
case opt
|
57
|
+
when '--suppressions'
|
58
|
+
unless File.exist? arg
|
59
|
+
$stderr.puts "harvest.rb: no such file or directory - #{arg}"
|
60
|
+
exit -1
|
61
|
+
end
|
62
|
+
suppression_files << arg
|
63
|
+
when "--multiplementations"
|
64
|
+
unless File.exist? arg
|
65
|
+
$stderr.puts "harvest.rb: no such file or directory - #{arg}"
|
66
|
+
exit -1
|
67
|
+
end
|
68
|
+
multimplementation_files << arg
|
69
|
+
when '--scan-path'
|
70
|
+
scan_path = true
|
71
|
+
when '--no-scan-ldpath'
|
72
|
+
scan_ldpath = false
|
73
|
+
when '--scan-directory'
|
74
|
+
scan_directories << arg
|
75
|
+
when '--recursive-scan'
|
76
|
+
recursive_scan = true
|
77
|
+
when "--elf-machine"
|
78
|
+
machine_str = arg.dup
|
79
|
+
|
80
|
+
# Remove the EM_ prefix if present
|
81
|
+
machine_str = machine_str[3..-1] if arg[0..2].upcase == "EM_"
|
82
|
+
|
83
|
+
# Remove underscores if present (we don't keep them in our
|
84
|
+
# constants)
|
85
|
+
machine_str.delete!("_")
|
86
|
+
|
87
|
+
machine_val = Elf::Machine.from_string(machine_str)
|
88
|
+
|
89
|
+
if machine_val.nil?
|
90
|
+
$stderr.puts "harvest.rb: unknown machine string - #{arg}"
|
91
|
+
else
|
92
|
+
$machines << machine_val unless machine_val.nil?
|
93
|
+
end
|
94
|
+
when '--postgres-username' then pg_params[:user] = arg
|
95
|
+
when '--postgres-password' then pg_params[:password] = arg
|
96
|
+
when '--postgres-hostname' then pg_params[:host] = arg
|
97
|
+
when '--postgres-port' then pg_params[:port] = arg
|
98
|
+
when '--postgres-database' then pg_params[:dbname] = arg
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
$machines = nil if $machines.empty?
|
103
|
+
|
104
|
+
db = PGconn.open(pg_params)
|
105
|
+
|
106
|
+
db.exec("DROP TABLE IF EXISTS symbols, multimplementations, objects CASCADE")
|
107
|
+
|
108
|
+
db.exec("CREATE TABLE objects ( id INTEGER PRIMARY KEY, name VARCHAR(4096), abi VARCHAR(255), exported BOOLEAN, UNIQUE(name, abi) )")
|
109
|
+
db.exec("CREATE TABLE multimplementations ( id INTEGER REFERENCES objects(id) ON DELETE CASCADE, path VARCHAR(4096), UNIQUE(path) )")
|
110
|
+
db.exec("CREATE TABLE symbols ( object INTEGER REFERENCES objects(id) ON DELETE CASCADE, symbol TEXT,
|
111
|
+
PRIMARY KEY(object, symbol) )")
|
112
|
+
|
113
|
+
db.exec("CREATE VIEW symbol_count AS
|
114
|
+
SELECT symbol, abi, COUNT(*) AS occurrences, BOOL_OR(objects.exported) AS exported FROM symbols INNER JOIN objects ON symbols.object = objects.id GROUP BY symbol, abi")
|
115
|
+
db.exec("CREATE VIEW duplicate_symbols AS
|
116
|
+
SELECT * FROM symbol_count WHERE occurrences > 1 AND exported = 't' ORDER BY occurrences DESC, symbol ASC")
|
117
|
+
|
118
|
+
db.exec("PREPARE newmulti (int, text) AS
|
119
|
+
INSERT INTO multimplementations (id, path) VALUES($1, $2)")
|
120
|
+
db.exec("PREPARE newobject (int, text, text, boolean) AS
|
121
|
+
INSERT INTO objects(id, name, abi, exported) VALUES($1, $2, $3, $4)")
|
122
|
+
db.exec("PREPARE newsymbol (int, text) AS
|
123
|
+
INSERT INTO symbols VALUES($1, $2)")
|
124
|
+
|
125
|
+
db.exec("PREPARE checkimplementation(text, text) AS
|
126
|
+
SELECT id FROM objects WHERE name = $1 AND abi = $2")
|
127
|
+
db.exec("PREPARE checkdupsymbol (int, text) AS
|
128
|
+
SELECT 1 FROM symbols WHERE object = $1 AND symbol = $2")
|
129
|
+
|
130
|
+
# Total suppressions are for directories to skip entirely
|
131
|
+
# Partial suppressions are the ones that apply only to a subset
|
132
|
+
# of symbols.
|
133
|
+
$total_suppressions = []
|
134
|
+
$partial_suppressions = []
|
135
|
+
|
136
|
+
suppression_files.each do |suppression|
|
137
|
+
File.open(suppression) do |file|
|
138
|
+
file.each_line do |line|
|
139
|
+
path, symbols = line.
|
140
|
+
gsub(/#\s.*/, '').
|
141
|
+
strip.
|
142
|
+
split(/\s+/, 2)
|
143
|
+
|
144
|
+
next unless path
|
145
|
+
|
146
|
+
if not symbols or symbols == ""
|
147
|
+
$total_suppressions << Regexp.new(path)
|
148
|
+
else
|
149
|
+
$partial_suppressions << [Regexp.new(path), Regexp.new(symbols)]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
multimplementations = []
|
156
|
+
|
157
|
+
multimplementation_files.each do |multimplementation|
|
158
|
+
File.open(multimplementation) do |file|
|
159
|
+
file.each_line do |line|
|
160
|
+
implementation, paths = line.
|
161
|
+
gsub(/#\s.*/, '').
|
162
|
+
strip.
|
163
|
+
split(/\s+/, 2)
|
164
|
+
|
165
|
+
next unless implementation
|
166
|
+
next unless paths
|
167
|
+
|
168
|
+
multimplementations << [ implementation, Regexp.new(paths) ]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
so_files = Set.new
|
174
|
+
|
175
|
+
# Extend Pathname with a so_files method
|
176
|
+
class Pathname
|
177
|
+
def maybe_queue
|
178
|
+
return nil if symlink?
|
179
|
+
|
180
|
+
$total_suppressions.each do |supp|
|
181
|
+
return nil if to_s =~ supp
|
182
|
+
end
|
183
|
+
|
184
|
+
elf = nil
|
185
|
+
|
186
|
+
begin
|
187
|
+
elf = Elf::File.open(self)
|
188
|
+
|
189
|
+
if ($machines.nil? or $machines.include?(elf.machine)) and
|
190
|
+
(elf.has_section?('.dynsym') and elf.has_section?('.dynstr') and
|
191
|
+
elf.has_section?('.dynamic')) and
|
192
|
+
(elf[".dynsym"].class == Elf::SymbolTable)
|
193
|
+
return to_s
|
194
|
+
else
|
195
|
+
return nil
|
196
|
+
end
|
197
|
+
# Explicitly list this so that it won't pollute the output
|
198
|
+
rescue Elf::File::NotAnELF
|
199
|
+
return nil
|
200
|
+
rescue Exception => e
|
201
|
+
$stderr.puts "harvest.rb: #{e.message} - #{self.to_s}"
|
202
|
+
ensure
|
203
|
+
elf.close unless elf.nil?
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def so_files(recursive = true)
|
208
|
+
res = Set.new
|
209
|
+
children.each do |entry|
|
210
|
+
begin
|
211
|
+
case entry.ftype
|
212
|
+
when "directory"
|
213
|
+
res.merge entry.so_files if recursive
|
214
|
+
when "file"
|
215
|
+
res << entry.maybe_queue
|
216
|
+
end
|
217
|
+
# When using C-c to stop, well, stop.
|
218
|
+
rescue Interrupt
|
219
|
+
raise
|
220
|
+
rescue Exception => e
|
221
|
+
$stderr.puts "Ignoring #{entry} (#{e.message})"
|
222
|
+
next
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
return res
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
if scan_ldpath
|
231
|
+
Elf::Utilities.system_library_path.each do |path|
|
232
|
+
begin
|
233
|
+
so_files.merge Pathname.new(path).so_files
|
234
|
+
rescue Errno::ENOENT
|
235
|
+
$stderr.puts "harvest.rb: No such file or directory - #{path}"
|
236
|
+
next
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
if scan_path and ENV['PATH']
|
242
|
+
ENV['PATH'].split(":").each do |path|
|
243
|
+
begin
|
244
|
+
so_files.merge Pathname.new(path).so_files(false)
|
245
|
+
rescue Errno::ENOENT
|
246
|
+
$stderr.puts "harvest.rb: No such file or directory - #{path}"
|
247
|
+
next
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
scan_directories.each do |path|
|
253
|
+
begin
|
254
|
+
so_files.merge Pathname.new(path).so_files(recursive_scan)
|
255
|
+
rescue Errno::ENOENT
|
256
|
+
$stderr.puts "harvest.rb: No such file or directory - #{path}"
|
257
|
+
next
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# if there are explicit files listed in the standard input, scan those
|
262
|
+
# right away.
|
263
|
+
ARGV.each do |path|
|
264
|
+
so_files << Pathname.new(path).maybe_queue
|
265
|
+
end
|
266
|
+
|
267
|
+
# finally if none of the above matched, try checking for data on the
|
268
|
+
# standard input
|
269
|
+
if ARGV.size == 0 and not scan_path and scan_directories.size == 0
|
270
|
+
$stdin.each_line do |path|
|
271
|
+
so_files << Pathname.new(path.chomp("\n")).maybe_queue
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
so_files.delete(nil)
|
276
|
+
|
277
|
+
db.exec("BEGIN TRANSACTION")
|
278
|
+
val = 0
|
279
|
+
|
280
|
+
begin
|
281
|
+
require 'progressbar'
|
282
|
+
|
283
|
+
pbar = ProgressBar.new("harvest", so_files.size)
|
284
|
+
rescue LoadError, NameError
|
285
|
+
end
|
286
|
+
|
287
|
+
so_files.each do |so|
|
288
|
+
local_suppressions = $partial_suppressions.dup.delete_if { |s| not so.to_s =~ s[0] }
|
289
|
+
|
290
|
+
begin
|
291
|
+
Elf::File.open(so) do |elf|
|
292
|
+
name = so
|
293
|
+
abi = "#{elf.elf_class} #{elf.abi} #{elf.machine.to_s.gsub("'", "\\'" )}"
|
294
|
+
|
295
|
+
impid = nil
|
296
|
+
|
297
|
+
multimplementations.each do |implementation, paths|
|
298
|
+
# Get the full matchdata because we might need to get the matches.
|
299
|
+
match = paths.match(so)
|
300
|
+
|
301
|
+
next unless match
|
302
|
+
|
303
|
+
while implementation =~ /\$([0-9]+)/ do
|
304
|
+
match_idx = $1.to_i
|
305
|
+
replacement = match[match_idx]
|
306
|
+
replacement = "" if replacement.nil?
|
307
|
+
implementation = implementation.gsub("$#{match_idx}", replacement)
|
308
|
+
end
|
309
|
+
|
310
|
+
name = implementation
|
311
|
+
db.exec("EXECUTE checkimplementation('#{implementation}', '#{abi}')").each do |row|
|
312
|
+
impid = row['id']
|
313
|
+
end
|
314
|
+
break
|
315
|
+
end
|
316
|
+
|
317
|
+
shared = (so != name) || (elf['.dynamic'].soname != nil)
|
318
|
+
|
319
|
+
unless impid
|
320
|
+
val += 1
|
321
|
+
impid = val
|
322
|
+
|
323
|
+
db.exec("EXECUTE newobject(#{impid}, '#{name}', '#{abi}', '#{shared}')")
|
324
|
+
end
|
325
|
+
|
326
|
+
db.exec("EXECUTE newmulti(#{impid}, '#{so}')") if so != name
|
327
|
+
|
328
|
+
elf['.dynsym'].each do |sym|
|
329
|
+
begin
|
330
|
+
next if sym.idx == 0 or
|
331
|
+
sym.bind != Elf::Symbol::Binding::Global or
|
332
|
+
sym.section.nil? or
|
333
|
+
sym.value == 0 or
|
334
|
+
sym.section.is_a? Integer or
|
335
|
+
sym.section.name == '.init' or
|
336
|
+
sym.section.name == '.bss'
|
337
|
+
|
338
|
+
skip = false
|
339
|
+
|
340
|
+
local_suppressions.each do |supp|
|
341
|
+
if sym.name =~ supp[1]
|
342
|
+
skip = true
|
343
|
+
break
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
next if skip or (db.exec("EXECUTE checkdupsymbol('#{impid}', '#{sym.name}@#{sym.version}')").num_tuples > 0)
|
348
|
+
|
349
|
+
db.exec("EXECUTE newsymbol('#{impid}', '#{sym.name}@#{sym.version}')")
|
350
|
+
|
351
|
+
rescue Exception
|
352
|
+
$stderr.puts "Mangling symbol #{sym.name}"
|
353
|
+
raise
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
rescue Exception
|
358
|
+
$stderr.puts "Checking #{so}"
|
359
|
+
raise
|
360
|
+
end
|
361
|
+
|
362
|
+
pbar.inc if pbar
|
363
|
+
end
|
364
|
+
|
365
|
+
db.exec("CREATE INDEX objects_name ON objects(name)")
|
366
|
+
db.exec("CREATE INDEX symbols_symbol ON symbols(symbol)")
|
367
|
+
db.exec("COMMIT")
|