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.
- data/README.md +64 -0
- data/lib/elf.rb +1 -1
- data/ruby-elf.gemspec +29 -0
- metadata +38 -74
- data/bin/cowstats +0 -266
- data/bin/elfgrep +0 -246
- data/bin/missingstatic +0 -113
- data/bin/rbelf-nm +0 -113
- data/bin/rbelf-read +0 -146
- data/bin/rbelf-size +0 -184
- data/bin/verify-lfs +0 -125
- data/extras/README.extras +0 -5
- data/extras/bindings-parsers.rb +0 -157
- data/manpages/cowstats.1.xml +0 -234
- data/manpages/elfgrep.1.xml +0 -423
- data/manpages/missingstatic.1.xml +0 -290
- data/manpages/rbelf-nm.1.xml +0 -339
- data/manpages/rbelf-size.1.xml +0 -345
- data/manpages/verify-lfs.1.xml +0 -136
- data/tools/link-collisions/known-broken +0 -154
- data/tools/link-collisions/multimplementations +0 -170
- data/tools/link-collisions/suppressions +0 -287
data/bin/rbelf-read
DELETED
@@ -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
|
data/bin/rbelf-size
DELETED
@@ -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
|
data/bin/verify-lfs
DELETED
@@ -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
|