elftools 0.2.0 → 0.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2aa2517a78c13a631e9889e03e380b024c75585
4
- data.tar.gz: 6d1de34194028eba0b787b148b648a518e6f0e1d
3
+ metadata.gz: 3b27e4fd08cf348de961dde3f2c606719558c031
4
+ data.tar.gz: b7822186925f38be8a76aeb9961a0484ee0cc2bd
5
5
  SHA512:
6
- metadata.gz: 4e3b9b1c4f4e0c7cf38efd85ae0c5c250e875fb50bda990286fcf0dc69684970b6eae99f6b2881a0938ea5597da6439ae46fa694823dc3e69322e202b60f622b
7
- data.tar.gz: fff51965be7467711d36af1db1374370654a7d8a771ca8f4dcc48e38fd3daff3fe928dc2dd034f3d7ded3ecadb4e8304bdc8feb996623fc052c6eeea03251742
6
+ metadata.gz: 9a0d0993f509e82c87c97776282057fe61ff8076018714da50ecc9c928e8b3863e7481a2ababf7ae56cb02d75dc03d5783f8d2bdf4b890b535075bed00f53bac
7
+ data.tar.gz: 591568c22193ada4c48874c276bde8cdb5c5587268f67e440c48b8968db395d9730888bd5d452e6f002e383e65e0a0dfb9bc7b6682b6e960bc84daa80f1cab15
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  [![Build Status](https://travis-ci.org/david942j/rbelftools.svg?branch=master)](https://travis-ci.org/david942j/rbelftools)
2
+ [![Build Status](https://ci.appveyor.com/api/projects/status/sq5c4gli8ir95h6k?svg=true&retina=true)](https://ci.appveyor.com/project/david942j/rbelftools)
2
3
  [![Code Climate](https://codeclimate.com/github/david942j/rbelftools/badges/gpa.svg)](https://codeclimate.com/github/david942j/rbelftools)
3
4
  [![Issue Count](https://codeclimate.com/github/david942j/rbelftools/badges/issue_count.svg)](https://codeclimate.com/github/david942j/rbelftools)
4
5
  [![Test Coverage](https://codeclimate.com/github/david942j/rbelftools/badges/coverage.svg)](https://codeclimate.com/github/david942j/rbelftools/coverage)
@@ -11,7 +12,7 @@ ELF parser in pure ruby implementation. This work is inspired by [pyelftools](ht
11
12
 
12
13
  The motivation to create this repository is want to be a dependency of [pwntools-ruby](https://github.com/peter50216/pwntools-ruby). Since ELF parser is a big work, it should not be implemented directly in pwntools.
13
14
 
14
- **rbelftools**'s target is to create a nice ELF parser library in ruby. More features are work in progress.
15
+ **rbelftools**'s target is to create a nice ELF parser library in ruby. More features remain a work in progress.
15
16
 
16
17
  # Install
17
18
 
@@ -70,7 +71,7 @@ symtab_section.num_symbols
70
71
 
71
72
  symtab_section.symbol_by_name('puts@@GLIBC_2.2.5')
72
73
  #=>
73
- # #<ELFTools::Symbol:0x00560b14af67a0
74
+ # #<ELFTools::Sections::Symbol:0x00560b14af67a0
74
75
  # @header={:st_name=>348, :st_info=>18, :st_other=>0, :st_shndx=>0, :st_value=>0, :st_size=>0},
75
76
  # @name="puts@@GLIBC_2.2.5">
76
77
 
@@ -115,26 +116,21 @@ relocations.map { |r| symtab.symbol_at(r.symbol_index).name }
115
116
 
116
117
  # Why rbelftools
117
118
 
118
- 1. Fully documented
119
-
119
+ 1. Fully documented
120
120
  Always important for an Open-Source project. Online document is [here](http://www.rubydoc.info/github/david942j/rbelftools/master/frames)
121
- 2. Fully tested
122
-
121
+ 2. Fully tested
123
122
  Of course.
124
- 3. Lazy loading on everything
125
-
123
+ 3. Lazy loading on everything
126
124
  To use **rbelftools**, only need to pass the stream object of ELF file.
127
125
  **rbelftools** will read the stream object **as least times as possible** when parsing
128
126
  the file. Most information will not be fetched until you need it, which makes
129
127
  **rbelftools** efficient.
130
- 4. To be a library
131
-
132
- **rbelftools** is designed to be a library for furthur usage.
128
+ 4. To be a library
129
+ **rbelftools** is designed to be a library for further usage.
133
130
  It will _not_ add any too trivial features.
134
131
  For example, to check if NX disabled, you can use
135
132
  `!elf.segment_by_type(:gnu_stack).executable?` but not `elf.nx?`
136
- 5. Section and segment parser
137
-
133
+ 5. Section and segment parser
138
134
  Providing common sections and segments parser. For example, .symtab, .shstrtab
139
135
  .dynamic sections and INTERP, DYNAMIC segments, etc.
140
136
 
@@ -143,12 +139,12 @@ relocations.map { |r| symtab.symbol_at(r.symbol_index).name }
143
139
  git clone https://github.com/david942j/rbelftools.git
144
140
  cd rbelftools
145
141
  bundle
146
- rake
142
+ bundle exec rake
147
143
  ```
148
144
  Any comments or suggestions are welcome!
149
145
 
150
146
  # Cross Platform
151
- **rbelftools** can be used on Linux and OSX. Should also work on Windows but not tested.
147
+ **rbelftools** can be used and has been fully tested on all platforms include Linux, OSX, and Windows!
152
148
 
153
149
  # License
154
150
  MIT License
@@ -8,110 +8,117 @@ module ELFTools
8
8
 
9
9
  # Section header types, records in +sh_type+.
10
10
  module SHT
11
- SHT_NULL = 0
12
- SHT_PROGBITS = 1
13
- SHT_SYMTAB = 2
14
- SHT_STRTAB = 3
15
- SHT_RELA = 4
16
- SHT_HASH = 5
17
- SHT_DYNAMIC = 6
18
- SHT_NOTE = 7
19
- SHT_NOBITS = 8
20
- SHT_REL = 9
21
- SHT_SHLIB = 10
22
- SHT_DYNSYM = 11
23
- SHT_NUM = 12
11
+ SHT_NULL = 0 # null section
12
+ SHT_PROGBITS = 1 # information defined by program itself
13
+ SHT_SYMTAB = 2 # symbol table section
14
+ SHT_STRTAB = 3 # string table section
15
+ SHT_RELA = 4 # relocation with addends
16
+ SHT_HASH = 5 # symbol hash table
17
+ SHT_DYNAMIC = 6 # information of dynamic linking
18
+ SHT_NOTE = 7 # note section
19
+ SHT_NOBITS = 8 # section occupies no space
20
+ SHT_REL = 9 # relocation
21
+ SHT_SHLIB = 10 # reserved
22
+ SHT_DYNSYM = 11 # symbols for dynamic
23
+ # Values between {SHT_LOPROC} and {SHT_HIPROC} are reserved for processor-specific semantics.
24
24
  SHT_LOPROC = 0x70000000
25
- SHT_HIPROC = 0x7fffffff
25
+ SHT_HIPROC = 0x7fffffff # see {SHT_LOPROC}
26
+ # Values between {SHT_LOUSER} and {SHT_HIUSER} are reserved for application programs.
26
27
  SHT_LOUSER = 0x80000000
27
- SHT_HIUSER = 0xffffffff
28
+ SHT_HIUSER = 0xffffffff # see {SHT_LOUSER}
28
29
  end
29
30
  include SHT
30
31
 
31
32
  # Program header types, records in +p_type+.
32
33
  module PT
33
- PT_NULL = 0
34
- PT_LOAD = 1
35
- PT_DYNAMIC = 2
36
- PT_INTERP = 3
37
- PT_NOTE = 4
38
- PT_SHLIB = 5
39
- PT_PHDR = 6
40
- PT_TLS = 7 # Thread local storage segment
34
+ PT_NULL = 0 # null segment
35
+ PT_LOAD = 1 # segment to be load
36
+ PT_DYNAMIC = 2 # dynamic tags
37
+ PT_INTERP = 3 # interpreter, same as .interp section
38
+ PT_NOTE = 4 # same as .note* section
39
+ PT_SHLIB = 5 # reserved
40
+ PT_PHDR = 6 # where program header starts
41
+ PT_TLS = 7 # thread local storage segment
41
42
  PT_LOOS = 0x60000000 # OS-specific
42
43
  PT_HIOS = 0x6fffffff # OS-specific
44
+ # Values between {PT_LOPROC} and {PT_HIPROC} are reserved for processor-specific semantics.
43
45
  PT_LOPROC = 0x70000000
44
- PT_HIPROC = 0x7fffffff
45
- PT_GNU_EH_FRAME = 0x6474e550
46
- PT_GNU_STACK = 0x6474e551
47
- PT_GNU_RELRO = 0x6474e552 # Read only after relocation
46
+ PT_HIPROC = 0x7fffffff # see {PT_LOPROC}
47
+ PT_GNU_EH_FRAME = 0x6474e550 # for exception handler
48
+ PT_GNU_STACK = 0x6474e551 # permission of stack
49
+ PT_GNU_RELRO = 0x6474e552 # read only after relocation
48
50
  end
49
51
  include PT
50
52
 
51
53
  # Dynamic table types, records in +d_tag+.
52
54
  module DT
53
- DT_NULL = 0
54
- DT_NEEDED = 1
55
- DT_PLTRELSZ = 2
56
- DT_PLTGOT = 3
57
- DT_HASH = 4
58
- DT_STRTAB = 5
59
- DT_SYMTAB = 6
60
- DT_RELA = 7
61
- DT_RELASZ = 8
62
- DT_RELAENT = 9
63
- DT_STRSZ = 10
64
- DT_SYMENT = 11
65
- DT_INIT = 12
66
- DT_FINI = 13
67
- DT_SONAME = 14
68
- DT_RPATH = 15
69
- DT_SYMBOLIC = 16
70
- DT_REL = 17
71
- DT_RELSZ = 18
72
- DT_RELENT = 19
73
- DT_PLTREL = 20
74
- DT_DEBUG = 21
75
- DT_TEXTREL = 22
76
- DT_JMPREL = 23
77
- DT_BIND_NOW = 24
78
- DT_INIT_ARRAY = 25
79
- DT_FINI_ARRAY = 26
80
- DT_INIT_ARRAYSZ = 27
81
- DT_FINI_ARRAYSZ = 28
82
- DT_RUNPATH = 29
83
- DT_FLAGS = 30
84
- DT_ENCODING = 32
55
+ DT_NULL = 0 # marks the end of the _DYNAMIC array
56
+ DT_NEEDED = 1 # libraries need to be linked by loader
57
+ DT_PLTRELSZ = 2 # total size of relocation entries
58
+ DT_PLTGOT = 3 # address of procedure linkage table or global offset table
59
+ DT_HASH = 4 # address of symbol hash table
60
+ DT_STRTAB = 5 # address of string table
61
+ DT_SYMTAB = 6 # address of symbol table
62
+ DT_RELA = 7 # address of a relocation table
63
+ DT_RELASZ = 8 # total size of the {DT_RELA} table
64
+ DT_RELAENT = 9 # size of each entry in the {DT_RELA} table
65
+ DT_STRSZ = 10 # total size of {DT_STRTAB}
66
+ DT_SYMENT = 11 # size of each entry in {DT_SYMTAB}
67
+ DT_INIT = 12 # where the initialization function is
68
+ DT_FINI = 13 # where the termination function is
69
+ DT_SONAME = 14 # the shared object name
70
+ DT_RPATH = 15 # has been superseded by {DT_RUNPATH}
71
+ DT_SYMBOLIC = 16 # has been superseded by the DF_SYMBOLIC flag
72
+ DT_REL = 17 # similar to {DT_RELA}
73
+ DT_RELSZ = 18 # total size of the {DT_REL} table
74
+ DT_RELENT = 19 # size of each entry in the {DT_REL} table
75
+ DT_PLTREL = 20 # type of relocation entry, either {DT_REL} or {DT_RELA}
76
+ DT_DEBUG = 21 # for debugging
77
+ DT_TEXTREL = 22 # has been superseded by the DF_TEXTREL flag
78
+ DT_JMPREL = 23 # address of relocation entries that are associated solely with the procedure linkage table
79
+ DT_BIND_NOW = 24 # if the loader needs to do relocate now, superseded by the DF_BIND_NOW flag
80
+ DT_INIT_ARRAY = 25 # address init array
81
+ DT_FINI_ARRAY = 26 # address of fini array
82
+ DT_INIT_ARRAYSZ = 27 # total size of init array
83
+ DT_FINI_ARRAYSZ = 28 # total size of fini array
84
+ DT_RUNPATH = 29 # path of libraries for searching
85
+ DT_FLAGS = 30 # flags
86
+ DT_ENCODING = 32 # just a lower bound
87
+ # Values between {DT_LOOS} and {DT_HIOS} are reserved for operating system-specific semantics.
85
88
  DT_LOOS = 0x6000000d
86
- DT_HIOS = 0x6ffff000
89
+ DT_HIOS = 0x6ffff000 # see {DT_LOOS}
90
+ # Values between {DT_VALRNGLO} and {DT_VALRNGHI} use the +d_un.d_val+ field of the dynamic structure.
87
91
  DT_VALRNGLO = 0x6ffffd00
88
- DT_VALRNGHI = 0x6ffffdff
92
+ DT_VALRNGHI = 0x6ffffdff # see {DT_VALRNGLO}
93
+ # Values between {DT_ADDRRNGLO} and {DT_ADDRRNGHI} use the +d_un.d_ptr+ field of the dynamic structure.
89
94
  DT_ADDRRNGLO = 0x6ffffe00
90
- DT_ADDRRNGHI = 0x6ffffeff
91
- DT_VERSYM = 0x6ffffff0
92
- DT_RELACOUNT = 0x6ffffff9
93
- DT_RELCOUNT = 0x6ffffffa
94
- DT_FLAGS_1 = 0x6ffffffb
95
- DT_VERDEF = 0x6ffffffc
96
- DT_VERDEFNUM = 0x6ffffffd
97
- DT_VERNEED = 0x6ffffffe
98
- DT_VERNEEDNUM = 0x6fffffff
95
+ DT_GNU_HASH = 0x6ffffef5 # the gnu hash
96
+ DT_ADDRRNGHI = 0x6ffffeff # see {DT_ADDRRNGLO}
97
+ DT_RELACOUNT = 0x6ffffff9 # relative relocation count
98
+ DT_RELCOUNT = 0x6ffffffa # relative relocation count
99
+ DT_FLAGS_1 = 0x6ffffffb # flags
100
+ DT_VERDEF = 0x6ffffffc # address of version definition table
101
+ DT_VERDEFNUM = 0x6ffffffd # number of entries in {DT_VERDEF}
102
+ DT_VERNEED = 0x6ffffffe # address of version dependency table
103
+ DT_VERNEEDNUM = 0x6fffffff # number of entries in {DT_VERNEED}
104
+ # Values between {DT_LOPROC} and {DT_HIPROC} are reserved for processor-specific semantics.
99
105
  DT_LOPROC = 0x70000000
100
- DT_HIPROC = 0x7fffffff
106
+ DT_HIPROC = 0x7fffffff # see {DT_LOPROC}
101
107
  end
102
108
  include DT
103
109
 
104
110
  # These constants define the various ELF target machines.
105
111
  module EM
106
- EM_NONE = 0
107
- EM_M32 = 1
108
- EM_SPARC = 2
109
- EM_386 = 3
110
- EM_68K = 4
111
- EM_88K = 5
112
- EM_486 = 6 # Perhaps disused
113
- EM_860 = 7
112
+ EM_NONE = 0 # none
113
+ EM_M32 = 1 # AT&T WE 32100
114
+ EM_SPARC = 2 # SPARC
115
+ EM_386 = 3 # Intel 80386
116
+ EM_68K = 4 # Motorola 68000
117
+ EM_88K = 5 # Motorola 88000
118
+ EM_486 = 6 # Intel 80486
119
+ EM_860 = 7 # Intel 80860
114
120
  EM_MIPS = 8 # MIPS R3000 (officially, big-endian only)
121
+
115
122
  # Next two are historical and binaries and
116
123
  # modules of these types will be rejected by Linux.
117
124
  EM_MIPS_RS3_LE = 10 # MIPS R3000 little-endian
@@ -190,11 +197,11 @@ module ELFTools
190
197
 
191
198
  # This module defines elf file types.
192
199
  module ET
193
- ET_NONE = 0
194
- ET_REL = 1
195
- ET_EXEC = 2
196
- ET_DYN = 3
197
- ET_CORE = 4
200
+ ET_NONE = 0 # no file type
201
+ ET_REL = 1 # relocatable file
202
+ ET_EXEC = 2 # executable file
203
+ ET_DYN = 3 # shared object
204
+ ET_CORE = 4 # core file
198
205
  # Return the type name according to +e_type+ in ELF file header.
199
206
  # @return [String] Type in string format.
200
207
  def self.mapping(type)
@@ -1,28 +1,26 @@
1
1
  module ELFTools
2
- # Define common methods for dynamic sections and
3
- # dynamic segments.
2
+ # Define common methods for dynamic sections and dynamic segments.
4
3
  #
5
- # Notice: this module can only be included by
6
- # {ELFTools::Sections::DynamicSection} and
7
- # {ELFTools::Segments::DynamicSegment} because
8
- # methods here assume some attributes exist.
4
+ # @note
5
+ # This module can only be included by {ELFTools::Sections::DynamicSection}
6
+ # and {ELFTools::Segments::DynamicSegment} because methods here assume some
7
+ # attributes exist.
9
8
  module Dynamic
10
9
  # Iterate all tags.
11
10
  #
12
- # Notice: this method assume the following methods
13
- # already exist:
14
- # header
15
- # tag_start
16
- # @param [Block] block You can give a block.
11
+ # @note
12
+ # This method assume the following methods already exist:
13
+ # header
14
+ # tag_start
15
+ # @yieldparam [ELFTools::Dynamic::Tag] tag
17
16
  # @return [Enumerator<ELFTools::Dynamic::Tag>, Array<ELFTools::Dynamic::Tag>]
18
17
  # If block is not given, an enumerator will be returned.
19
18
  # Otherwise, return array of tags.
20
- def each_tags
19
+ def each_tags(&block)
21
20
  return enum_for(:each_tags) unless block_given?
22
21
  arr = []
23
22
  0.step do |i|
24
- tag = tag_at(i)
25
- yield tag
23
+ tag = tag_at(i).tap(&block)
26
24
  arr << tag
27
25
  break if tag.header.d_tag == ELFTools::Constants::DT_NULL
28
26
  end
@@ -68,13 +66,13 @@ module ELFTools
68
66
  # Get the +n+-th tag.
69
67
  #
70
68
  # Tags are lazy loaded.
71
- # Notice: this method assume the following methods
72
- # already exist:
73
- # header
74
- # tag_start
75
- #
76
- # Notice: we cannot do bound checking of +n+ here since
77
- # the only way to get size of tags is calling +tags.size+.
69
+ # @note
70
+ # This method assume the following methods already exist:
71
+ # header
72
+ # tag_start
73
+ # @note
74
+ # We cannot do bound checking of +n+ here since the only way to get size
75
+ # of tags is calling +tags.size+.
78
76
  # @param [Integer] n The index.
79
77
  # @return [ELFTools::Dynamic::Tag] The desired tag.
80
78
  def tag_at(n)
@@ -102,11 +100,11 @@ module ELFTools
102
100
  # A tag class.
103
101
  class Tag
104
102
  attr_reader :header # @return [ELFTools::Structs::ELF_Dyn] The dynamic tag header.
105
- attr_reader :stream # @return [File] Streaming object.
103
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
106
104
 
107
105
  # Instantiate a {ELFTools::Dynamic::Tag} object.
108
106
  # @param [ELF_Dyn] header The dynamic tag header.
109
- # @param [File] stream Streaming object.
107
+ # @param [#pos=, #read] stream Streaming object.
110
108
  # @param [Method] str_offset
111
109
  # Call this method to get the string offset related
112
110
  # to file.
@@ -116,6 +114,7 @@ module ELFTools
116
114
  @str_offset = str_offset
117
115
  end
118
116
 
117
+ # Some dynamic have name.
119
118
  TYPE_WITH_NAME = [Constants::DT_NEEDED,
120
119
  Constants::DT_SONAME,
121
120
  Constants::DT_RPATH,
@@ -150,7 +149,7 @@ module ELFTools
150
149
  #
151
150
  # Only tags with name would return a name.
152
151
  # Others would return +nil+.
153
- # @return [String, NilClass] The name.
152
+ # @return [String, nil] The name.
154
153
  def name
155
154
  return nil unless name?
156
155
  Util.cstring(stream, @str_offset.call + header.d_val.to_i)
@@ -8,13 +8,13 @@ require 'elftools/structs'
8
8
  module ELFTools
9
9
  # The main class for using elftools.
10
10
  class ELFFile
11
- attr_reader :stream # @return [File] The +File+ object.
11
+ attr_reader :stream # @return [#pos=, #read] The +File+ object.
12
12
  attr_reader :elf_class # @return [Integer] 32 or 64.
13
13
  attr_reader :endian # @return [Symbol] +:little+ or +:big+.
14
14
 
15
15
  # Instantiate an {ELFFile} object.
16
16
  #
17
- # @param [File] stream
17
+ # @param [#pos=, #read] stream
18
18
  # The +File+ object to be fetch information from.
19
19
  # @example
20
20
  # ELFFile.new(File.open('/bin/cat'))
@@ -27,7 +27,7 @@ module ELFTools
27
27
  # Return the file header.
28
28
  #
29
29
  # Lazy loading.
30
- # @retrn [ELFTools::Structs::ELF_Ehdr] The header.
30
+ # @return [ELFTools::Structs::ELF_Ehdr] The header.
31
31
  def header
32
32
  return @header if defined?(@header)
33
33
  stream.pos = 0
@@ -37,7 +37,7 @@ module ELFTools
37
37
  end
38
38
 
39
39
  # Return the BuildID of ELF.
40
- # @return [String, NilClass]
40
+ # @return [String, nil]
41
41
  # BuildID in hex form will be returned.
42
42
  # +nil+ is returned if the .note.gnu.build-id section
43
43
  # is not found.
@@ -52,7 +52,7 @@ module ELFTools
52
52
  note.desc.unpack('H*').first
53
53
  end
54
54
 
55
- # Get Machine architecture.
55
+ # Get machine architecture.
56
56
  #
57
57
  # Mappings of architecture can be found
58
58
  # in {ELFTools::Constants::EM.mapping}.
@@ -89,7 +89,7 @@ module ELFTools
89
89
 
90
90
  # Acquire the section named as +name+.
91
91
  # @param [String] name The desired section name.
92
- # @return [ELFTools::Sections::Section, NilClass] The target section.
92
+ # @return [ELFTools::Sections::Section, nil] The target section.
93
93
  # @example
94
94
  # elf.section_by_name('.note.gnu.build-id')
95
95
  # #=> #<ELFTools::Sections::Section:0x005647b1282428>
@@ -107,17 +107,15 @@ module ELFTools
107
107
  # only be created whenever accessing it.
108
108
  # This method is useful for {#section_by_name}
109
109
  # since not all sections need to be created.
110
- # @param [Block] block
111
- # Just like +Array#each+, you can give a block.
110
+ # @yieldparam [ELFTools::Sections::Section] section A section.
111
+ # @yieldreturn [void]
112
112
  # @return [Enumerator<ELFTools::Sections::Section>, Array<ELFTools::Sections::Section>]
113
113
  # As +Array#each+, if block is not given, a enumerator will be returned,
114
114
  # otherwise, the whole sections will be returned.
115
- def each_sections
115
+ def each_sections(&block)
116
116
  return enum_for(:each_sections) unless block_given?
117
117
  Array.new(num_sections) do |i|
118
- sec = section_at(i)
119
- yield sec
120
- sec
118
+ section_at(i).tap(&block)
121
119
  end
122
120
  end
123
121
 
@@ -132,7 +130,7 @@ module ELFTools
132
130
  #
133
131
  # Sections are lazy loaded.
134
132
  # @param [Integer] n The index.
135
- # @return [ELFTools::Sections::Section, NilClass]
133
+ # @return [ELFTools::Sections::Section, nil]
136
134
  # The target section.
137
135
  # If +n+ is out of bound, +nil+ is returned.
138
136
  def section_at(n)
@@ -142,13 +140,12 @@ module ELFTools
142
140
 
143
141
  # Fetch all sections with specific type.
144
142
  #
145
- # The available types are listed in {ELFTools::Constants},
146
- # start with +SHT_+.
143
+ # The available types are listed in {ELFTools::Constants::PT}.
147
144
  # This method accept giving block.
148
145
  # @param [Integer, Symbol, String] type
149
146
  # The type needed, similar format as {#segment_by_type}.
150
- # @param [Block] block
151
- # Block will be yielded whenever find a section.
147
+ # @yieldparam [ELFTools::Sections::Section] section A section in specific type.
148
+ # @yieldreturn [void]
152
149
  # @return [Array<ELFTools::Sections::section>] The target sections.
153
150
  # @example
154
151
  # elf = ELFTools::ELFFile.new(File.open('spec/files/amd64.elf'))
@@ -183,16 +180,14 @@ module ELFTools
183
180
  # only be created whenever accessing it.
184
181
  # This method is useful for {#segment_by_type}
185
182
  # since not all segments need to be created.
186
- # @param [Block] block
187
- # Just like +Array#each+, you can give a block.
183
+ # @yieldparam [ELFTools::Segments::Segment] segment A segment.
184
+ # @yieldreturn [void]
188
185
  # @return [Array<ELFTools::Segments::Segment>]
189
186
  # Whole segments will be returned.
190
- def each_segments
187
+ def each_segments(&block)
191
188
  return enum_for(:each_segments) unless block_given?
192
189
  Array.new(num_segments) do |i|
193
- seg = segment_at(i)
194
- yield seg
195
- seg
190
+ segment_at(i).tap(&block)
196
191
  end
197
192
  end
198
193
 
@@ -204,11 +199,11 @@ module ELFTools
204
199
  end
205
200
 
206
201
  # Get the first segment with +p_type=type+.
207
- # The available types are listed in {ELFTools::Constants},
208
- # start with +PT_+.
202
+ # The available types are listed in {ELFTools::Constants::PT}.
209
203
  #
210
- # Notice: this method will return the first segment found,
211
- # to found all segments with specific type you can use {#segments_by_type}.
204
+ # @note
205
+ # This method will return the first segment found,
206
+ # to found all segments with specific type you can use {#segments_by_type}.
212
207
  # @param [Integer, Symbol, String] type
213
208
  # See examples for clear usage.
214
209
  # @return [ELFTools::Segments::Segment] The target segment.
@@ -256,8 +251,8 @@ module ELFTools
256
251
  # This method accept giving block.
257
252
  # @param [Integer, Symbol, String] type
258
253
  # The type needed, same format as {#segment_by_type}.
259
- # @param [Block] block
260
- # Block will be yielded whenever find a segement.
254
+ # @yieldparam [ELFTools::Segments::Segment] segment A segment in specific type.
255
+ # @yieldreturn [void]
261
256
  # @return [Array<ELFTools::Segments::Segment>] The target segments.
262
257
  def segments_by_type(type, &block)
263
258
  type = Util.to_constant(Constants::PT, type)
@@ -268,7 +263,7 @@ module ELFTools
268
263
  #
269
264
  # Segments are lazy loaded.
270
265
  # @param [Integer] n The index.
271
- # @return [ELFTools::Segments::Segment, NilClass]
266
+ # @return [ELFTools::Segments::Segment, nil]
272
267
  # The target segment.
273
268
  # If +n+ is out of bound, +nil+ is returned.
274
269
  def segment_at(n)
@@ -1,3 +1,4 @@
1
1
  module ELFTools
2
+ # Being raised when parsing error.
2
3
  class ELFError < StandardError; end
3
4
  end
@@ -7,9 +7,10 @@ module ELFTools
7
7
  # Instantiate a {LazyArray} object.
8
8
  # @param [Integer] size
9
9
  # The size of array.
10
- # @param [Block] block
11
- # At first time accessing +i+-th element,
12
- # block will be called as +block.call(i)+.
10
+ # @yieldparam [Integer] i
11
+ # Needs +i+-th element.
12
+ # @yieldreturn [Object]
13
+ # Value of the +i+-th element.
13
14
  # @example
14
15
  # arr = LazyArray.new(10) { |i| p i; i * i }
15
16
  # p arr[2]
data/lib/elftools/note.rb CHANGED
@@ -2,17 +2,18 @@ require 'elftools/structs'
2
2
  require 'elftools/util'
3
3
 
4
4
  module ELFTools
5
- # Since both note sections and note segments
6
- # refer to notes, this module defines common
7
- # methods for {ELFTools::Sections::NoteSection} and {ELFTools::Segments::NoteSegment}.
5
+ # Since both note sections and note segments refer to notes, this module
6
+ # defines common methods for {ELFTools::Sections::NoteSection} and
7
+ # {ELFTools::Segments::NoteSegment}.
8
8
  #
9
- # Notice: this module can only be included in {ELFTools::Sections::NoteSection} and
10
- # {ELFTools::Segments::NoteSegment} since some methods assume some attributes already
11
- # exist.
9
+ # @note
10
+ # This module can only be included in {ELFTools::Sections::NoteSection} and
11
+ # {ELFTools::Segments::NoteSegment} since some methods here assume some
12
+ # attributes already exist.
12
13
  module Note
13
- # Since size of {ELFTools::Structs::ELF_Nhdr} will not change no
14
- # matter what endian and what arch, we can do this here.
15
- # This value should equal to 12.
14
+ # Since size of {ELFTools::Structs::ELF_Nhdr} will not change no matter in
15
+ # what endian and what arch, we can do this here. This value should equal
16
+ # to 12.
16
17
  SIZE_OF_NHDR = Structs::ELF_Nhdr.new(endian: :little).num_bytes
17
18
 
18
19
  # Iterate all notes in a note section or segment.
@@ -30,13 +31,16 @@ module ELFTools
30
31
  # | ... |
31
32
  # +---------------+
32
33
  #
33
- # Notice: This method assume following methods exist:
34
- # stream
35
- # note_start
36
- # note_total_size
37
- # @return [Array<ELFTools::Note::Note>]
38
- # The array of notes will be returned.
34
+ # @note
35
+ # This method assume following methods exist:
36
+ # stream
37
+ # note_start
38
+ # note_total_size
39
+ # @return [Enumerator<ELFTools::Note::Note>, Array<ELFTools::Note::Note>]
40
+ # If block is not given, an enumerator will be returned.
41
+ # Otherwise, return the array of notes.
39
42
  def each_notes
43
+ return enum_for(:each_notes) unless block_given?
40
44
  @notes_offset_map ||= {}
41
45
  cur = note_start
42
46
  notes = []
@@ -49,19 +53,23 @@ module ELFTools
49
53
  desc_size = Util.align(note.header.n_descsz, 2)
50
54
  cur += SIZE_OF_NHDR + name_size + desc_size
51
55
  notes << note
52
- yield note if block_given?
56
+ yield note
53
57
  end
54
58
  notes
55
59
  end
56
60
 
57
61
  # Simply +#notes+ to get all notes.
58
- alias notes each_notes
62
+ # @return [Array<ELFTools::Note::Note>]
63
+ # Whole notes.
64
+ def notes
65
+ each_notes.to_a
66
+ end
59
67
 
60
68
  private
61
69
 
62
70
  # Get the endian.
63
71
  #
64
- # Notice: This method assume method +header+ exists.
72
+ # @note This method assume method +header+ exists.
65
73
  # @return [Symbol] +:little+ or +:big+.
66
74
  def endian
67
75
  header.class.self_endian
@@ -75,12 +83,12 @@ module ELFTools
75
83
  # Class of a note.
76
84
  class Note
77
85
  attr_reader :header # @return [ELFTools::Structs::ELF_Nhdr] Note header.
78
- attr_reader :stream # @return [File] Streaming object.
86
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
79
87
  attr_reader :offset # @return [Integer] Address of this note start, includes note header.
80
88
 
81
89
  # Instantiate a {ELFTools::Note::Note} object.
82
90
  # @param [ELF_Nhdr] header The note header.
83
- # @param [File] stream Streaming object.
91
+ # @param [#pos=, #read] stream Streaming object.
84
92
  # @param [Integer] offset
85
93
  # Start address of this note, includes the header.
86
94
  def initialize(header, stream, offset)
@@ -23,7 +23,7 @@ module ELFTools
23
23
  #
24
24
  # relocations are lazy loaded.
25
25
  # @param [Integer] n The index.
26
- # @return [ELFTools::Relocation, NilClass]
26
+ # @return [ELFTools::Relocation, nil]
27
27
  # The target relocation.
28
28
  # If +n+ is out of bound, +nil+ is returned.
29
29
  def relocation_at(n)
@@ -35,17 +35,15 @@ module ELFTools
35
35
  #
36
36
  # All relocations are lazy loading, the relocation
37
37
  # only be created whenever accessing it.
38
- # @param [Block] block
39
- # Just like +Array#each+, you can give a block.
38
+ # @yieldparam [ELFTools::Relocation] rel A relocation object.
39
+ # @yieldreturn [void]
40
40
  # @return [Enumerator<ELFTools::Relocation>, Array<ELFTools::Relocation>]
41
41
  # If block is not given, an enumerator will be returned.
42
42
  # Otherwise, the whole relocations will be returned.
43
- def each_relocations
43
+ def each_relocations(&block)
44
44
  return enum_for(:each_relocations) unless block_given?
45
45
  Array.new(num_relocations) do |i|
46
- rel = relocation_at(i)
47
- yield rel
48
- rel
46
+ relocation_at(i).tap(&block)
49
47
  end
50
48
  end
51
49
 
@@ -75,7 +73,7 @@ module ELFTools
75
73
  # XXX: move this to an independent file?
76
74
  class Relocation
77
75
  attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header.
78
- attr_reader :stream # @return [File] Streaming object.
76
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
79
77
 
80
78
  # Instantiate a {Relocation} object.
81
79
  def initialize(header, stream)
@@ -4,12 +4,12 @@ module ELFTools
4
4
  # Base class of sections.
5
5
  class Section
6
6
  attr_reader :header # @return [ELFTools::Structs::ELF_Shdr] Section header.
7
- attr_reader :stream # @return [File] Streaming object.
7
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
8
8
 
9
9
  # Instantiate a {Section} object.
10
10
  # @param [ELFTools::Structs::ELF_Shdr] header
11
11
  # The section header object.
12
- # @param [File] stream
12
+ # @param [#pos=, #read] stream
13
13
  # The streaming object for further dump.
14
14
  # @param [ELFTools::Sections::StrTabSection, Proc] strtab
15
15
  # The string table object. For fetching section names.
@@ -16,7 +16,7 @@ module ELFTools
16
16
  class << Section
17
17
  # Use different class according to +header.sh_type+.
18
18
  # @param [ELFTools::Structs::ELF_Shdr] header Section header.
19
- # @param [File] stream Streaming object.
19
+ # @param [#pos=, #read] stream Streaming object.
20
20
  # @return [ELFTools::Sections::Section]
21
21
  # Return object dependes on +header.sh_type+.
22
22
  def create(header, stream, *args)
@@ -11,15 +11,14 @@ module ELFTools
11
11
  # to easily fetch other sections.
12
12
  # @param [ELFTools::Structs::ELF_Shdr] header
13
13
  # See {Section#initialize} for more information.
14
- # @param [File] stream
14
+ # @param [#pos=, #read] stream
15
15
  # See {Section#initialize} for more information.
16
16
  # @param [Proc] section_at
17
17
  # The method for fetching other sections by index.
18
18
  # This lambda should be {ELFTools::ELFFile#section_at}.
19
- def initialize(header, stream, section_at: nil, **_kwagrs)
19
+ def initialize(header, stream, section_at: nil, **_kwargs)
20
20
  @section_at = section_at
21
21
  # For faster #symbol_by_name
22
- @symbol_name_map = {}
23
22
  super
24
23
  end
25
24
 
@@ -36,7 +35,7 @@ module ELFTools
36
35
  #
37
36
  # Symbols are lazy loaded.
38
37
  # @param [Integer] n The index.
39
- # @return [ELFTools::Symbol, NilClass]
38
+ # @return [ELFTools::Sections::Symbol, nil]
40
39
  # The target symbol.
41
40
  # If +n+ is out of bound, +nil+ is returned.
42
41
  def symbol_at(n)
@@ -50,30 +49,31 @@ module ELFTools
50
49
  # only be created whenever accessing it.
51
50
  # This method is useful for {#symbol_by_name}
52
51
  # since not all symbols need to be created.
53
- # @param [Block] block
54
- # Just like +Array#each+, you can give a block.
55
- # @return [Array<ELFTools::symbol>]
56
- # The whole symbols will be returned.
57
- def each_symbols
52
+ # @yieldparam [ELFTools::Sections::Symbol] sym A symbol object.
53
+ # @yieldreturn [void]
54
+ # @return [Enumerator<ELFTools::Sections::Symbol>, Array<ELFTools::Sections::Symbol>]
55
+ # If block is not given, an enumerator will be returned.
56
+ # Otherwise return array of symbols.
57
+ def each_symbols(&block)
58
+ return enum_for(:each_symbols) unless block_given?
58
59
  Array.new(num_symbols) do |i|
59
- sym = symbol_at(i)
60
- block_given? ? yield(sym) : sym
60
+ symbol_at(i).tap(&block)
61
61
  end
62
62
  end
63
63
 
64
- alias symbols each_symbols
64
+ # Simply use {#symbols} to get all symbols.
65
+ # @return [Array<ELFTools::Sections::Symbol>]
66
+ # The whole symbols.
67
+ def symbols
68
+ each_symbols.to_a
69
+ end
65
70
 
66
- # Get symbol by it's name.
71
+ # Get symbol by its name.
67
72
  # @param [String] name
68
73
  # The name of symbol.
69
- # @return [ELFTools::Symbol] Desired symbol.
74
+ # @return [ELFTools::Sections::Symbol] Desired symbol.
70
75
  def symbol_by_name(name)
71
- return @symbol_name_map[name] if @symbol_name_map[name]
72
- each_symbols do |symbol|
73
- @symbol_name_map[symbol.name] = symbol
74
- return symbol if symbol.name == name
75
- end
76
- nil
76
+ each_symbols.find { |symbol| symbol.name == name }
77
77
  end
78
78
 
79
79
  # Return the symbol string section.
@@ -98,12 +98,12 @@ module ELFTools
98
98
  # XXX: Should this class be defined in an independent file?
99
99
  class Symbol
100
100
  attr_reader :header # @return [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] Section header.
101
- attr_reader :stream # @return [File] Streaming object.
101
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
102
102
 
103
- # Instantiate a {ELFTools::Symbol} object.
103
+ # Instantiate a {ELFTools::Sections::Symbol} object.
104
104
  # @param [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] header
105
105
  # The symbol header.
106
- # @param [File] stream The streaming object.
106
+ # @param [#pos=, #read] stream The streaming object.
107
107
  # @param [ELFTools::Sections::StrTabSection, Proc] symstr
108
108
  # The symbol string section.
109
109
  # If +Proc+ is given, it will be called at the first time
@@ -3,12 +3,12 @@ module ELFTools
3
3
  # Base class of segments.
4
4
  class Segment
5
5
  attr_reader :header # @return [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] Program header.
6
- attr_reader :stream # @return [File] Streaming object.
6
+ attr_reader :stream # @return [#pos=, #read] Streaming object.
7
7
 
8
8
  # Instantiate a {Segment} object.
9
9
  # @param [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] header
10
10
  # Program header.
11
- # @param [File] stream
11
+ # @param [#pos=, #read] stream
12
12
  # Streaming object.
13
13
  # @param [Method] offset_from_vma
14
14
  # The method to get offset of file, given virtual memory address.
@@ -13,7 +13,7 @@ module ELFTools
13
13
  class << Segment
14
14
  # Use different class according to +header.p_type+.
15
15
  # @param [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] header Program header of a segment.
16
- # @param [File] stream Streaming object.
16
+ # @param [#pos=, #read] stream Streaming object.
17
17
  # @return [ELFTools::Segments::Segment]
18
18
  # Return object dependes on +header.p_type+.
19
19
  def create(header, stream, *args)
@@ -8,6 +8,7 @@ module ELFTools
8
8
  module Structs
9
9
  # The base structure to define common methods.
10
10
  class ELFStruct < BinData::Record
11
+ # DRY. Many fields have different type in different arch.
11
12
  CHOICE_SIZE_T = {
12
13
  selection: :elf_class, choices: { 32 => :uint32, 64 => :uint64 }
13
14
  }.freeze
@@ -15,7 +16,7 @@ module ELFTools
15
16
  attr_accessor :elf_class # @return [Integer] 32 or 64.
16
17
 
17
18
  # Hacking to get endian of current class
18
- # @return [Symbol, NilClass] +:little+ or +:big+.
19
+ # @return [Symbol, nil] +:little+ or +:big+.
19
20
  def self.self_endian
20
21
  bindata_name[-2..-1] == 'ge' ? :big : :little
21
22
  end
@@ -89,6 +90,7 @@ module ELFTools
89
90
  uint64 :p_memsz
90
91
  uint64 :p_align
91
92
  end
93
+ # Get program header class according to bits.
92
94
  ELF_Phdr = {
93
95
  32 => ELF32_Phdr,
94
96
  64 => ELF64_Phdr
@@ -115,6 +117,7 @@ module ELFTools
115
117
  uint64 :st_value # Value of the symbol
116
118
  uint64 :st_size # Associated symbol size
117
119
  end
120
+ # Get symbol header class according to bits.
118
121
  ELF_sym = {
119
122
  32 => ELF32_sym,
120
123
  64 => ELF64_sym
data/lib/elftools/util.rb CHANGED
@@ -47,7 +47,7 @@ module ELFTools
47
47
  end
48
48
 
49
49
  # Read from stream until reach a null-byte.
50
- # @param [File] stream Streaming object
50
+ # @param [#pos=, #read] stream Streaming object
51
51
  # @param [Integer] offset Start from here.
52
52
  # @return [String] Result string will never contain null byte.
53
53
  # @example
@@ -80,9 +80,9 @@ module ELFTools
80
80
  # The return value will be objects in +enum+ with attribute
81
81
  # +.type+ equals to +type+.
82
82
  def select_by_type(enum, type)
83
- enum.select do |sec|
84
- if sec.type == type
85
- yield sec if block_given?
83
+ enum.select do |obj|
84
+ if obj.type == type
85
+ yield obj if block_given?
86
86
  true
87
87
  end
88
88
  end
@@ -1,3 +1,4 @@
1
1
  module ELFTools
2
- VERSION = '0.2.0'.freeze
2
+ # Current gem version
3
+ VERSION = '0.2.1'.freeze
3
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elftools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-17 00:00:00.000000000 Z
11
+ date: 2017-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.9'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.9'
97
111
  description: |2
98
112
  A light weight ELF parser. elftools is designed to be a low-level ELF parser.
99
113
  Inspired by https://github.com/eliben/pyelftools.