ruby-elf 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/bin/elfgrep CHANGED
@@ -18,169 +18,190 @@
18
18
 
19
19
  require 'elf/tools'
20
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
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
- def self.files_with_matches_cb
62
- @show = :files_with_matches
63
- end
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.files_without_match_cb
66
- @show = :files_without_match
67
- end
68
-
69
- def self.with_filename_cb
70
- @print_filename = true
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.no_filename_cb
74
- @print_filename = false
75
- end
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.regexp_cb(pattern)
78
- @patterns << pattern
79
- end
86
+ def self.fixed_strings_cb
87
+ @match = :fixed_strings
88
+ end
80
89
 
81
- def self.before_options
82
- @invert_match = false
83
- @match_undefined = true
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
- @patterns = []
89
- end
94
+ def self.files_without_match_cb
95
+ @show = :files_without_match
96
+ end
90
97
 
91
- def self.after_options
92
- if @no_match_undefined and @no_match_defined
93
- puterror "you need to match at least defined or undefined symbols"
94
- exit -1
95
- end
98
+ def self.with_filename_cb
99
+ @print_filename = true
100
+ end
96
101
 
97
- @match_undefined = !@no_match_undefined
98
- @match_defined = !@no_match_defined
102
+ def self.no_filename_cb
103
+ @print_filename = false
104
+ end
99
105
 
100
- # if we don't have listed patterns yet (i.e. no -e option), let's
101
- # check whether we have at least one argument and if that argument
102
- # doesn't start with '@'. If we have no arguments, the targets are
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
- @patterns << ARGV.delete_at(0)
111
- end
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
- if @patterns.size == 0
114
- puterror "you need to provide at least expression"
115
- exit -1
116
- end
116
+ @match_undefined = @match_symbols != :defined
117
+ @match_defined = @match_symbols != :undefined
117
118
 
118
- @print_filename = true if @print_filename.nil? and not single_target?
119
- @file_prefix_fmt = @print_filename ? "%s#{@null ? "\0" : ":"} " : ""
120
- @file_list_fmt = "%s#{@null ? "\0" : "\n"}"
121
-
122
- regexp_options = @ignore_case ? Regexp::IGNORECASE : 0
123
- @regexp = Regexp.union(@patterns.collect { |pattern|
124
- if @match == :fixed_strings
125
- pattern.split(/\r?\n/).collect { |string|
126
- Regexp.new(Regexp.escape(string), regexp_options)
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
- def self.analysis(file)
135
- file_prefix = sprintf(@file_prefix_fmt, file)
136
- file_list = sprintf(@file_list_fmt, file)
129
+ @patterns << @targets.delete_at(0)
130
+ end
137
131
 
138
- Elf::File.open(file) do |elf|
139
- table = [".dynsym", ".symtab"].find do |table|
140
- begin
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
- if table.nil?
148
- putnotice "#{file}: unable to find symbol table"
149
- return
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
- matches = 0
153
- elf[table].each do |symbol|
154
- next if
155
- (symbol.section == Elf::Section::Abs) or
156
- (symbol.name == '') or
157
- (symbol.section == Elf::Section::Undef and
158
- not @match_undefined) or
159
- (symbol.section != Elf::Section::Undef and
160
- not @match_defined)
161
-
162
- symname = symbol.name
163
- symname += "@#{symbol.version}" if @match_version
164
-
165
- # We don't care where it matches, but we do care that it matches
166
- # or not; we use an invert match since we have to further compare
167
- # that to @invert_match
168
- if (@invert_match == (@regexp =~ symname).nil?)
169
- matches = matches+1
170
-
171
- break unless @show == :full_match
172
- next if @count
173
-
174
- puts "#{file_prefix}#{symbol.address_string} #{symbol.nm_code rescue '?'} #{symname}"
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
- 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
- ]
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
- 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
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
- def self.exclude_regexp_cb(arg)
43
- @exclude_regexps << Regexp.new(arg)
44
- end
48
+ @hidden_only = false
49
+ @show_type = false
45
50
 
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
51
+ @all_defined = []
52
+ end
61
53
 
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
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
- unless elf.has_section?('.symtab')
69
- putnotice "#{file}: no .symtab section found"
70
- next
61
+
62
+ def self.exclude_regexp_cb(arg)
63
+ @exclude_patterns << Regexp.new(arg)
71
64
  end
72
65
 
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
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
- @all_defined << sym
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
- @all_defined.each do |symbol|
94
- next if @exclude_names.include? symbol.name
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
- excluded = false
97
- @exclude_regexps.each do |exclude_sym|
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
- if @show_type
103
- begin
104
- prefix = "#{symbol.nm_code} "
105
- rescue Elf::Symbol::UnknownNMCode => e
106
- puterror e.message
107
- prefix = "? "
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