ruby-elf 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/elfgrep CHANGED
@@ -74,16 +74,6 @@ def self.no_filename_cb
74
74
  @print_filename = false
75
75
  end
76
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
77
  def self.regexp_cb(pattern)
88
78
  @patterns << pattern
89
79
  end
@@ -99,11 +89,6 @@ def self.before_options
99
89
  end
100
90
 
101
91
  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
92
  if @no_match_undefined and @no_match_defined
108
93
  puterror "you need to match at least defined or undefined symbols"
109
94
  exit -1
@@ -112,27 +97,43 @@ def self.after_options
112
97
  @match_undefined = !@no_match_undefined
113
98
  @match_defined = !@no_match_defined
114
99
 
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] !~ /^@/)
109
+
110
+ @patterns << ARGV.delete_at(0)
111
+ end
112
+
113
+ if @patterns.size == 0
114
+ puterror "you need to provide at least expression"
115
+ exit -1
116
+ end
117
+
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
+
115
122
  regexp_options = @ignore_case ? Regexp::IGNORECASE : 0
116
123
  @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
- })
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)
123
132
  end
124
133
 
125
134
  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")
135
+ file_prefix = sprintf(@file_prefix_fmt, file)
136
+ file_list = sprintf(@file_list_fmt, file)
136
137
 
137
138
  Elf::File.open(file) do |elf|
138
139
  table = [".dynsym", ".symtab"].find do |table|
data/bin/rbelf-size CHANGED
@@ -43,12 +43,18 @@ def self.analysis(file)
43
43
  :rodata => 0,
44
44
  :relro => 0,
45
45
  :bss => 0,
46
+ :overhead => 0,
46
47
  :total => 0
47
48
  }
48
49
 
49
50
  # Get the size of each section, and then, depending on its type,
50
51
  # flags and eventually name, decide what to sum it to.
51
52
  elf.each_section do |section|
53
+ # This tool only interests itself with size of sections that are
54
+ # loaded into memory at runtime, and not those that only impact
55
+ # the size of the on-disk file.
56
+ next unless section.flags.include?(Elf::Section::Flags::Alloc)
57
+
52
58
  case
53
59
  # When the section is NoBits, it is not allocated in the file,
54
60
  # and is only allocated in ram, this is the case of .bss and
@@ -65,9 +71,7 @@ def self.analysis(file)
65
71
  #
66
72
  # We check further though since we might want to count it
67
73
  # separately.
68
- when (section.flags.include?(Elf::Section::Flags::Write) and
69
- section.flags.include?(Elf::Section::Flags::Alloc))
70
-
74
+ when section.flags.include?(Elf::Section::Flags::Write)
71
75
  # This makes it GCC-specific but that's just because I
72
76
  # cannot find anything in ELF specs that gives an easy way
73
77
  # to deal with this.
@@ -76,7 +80,21 @@ def self.analysis(file)
76
80
  # the exception of prelinking, where this area can then
77
81
  # become mostly read-only and thus not creating dirty pages.
78
82
  sectype = (section.name =~ /^\.data\.rel\.ro(\..+)?/) ? :relro : :data
79
- when section.flags.include?(Elf::Section::Flags::Alloc)
83
+ # A number of sections are loaded into memory on the image but
84
+ # are not really used for anything beside providing metadata for
85
+ # link editor and loader; these section are an object's
86
+ # "overhead" and can usually be reduced by reducing the amount
87
+ # of symbols exposed by the object itself.
88
+ when (section.class == Elf::StringTable or
89
+ section.class == Elf::SymbolTable or
90
+ section.type == Elf::Section::Type::Dynamic or
91
+ section.type == Elf::Section::Type::GNU::VerDef or
92
+ section.type == Elf::Section::Type::GNU::VerNeed or
93
+ section.type == Elf::Section::Type::GNU::VerSym or
94
+ section.type == Elf::Section::Type::Hash or
95
+ section.type == Elf::Section::Type::GNU::Hash)
96
+ sectype = :overhead
97
+ else
80
98
  sectype = :rodata
81
99
  end
82
100
 
@@ -111,13 +129,17 @@ end
111
129
 
112
130
  def self.standard_size(results, file)
113
131
  if @header
114
- puts " exec data rodata relro bss total filename"
132
+ puts " exec data rodata relro bss overhead total filename"
115
133
  @header = false
116
134
  end
117
135
 
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}"
136
+ printf("% 9d % 9d % 9d % 9d % 9d % 9d % 9d %s\n",
137
+ results[:exec],
138
+ results[:data],
139
+ results[:rodata],
140
+ results[:relro],
141
+ results[:bss],
142
+ results[:overhead],
143
+ results[:total],
144
+ file)
123
145
  end
