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/rbelf-read ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # Copyright © 2008-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
+ # proof-of-concept reimplementation of readelf(1)
20
+
21
+ require 'elf/tools'
22
+
23
+ module Elf::Tools
24
+ class ReadElf < Elf::Tool
25
+ def self.initialize
26
+ super
27
+ @options |= [
28
+ ["--all", "-a", GetoptLong::NO_ARGUMENT],
29
+ ["--section-headers", "-S", GetoptLong::NO_ARGUMENT],
30
+ ["--dynamic", "-d", GetoptLong::NO_ARGUMENT],
31
+ ]
32
+ end
33
+
34
+ def self.all_cb
35
+ @section_headers = true
36
+ @dynamic = true
37
+ end
38
+
39
+ def self.after_options
40
+ end
41
+
42
+ def self.analysis(file)
43
+ elf = Elf::File.open(file)
44
+
45
+ @addrsize = (elf.elf_class == Elf::Class::Elf32 ? 8 : 16)
46
+
47
+ @output_mutex.synchronize {
48
+ printf("\nFile: %s\n", file) if @targets.size != 1
49
+ read_sections(elf) if @section_headers
50
+ read_dynamic(elf) if @dynamic
51
+ }
52
+ end
53
+
54
+ def self.read_sections(elf)
55
+ printf("There are %d section headers, starting at offset 0x%x:\n\nSection Headers:\n",
56
+ elf.sections, elf.shoff)
57
+
58
+ printf("[Nr] Name Type Addr Off Size ES Flags Lk Inf Al\n")
59
+
60
+ elf.each_section do |section|
61
+ printf("[%2d] %s %s %0#{@addrsize}x %08x %08x %2d %s %2d %3d %2d\n",
62
+ section.index,
63
+ section.name.ljust(20),
64
+ section.type.mnemonic.upcase.ljust(13),
65
+ section.addr, section.offset, section.size, section.entsize,
66
+ section.flags_s.ljust(5), section.link.to_i, section.info, section.addralign)
67
+ end
68
+
69
+ printf("\n")
70
+ end
71
+
72
+ def self.read_dynamic(elf)
73
+ dynsection = elf[".dynamic"]
74
+
75
+ if dynsection.nil?
76
+ printf("\nThere is no dynamic section in this file.\n")
77
+ return
78
+ end
79
+
80
+ printf("\nDynamic section at offset 0x%x contains %d entries:\n",
81
+ dynsection.offset, dynsection.size)
82
+ printf(" Tag Type Name/Value\n")
83
+
84
+ dynsection.each_entry do |entry|
85
+ case entry.type
86
+ when Elf::Dynamic::Type::Needed
87
+ val = "Shared library: [#{entry.parsed}]"
88
+ when Elf::Dynamic::Type::Auxiliary
89
+ val = "Auxiliary library: [#{entry.parsed}]"
90
+ when Elf::Dynamic::Type::SoName
91
+ val = "Library soname: [#{entry.parsed}]"
92
+ when Elf::Dynamic::Type::StrSz, Elf::Dynamic::Type::SymEnt,
93
+ Elf::Dynamic::Type::PltRelSz, Elf::Dynamic::Type::RelASz,
94
+ Elf::Dynamic::Type::RelAEnt
95
+
96
+ val = "#{entry.value} (bytes)"
97
+ when Elf::Dynamic::Type::VerDefNum, Elf::Dynamic::Type::VerNeedNum, Elf::Dynamic::Type::RelACount
98
+ val = entry.value
99
+ when Elf::Dynamic::Type::GNUPrelinked
100
+ val = entry.parsed.getutc.strftime('%Y-%m-%dT%H:%M:%S')
101
+ else
102
+ val = sprintf("0x%x", entry.value)
103
+ end
104
+
105
+ printf(" 0x%016x %-20s %s\n", entry.type.to_i, "(#{entry.type.to_s})", val)
106
+
107
+ break if entry.type == Elf::Dynamic::Type::Null
108
+ end
109
+ end
110
+ end
111
+ end
data/bin/rbelf-size CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- mode: ruby; coding: utf-8 -*-
3
- # Copyright © 2008-2010 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
3
+ # Copyright © 2008-2011 Diego E. "Flameeyes" Pettenò <flameeyes@gmail.com>
4
4
  #
5
5
  # This program is free software; you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -20,126 +20,163 @@
20
20
 
