elftools 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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.