ruby-elf 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/bin/elfgrep
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
3
|
+
# Copyright © 2011 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 'elf/tools'
|
20
|
+
|
21
|
+
Options = [
|
22
|
+
# Expression to match on the symbol name
|
23
|
+
["--regexp", "-e", GetoptLong::REQUIRED_ARGUMENT],
|
24
|
+
# Append the version information when matching the symbol
|
25
|
+
# name
|
26
|
+
["--match-version", "-V", GetoptLong::NO_ARGUMENT],
|
27
|
+
# Don't match undefined symbols
|
28
|
+
["--no-match-undefined", "-U", GetoptLong::NO_ARGUMENT],
|
29
|
+
# Don't match defined symbols
|
30
|
+
["--no-match-defined", "-D", GetoptLong::NO_ARGUMENT],
|
31
|
+
# Invert selection, show symbols not matching the
|
32
|
+
# expression
|
33
|
+
["--invert-match", "-v", GetoptLong::NO_ARGUMENT],
|
34
|
+
# List only files with matches
|
35
|
+
["--files-with-matches", "-l", GetoptLong::NO_ARGUMENT],
|
36
|
+
# List only files without match
|
37
|
+
["--files-without-match", "-L", GetoptLong::NO_ARGUMENT],
|
38
|
+
# Print the name of the file for each match
|
39
|
+
["--with-filename", "-H", GetoptLong::NO_ARGUMENT],
|
40
|
+
# Don't print the name of the file for each match
|
41
|
+
["--no-filename", "-h", GetoptLong::NO_ARGUMENT],
|
42
|
+
# Only output matches' count
|
43
|
+
["--count", "-c", GetoptLong::NO_ARGUMENT],
|
44
|
+
# Match fixed strings and not regular expressions
|
45
|
+
["--fixed-strings", "-F", GetoptLong::NO_ARGUMENT],
|
46
|
+
# Make elfgrep case-insensitive
|
47
|
+
["--ignore-case", "-i", GetoptLong::NO_ARGUMENT],
|
48
|
+
# Use NULLs to terminate filenames
|
49
|
+
["--null", "-Z", GetoptLong::NO_ARGUMENT],
|
50
|
+
]
|
51
|
+
|
52
|
+
# We define callbacks for some behaviour-changing options as those
|
53
|
+
# will let us consider them positionally, similar to what grep(1)
|
54
|
+
# does. If you try -lLl and similar combinations on grep(1), the last
|
55
|
+
# one passed is the one to be considered.
|
56
|
+
|
57
|
+
def self.fixed_strings_cb
|
58
|
+
@match = :fixed_strings
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.files_with_matches_cb
|
62
|
+
@show = :files_with_matches
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.files_without_match_cb
|
66
|
+
@show = :files_without_match
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.with_filename_cb
|
70
|
+
@print_filename = true
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.no_filename_cb
|
74
|
+
@print_filename = false
|
75
|
+
end
|
76
|
+
|
77
|
+
# we make this a method so that we don't have to worry about deciding
|
78
|
+
# on the base of how many targets we have; we have to do this
|
79
|
+
# because we cannot know, in after_options, whether the user passed
|
80
|
+
# @-file lists.
|
81
|
+
def self.print_filename
|
82
|
+
@print_filename = !@single_target if @print_filename.nil?
|
83
|
+
|
84
|
+
@print_filename
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.regexp_cb(pattern)
|
88
|
+
@patterns << pattern
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.before_options
|
92
|
+
@invert_match = false
|
93
|
+
@match_undefined = true
|
94
|
+
@match_defined = true
|
95
|
+
@show = :full_match
|
96
|
+
@match = :regexp
|
97
|
+
|
98
|
+
@patterns = []
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.after_options
|
102
|
+
if @patterns.size ==0
|
103
|
+
puterror "you need to provide at least expression"
|
104
|
+
exit -1
|
105
|
+
end
|
106
|
+
|
107
|
+
if @no_match_undefined and @no_match_defined
|
108
|
+
puterror "you need to match at least defined or undefined symbols"
|
109
|
+
exit -1
|
110
|
+
end
|
111
|
+
|
112
|
+
@match_undefined = !@no_match_undefined
|
113
|
+
@match_defined = !@no_match_defined
|
114
|
+
|
115
|
+
regexp_options = @ignore_case ? Regexp::IGNORECASE : 0
|
116
|
+
@regexp = Regexp.union(@patterns.collect { |pattern|
|
117
|
+
# escape the pattern, so that it works like
|
118
|
+
# it was a fixed string.
|
119
|
+
pattern = Regexp.escape(pattern) if @match == :fixed_strings
|
120
|
+
|
121
|
+
Regexp.new(pattern, regexp_options)
|
122
|
+
})
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.analysis(file)
|
126
|
+
if not @print_filename
|
127
|
+
file_prefix = ""
|
128
|
+
else
|
129
|
+
file_prefix = sprintf("%s%s ",
|
130
|
+
file,
|
131
|
+
@null ? "\0" : ":")
|
132
|
+
end
|
133
|
+
file_list = sprintf("%s%s",
|
134
|
+
file,
|
135
|
+
@null ? "\0" : "\n")
|
136
|
+
|
137
|
+
Elf::File.open(file) do |elf|
|
138
|
+
table = [".dynsym", ".symtab"].find do |table|
|
139
|
+
begin
|
140
|
+
(elf[table].class == Elf::SymbolTable)
|
141
|
+
rescue Elf::File::MissingSection
|
142
|
+
false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
if table.nil?
|
147
|
+
putnotice "#{file}: unable to find symbol table"
|
148
|
+
return
|
149
|
+
end
|
150
|
+
|
151
|
+
matches = 0
|
152
|
+
elf[table].each do |symbol|
|
153
|
+
next if
|
154
|
+
(symbol.section == Elf::Section::Abs) or
|
155
|
+
(symbol.name == '') or
|
156
|
+
(symbol.section == Elf::Section::Undef and
|
157
|
+
not @match_undefined) or
|
158
|
+
(symbol.section != Elf::Section::Undef and
|
159
|
+
not @match_defined)
|
160
|
+
|
161
|
+
symname = symbol.name
|
162
|
+
symname += "@#{symbol.version}" if @match_version
|
163
|
+
|
164
|
+
# We don't care where it matches, but we do care that it matches
|
165
|
+
# or not; we use an invert match since we have to further compare
|
166
|
+
# that to @invert_match
|
167
|
+
if (@invert_match == (@regexp =~ symname).nil?)
|
168
|
+
matches = matches+1
|
169
|
+
|
170
|
+
break unless @show == :full_match
|
171
|
+
next if @count
|
172
|
+
|
173
|
+
puts "#{file_prefix}#{symbol.address_string} #{symbol.nm_code rescue '?'} #{symname}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
if @show == :files_with_matches
|
178
|
+
puts file_list if matches > 0
|
179
|
+
elsif @show == :files_without_match
|
180
|
+
puts file_list if matches == 0
|
181
|
+
elsif @count
|
182
|
+
puts "#{file_prefix}#{matches}"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/bin/missingstatic
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- mode: ruby; 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
|
+
# check for functions that are not used but in their translation unit
|
20
|
+
|
21
|
+
require 'elf/tools'
|
22
|
+
|
23
|
+
Options = [
|
24
|
+
# Exclude functions with a given prefix (exported functions)
|
25
|
+
["--exclude-regexp", "-x", GetoptLong::REQUIRED_ARGUMENT],
|
26
|
+
# Only scan hidden symbols, ignore exported ones
|
27
|
+
["--hidden-only", "-h", GetoptLong::NO_ARGUMENT],
|
28
|
+
# Show the type of symbol (function, variable, constant)
|
29
|
+
["--show-type", "-t", GetoptLong::NO_ARGUMENT],
|
30
|
+
# Exclude symbols present in a tags file (from exuberant-ctags)
|
31
|
+
["--exclude-tags", "-X", GetoptLong::REQUIRED_ARGUMENT]
|
32
|
+
]
|
33
|
+
|
34
|
+
def self.exclude_tags_cb(arg)
|
35
|
+
@exclude_names += File.readlines(arg).delete_if do |line|
|
36
|
+
line[0..0] == '!' # Internal exuberant-ctags symbol
|
37
|
+
end.collect do |line|
|
38
|
+
line.split[0]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.exclude_regexp_cb(arg)
|
43
|
+
@exclude_regexps << Regexp.new(arg)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.before_options
|
47
|
+
# The main symbol is used by all the standalone executables,
|
48
|
+
# reporting it is pointless as it will always be a false
|
49
|
+
# positive. It cannot be marked static.
|
50
|
+
#
|
51
|
+
# The excluded_names variable will contain also all the used symbols
|
52
|
+
@exclude_names = ["main"]
|
53
|
+
@exclude_regexps = []
|
54
|
+
@hidden_only = false
|
55
|
+
@show_type = false
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.after_options
|
59
|
+
@all_defined = []
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.analysis(filename)
|
63
|
+
Elf::File.open(filename) do |elf|
|
64
|
+
if elf.type != Elf::File::Type::Rel
|
65
|
+
putnotice "#{file}: not an object file"
|
66
|
+
next
|
67
|
+
end
|
68
|
+
unless elf.has_section?('.symtab')
|
69
|
+
putnotice "#{file}: no .symtab section found"
|
70
|
+
next
|
71
|
+
end
|
72
|
+
|
73
|
+
# Gather all the symbols, defined and missing in the translation unit
|
74
|
+
elf['.symtab'].each do |sym|
|
75
|
+
if sym.section == Elf::Section::Undef
|
76
|
+
@exclude_names << sym.name
|
77
|
+
elsif sym.bind == Elf::Symbol::Binding::Local
|
78
|
+
next
|
79
|
+
elsif (sym.section.is_a? Elf::Section) or
|
80
|
+
(sym.section == Elf::Section::Common)
|
81
|
+
next if @hidden_only and
|
82
|
+
sym.visibility != Elf::Symbol::Visibility::Hidden
|
83
|
+
|
84
|
+
@all_defined << sym
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.results
|
91
|
+
@exclude_names.uniq!
|
92
|
+
|
93
|
+
@all_defined.each do |symbol|
|
94
|
+
next if @exclude_names.include? symbol.name
|
95
|
+
|
96
|
+
excluded = false
|
97
|
+
@exclude_regexps.each do |exclude_sym|
|
98
|
+
break if excluded = exclude_sym.match(symbol.name)
|
99
|
+
end
|
100
|
+
next if excluded
|
101
|
+
|
102
|
+
if @show_type
|
103
|
+
begin
|
104
|
+
prefix = "#{symbol.nm_code} "
|
105
|
+
rescue Elf::Symbol::UnknownNMCode => e
|
106
|
+
puterror e.message
|
107
|
+
prefix = "? "
|
108
|
+
end
|
109
|
+
end
|
110
|
+
puts "#{prefix}#{symbol.name} (#{symbol.file.path})"
|
111
|
+
end
|
112
|
+
end
|
data/bin/rbelf-size
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- mode: ruby; 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
|
+
# replacement for size(1) utility that takes into consideration .rodata sections
|
20
|
+
|
21
|
+
require 'elf/tools'
|
22
|
+
|
23
|
+
Options = [
|
24
|
+
# Give relocation data for shared object assesment
|
25
|
+
["--relocation-stats", "-r", GetoptLong::NO_ARGUMENT],
|
26
|
+
# Use deciBel scale for the shared-to-relocated ratio
|
27
|
+
["--decibel", "-d", GetoptLong::NO_ARGUMENT]
|
28
|
+
]
|
29
|
+
|
30
|
+
def self.before_options
|
31
|
+
@relocation_stats = false
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.after_options
|
35
|
+
@header = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.analysis(file)
|
39
|
+
Elf::File.open(file) do |elf|
|
40
|
+
results = {
|
41
|
+
:exec => 0,
|
42
|
+
:data => 0,
|
43
|
+
:rodata => 0,
|
44
|
+
:relro => 0,
|
45
|
+
:bss => 0,
|
46
|
+
:total => 0
|
47
|
+
}
|
48
|
+
|
49
|
+
# Get the size of each section, and then, depending on its type,
|
50
|
+
# flags and eventually name, decide what to sum it to.
|
51
|
+
elf.each_section do |section|
|
52
|
+
case
|
53
|
+
# When the section is NoBits, it is not allocated in the file,
|
54
|
+
# and is only allocated in ram, this is the case of .bss and
|
55
|
+
# .tbss sections.
|
56
|
+
when section.type == Elf::Section::Type::NoBits
|
57
|
+
sectype = :bss
|
58
|
+
# If the section contains executable code, count it separately;
|
59
|
+
# size(1) will count it all as text, but we don't need to do
|
60
|
+
# that.
|
61
|
+
when section.flags.include?(Elf::Section::Flags::ExecInstr)
|
62
|
+
sectype = :exec
|
63
|
+
# If the section is going to be allocated and writeable at
|
64
|
+
# runtime, it is usually a data section, of some kind.
|
65
|
+
#
|
66
|
+
# We check further though since we might want to count it
|
67
|
+
# separately.
|
68
|
+
when (section.flags.include?(Elf::Section::Flags::Write) and
|
69
|
+
section.flags.include?(Elf::Section::Flags::Alloc))
|
70
|
+
|
71
|
+
# This makes it GCC-specific but that's just because I
|
72
|
+
# cannot find anything in ELF specs that gives an easy way
|
73
|
+
# to deal with this.
|
74
|
+
#
|
75
|
+
# By all means, .data.rel.ro is just the same as .data, with
|
76
|
+
# the exception of prelinking, where this area can then
|
77
|
+
# become mostly read-only and thus not creating dirty pages.
|
78
|
+
sectype = (section.name =~ /^\.data\.rel\.ro(\..+)?/) ? :relro : :data
|
79
|
+
when section.flags.include?(Elf::Section::Flags::Alloc)
|
80
|
+
sectype = :rodata
|
81
|
+
end
|
82
|
+
|
83
|
+
results[sectype] += section.size unless sectype.nil?
|
84
|
+
end
|
85
|
+
|
86
|
+
results[:total] = results.values.inject { |sum, val| sum += val }
|
87
|
+
|
88
|
+
if @relocation_stats
|
89
|
+
relocation_stats(results, file)
|
90
|
+
else
|
91
|
+
standard_size(results, file)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.relocation_stats(results, file)
|
97
|
+
if @header
|
98
|
+
puts " shared private relocated ratio filename"
|
99
|
+
@header = false
|
100
|
+
end
|
101
|
+
|
102
|
+
size_shared = results[:exec] + results[:rodata]
|
103
|
+
size_private = results[:data] + results[:bss]
|
104
|
+
size_relocated = results[:relro]
|
105
|
+
|
106
|
+
ratio = size_shared.to_f/size_relocated
|
107
|
+
ratio = 10 * Math::log10(ratio) if @decibel
|
108
|
+
|
109
|
+
printf "% 12s % 12s % 12s % 12.2f %s\n", size_shared, size_private, size_relocated, ratio, file
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.standard_size(results, file)
|
113
|
+
if @header
|
114
|
+
puts " exec data rodata relro bss total filename"
|
115
|
+
@header = false
|
116
|
+
end
|
117
|
+
|
118
|
+
results.each_pair do |key, val|
|
119
|
+
results[key] = val.to_s.rjust(9)
|
120
|
+
end
|
121
|
+
|
122
|
+
puts "#{results[:exec]} #{results[:data]} #{results[:rodata]} #{results[:relro]} #{results[:bss]} #{results[:total]} #{file}"
|
123
|
+
end
|
data/bin/verify-lfs
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- mode: ruby; coding: utf-8 -*-
|
3
|
+
# Copyright © 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 verifies whether a file or a tree of files is using
|
20
|
+
# non-LFS interfaces, or mixing non-LFS and LFS interfaces.
|
21
|
+
|
22
|
+
require 'elf/tools'
|
23
|
+
|
24
|
+
Options = [
|
25
|
+
# Scan only object files (rather than non-object files)
|
26
|
+
["--objects", "-o", GetoptLong::NO_ARGUMENT]
|
27
|
+
]
|
28
|
+
|
29
|
+
SymbolNamesList = [
|
30
|
+
"__[fl]?xstat",
|
31
|
+
"statv?fs",
|
32
|
+
"(|_IO_)f[gs]etpos",
|
33
|
+
"(read|scan)dir",
|
34
|
+
"getdirentries",
|
35
|
+
"mko?stemp",
|
36
|
+
"(|__)p(read|write)",
|
37
|
+
"p(read|write)v",
|
38
|
+
"(send|tmp)file",
|
39
|
+
"[gs]etrlimit",
|
40
|
+
"versionsort",
|
41
|
+
"f?truncate",
|
42
|
+
"(|f(|re))open",
|
43
|
+
"openat",
|
44
|
+
"fseeko",
|
45
|
+
"ftello",
|
46
|
+
"lseek",
|
47
|
+
"glob(|free)",
|
48
|
+
"ftw",
|
49
|
+
"lockf"
|
50
|
+
]
|
51
|
+
|
52
|
+
SymbolNames = "(#{SymbolNamesList.join("|")})"
|
53
|
+
|
54
|
+
def self.before_options
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.after_options
|
58
|
+
@files_mixing = []
|
59
|
+
@files_nolfs = []
|
60
|
+
|
61
|
+
if @objects
|
62
|
+
@elftypes = [ Elf::File::Type::Rel ]
|
63
|
+
@elfdescr = "a relocatable object file"
|
64
|
+
@elftable = ".symtab"
|
65
|
+
else
|
66
|
+
@elftypes = [ Elf::File::Type::Exec, Elf::File::Type::Dyn ]
|
67
|
+
@elfdescr = "an executable or dynamic file"
|
68
|
+
@elftable = ".dynsym"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.analysis(file)
|
73
|
+
Elf::File.open(file) do |elf|
|
74
|
+
unless @elftypes.include? elf.type
|
75
|
+
putnotice "#{file}: not #{@elfdescr}"
|
76
|
+
next
|
77
|
+
end
|
78
|
+
|
79
|
+
if not elf.has_section?(@elftable) or elf[@elftable].class != Elf::SymbolTable
|
80
|
+
putnotice "#{file}: not a dynamically linked file"
|
81
|
+
next
|
82
|
+
end
|
83
|
+
|
84
|
+
if elf.elf_class == Elf::Class::Elf64
|
85
|
+
putnotice "#{file}: testing 64-bit ELF files is meaningless"
|
86
|
+
next
|
87
|
+
end
|
88
|
+
|
89
|
+
use_stat32 = false
|
90
|
+
use_stat64 = false
|
91
|
+
|
92
|
+
elf[@elftable].each do |symbol|
|
93
|
+
next unless symbol.section == Elf::Section::Undef
|
94
|
+
|
95
|
+
use_stat32 ||= (symbol.to_s =~ /^#{SymbolNames}$/)
|
96
|
+
use_stat64 ||= (symbol.to_s =~ /^#{SymbolNames}64$/)
|
97
|
+
|
98
|
+
# avoid running the whole list if we hit both as we cannot hit
|
99
|
+
# _more_
|
100
|
+
break if use_stat32 and use_stat64
|
101
|
+
end
|
102
|
+
|
103
|
+
if use_stat32 and use_stat64
|
104
|
+
@files_mixing << file
|
105
|
+
elsif use_stat32 and not use_stat64
|
106
|
+
@files_nolfs << file
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.results
|
112
|
+
if @files_mixing.size > 0
|
113
|
+
puts "The following files are mixing LFS and non-LFS library calls:"
|
114
|
+
puts " " + @files_mixing.join("\n ")
|
115
|
+
end
|
116
|
+
if @files_nolfs.size > 0
|
117
|
+
puts "The following files are using non-LFS library calls:"
|
118
|
+
puts " " + @files_nolfs.join("\n ")
|
119
|
+
end
|
120
|
+
end
|