21
21
  require 'elf/tools'
22
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
- ]
23
+ module Elf::Tools
24
+ class Size < Elf::Tool
25
+ def self.initialize
26
+ super
27
+ @options |= [
28
+ # Give relocation data for shared object assesment
29
+ ["--relocation-stats", "-r", GetoptLong::NO_ARGUMENT],
30
+ # Use deciBel scale for the shared-to-relocated ratio
31
+ ["--decibel", "-d", GetoptLong::NO_ARGUMENT],
32
+ # Show differences between the first parameter and
33
+ # the following.
34
+ ["--differential", "-D", GetoptLong::NO_ARGUMENT],
35
+ ]
36
+
37
+ @relocation_stats = false
38
+ end
29
39
 
30
- def self.before_options
31
- @relocation_stats = false
32
- end
40
+ def self.after_options
41
+ # to properly handle the differential size count, we have to
42
+ # process all the files in sequence; this means that we cannot
43
+ # use multithreaded scan here.
44
+ @execution_threads = nil if @differential
33
45
 
34
- def self.after_options
35
- @header = true
36
- end
46
+ @processing = []
37
47
 
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
- :overhead => 0,
47
- :total => 0
48
- }
49
-
50
- # Get the size of each section, and then, depending on its type,
51
- # flags and eventually name, decide what to sum it to.
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
-
58
- case
59
- # When the section is NoBits, it is not allocated in the file,
60
- # and is only allocated in ram, this is the case of .bss and
61
- # .tbss sections.
62
- when section.type == Elf::Section::Type::NoBits
63
- sectype = :bss
64
- # If the section contains executable code, count it separately;
65
- # size(1) will count it all as text, but we don't need to do
66
- # that.
67
- when section.flags.include?(Elf::Section::Flags::ExecInstr)
68
- sectype = :exec
69
- # If the section is going to be allocated and writeable at
70
- # runtime, it is usually a data section, of some kind.
71
- #
72
- # We check further though since we might want to count it
73
- # separately.
74
- when section.flags.include?(Elf::Section::Flags::Write)
75
- # This makes it GCC-specific but that's just because I
76
- # cannot find anything in ELF specs that gives an easy way
77
- # to deal with this.
78
- #
79
- # By all means, .data.rel.ro is just the same as .data, with
80
- # the exception of prelinking, where this area can then
81
- # become mostly read-only and thus not creating dirty pages.
82
- sectype = (section.name =~ /^\.data\.rel\.ro(\..+)?/) ? :relro : :data
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
48
+ results_formats = {:filename => " %s\n"}
49
+
50
+ if @relocation_stats
51
+ @processing << :relocation_stats
52
+ @processing << :convert_ratio if @decibel
53
+ @results_fields = [ :shared, :private, :relocated, :ratio, :filename ]
97
54
  else
98
- sectype = :rodata
55
+ @processing << :count_allocated
56
+ @results_fields = [ :exec, :data, :rodata, :relro, :bss, :overhead, :allocated, :filename ]
99
57
  end
100
58
 
101
- results[sectype] += section.size unless sectype.nil?
59
+ @processing << :apply_differential if @differential
60
+ @processing << :print_results
61
+ @processing << :differential_format if @differential
62
+
63
+ printf( (@results_fields.collect { |field| results_formats[field] || "% 12s" }).join(" "),
64
+ *@results_fields)
65
+
66
+ results_formats[:ratio] = "%12.2f" # special format only for printing
67
+
68
+ @format = (@results_fields.collect { |field| results_formats[field] || "% 12d" }).join(" ")
102
69
  end
103
70
 
