Class: Elf::File
- Inherits:
-
File
- Object
- File
- Elf::File
- Includes:
- BytestreamReader
- Defined in:
- lib/elf/file.rb
Defined Under Namespace
Modules: ARM Classes: InvalidDataEncoding, InvalidElfClass, InvalidElfType, InvalidMachine, InvalidOsAbi, MissingSection, MissingStringTable, NotAnELF, StringTableNotLoaded, Type, UnsupportedElfVersion
Constant Summary
Constants included from BytestreamReader
BytestreamReader::BigEndian, BytestreamReader::LittleEndian
Instance Attribute Summary collapse
-
#abi ⇒ Object
readonly
Returns the value of attribute abi.
-
#abi_version ⇒ Object
readonly
Returns the value of attribute abi_version.
-
#data_encoding ⇒ Object
readonly
Returns the value of attribute data_encoding.
-
#ehsize ⇒ Object
readonly
Returns the value of attribute ehsize.
-
#elf_class ⇒ Object
readonly
Returns the value of attribute elf_class.
-
#entry_address ⇒ Object
readonly
Returns the value of attribute entry_address.
-
#flags ⇒ Object
readonly
Returns the value of attribute flags.
-
#machine ⇒ Object
readonly
Returns the value of attribute machine.
-
#phentsize ⇒ Object
readonly
Returns the value of attribute phentsize.
-
#phnum ⇒ Object
readonly
Returns the value of attribute phnum.
-
#phoff ⇒ Object
readonly
Returns the value of attribute phoff.
-
#shentsize ⇒ Object
readonly
Returns the value of attribute shentsize.
-
#shnum ⇒ Object
readonly
Returns the value of attribute shnum.
-
#shoff ⇒ Object
readonly
raw data access.
-
#shstrndx ⇒ Object
readonly
Returns the value of attribute shstrndx.
-
#string_table ⇒ Object
readonly
Returns the value of attribute string_table.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Instance Method Summary collapse
- #[](sect_idx_or_name) ⇒ Object
-
#address_print_size ⇒ Object
Returns the hex address size for the file.
- #arm_be8? ⇒ Boolean
- #arm_eabi_version ⇒ Object
- #each_section ⇒ Object
- #find_section_by_addr(addr) ⇒ Object
- #has_section?(sect_idx_or_name) ⇒ Boolean
-
#initialize(path) ⇒ File
constructor
A new instance of File.
-
#is_compatible(other) ⇒ Object
Checks whether two ELF files are compatible one with the other for linking.
- #load_section(sect_idx_or_name) ⇒ Object
- #read_addr ⇒ Object
- #read_off ⇒ Object
- #sections ⇒ Object
- #summary ⇒ Object
Methods included from BytestreamReader
#read_array_s16_be, #read_array_s16_le, #read_array_s32_be, #read_array_s32_le, #read_array_s64_be, #read_array_s64_le, #read_array_s8, #read_array_u16_be, #read_array_u16_le, #read_array_u32_be, #read_array_u32_le, #read_array_u64_be, #read_array_u64_le, #read_array_u8, #read_s16, #read_s16_be, #read_s16_le, #read_s32, #read_s32_be, #read_s32_le, #read_s64, #read_s64_be, #read_s64_le, #read_s8, #read_u16, #read_u16_be, #read_u16_le, #read_u32, #read_u32_be, #read_u32_le, #read_u64, #read_u64_be, #read_u64_le, #read_u8, #readexactly, #set_endian
Constructor Details
#initialize(path) ⇒ File
Returns a new instance of File.
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/elf/file.rb', line 152 def initialize(path) _checkvalidpath(path) super(path, "rb") begin begin raise NotAnELF unless readexactly(4) == MagicString rescue EOFError raise NotAnELF end begin @elf_class = Class[read_u8] rescue Value::OutOfBound => e raise InvalidElfClass.new(e.val) end begin @data_encoding = DataEncoding[read_u8] rescue Value::OutOfBound => e raise InvalidDataEncoding.new(e.val) end @version = read_u8 raise UnsupportedElfVersion.new(@version) if @version > 1 begin @abi = OsAbi[read_u8] rescue Value::OutOfBound => e raise InvalidOsAbi.new(e.val) end @abi_version = read_u8 seek(16, IO::SEEK_SET) set_endian(DataEncoding::BytestreamMapping[@data_encoding]) begin @type = Type[read_half] rescue Value::OutOfBound => e raise InvalidElfType.new(e.val) end begin @machine = Machine[read_half] rescue Value::OutOfBound => e raise InvalidMachine.new(e.val) end @version = read_word @entry_address = read_addr @phoff = read_off @shoff = read_off @flags = read_word @ehsize = read_half @phentsize = read_half @phnum = read_half @shentsize = read_half @shnum = read_half @shstrndx = read_half elf32 = elf_class == Class::Elf32 @sections = {} @sections_data = [] seek(@shoff) for i in 1..@shnum sectdata = {} sectdata[:idx] = i-1 sectdata[:name_idx] = read_word sectdata[:type_id] = read_word sectdata[:flags_val] = elf32 ? read_word : read_xword sectdata[:addr] = read_addr sectdata[:offset] = read_off sectdata[:size] = elf32 ? read_word : read_xword sectdata[:link] = read_word sectdata[:info] = read_word sectdata[:addralign] = elf32 ? read_word : read_xword sectdata[:entsize] = elf32 ? read_word : read_xword @sections_data << sectdata end # When the section header string table index is set to zero, # there is not going to be a string table in the file, this # happens usually when the file is a static ELF file built # directly with an assembler, or when it was passed through # the elfkickers' sstrip utility. # # To handle this specific case, set the @string_table attribute # to false, that is distinct from nil, and raise # MissingStringTable on request. If the string table is not yet # loaded raise instead StringTableNotLoaded. if @shstrndx == 0 or not self[@shstrndx].is_a? StringTable @string_table = false else @string_table = self[@shstrndx] @sections_names = {} @sections_data.each do |sectdata| @sections_names[@string_table[sectdata[:name_idx]]] = sectdata[:idx] end end rescue ::Exception => e close raise e end end |
Instance Attribute Details
#abi ⇒ Object (readonly)
Returns the value of attribute abi.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def abi @abi end |
#abi_version ⇒ Object (readonly)
Returns the value of attribute abi_version.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def abi_version @abi_version end |
#data_encoding ⇒ Object (readonly)
Returns the value of attribute data_encoding.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def data_encoding @data_encoding end |
#ehsize ⇒ Object (readonly)
Returns the value of attribute ehsize.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def ehsize @ehsize end |
#elf_class ⇒ Object (readonly)
Returns the value of attribute elf_class.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def elf_class @elf_class end |
#entry_address ⇒ Object (readonly)
Returns the value of attribute entry_address.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def entry_address @entry_address end |
#flags ⇒ Object (readonly)
Returns the value of attribute flags.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def flags @flags end |
#machine ⇒ Object (readonly)
Returns the value of attribute machine.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def machine @machine end |
#phentsize ⇒ Object (readonly)
Returns the value of attribute phentsize.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def phentsize @phentsize end |
#phnum ⇒ Object (readonly)
Returns the value of attribute phnum.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def phnum @phnum end |
#phoff ⇒ Object (readonly)
Returns the value of attribute phoff.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def phoff @phoff end |
#shentsize ⇒ Object (readonly)
Returns the value of attribute shentsize.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def shentsize @shentsize end |
#shnum ⇒ Object (readonly)
Returns the value of attribute shnum.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def shnum @shnum end |
#shoff ⇒ Object (readonly)
raw data access
93 94 95 |
# File 'lib/elf/file.rb', line 93 def shoff @shoff end |
#shstrndx ⇒ Object (readonly)
Returns the value of attribute shstrndx.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def shstrndx @shstrndx end |
#string_table ⇒ Object (readonly)
Returns the value of attribute string_table.
90 91 92 |
# File 'lib/elf/file.rb', line 90 def string_table @string_table end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def type @type end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
86 87 88 |
# File 'lib/elf/file.rb', line 86 def version @version end |
Instance Method Details
#[](sect_idx_or_name) ⇒ Object
299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/elf/file.rb', line 299 def [](sect_idx_or_name) if sect_idx_or_name.is_a? String and not @string_table.is_a? Elf::Section raise MissingStringTable.new(sect_idx_or_name) if @string_table == false raise StringTableNotLoaded.new(sect_idx_or_name) if @string_table.nil? end load_section(sect_idx_or_name) unless @sections.has_key? sect_idx_or_name return @sections[sect_idx_or_name] end |
#address_print_size ⇒ Object
Returns the hex address size for the file.
Since each ELF file uses either 32- or 64-bit addresses, it is important to know how many characters a file’s address would require when printed as an hexadecimal string.
347 348 349 |
# File 'lib/elf/file.rb', line 347 def address_print_size (@elf_class == Elf::Class::Elf32 ? 8 : 16) end |
#arm_be8? ⇒ Boolean
401 402 403 404 405 |
# File 'lib/elf/file.rb', line 401 def arm_be8? return nil if machine != Elf::Machine::ARM return (@flags & ARM::EFlags_BE8) == ARM::EFlags_BE8 end |
#arm_eabi_version ⇒ Object
395 396 397 398 399 |
# File 'lib/elf/file.rb', line 395 def arm_eabi_version return nil if machine != Elf::Machine::ARM return (@flags & ARM::EFlags_EABI_Mask) >> 24 end |
#each_section ⇒ Object
311 312 313 314 315 316 |
# File 'lib/elf/file.rb', line 311 def each_section @sections_data.each do |sectdata| load_section(sectdata[:idx]) yield @sections[sectdata[:idx]] end end |
#find_section_by_addr(addr) ⇒ Object
318 319 320 321 322 323 324 |
# File 'lib/elf/file.rb', line 318 def find_section_by_addr(addr) @sections_data.each do |sectdata| next unless sectdata[:addr] == addr load_section(sectdata[:idx]) return @sections[sectdata[:idx]] end end |
#has_section?(sect_idx_or_name) ⇒ Boolean
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/elf/file.rb', line 326 def has_section?(sect_idx_or_name) if sect_idx_or_name.is_a? String and not @string_table.is_a? Elf::Section raise MissingStringTable.new(sect_idx_or_name) if @string_table == false raise StringTableNotLoaded.new(sect_idx_or_name) if @string_table.nil? end if sect_idx_or_name.is_a? Integer return @sections_data[sect_idx_or_name] != nil elsif sect_idx_or_name.is_a? String return @sections_names.has_key?(sect_idx_or_name) else raise TypeError.new("wrong argument type #{sect_idx_or_name.class} (expected String or Integer)") end end |
#is_compatible(other) ⇒ Object
Checks whether two ELF files are compatible one with the other for linking
This function has to check whether two ELF files can be linked together (either at build time or at load time), and thus checks for class, encoding, versioning, ABI and machine type.
Note that it explicitly does not check for ELF file type since you can link different type of files together, like an Executable with a Dynamic library.
373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/elf/file.rb', line 373 def is_compatible(other) raise TypeError.new("wrong argument type #{other.class} (expected Elf::File)") unless other.is_a? Elf::File compatible_abi = (@abi.linux_compatible? && other.abi.linux_compatible?) \ || ([@abi, @abi_version] == [other.abi, other.abi_version]) @elf_class == other.elf_class and @data_encoding == other.data_encoding and @version == other.version and @machine == other.machine and compatible_abi end |
#load_section(sect_idx_or_name) ⇒ Object
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/elf/file.rb', line 267 def load_section(sect_idx_or_name) if sect_idx_or_name.is_a? Integer raise MissingSection.new(sect_idx_or_name) unless @sections_data[sect_idx_or_name] @sections[sect_idx_or_name] = Section.read(self, sect_idx_or_name, @sections_data[sect_idx_or_name]) else raise MissingSection.new(sect_idx_or_name) unless @sections_names[sect_idx_or_name] load_section @sections_names[sect_idx_or_name] @sections[sect_idx_or_name] = @sections[@sections_names[sect_idx_or_name]] end end |
#read_addr ⇒ Object
95 96 97 98 99 100 |
# File 'lib/elf/file.rb', line 95 def read_addr case @elf_class when Class::Elf32 then read_u32 when Class::Elf64 then read_u64 end end |
#read_off ⇒ Object
102 103 104 105 106 107 |
# File 'lib/elf/file.rb', line 102 def read_off case @elf_class when Class::Elf32 then read_u32 when Class::Elf64 then read_u64 end end |
#sections ⇒ Object
295 296 297 |
# File 'lib/elf/file.rb', line 295 def sections return @sections_data.size end |
#summary ⇒ Object
351 352 353 354 355 356 357 358 359 360 361 362 |
# File 'lib/elf/file.rb', line 351 def summary $stdout.puts "ELF file #{path}" $stdout.puts "ELF class: #{@elf_class} #{@data_encoding} ver. #{@version}" $stdout.puts "ELF ABI: #{@abi} ver. #{@abi_version}" $stdout.puts "ELF type: #{@type} machine: #{@machine}" $stdout.puts "Sections:" @sections.values.uniq.each do |sh| sh.summary end return nil end |