diff --git a/Gemfile.lock b/Gemfile.lock index ab95540..44cce82 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,12 +11,12 @@ GEM bindata (2.4.4) coderay (1.1.2) diff-lcs (1.3) - docile (1.3.0) + docile (1.3.1) jaro_winkler (1.5.1) json (2.1.0) method_source (0.9.0) parallel (1.12.1) - parser (2.5.1.0) + parser (2.5.1.2) ast (~> 2.4.0) powerpack (0.1.2) pry (0.11.3) @@ -30,22 +30,22 @@ GEM rspec-mocks (~> 3.8.0) rspec-core (3.8.0) rspec-support (~> 3.8.0) - rspec-expectations (3.8.0) + rspec-expectations (3.8.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.8.0) rspec-mocks (3.8.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.8.0) rspec-support (3.8.0) - rubocop (0.57.2) + rubocop (0.59.2) jaro_winkler (~> 1.5.1) parallel (~> 1.10) - parser (>= 2.5) + parser (>= 2.5, != 2.5.1.1) powerpack (~> 0.1) rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) - ruby-progressbar (1.9.0) + ruby-progressbar (1.10.0) simplecov (0.16.1) docile (~> 1.1) json (>= 1.8, < 3) @@ -62,9 +62,9 @@ DEPENDENCIES pry (~> 0.10) rake (~> 12.1) rspec (~> 3.7) - rubocop (~> 0.54) + rubocop (~> 0.59) simplecov (~> 0.16.1) yard (~> 0.9) BUNDLED WITH - 1.16.1 + 1.16.6 diff --git a/elftools.gemspec b/elftools.gemspec index 9d015c0..4b09f29 100644 --- a/elftools.gemspec +++ b/elftools.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'pry', '~> 0.10' s.add_development_dependency 'rake', '~> 12.1' s.add_development_dependency 'rspec', '~> 3.7' - s.add_development_dependency 'rubocop', '~> 0.54' + s.add_development_dependency 'rubocop', '~> 0.59' s.add_development_dependency 'simplecov', '~> 0.16.1' s.add_development_dependency 'yard', '~> 0.9' end diff --git a/lib/elftools/dynamic.rb b/lib/elftools/dynamic.rb index 0f58376..377b454 100644 --- a/lib/elftools/dynamic.rb +++ b/lib/elftools/dynamic.rb @@ -18,6 +18,7 @@ module Dynamic # Otherwise, return array of tags. def each_tags(&block) return enum_for(:each_tags) unless block_given? + arr = [] 0.step do |i| tag = tag_at(i).tap(&block) @@ -77,8 +78,10 @@ def tag_by_type(type) # @return [ELFTools::Dynamic::Tag] The desired tag. def tag_at(n) return if n < 0 + @tag_at_map ||= {} return @tag_at_map[n] if @tag_at_map[n] + dyn = Structs::ELF_Dyn.new(endian: endian) dyn.elf_class = header.elf_class stream.pos = tag_start + n * dyn.num_bytes @@ -153,6 +156,7 @@ def name? # @return [String, nil] The name. def name return nil unless name? + Util.cstring(stream, @str_offset.call + header.d_val.to_i) end end diff --git a/lib/elftools/elf_file.rb b/lib/elftools/elf_file.rb index 3530e1c..d5a8634 100644 --- a/lib/elftools/elf_file.rb +++ b/lib/elftools/elf_file.rb @@ -32,6 +32,7 @@ def initialize(stream) # @return [ELFTools::Structs::ELF_Ehdr] The header. def header return @header if defined?(@header) + stream.pos = 0 @header = Structs::ELF_Ehdr.new(endian: endian, offset: stream.pos) @header.elf_class = elf_class @@ -49,8 +50,10 @@ def header def build_id section = section_by_name('.note.gnu.build-id') return nil if section.nil? + note = section.notes.first return nil if note.nil? + note.desc.unpack('H*').first end @@ -116,6 +119,7 @@ def section_by_name(name) # otherwise, the whole sections will be returned. def each_sections(&block) return enum_for(:each_sections) unless block_given? + Array.new(num_sections) do |i| section_at(i).tap(&block) end @@ -188,6 +192,7 @@ def num_segments # Whole segments will be returned. def each_segments(&block) return enum_for(:each_segments) unless block_given? + Array.new(num_segments) do |i| segment_at(i).tap(&block) end @@ -324,6 +329,7 @@ def loaded_headers explore = lambda do |obj| return obj if obj.is_a?(::ELFTools::Structs::ELFStruct) return obj.map(&explore) if obj.is_a?(Array) + obj.instance_variables.map do |s| explore.call(obj.instance_variable_get(s)) end @@ -335,12 +341,14 @@ def identify stream.pos = 0 magic = stream.read(4) raise ELFError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG + ei_class = stream.read(1).ord @elf_class = { 1 => 32, 2 => 64 }[ei_class] raise ELFError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil? + ei_data = stream.read(1).ord @endian = { 1 => :little, diff --git a/lib/elftools/lazy_array.rb b/lib/elftools/lazy_array.rb index 908ff7f..7756b80 100644 --- a/lib/elftools/lazy_array.rb +++ b/lib/elftools/lazy_array.rb @@ -38,6 +38,7 @@ def initialize(size, &block) def [](i) # XXX: support negative index? return nil if i < 0 || i >= @internal.size + @internal[i] ||= @block.call(i) end end diff --git a/lib/elftools/note.rb b/lib/elftools/note.rb index 558a79f..989affa 100644 --- a/lib/elftools/note.rb +++ b/lib/elftools/note.rb @@ -41,6 +41,7 @@ module Note # Otherwise, return the array of notes. def each_notes return enum_for(:each_notes) unless block_given? + @notes_offset_map ||= {} cur = note_start notes = [] @@ -101,6 +102,7 @@ def initialize(header, stream, offset) # @return [String] The name. def name return @name if @name + stream.pos = @offset + SIZE_OF_NHDR @name = stream.read(header.n_namesz)[0..-2] end @@ -108,7 +110,8 @@ def name # Description of this note. # @return [String] The description. def desc - return @desc if @desc + return @desc if instance_variable_defined?(:@desc) + stream.pos = @offset + SIZE_OF_NHDR + Util.align(header.n_namesz, 2) @desc = stream.read(header.n_descsz) end diff --git a/lib/elftools/sections/relocation_section.rb b/lib/elftools/sections/relocation_section.rb index 3e63380..ba35cff 100644 --- a/lib/elftools/sections/relocation_section.rb +++ b/lib/elftools/sections/relocation_section.rb @@ -42,6 +42,7 @@ def relocation_at(n) # Otherwise, the whole relocations will be returned. def each_relocations(&block) return enum_for(:each_relocations) unless block_given? + Array.new(num_relocations) do |i| relocation_at(i).tap(&block) end diff --git a/lib/elftools/sections/sym_tab_section.rb b/lib/elftools/sections/sym_tab_section.rb index 57f1352..48a987c 100644 --- a/lib/elftools/sections/sym_tab_section.rb +++ b/lib/elftools/sections/sym_tab_section.rb @@ -56,6 +56,7 @@ def symbol_at(n) # Otherwise return array of symbols. def each_symbols(&block) return enum_for(:each_symbols) unless block_given? + Array.new(num_symbols) do |i| symbol_at(i).tap(&block) end diff --git a/lib/elftools/structs.rb b/lib/elftools/structs.rb index fabcfa7..6145766 100644 --- a/lib/elftools/structs.rb +++ b/lib/elftools/structs.rb @@ -54,6 +54,7 @@ def self_endian # @return [String] def pack(val, bytes) raise ArgumentError, "Not supported assign type #{val.class}" unless val.is_a?(Integer) + number = val & ((1 << (8 * bytes)) - 1) out = [] bytes.times do diff --git a/lib/elftools/util.rb b/lib/elftools/util.rb index 0fbceb7..4412db1 100644 --- a/lib/elftools/util.rb +++ b/lib/elftools/util.rb @@ -17,6 +17,7 @@ module ClassMethods def align(num, bit) n = 2**bit return num if (num % n).zero? + (num + n) & ~(n - 1) end @@ -36,6 +37,7 @@ def to_constant(mod, val) # if val is an integer, check if exists in mod if val.is_a?(Integer) return val if mod.constants.any? { |c| mod.const_get(c) == val } + raise ArgumentError, "No constants in #{module_name} is #{val}" end val = val.to_s.upcase @@ -43,6 +45,7 @@ def to_constant(mod, val) val = prefix + '_' + val unless val.start_with?(prefix) val = val.to_sym raise ArgumentError, "No constants in #{module_name} named \"#{val}\"" unless mod.const_defined?(val) + mod.const_get(val) end @@ -61,6 +64,7 @@ def cstring(stream, offset) c = stream.read(1) return nil if c.nil? # reach EOF break if c == "\x00" + ret += c end ret