ruby-elf 1.0.7 → 1.0.8

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.
@@ -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