data/lib/elf.rb CHANGED
@@ -28,15 +28,8 @@ require 'elf/symbol'
28
28
  require 'elf/file'
29
29
  require 'elf/section'
30
30
 
31
- # We need this quite e lot
32
- class Integer
33
- def hex
34
- sprintf "%x", self
35
- end
36
- end
37
-
38
31
  module Elf
39
- VERSION = "1.0.0"
32
+ VERSION = "1.0.1"
40
33
 
41
34
  MagicString = "\177ELF"
42
35
 
data/lib/elf/file.rb CHANGED
@@ -230,7 +230,8 @@ module Elf
230
230
  # When the section header string table index is set to zero,
231
231
  # there is not going to be a string table in the file, this
232
232
  # happens usually when the file is a static ELF file built
233
- # directly with an assembler.
233
+ # directly with an assembler, or when it was passed through
234
+ # the elfkickers' sstrip utility.
234
235
  #
235
236
  # To handle this specific case, set the @string_table attribute
236
237
  # to false, that is distinct from nil, and raise
@@ -316,7 +317,7 @@ module Elf
316
317
  def has_section?(sect_idx_or_name)
317
318
 
318
319
  if sect_idx_or_name.is_a? String and not @string_table.is_a? Elf::Section
319
- return false if @string_table == false
320
+ raise MissingStringTable.new(sect_idx_or_name) if @string_table == false
320
321
  raise StringTableNotLoaded.new(sect_idx_or_name) if @string_table.nil?
321
322
  end
322
323
 
data/lib/elf/symbol.rb CHANGED
@@ -133,14 +133,18 @@ module Elf
133
133
  end
134
134
 
135
135
  rescue Elf::Value::OutOfBound => e
136
- e.append_message("While processing symbol #{@idx}. Symbol info: 0x#{info.hex}")
136
+ e.append_message(sprintf("While processing symbol %d. Symbol 'info' value: 0x%x",
137
+ @idx,
138
+ info))
137
139
  raise e
138
140
  end
139
141
 
140
142
  begin
141
143
  @visibility = Visibility[@other & 0x03]
142
144
  rescue Elf::Value::OutOfBound => e
143
- e.append_message("While procesing symbol #{@idx}. Symbol other info: 0x#{@other.hex}")
145
+ e.append_message(sprintf("While procesing symbol %d. Symbol 'other' value: 0x%x",
146
+ @idx,
147
+ other))
144
148
  raise e
145
149
  end
146
150
 
@@ -223,7 +227,7 @@ module Elf
223
227
  section = if symbol.section.nil?
224
228
  nil
225
229
  elsif symbol.section.is_a?(Integer)
226
- symbol.section.hex
230
+ sprintf("%x", symbol.section)
227
231
  else
228
232
  symbol.section.name
229
233
  end
data/lib/elf/tools.rb CHANGED
@@ -67,14 +67,9 @@ def self.parse_arguments
67
67
  if opt == "--help"
68
68
  # check if we're executing from a tarball or the git repository,
69
69
  # if so we can't use the system man page.
70
- require 'pathname'
71
- filepath = Pathname.new($0)
72
- localman = filepath.dirname + "../manpages" + filepath.basename.sub(".rb", ".1")
73
- if localman.exist?
74
- exec("man #{localman.to_s}")
75
- else
76
- exec("man #{to_s}")
77
- end
70
+ manpage = File.expand_path("../../../manpages/#{to_s}.1", __FILE__)
71
+ manpage = to_s unless File.exist?(manpage)
72
+ exec("man #{manpage}")
78
73
  end
79
74
 
80
75
  attrname = opt.gsub(/^--/, "").gsub("-", "_")
@@ -99,6 +94,16 @@ def self.parse_arguments
99
94
  raise ArgumentError("wrong number of arguments in callback (#{cb.arity} for #{arg.size})")
100
95
  end
101
96
  end
97
+
98
+ @parsed_options = true
99
+ end
100
+
101
+ def self.single_target?
102
+ raise Exception.new("You can't call this until options are parsed") unless @parsed_options
103
+
104
+ # We consider having a single target means that we're given exactly
105
+ # one argument, and that argument is not a targets' list itself.
106
+ return (ARGV.size == 1 and ARGV[0] !~ /^@/)
102
107
  end
103
108
 
104
109
  def execute(filename)
@@ -178,8 +183,6 @@ end
178
183
 
179
184
  # Execute the analysis function on all the lines of a file
180
185
  def self.execute_on_file(file)