104
- results[:total] = results.values.inject { |sum, val| sum += val }
71
+ def self.analysis(file)
72
+ Elf::File.open(file) do |elf|
73
+ results = {
74
+ :exec => 0,
75
+ :data => 0,
76
+ :rodata => 0,
77
+ :relro => 0,
78
+ :bss => 0,
79
+ :overhead => 0,
80
+ :allocated => 0
81
+ }
82
+
83
+ # Get the size of each section, and then, depending on its type,
84
+ # flags and eventually name, decide what to sum it to.
85
+ elf.each_section do |section|
86
+ # This tool only interests itself with size of sections that are
87
+ # loaded into memory at runtime, and not those that only impact
88
+ # the size of the on-disk file.
89
+ next unless section.flags.include?(Elf::Section::Flags::Alloc)
90
+
91
+ case
92
+ # When the section is NoBits, it is not allocated in the file,
93
+ # and is only allocated in ram, this is the case of .bss and
94
+ # .tbss sections.
95
+ when section.type == Elf::Section::Type::NoBits
96
+ sectype = :bss
97
+ # If the section contains executable code, count it separately;
98
+ # size(1) will count it all as text, but we don't need to do
99
+ # that.
100
+ when section.flags.include?(Elf::Section::Flags::ExecInstr)
101
+ sectype = :exec
102
+ # If the section is going to be allocated and writeable at
103
+ # runtime, it is usually a data section, of some kind.
104
+ #
105
+ # We check further though since we might want to count it
106
+ # separately.
107
+ when section.flags.include?(Elf::Section::Flags::Write)
108
+ # This makes it GCC-specific but that's just because I
109
+ # cannot find anything in ELF specs that gives an easy way
110
+ # to deal with this.
111
+ #
112
+ # By all means, .data.rel.ro is just the same as .data, with
113
+ # the exception of prelinking, where this area can then
114
+ # become mostly read-only and thus not creating dirty pages.
115
+ sectype = (section.name =~ /^\.data\.rel\.ro(\..+)?/) ? :relro : :data
116
+ # A number of sections are loaded into memory on the image but
117
+ # are not really used for anything beside providing metadata for
118
+ # link editor and loader; these section are an object's
119
+ # "overhead" and can usually be reduced by reducing the amount
120
+ # of symbols exposed by the object itself.
121
+ when (section.class == Elf::StringTable or
122
+ section.class == Elf::SymbolTable or
123
+ section.type == Elf::Section::Type::Dynamic or
124
+ section.type == Elf::Section::Type::GNU::VerDef or
125
+ section.type == Elf::Section::Type::GNU::VerNeed or
126
+ section.type == Elf::Section::Type::GNU::VerSym or
127
+ section.type == Elf::Section::Type::Hash or
128
+ section.type == Elf::Section::Type::GNU::Hash)
129
+ sectype = :overhead
130
+ else
131
+ sectype = :rodata
132
+ end
133
+
134
+ results[sectype] += section.size unless sectype.nil?
135
+ end
136
+
137
+ results[:filename] = file
138
+
139
+ @processing.each do |process|
140
+ method(process).call(results)
141
+ end
142
+ end
143
+ end
105
144
 
106
- if @relocation_stats
107
- relocation_stats(results, file)
108
- else
109
- standard_size(results, file)
145
+ def self.count_allocated(results)
146
+ results[:allocated] = results.values.inject { |sum, val| sum += val rescue sum}
110
147
  end
111
- end
112
- end
113
148
 
114
- def self.relocation_stats(results, file)
115
- if @header
116
- puts " shared private relocated ratio filename"
117
- @header = false
118
- end
149
+ def self.apply_differential(results)
150
+ if @first_results.nil?
151
+ (@first_results = results.dup).delete(:filename)
152
+ return
153
+ end
119
154
 
120
- size_shared = results[:exec] + results[:rodata]
121
- size_private = results[:data] + results[:bss]
122
- size_relocated = results[:relro]
155
+ @results_fields.each do |field|
156
+ results[field] = results[field] - @first_results[field] rescue nil
157
+ end
158
+ end
123
159
 
124
- ratio = size_shared.to_f/size_relocated
125
- ratio = 10 * Math::log10(ratio) if @decibel
160
+ def self.differential_format(results)
161
+ @format.gsub!(/%( [0-9]+d)/, '%+\1')
162
+ @processing.delete(:differential_format)
163
+ end
126
164
 
127
- printf "% 12s % 12s % 12s % 12.2f %s\n", size_shared, size_private, size_relocated, ratio, file
128
- end
165
+ def self.relocation_stats(results)
166
+ results[:shared] = results[:exec] + results[:rodata]
167
+ results[:private] = results[:data] + results[:bss]
168
+ results[:relocated] = results[:relro]
129
169
 
130
- def self.standard_size(results, file)
131
- if @header
132
- puts " exec data rodata relro bss overhead total filename"
133
- @header = false
134
- end
170
+ results[:ratio] = results[:shared].to_f/results[:relocated]
171
+ end
172
+
173
+ def self.convert_ratio(results)
174
+ results[:ratio] = 10 * Math::log10(results[:ratio])
175
+ end
135
176
 
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)
177
+ def self.print_results(results)
178
+ printf(@format,
179
+ *(@results_fields.collect { |field| results[field] }))
180
+ end
181
+ end
145
182
  end
