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/elfgrep
CHANGED
@@ -18,169 +18,190 @@
|
|
18
18
|
|
19
19
|
require 'elf/tools'
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
21
|
+
module Elf::Tools
|
22
|
+
class ElfGrep < Elf::Tool
|
23
|
+
def self.initialize
|
24
|
+
super
|
25
|
+
|
26
|
+
@options |= [
|
27
|
+
# Expression to match on the symbol name
|
28
|
+
["--regexp", "-e", GetoptLong::REQUIRED_ARGUMENT],
|
29
|
+
# Append the version information when matching the symbol
|
30
|
+
# name
|
31
|
+
["--match-version", "-V", GetoptLong::NO_ARGUMENT],
|
32
|
+
# Don't match undefined symbols
|
33
|
+
["--match-undefined", "-U", GetoptLong::NO_ARGUMENT],
|
34
|
+
# Don't match defined symbols
|
35
|
+
["--match-defined", "-D", GetoptLong::NO_ARGUMENT],
|
36
|
+
# Invert selection, show symbols not matching the
|
37
|
+
# expression
|
38
|
+
["--invert-match", "-v", GetoptLong::NO_ARGUMENT],
|
39
|
+
# List only files with matches
|
40
|
+
["--files-with-matches", "-l", GetoptLong::NO_ARGUMENT],
|
41
|
+
# List only files without match
|
42
|
+
["--files-without-match", "-L", GetoptLong::NO_ARGUMENT],
|
43
|
+
# Print the name of the file for each match
|
44
|
+
["--with-filename", "-H", GetoptLong::NO_ARGUMENT],
|
45
|
+
# Don't print the name of the file for each match
|
46
|
+
["--no-filename", "-h", GetoptLong::NO_ARGUMENT],
|
47
|
+
# Only output matches' count
|
48
|
+
["--count", "-c", GetoptLong::NO_ARGUMENT],
|
49
|
+
# Match fixed strings and not regular expressions
|
50
|
+
["--fixed-strings", "-F", GetoptLong::NO_ARGUMENT],
|
51
|
+
# Make elfgrep case-insensitive
|
52
|
+
["--ignore-case", "-i", GetoptLong::NO_ARGUMENT],
|
53
|
+
# Use NULLs to terminate filenames
|
54
|
+
["--null", "-Z", GetoptLong::NO_ARGUMENT],
|
55
|
+
]
|
56
|
+
|
57
|
+
@invert_match = false
|
58
|
+
@show = :full_match
|
59
|
+
@match = :regexp
|
60
|
+
@match_symbols = nil
|
61
|
+
|
62
|
+
@patterns = []
|
63
|
+
end
|
60
64
|
|
61
|
-
|
62
|
-
|
63
|
-
|
65
|
+
# We define callbacks for some behaviour-changing options as those
|
66
|
+
# will let us consider them positionally, similar to what grep(1)
|
67
|
+
# does. If you try -lLl and similar combinations on grep(1), the last
|
68
|
+
# one passed is the one to be considered.
|
64
69
|
|
65
|
-
def self.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
70
|
+
def self.match_undefined_cb
|
71
|
+
if @match_symbols == :defined
|
72
|
+
@match_symbols = :all
|
73
|
+
else
|
74
|
+
@match_symbols = :undefined
|
75
|
+
end
|
76
|
+
end
|
72
77
|
|
73
|
-
def self.
|
74
|
-
|
75
|
-
|
78
|
+
def self.match_defined_cb
|
79
|
+
if @match_symbols == :undefined
|
80
|
+
@match_symbols = :all
|
81
|
+
else
|
82
|
+
@match_symbols = :defined
|
83
|
+
end
|
84
|
+
end
|
76
85
|
|
77
|
-
def self.
|
78
|
-
|
79
|
-
end
|
86
|
+
def self.fixed_strings_cb
|
87
|
+
@match = :fixed_strings
|
88
|
+
end
|
80
89
|
|
81
|
-
def self.
|
82
|
-
|
83
|
-
|
84
|
-
@match_defined = true
|
85
|
-
@show = :full_match
|
86
|
-
@match = :regexp
|
90
|
+
def self.files_with_matches_cb
|
91
|
+
@show = :files_with_matches
|
92
|
+
end
|
87
93
|
|
88
|
-
|
89
|
-
|
94
|
+
def self.files_without_match_cb
|
95
|
+
@show = :files_without_match
|
96
|
+
end
|
90
97
|
|
91
|
-
def self.
|
92
|
-
|
93
|
-
|
94
|
-
exit -1
|
95
|
-
end
|
98
|
+
def self.with_filename_cb
|
99
|
+
@print_filename = true
|
100
|
+
end
|
96
101
|
|
97
|
-
|
98
|
-
|
102
|
+
def self.no_filename_cb
|
103
|
+
@print_filename = false
|
104
|
+
end
|
99
105
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# to be given by stdin, and that won't include the actual pattern,
|
104
|
-
# if we have an @-prefixed argument, that's a list of targets and
|
105
|
-
# can't include the pattern either.
|
106
|
-
if (@patterns.size == 0 and
|
107
|
-
ARGV.size >= 1 and
|
108
|
-
ARGV[0] !~ /^@/)
|
106
|
+
def self.regexp_cb(pattern)
|
107
|
+
@patterns << pattern
|
108
|
+
end
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
def self.after_options
|
111
|
+
if @no_match_undefined and @no_match_defined
|
112
|
+
puterror "you need to match at least defined or undefined symbols"
|
113
|
+
exit -1
|
114
|
+
end
|
112
115
|
|
113
|
-
|
114
|
-
|
115
|
-
exit -1
|
116
|
-
end
|
116
|
+
@match_undefined = @match_symbols != :defined
|
117
|
+
@match_defined = @match_symbols != :undefined
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
}
|
128
|
-
else
|
129
|
-
Regexp.new(pattern, regexp_options)
|
130
|
-
end
|
131
|
-
}.flatten)
|
132
|
-
end
|
119
|
+
# if we don't have listed patterns yet (i.e. no -e option), let's
|
120
|
+
# check whether we have at least one argument and if that argument
|
121
|
+
# doesn't start with '@'. If we have no arguments, the targets are
|
122
|
+
# to be given by stdin, and that won't include the actual pattern,
|
123
|
+
# if we have an @-prefixed argument, that's a list of targets and
|
124
|
+
# can't include the pattern either.
|
125
|
+
if (@patterns.size == 0 and
|
126
|
+
@targets.size >= 1 and
|
127
|
+
@targets[0] !~ /^@/)
|
133
128
|
|
134
|
-
|
135
|
-
|
136
|
-
file_list = sprintf(@file_list_fmt, file)
|
129
|
+
@patterns << @targets.delete_at(0)
|
130
|
+
end
|
137
131
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
(elf[table].class == Elf::SymbolTable)
|
142
|
-
rescue Elf::File::MissingSection
|
143
|
-
false
|
132
|
+
if @patterns.size == 0
|
133
|
+
puterror "you need to provide at least expression"
|
134
|
+
exit -1
|
144
135
|
end
|
145
|
-
end
|
146
136
|
|
147
|
-
|
148
|
-
|
149
|
-
|
137
|
+
@print_filename = (@recursive or @targets.size > 1) if @print_filename.nil?
|
138
|
+
@file_prefix_fmt = @print_filename ? "%s#{@null ? "\0" : ":"} " : ""
|
139
|
+
@file_list_fmt = "%s#{@null ? "\0" : "\n"}"
|
140
|
+
|
141
|
+
regexp_options = @ignore_case ? Regexp::IGNORECASE : 0
|
142
|
+
@regexp = Regexp.union(@patterns.collect { |pattern|
|
143
|
+
if @match == :fixed_strings
|
144
|
+
pattern.split(/\r?\n/).collect { |string|
|
145
|
+
Regexp.new(Regexp.escape(string), regexp_options)
|
146
|
+
}
|
147
|
+
else
|
148
|
+
Regexp.new(pattern, regexp_options)
|
149
|
+
end
|
150
|
+
}.flatten)
|
150
151
|
end
|
151
152
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
153
|
+
def self.analysis(file)
|
154
|
+
file_prefix = sprintf(@file_prefix_fmt, file)
|
155
|
+
file_list = sprintf(@file_list_fmt, file)
|
156
|
+
|
157
|
+
Elf::File.open(file) do |elf|
|
158
|
+
table = [".dynsym", ".symtab"].find do |table|
|
159
|
+
begin
|
160
|
+
(elf[table].class == Elf::SymbolTable)
|
161
|
+
rescue Elf::File::MissingSection, Elf::File::MissingStringTable
|
162
|
+
false
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
if table.nil?
|
167
|
+
putnotice "#{file}: unable to find symbol table"
|
168
|
+
return
|
169
|
+
end
|
170
|
+
|
171
|
+
matches = 0
|
172
|
+
elf[table].each do |symbol|
|
173
|
+
next if
|
174
|
+
(symbol.section == Elf::Section::Abs) or
|
175
|
+
(symbol.name == '') or
|
176
|
+
(symbol.section == Elf::Section::Undef and
|
177
|
+
not @match_undefined) or
|
178
|
+
(symbol.section != Elf::Section::Undef and
|
179
|
+
not @match_defined)
|
180
|
+
|
181
|
+
symname = symbol.name
|
182
|
+
symname += "@#{symbol.version}" if @match_version
|
183
|
+
|
184
|
+
# We don't care where it matches, but we do care that it matches
|
185
|
+
# or not; we use an invert match since we have to further compare
|
186
|
+
# that to @invert_match
|
187
|
+
if (@invert_match == (@regexp =~ symname).nil?)
|
188
|
+
matches = matches+1
|
189
|
+
|
190
|
+
break unless @show == :full_match
|
191
|
+
next if @count
|
192
|
+
|
193
|
+
puts "#{file_prefix}#{symbol.address_string} #{symbol.nm_code rescue '?'} #{symname}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
if @show == :files_with_matches
|
198
|
+
puts file_list if matches > 0
|
199
|
+
elsif @show == :files_without_match
|
200
|
+
puts file_list if matches == 0
|
201
|
+
elsif @count
|
202
|
+
puts "#{file_prefix}#{matches}"
|
203
|
+
end
|
175
204
|
end
|
176
205
|
end
|
177
|
-
|
178
|
-
if @show == :files_with_matches
|
179
|
-
puts file_list if matches > 0
|
180
|
-
elsif @show == :files_without_match
|
181
|
-
puts file_list if matches == 0
|
182
|
-
elsif @count
|
183
|
-
puts "#{file_prefix}#{matches}"
|
184
|
-
end
|
185
206
|
end
|
186
207
|
end
|
data/bin/missingstatic
CHANGED
@@ -20,93 +20,94 @@
|
|
20
20
|
|
21
21
|
require 'elf/tools'
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
module Elf::Tools
|
24
|
+
class MissingStatic < Elf::Tool
|
25
|
+
def self.initialize
|
26
|
+
super
|
27
|
+
@options |= [
|
28
|
+
# Exclude functions with a given prefix (exported functions)
|
29
|
+
["--exclude-regexp", "-x", GetoptLong::REQUIRED_ARGUMENT],
|
30
|
+
# Only scan hidden symbols, ignore exported ones
|
31
|
+
["--hidden-only", "-h", GetoptLong::NO_ARGUMENT],
|
32
|
+
# Show the type of symbol (function, variable, constant)
|
33
|
+
["--show-type", "-t", GetoptLong::NO_ARGUMENT],
|
34
|
+
# Exclude symbols present in a tags file (from exuberant-ctags)
|
35
|
+
["--exclude-tags", "-X", GetoptLong::REQUIRED_ARGUMENT]
|
36
|
+
]
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
# List of patterns to exclude; this include all the used
|
39
|
+
# symbols, the entrypoints to the system's dynamic loader, and
|
40
|
+
# those provided by the user as to be ignored.
|
41
|
+
#
|
42
|
+
# For technical limits, we have two arrays, one includes all the
|
43
|
+
# regular expressions given by the user, the other is a list of
|
44
|
+
# full strings matching.
|
45
|
+
@exclude_patterns = []
|
46
|
+
@exclude_symbols = Set.new([ "main" ])
|
41
47
|
|
42
|
-
|
43
|
-
|
44
|
-
end
|
48
|
+
@hidden_only = false
|
49
|
+
@show_type = false
|
45
50
|
|
46
|
-
|
47
|
-
|
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
|
51
|
+
@all_defined = []
|
52
|
+
end
|
61
53
|
|
62
|
-
def self.
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
54
|
+
def self.exclude_tags_cb(arg)
|
55
|
+
@exclude_symbols |= File.readlines(arg).delete_if do |line|
|
56
|
+
line[0..0] == '!' # Internal exuberant-ctags symbol
|
57
|
+
end.collect do |line|
|
58
|
+
line.split[0]
|
59
|
+
end
|
67
60
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
61
|
+
|
62
|
+
def self.exclude_regexp_cb(arg)
|
63
|
+
@exclude_patterns << Regexp.new(arg)
|
71
64
|
end
|
72
65
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
66
|
+
def self.analysis(filename)
|
67
|
+
Elf::File.open(filename) do |elf|
|
68
|
+
if elf.type != Elf::File::Type::Rel
|
69
|
+
putnotice "#{file}: not an object file"
|
70
|
+
next
|
71
|
+
end
|
72
|
+
unless elf.has_section?('.symtab')
|
73
|
+
putnotice "#{file}: no .symtab section found"
|
74
|
+
next
|
75
|
+
end
|
83
76
|
|
84
|
-
|
77
|
+
# Gather all the symbols, defined and missing in the translation unit
|
78
|
+
elf['.symtab'].each do |sym|
|
79
|
+
if sym.section == Elf::Section::Undef
|
80
|
+
@exclude_symbols << sym.name
|
81
|
+
elsif sym.bind == Elf::Symbol::Binding::Local
|
82
|
+
next
|
83
|
+
elsif (sym.section.is_a? Elf::Section) or
|
84
|
+
(sym.section == Elf::Section::Common)
|
85
|
+
next if @hidden_only and
|
86
|
+
sym.visibility != Elf::Symbol::Visibility::Hidden
|
87
|
+
|
88
|
+
@all_defined << sym
|
89
|
+
end
|
90
|
+
end
|
85
91
|
end
|
86
92
|
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.results
|
91
|
-
@exclude_names.uniq!
|
92
93
|
|
93
|
-
|
94
|
-
|
94
|
+
def self.results
|
95
|
+
@exclude_patterns << Regexp.union(@exclude_symbols.collect { |sym| /^#{Regexp.escape(sym)}$/ })
|
96
|
+
exclusions = Regexp.union(@exclude_patterns)
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
break if excluded = exclude_sym.match(symbol.name)
|
99
|
-
end
|
100
|
-
next if excluded
|
98
|
+
@all_defined.each do |symbol|
|
99
|
+
next if symbol.name =~ exclusions
|
101
100
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
101
|
+
if @show_type
|
102
|
+
begin
|
103
|
+
prefix = "#{symbol.nm_code} "
|
104
|
+
rescue Elf::Symbol::UnknownNMCode => e
|
105
|
+
puterror e.message
|
106
|
+
prefix = "? "
|
107
|
+
end
|
108
|
+
end
|
109
|
+
puts "#{prefix}#{symbol.name} (#{symbol.file.path})"
|
108
110
|
end
|
109
111
|
end
|
110
|
-
puts "#{prefix}#{symbol.name} (#{symbol.file.path})"
|
111
112
|
end
|
112
113
|
end
|