memory_io 0.1.1 → 0.2.0

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
- SHA1:
3
- metadata.gz: e17e1f92566207d70c15b219aee13f363351c8e6
4
- data.tar.gz: 6de663775256debf502563107010d6c058a9476c
2
+ SHA256:
3
+ metadata.gz: 3de5ed7bf7e1f8543bbb290ed472f008ed9d8f4c1af032a11831bd904378c11e
4
+ data.tar.gz: e99b29afb7cdcc7941bb6249bbe453cea2cb3a6cb6eab72a8965bfa5ef9802e3
5
5
  SHA512:
6
- metadata.gz: 0c5cc2882d17b308bcd2edd3bd298dc063555635e232f489c20cf378811272839dcce6fead1dd22605d6b77795acb3e08623e74d1650fadaa0ef62229083e8db
7
- data.tar.gz: 937ba157cbf68e9e207aacefe2b00bcc1153cd128e41ec1fff1be1d00d3715c3ed6258d7e4eb5d3c0cab40fc2d486a0158f23ad73d8b98c12d4fff76408e7c6c
6
+ metadata.gz: d4d3d9e60c649dd8d4e6f3c3dfe3bb777d2a7ffd2065699e3f86fef27f9ddf079b90acc7d7a5be244301d45ba46d9c713b950bbaa7a113843631287fb1e9653f
7
+ data.tar.gz: 2246f04654d036e8df50440cf2c3d9ebe50933921f5720bf5f69308648ab34849d869b3969f581579dba8930ae1fbd0e5a1d6e27246900129cef39212e2876bf
data/README.md CHANGED
@@ -17,9 +17,9 @@ However, gdb doesn't support writing Ruby scripts
17
17
  (unless you use [gdb-ruby](https://github.com/david942j/gdb-ruby), which has dependency of **MemoryIO**).
18
18
  So I create this repo and want to make the debug procedure much easier.
19
19
 
20
- This repo has two main targets:
20
+ This repository has two main goals:
21
21
 
22
- 1. To communiate with memory easily.
22
+ 1. To communicate with memory easily.
23
23
  2. To collect all common structures for debugging/learning.
24
24
 
25
25
  ## Why
@@ -51,7 +51,7 @@ process.read(0x601000, 1, as: 'basic/u64')
51
51
  process.read(0x601000, 1, as: :u64)
52
52
  ```
53
53
 
54
- Goto [the online document](http://www.rubydoc.info/github/david942j/memory_io/master/MemoryIO/Types) for more details
54
+ Go to [the online document](http://www.rubydoc.info/github/david942j/memory_io/master/MemoryIO/Types) for more details
55
55
  of each type.
56
56
 
57
57
  ### BASIC
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # MemoryIO - Read/Write structures in memory.
2
4
  #
3
5
  # @author david942j
@@ -1,4 +1,5 @@
1
1
  # encoding: ascii-8bit
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'memory_io/types/types'
4
5
 
@@ -11,14 +12,14 @@ module MemoryIO
11
12
  #
12
13
  # @param [#pos, #pos=, #read, #write] stream
13
14
  # The file-like object to be read/written.
14
- # +file+ can be unwritable if you will not invoke any write-related method.
15
+ # +file+ can be un-writable if you will not invoke any write-related method.
15
16
  #
16
17
  # If +stream.read(*)+ returns empty string or +nil+, it would be seen as reaching EOF.
17
18
  def initialize(stream)
18
19
  @stream = stream
19
20
  end
20
21
 
21
- # Read and convert result into custom type/stucture.
22
+ # Read and convert result into custom type/structure.
22
23
  #
23
24
  # @param [Integer] num_elements
24
25
  # Number of elements to be read.
@@ -43,7 +44,7 @@ module MemoryIO
43
44
  #
44
45
  # @return [String, Object, Array<Object>]
45
46
  # There're multiple possible return types,
46
- # which dependes on the value of parameter +num_elements+, +as+, and +force_array+.
47
+ # which depends on the value of parameter +num_elements+, +as+, and +force_array+.
47
48
  #
48
49
  # See examples for clear usage. The rule of return type is listed as following:
49
50
  #
@@ -102,6 +103,7 @@ module MemoryIO
102
103
  def read(num_elements, from: nil, as: nil, force_array: false)
103
104
  stream.pos = from if from
104
105
  return stream.read(num_elements) if as.nil?
106
+
105
107
  conv = to_proc(as, :read)
106
108
  # TODO: handle eof
107
109
  ret = Array.new(num_elements) { conv.call(stream) }
@@ -123,7 +125,7 @@ module MemoryIO
123
125
  #
124
126
  # A +Proc+ is allowed, which should accept +stream+ and one object as arguments.
125
127
  #
126
- # If +objects+ is a descendent instance of {Types::Type} and +as+ is +nil,
128
+ # If +objects+ is a descendant instance of {Types::Type} and +as+ is +nil,
127
129
  # +objects.class+ will be used for +as+.
128
130
  # Otherwise, when +as = nil+, this method will simply call +stream.write(objects)+.
129
131
  #
@@ -163,6 +165,7 @@ module MemoryIO
163
165
  stream.pos = from if from
164
166
  as ||= objects.class if objects.class.ancestors.include?(MemoryIO::Types::Type)
165
167
  return stream.write(objects) if as.nil?
168
+
166
169
  conv = to_proc(as, :write)
167
170
  Array(objects).map { |o| conv.call(stream, o) }
168
171
  end
@@ -182,8 +185,10 @@ module MemoryIO
182
185
  ret = as.respond_to?(rw) ? as.method(rw) : as
183
186
  ret = ret.respond_to?(:call) ? ret : MemoryIO::Types.get_proc(ret, rw)
184
187
  raise ArgumentError, <<-EOERR.strip unless ret.respond_to?(:call)
188
+
185
189
  Invalid argument `as`: #{as.inspect}. It should be either a Proc or a supported type of MemoryIO::Types.
186
190
  EOERR
191
+
187
192
  ret
188
193
  end
189
194
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MemoryIO
2
4
  # Records information of a process.
3
5
  class Process
@@ -26,6 +28,7 @@ module MemoryIO
26
28
  @perm = MemoryIO::Util.file_permission(@mem)
27
29
  # TODO: raise custom exception
28
30
  raise Errno::ENOENT, @mem if perm.nil?
31
+
29
32
  # FIXME: use logger
30
33
  warn(<<-EOS.strip) unless perm.readable? || perm.writable?
31
34
  You have no permission to read/write this process.
@@ -59,11 +62,13 @@ $ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
59
62
  def bases
60
63
  file = "/proc/#{@pid}/maps"
61
64
  stat = MemoryIO::Util.file_permission(file)
62
- return {} unless stat && stat.readable?
65
+ return {} unless stat&.readable?
66
+
63
67
  maps = ::IO.binread(file).split("\n").map do |line|
64
68
  # 7f76515cf000-7f76515da000 r-xp 00000000 fd:01 29360257 /lib/x86_64-linux-gnu/libnss_files-2.24.so
65
69
  addr, _perm, _offset, _dev, _inode, pathname = line.strip.split(' ', 6)
66
70
  next nil if pathname.nil?
71
+
67
72
  addr = addr.to_i(16)
68
73
  pathname = pathname[1..-2] if pathname =~ /^\[.+\]$/
69
74
  pathname = ::File.basename(pathname)
@@ -104,7 +109,7 @@ $ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
104
109
  # #=> "\x7fELF"
105
110
  # @see IO#read
106
111
  def read(addr, num_elements, **options)
107
- mem_io(:read) { |io| io.read(num_elements, from: MemoryIO::Util.safe_eval(addr, bases), **options) }
112
+ mem_io(:read) { |io| io.read(num_elements, from: MemoryIO::Util.safe_eval(addr, **bases), **options) }
108
113
  end
109
114
 
110
115
  # Write objects at +addr+.
@@ -128,7 +133,7 @@ $ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
128
133
  # #=> 'BBBBCCCCAAAAAAAA'
129
134
  # @see IO#write
130
135
  def write(addr, objects, **options)
131
- mem_io(:write) { |io| io.write(objects, from: MemoryIO::Util.safe_eval(addr, bases), **options) }
136
+ mem_io(:write) { |io| io.write(objects, from: MemoryIO::Util.safe_eval(addr, **bases), **options) }
132
137
  end
133
138
 
134
139
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'memory_io/types/type'
2
4
 
3
5
  module MemoryIO
@@ -6,7 +8,7 @@ module MemoryIO
6
8
  module Basic
7
9
  # Register numbers to {Types}.
8
10
  #
9
- # All types registerd by this class are assumed as *little endian*.
11
+ # All types registered by this class are assumed as *little endian*.
10
12
  #
11
13
  # This class registered (un)signed {8, 16, 32, 64)-bit integers and IEEE-754 floating numbers.
12
14
  class Number
@@ -1,4 +1,5 @@
1
1
  # encoding: ascii-8bit
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'memory_io/types/type'
4
5
 
@@ -10,15 +11,17 @@ module MemoryIO
10
11
  module Clang
11
12
  # A null-terminated string.
12
13
  class CStr < Types::Type
14
+
13
15
  # @api private
14
16
  #
15
17
  # @return [String]
16
18
  # String without null byte.
17
19
  def self.read(stream)
18
- ret = ''
20
+ ret = +''
19
21
  loop do
20
22
  c = stream.read(1)
21
23
  break if c.nil? || c == '' || c == "\x00"
24
+
22
25
  ret << c
23
26
  end
24
27
  ret
@@ -30,7 +33,7 @@ module MemoryIO
30
33
  # A null byte would be appended if +val+ not ends with null byte.
31
34
  def self.write(stream, val)
32
35
  val = val.to_s
33
- val << "\x00" unless val.end_with?("\x00")
36
+ val += "\x00" unless val.end_with?("\x00")
34
37
  stream.write(val)
35
38
  end
36
39
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'memory_io/types/type'
2
4
 
3
5
  module MemoryIO
@@ -16,6 +18,7 @@ module MemoryIO
16
18
  # }
17
19
  # };
18
20
  class String < MemoryIO::Types::Type
21
+
19
22
  # std::string uses inlined-buffer if string length isn't larger than {LOCAL_CAPACITY}.
20
23
  LOCAL_CAPACITY = 15
21
24
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MemoryIO
2
4
  module Types
3
5
  # @api private
@@ -39,6 +41,7 @@ module MemoryIO
39
41
  def doc
40
42
  return @force_doc if @force_doc
41
43
  return '' unless @caller
44
+
42
45
  parse_file_doc(@caller.absolute_path, @caller.lineno)
43
46
  end
44
47
 
@@ -47,13 +50,16 @@ module MemoryIO
47
50
  # @return [String]
48
51
  def parse_file_doc(file, lineno)
49
52
  return '' unless ::File.file?(file)
53
+
50
54
  strings = []
51
55
  lines = ::IO.binread(file).split("\n")
52
56
  (lineno - 1).downto(1) do |no|
53
57
  str = lines[no - 1]
54
58
  break if str.nil?
59
+
55
60
  str.strip!
56
61
  break unless str.start_with?('#')
62
+
57
63
  strings.unshift(str[2..-1] || '')
58
64
  end
59
65
  trim_docstring(strings)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
 
3
5
  require 'memory_io/types/record'
@@ -5,7 +7,7 @@ require 'memory_io/util'
5
7
 
6
8
  module MemoryIO
7
9
  module Types
8
- # The base class, all descendents of this class would be consider as a valid 'type'.
10
+ # The base class, all descendants of this class would be consider as a valid 'type'.
9
11
  class Type
10
12
  # The size of +size_t+. i.e. +sizeof(size_t)+.
11
13
  SIZE_T = 8
@@ -92,7 +94,7 @@ module MemoryIO
92
94
  # Register a new type.
93
95
  #
94
96
  # @param [#read, #write] object
95
- # Normally, +object+ is a descendent class of {Type}.
97
+ # Normally, +object+ is a descendant class of {Type}.
96
98
  #
97
99
  # @option [Symbol, Array<Symbol>] alias
98
100
  # Custom symbol name(s) that can be used in {.find}.
@@ -128,8 +130,10 @@ Register '#{object.inspect}' fails because another object with same name has bee
128
130
  Specify an alias such as `register(MyClass, alias: :custom_alias_name)`.
129
131
  EOS
130
132
  raise reg_fail if aliases.any? && aliases.all? { |ali| @map[ali] }
133
+
131
134
  keys = get_keys(object).concat(aliases).uniq.reject { |k| @map[k] }
132
135
  raise reg_fail if keys.empty?
136
+
133
137
  rec = MemoryIO::Types::Record.new(object, keys, option)
134
138
  keys.each { |k| @map[k] = rec }
135
139
  end
@@ -156,6 +160,7 @@ Specify an alias such as `register(MyClass, alias: :custom_alias_name)`.
156
160
  # @return [Array<Symbol>]
157
161
  def get_keys(klass)
158
162
  return [] unless klass.instance_of?(Class)
163
+
159
164
  snake = MemoryIO::Util.underscore(klass.name)
160
165
  snake.gsub!(%r[^memory_io/types/], '')
161
166
  ret = [snake]
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'memory_io/types/type'
2
4
  require 'memory_io/util'
3
5
 
4
- Dir[File.join(__dir__, '**', '*.rb')].each { |f| require f }
6
+ Dir.glob(File.join(__dir__, '**', '*.rb')).sort.each { |f| require f unless f == __FILE__ }
5
7
 
6
8
  module MemoryIO
7
9
  # Module that includes multiple types.
@@ -53,7 +55,7 @@ module MemoryIO
53
55
  # #=> #<Method: MemoryIO::Types::Number#read>
54
56
  def get_proc(name, rw)
55
57
  klass = find(name)
56
- klass && klass.method(rw)
58
+ klass&.method(rw)
57
59
  end
58
60
  end
59
61
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
  require 'dentaku'
3
5
 
@@ -24,6 +26,7 @@ module MemoryIO
24
26
  # #=> 'my_module/my_class'
25
27
  def underscore(str)
26
28
  return '' if str.empty?
29
+
27
30
  str = str.gsub('::', '/')
28
31
  str.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
29
32
  str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
@@ -41,6 +44,7 @@ module MemoryIO
41
44
  # +nil+ for file not exists or is inaccessible.
42
45
  def file_permission(file)
43
46
  return nil unless File.file?(file)
47
+
44
48
  stat = File.stat(file)
45
49
  # we do a trick here because /proc/[pid]/mem might be marked as readable but fails at sysopen.
46
50
  os = OpenStruct.new(readable?: stat.readable_real?, writable?: stat.writable_real?)
@@ -72,6 +76,7 @@ module MemoryIO
72
76
  # #=> 56960 # 0xde80
73
77
  def safe_eval(str, **vars)
74
78
  return str if str.is_a?(Integer)
79
+
75
80
  # dentaku 2 doesn't support hex
76
81
  str = str.gsub(/0x[0-9a-zA-Z]+/) { |c| c.to_i(16) }
77
82
  Dentaku::Calculator.new.store(vars).evaluate(str)
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MemoryIO
2
4
  # Current gem version.
3
- VERSION = '0.1.1'.freeze
5
+ VERSION = '0.2.0'
4
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memory_io
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-30 00:00:00.000000000 Z
11
+ date: 2020-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dentaku
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '12.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '12.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.52'
61
+ version: '0.59'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.52'
68
+ version: '0.59'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.13.0
75
+ version: '0.17'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.13.0
82
+ version: '0.17'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +94,9 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.9'
97
- description: ''
97
+ description: 'Read/Write complicated structures in memory easily.
98
+
99
+ '
98
100
  email:
99
101
  - david942j@gmail.com
100
102
  executables: []
@@ -125,15 +127,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
127
  requirements:
126
128
  - - ">="
127
129
  - !ruby/object:Gem::Version
128
- version: 2.1.0
130
+ version: '2.3'
129
131
  required_rubygems_version: !ruby/object:Gem::Requirement
130
132
  requirements:
131
133
  - - ">="
132
134
  - !ruby/object:Gem::Version
133
135
  version: '0'
134
136
  requirements: []
135
- rubyforge_project:
136
- rubygems_version: 2.6.14
137
+ rubygems_version: 3.0.3
137
138
  signing_key:
138
139
  specification_version: 4
139
140
  summary: memory_io