181
- @single_target = false
182
-
183
186
  file = $stdin if file == "-"
184
187
  file = File.new(file) if file.class == String
185
188
 
@@ -197,13 +200,6 @@ def self.main
197
200
  parse_arguments
198
201
  after_options if respond_to? :after_options
199
202
 
200
- # We set the @single_target attribute to true if we're given a
201
- # single filename as a target, so that tools like elfgrep can
202
- # avoid printing again the filename on the output. Since we could
203
- # be given a single @-prefixed file to use as a list, we'll reset
204
- # @single_target in self.execute_on_file
205
- @single_target = (ARGV.size == 1)
206
-
207
203
  if ARGV.size == 0
208
204
  execute_on_file($stdin)
209
205
  else
@@ -0,0 +1,234 @@
1
+ <?xml version='1.0'?>
2
+ <!--
3
+ Copyright © 2008-2011, Diego "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
+ <article xmlns="http://docbook.org/ns/docbook"
20
+ xmlns:xl="http://www.w3.org/1999/xlink"
21
+ xmlns:xi="http://www.w3.org/2001/XInclude"
22
+ version="5.0" xml:lang="en">
23
+ <info>
24
+ <title>cowstats</title>
25
+
26
+ <xi:include parse="xml" href="author.xmli" />
27
+ </info>
28
+
29
+ <section>
30
+ <title>Reference</title>
31
+
32
+ <refentry>
33
+ <info>
34
+ <date>October 2008</date>
35
+ <productname>ruby-elf</productname>
36
+ </info>
37
+ <refmeta>
38
+ <refentrytitle>cowstats</refentrytitle>
39
+ <manvolnum>1</manvolnum>
40
+ </refmeta>
41
+ <refnamediv>
42
+ <refname>cowstats</refname>
43
+ <refpurpose>ELF Copy-on-Write analyzer</refpurpose>
44
+ </refnamediv>
45
+ <refsynopsisdiv>
46
+ <cmdsynopsis>
47
+ <command>cowstats</command>
48
+ <arg choice="opt"><option>--statistics</option></arg>
49
+ <arg choice="opt"><option>--total</option></arg>
50
+ <arg choice="opt"><option>--ignore-cxx</option></arg>
51
+ <arg choice="opt"><option>--ignore-profiling</option></arg>
52
+ <arg choice="opt"><option>--ignore-data-rel-ro</option></arg>
53
+ <arg choice="opt">
54
+ <option>--sort-by</option>
55
+ <replaceable>section-column</replaceable>
56
+ </arg>
57
+
58
+ <xi:include href="common.xmli" xpointer="xpointer(id('filelist.synopsis')/*)" />
59
+ </cmdsynopsis>
60
+ </refsynopsisdiv>
61
+
62
+ <refsect1>
63
+ <title>Description</title>
64
+ <para>
65
+ <command>cowstats</command> is a script that analyses ELF object files, results of
66
+ compilation of C, C++ or other languages on an Unix system, and reports about the
67
+ variables that enter Copy-on-Write sections.
68
+ </para>
69
+
70
+ <para>
71
+ Static variables (initialised and not) and constant pointers on PIC or PIE enabled object
72
+ files are emitted in the so-called Copy-on-Write sections, which require copying over
73
+ pages from the original ELF executable file to a private resident area of memory at
74
+ runtime.
75
+ </para>
76
+
77
+ <para>
78
+ <command>cowstats</command> reports the possible symbols that were emitted in
79
+ Copy-on-Write sections so that they can be looked after to see if they can be made
80
+ constant and/or removed or reworked.
81
+ </para>
82
+ </refsect1>
83
+
84
+ <refsect1>
85
+ <title>Options</title>
86
+
87
+ <variablelist>
88
+ <varlistentry>
89
+ <term><option>-s</option></term>
90
+ <term><option>--statistics</option></term>
91
+ <listitem>
92
+ <para>
93
+ Instead of reporting all the variables found in Copy-on-Write sections, only
94
+ generate a table showing the sie of data in Copy-on-Write sections per each file,
95
+ divided into <constant>.data</constant>, <constant>.bss</constant> and
96
+ <constant>.data.rel</constant> (for variables, uninitialised variables, and
97
+ relocated variables and constants).
98
+ </para>
99
+ </listitem>
100
+ </varlistentry>
101
+
102
+ <varlistentry>
103
+ <term><option>-t</option></term>
104
+ <term><option>--total</option></term>
105
+ <listitem>
106
+ <para>
107
+ Shows some rough totals for the amount of data in Copy-on-Write sections for the
108
+ program, assuming all the object files given are linked in the same executable. This
109
+ will also show a rough page-based total, which bases itself on 4K-sized pages.
110
+ </para>
111
+ </listitem>
112
+ </varlistentry>
113
+
114
+ <varlistentry>
115
+ <term><option>-x</option></term>
116
+ <term><option>--ignore-cxx</option></term>
117
+ <listitem>
118
+ <para>
119
+ Ignore some C++ entries that could be considered false positives. C++ object files
120
+ will report as CoW data the vtables and typeinfo objects for C++ classes, since they
121
+ are actually emitted in Copy-on-Write sections. Since they cannot be moved from
122
+ thre, this option hides them on the output, to reduce clutter and noise.
123
+ </para>
124
+ </listitem>
125
+ </varlistentry>
126
+
127
+ <varlistentry>
128
+ <term><option>-p</option></term>
129
+ <term><option>--ignore-profiling</option></term>
130
+ <listitem>
131
+ <para>
132
+ Similarly to C++, also profiling (with <command>gcov</command>) will add some
133
+ symbols that would be identified as CoW data. Use this option to avoid reporting
134
+ those symbols.
135
+ </para>
136
+ </listitem>
137
+ </varlistentry>
138
+
139
+ <varlistentry>
140
+ <term><option>-r</option></term>
141
+ <term><option>--ignore-data-rel-ro</option></term>
142
+ <listitem>
143
+ <para>
144
+ Don't report constants found in the .data.rel.ro section, and consider it as
145
+ non-relocated. This is helpful to reduce the noise when looking for writable data
146
+ symbols, or when analysing non-PIC builds.
147
+ </para>
148
+ </listitem>
149
+ </varlistentry>
150
+
151
+ <varlistentry>
152
+ <term>
153
+ <option>-S</option>
154
+ <replaceable>section-column</replaceable>
155
+ </term>
156
+ <term>
157
+ <option>--sort-by</option>
158
+ <replaceable>section-column</replaceable>
159
+ </term>
160
+
161
+ <listitem>
162
+ <para>
163
+ Sort the output of <option>--statistics</option> by the given column. Useful when
164
+ looking for which objects have the most hit for one particular CoW problem. The
165
+ column can be one of the following section names:
166
+ </para>
167
+
168
+ <itemizedlist>
169
+ <listitem><para>.bss</para></listitem>
170
+ <listitem><para>.data</para></listitem>
171
+ <listitem><para>.data.rel</para></listitem>
172
+ <listitem><para>.data.rel.ro</para></listitem>
173
+ </itemizedlist>
174
+ </listitem>
175
+ </varlistentry>
176
+
177
+ <xi:include href="common.xmli" xpointer="xpointer(id('filelist.option')/*)" />
178
+
179
+ </variablelist>
180
+ </refsect1>
181
+
182
+ <refsect1>
183
+ <title>Bugs</title>
184
+
185
+ <para>
186
+ <command>cowstats</command> is still an experiment, and is
187
+ not yet entirely complete, there are thus a number of bugs
188
+ that haven't been discovered or well tested yet.
189
+ </para>
190
+
191
+ <para>
192
+ A known "bug" or misbehaviour is that <command>cowstats</command> cannot know whether
193
+ multple object files will be linked together in the same module (executable or shared
194
+ object) or not. For this reason the output of <option>--total</option> might not be
195
+ consistent with the runtime behaviour of the module itself.
196
+ </para>
197
+
198
+ <xi:include href="common.xmli" xpointer="xpointer(id('filelist.bugpara')/*)" />
199
+ </refsect1>
200
+
201
+ <refsect1>
202
+ <title>See Also</title>
203
+ <para>
204
+ <citation xl:href="http://blog.flameeyes.eu/">Flameeyes's Weblog</citation>
205
+ http://blog.flameeyes.eu/
206
+ </para>
207
+
208
+ <para>
209
+ Related tools:
210
+
211
+ <citerefentry>
212
+ <refentrytitle>rbelf-size</refentrytitle>
213
+ <manvolnum>1</manvolnum>
214
+ </citerefentry>,
215
+
216
+ <citerefentry>
217
+ <refentrytitle>objdump</refentrytitle>
218
+ <manvolnum>1</manvolnum>
219
+ </citerefentry>.
220
+ </para>
221
+ </refsect1>
222
+ </refentry>
223
+ </section>
224
+ </article>
225
+ <!--
226
+ Local Variables:
227
+ mode: nxml
228
+ mode: auto-fill
229
+ mode: flyspell
230
+ ispell-local-dictionary: "english"
231
+ fill-column: 100
232
+ indent-tabs-mode: nil
233
+ End:
234
+ -->