memory_io 0.1.1 → 0.2.0

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
- 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