data/bin/verify-lfs CHANGED
@@ -21,100 +21,105 @@
21
21
 
22
22
  require 'elf/tools'
23
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"
24
+ module Elf::Tools
25
+ class VerifyLFS < Elf::Tool
26
+ SymbolNamesList = [
27
+ "__[fl]?xstat",
28
+ "statv?fs",
29
+ "(|_IO_)f[gs]etpos",
30
+ "(read|scan)dir",
31
+ "getdirentries",
32
+ "mko?stemp",
33
+ "(|__)p(read|write)",
34
+ "p(read|write)v",
35
+ "(send|tmp)file",
36
+ "[gs]etrlimit",
37
+ "versionsort",
38
+ "f?truncate",
39
+ "(|f(|re))open",
40
+ "openat",
41
+ "fseeko",
42
+ "ftello",
43
+ "lseek",
44
+ "glob(|free)",
45
+ "ftw",
46
+ "lockf"
47
+ ]
48
+
49
+ SymbolRegex32 = Regexp.union(SymbolNamesList.collect { |sym| /^#{sym}$/ })
50
+ SymbolRegex64 = Regexp.union(SymbolNamesList.collect { |sym| /^#{sym}64$/ })
51
+
52
+ def self.initialize
53
+ super
54
+ @options |= [
55
+ # Scan only object files (rather than non-object files)
56
+ ["--objects", "-o", GetoptLong::NO_ARGUMENT]
50
57
  ]
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
58
  end
83
59
 
84
- if elf.elf_class == Elf::Class::Elf64
85
- putnotice "#{file}: testing 64-bit ELF files is meaningless"
86
- next
60
+ def self.after_options
61
+ @files_mixing = []
62
+ @files_nolfs = []
63
+
64
+ if @objects
65
+ @elftypes = [ Elf::File::Type::Rel ]
66
+ @elfdescr = "a relocatable object file"
67
+ @elftable = ".symtab"
68
+ else
69
+ @elftypes = [ Elf::File::Type::Exec, Elf::File::Type::Dyn ]
70
+ @elfdescr = "an executable or dynamic file"
71
+ @elftable = ".dynsym"
72
+ end
87
73
  end
88
74
 
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
75
+ def self.analysis(file)
76
+ Elf::File.open(file) do |elf|
77
+ unless @elftypes.include? elf.type
78
+ putnotice "#{file}: not #{@elfdescr}"
79
+ next
80
+ end
81
+
82
+ if not elf.has_section?(@elftable) or elf[@elftable].class != Elf::SymbolTable
83
+ putnotice "#{file}: not a dynamically linked file"
84
+ next
85
+ end
86
+
87
+ if elf.elf_class == Elf::Class::Elf64
88
+ putnotice "#{file}: testing 64-bit ELF files is meaningless"
89
+ next
90
+ end
91
+
92
+ use_stat32 = false
93
+ use_stat64 = false
94
+
95
+ elf[@elftable].each do |symbol|
96
+ next unless symbol.section == Elf::Section::Undef
97
+
98
+ use_stat32 ||= (symbol.to_s =~ SymbolRegex32)
99
+ use_stat64 ||= (symbol.to_s =~ SymbolRegex64)
100
+
101
+ # avoid running the whole list if we hit both as we cannot hit
102
+ # _more_
103
+ break if use_stat32 and use_stat64
104
+ end
105
+
106
+ if use_stat32 and use_stat64
107
+ @files_mixing << file
108
+ elsif use_stat32 and not use_stat64
109
+ @files_nolfs << file
110
+ end
111
+ end
101
112
  end
102
113
 
103
- if use_stat32 and use_stat64
104
- @files_mixing << file
105
- elsif use_stat32 and not use_stat64
106
- @files_nolfs << file
114
+ def self.results
115
+ if @files_mixing.size > 0
116
+ puts "The following files are mixing LFS and non-LFS library calls:"
117
+ puts " " + @files_mixing.join("\n ")
118
+ end
119
+ if @files_nolfs.size > 0
120
+ puts "The following files are using non-LFS library calls:"
121
+ puts " " + @files_nolfs.join("\n ")
122
+ end
107
123
  end
108
124
  end
109
125
  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