ruby-elf 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,146 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # -*- mode: ruby; coding: utf-8 -*-
3
- # Copyright © 2008-2011 Diego Elio Pettenò <flameeyes@flameeyes.eu>
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
- ["--file-header", "-h", GetoptLong::NO_ARGUMENT],
30
- ["--section-headers", "-S", GetoptLong::NO_ARGUMENT],
31
- ["--dynamic", "-d", GetoptLong::NO_ARGUMENT],
32
- ]
33
- end
34
-
35
- def self.all_cb
36
- @section_headers = true
37
- @dynamic = true
38
- end
39
-
40
- def self.after_options
41
- end
42
-
43
- def self.analysis(file)
44
- elf = Elf::File.open(file)
45
-
46
- @output_mutex.synchronize {
47
- printf("\nFile: %s\n", file) if @targets.size != 1
48
- read_file_header(elf) if @file_header
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#{elf.address_print_size}x %08x %08x %2d %s %2d %3d %2d\n",
62
- section.index,
63
- section.name.ljust(23),
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
-
111
- def self.put_header(key, value)
112
- printf " %s %s\n", "#{key}:".ljust(34), value
113
- end
114
-
115
- def self.read_file_header(elf)
116
- puts "ELF Header:"
117
- # put this verbatim, since it never should change
118
- puts " Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00"
119
-
120
- put_header("Class", case elf.elf_class
121
- when Elf::Class::Elf32 then "ELF32"
122
- when Elf::Class::Elf64 then "ELF64"
123
- end)
124
- put_header("Data", "2's complement, " + case elf.data_encoding
125
- when Elf::DataEncoding::Lsb then 'little endian'
126
- when Elf::DataEncoding::Msb then 'big endian'
127
- end)
128
- put_header("Ident Version", elf.version)
129
- put_header("OS/ABI", elf.abi)
130
- put_header("ABI Version", elf.abi_version)
131
- put_header("Type", "#{elf.type.mnemonic.upcase} (#{elf.type})")
132
- put_header("Machine", elf.machine)
133
- put_header("Version", elf.version)
134
- put_header("Entry point address", sprintf("0x%x", elf.entry_address))
135
- put_header("Start of program headers", "#{elf.phoff} (bytes into file)")
136
- put_header("Start of section headers", "#{elf.shoff} (bytes into file)")
137
- put_header("Flags", sprintf("0x%x", elf.flags))
138
- put_header("Size of this header", "#{elf.ehsize} (bytes)")
139
- put_header("Size of program headers", "#{elf.phentsize} (bytes)")
140
- put_header("Number of program headers", elf.phnum);
141
- put_header("Size of section headers", "#{elf.shentsize} (bytes)")
142
- put_header("Number of section headers", elf.shnum)
143
- put_header("Section header string table index", elf.shstrndx)
144
- end
145
- end
146
- end
@@ -1,184 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # -*- mode: ruby; coding: utf-8 -*-
3
- # Copyright © 2008-2011 Diego Elio Pettenò <flameeyes@flameeyes.eu>
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
- 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
39
-
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
45
-
46
- @processing = []
47
-
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 ]
54
- else
55
- @processing << :count_allocated
56
- @results_fields = [ :exec, :data, :rodata, :relro, :bss, :overhead, :allocated, :filename ]
57
- end
58
-
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(" ")
69
- end
70
-
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
144
-
145
- def self.count_allocated(results)
146
- results[:allocated] = results.values.inject { |sum, val|
147
- sum = val.is_a?(String) ? sum : (sum+val)
148
- }
149
- end
150
-
151
- def self.apply_differential(results)
152
- if @first_results.nil?
153
- (@first_results = results.dup).delete(:filename)
154
- return
155
- end
156
-
157
- @results_fields.each do |field|
158
- results[field] = results[field] - @first_results[field] rescue nil
159
- end
160
- end
161
-
162
- def self.differential_format(results)
163
- @format.gsub!(/%( [0-9]+d)/, '%+\1')
164
- @processing.delete(:differential_format)
165
- end
166
-
167
- def self.relocation_stats(results)
168
- results[:shared] = results[:exec] + results[:rodata]
169
- results[:private] = results[:data] + results[:bss]
170
- results[:relocated] = results[:relro]
171
-
172
- results[:ratio] = results[:shared].to_f/results[:relocated]
173
- end
174
-
175
- def self.convert_ratio(results)
176
- results[:ratio] = 10 * Math::log10(results[:ratio])
177
- end
178
-
179
- def self.print_results(results)
180
- printf(@format,
181
- *(@results_fields.collect { |field| results[field] }))
182
- end
183
- end
184
- end
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # -*- mode: ruby; coding: utf-8 -*-
3
- # Copyright © 2010 Diego Elio Pettenò <flameeyes@flameeyes.eu>
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
- 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]
57
- ]
58
- end
59
-
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
73
- end
74
-
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
112
- end
113
-
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
123
- end
124
- end
125
- end