gdb 0.2.1 → 0.3.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 +4 -4
- data/README.md +2 -2
- data/lib/gdb/gdb.rb +51 -29
- data/lib/gdb/version.rb +1 -1
- metadata +23 -10
- data/lib/gdb/type_io.rb +0 -148
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 465e52470a227ee794a0ad1cbc6e643b6e7892d6
|
4
|
+
data.tar.gz: 377b2acb9be71480b63999833ea24247dcceba1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efbff6edff5a76a1774bb4a5ba2300885cce78ff783730270fef4f0d5b8b1503539efa626f6cd56a220f4a9ccc0a2646c96eaa6d0392e7ff64511f9ef143f39b
|
7
|
+
data.tar.gz: b91c6d713bc611fefcfa1898097ccfa402e18220f737f39ab1de6ee830603c760283a6a761ba7c745a4001255b316ccf8a9945df327781a7208335308d84ade0
|
data/README.md
CHANGED
@@ -104,8 +104,8 @@ gdb.run('-c "echo cat"')
|
|
104
104
|
rdi = gdb.reg(:rdi)
|
105
105
|
#=> 3
|
106
106
|
rsi = gdb.reg(:rsi)
|
107
|
-
argv = gdb.readm(rsi, rdi, as: :
|
108
|
-
argv.map{ |c|'0x%x' % c }
|
107
|
+
argv = gdb.readm(rsi, rdi, as: :u64)
|
108
|
+
argv.map { |c| '0x%x' % c }
|
109
109
|
#=> ['0x7fffffffe61b', '0x7fffffffe625', '0x7fffffffe628']
|
110
110
|
|
111
111
|
# 3. overwrite argv[2]'s 'cat' to 'FAT'
|
data/lib/gdb/gdb.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'io/console'
|
2
|
+
require 'memory_io'
|
2
3
|
require 'pty'
|
3
4
|
require 'readline'
|
4
5
|
|
5
6
|
require 'gdb/eval_context'
|
6
7
|
require 'gdb/gdb_error'
|
7
8
|
require 'gdb/tube/tube'
|
8
|
-
require 'gdb/type_io'
|
9
9
|
|
10
10
|
module GDB
|
11
11
|
# For launching a gdb process.
|
@@ -156,19 +156,35 @@ module GDB
|
|
156
156
|
|
157
157
|
# Read current process's memory.
|
158
158
|
#
|
159
|
-
#
|
159
|
+
# @param [Integer, String] addr
|
160
|
+
# Address to start to read.
|
161
|
+
# +addr+ can be a string like 'heap+0x10'.
|
162
|
+
# Supported variables are names in /proc/$pid/maps such as +heap/libc/stack/ld+.
|
160
163
|
#
|
161
|
-
# @param [
|
162
|
-
#
|
164
|
+
# @param [Integer] num_elements
|
165
|
+
# Number of elements to read.
|
166
|
+
# If +num_elements+ equals to 1, an object read will be returned.
|
167
|
+
# Otherwise, an array with size +num_elements+ will be returned.
|
163
168
|
#
|
164
|
-
# @
|
165
|
-
#
|
169
|
+
# @option [Symbol, Class] as
|
170
|
+
# Types that supported by [MemoryIO](https://github.com/david942j/memory_io).
|
171
|
+
#
|
172
|
+
# @return [Object, Array<Object>]
|
173
|
+
# Return types are decided by value of +num_elements+ and option +as+.
|
166
174
|
#
|
167
175
|
# @yieldparam [IO] io
|
168
|
-
#
|
176
|
+
# The +IO+ object that points to +addr+,
|
177
|
+
# read from it.
|
169
178
|
#
|
170
179
|
# @yieldreturn [Object]
|
171
|
-
#
|
180
|
+
# Whatever you read from +io+.
|
181
|
+
#
|
182
|
+
# @example
|
183
|
+
# gdb = GDB::GDB.new('spec/binaries/amd64.elf')
|
184
|
+
# gdb.break('main')
|
185
|
+
# gdb.run
|
186
|
+
# gdb.read_memory('amd64.elf', 4)
|
187
|
+
# #=> "\x7fELF"
|
172
188
|
#
|
173
189
|
# @example
|
174
190
|
# # example of fetching argv
|
@@ -179,41 +195,47 @@ module GDB
|
|
179
195
|
# #=> "\x7fELF"
|
180
196
|
# argc = gdb.register(:rdi)
|
181
197
|
# #=> 4
|
182
|
-
# args = gdb.read_memory(gdb.register(:rsi), argc, as: :
|
198
|
+
# args = gdb.read_memory(gdb.register(:rsi), argc, as: :u64)
|
183
199
|
# Array.new(3) do |i|
|
184
200
|
# gdb.read_memory(args[i + 1], 1) do |m|
|
185
201
|
# str = ''
|
186
|
-
#
|
202
|
+
# loop do
|
203
|
+
# c = m.read(1)
|
204
|
+
# break if c == "\x00"
|
205
|
+
# str << c
|
206
|
+
# end
|
187
207
|
# str
|
188
208
|
# end
|
189
209
|
# end
|
190
|
-
# #=> ["pusheen
|
210
|
+
# #=> ["pusheen", "the", "cat"]
|
191
211
|
#
|
192
|
-
# # or, use our build-in types
|
193
|
-
# gdb.read_memory(args[1], 3, as: :
|
194
|
-
# #=> ["pusheen
|
195
|
-
def read_memory(
|
212
|
+
# # or, use our build-in types of gem +memory_io+.
|
213
|
+
# gdb.read_memory(args[1], 3, as: :c_str)
|
214
|
+
# #=> ["pusheen", "the", "cat"]
|
215
|
+
def read_memory(addr, num_elements, options = {}, &block)
|
196
216
|
check_alive! # this would set @pid
|
197
|
-
|
198
|
-
|
199
|
-
end
|
217
|
+
options[:as] = block if block_given?
|
218
|
+
MemoryIO.attach(@pid).read(addr, num_elements, **options)
|
200
219
|
end
|
201
220
|
alias readm read_memory
|
202
221
|
|
203
|
-
# Write
|
222
|
+
# Write an object to process at specific address.
|
204
223
|
#
|
205
|
-
# @param [Integer] addr
|
224
|
+
# @param [Integer, String] addr
|
206
225
|
# Target address.
|
207
|
-
#
|
208
|
-
#
|
226
|
+
# +addr+ can be a string like 'heap+0x10'.
|
227
|
+
# Supported variables are names in +/proc/$pid/maps+ such as +heap/libc/stack/ld+.
|
228
|
+
# @param [Objects, Array<Objects>] objects
|
229
|
+
# Objects to be written.
|
209
230
|
#
|
210
|
-
# @
|
211
|
-
#
|
212
|
-
|
231
|
+
# @option [Symbol, Class] as
|
232
|
+
# See {#read_memory}.
|
233
|
+
#
|
234
|
+
# @return [void]
|
235
|
+
def write_memory(addr, objects, options = {}, &block)
|
213
236
|
check_alive! # this would set @pid
|
214
|
-
|
215
|
-
|
216
|
-
end
|
237
|
+
options[:as] = block if block_given?
|
238
|
+
MemoryIO.attach(@pid).write(addr, objects, **options)
|
217
239
|
end
|
218
240
|
alias writem write_memory
|
219
241
|
|
@@ -251,7 +273,7 @@ module GDB
|
|
251
273
|
|
252
274
|
# Raise {GDBError} if process is not running.
|
253
275
|
#
|
254
|
-
# @return [
|
276
|
+
# @return [void]
|
255
277
|
def check_alive!
|
256
278
|
raise GDBError, 'Process is not running' unless alive?
|
257
279
|
end
|
data/lib/gdb/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- david942j
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: memory_io
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: codeclimate-test-reporter
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,42 +58,42 @@ dependencies:
|
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '12.
|
61
|
+
version: '12.3'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '12.
|
68
|
+
version: '12.3'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
75
|
+
version: '3.7'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '3.
|
82
|
+
version: '3.7'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rubocop
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
87
|
- - "~>"
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0.
|
89
|
+
version: '0.52'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0.
|
96
|
+
version: '0.52'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: simplecov
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -127,7 +141,6 @@ files:
|
|
127
141
|
- lib/gdb/scripts/gdbinit.py
|
128
142
|
- lib/gdb/tube/buffer.rb
|
129
143
|
- lib/gdb/tube/tube.rb
|
130
|
-
- lib/gdb/type_io.rb
|
131
144
|
- lib/gdb/version.rb
|
132
145
|
homepage: https://github.com/david942j/gdb-ruby
|
133
146
|
licenses:
|
@@ -149,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
162
|
version: '0'
|
150
163
|
requirements: []
|
151
164
|
rubyforge_project:
|
152
|
-
rubygems_version: 2.
|
165
|
+
rubygems_version: 2.6.14
|
153
166
|
signing_key:
|
154
167
|
specification_version: 4
|
155
168
|
summary: GDB Ruby-binding and Ruby command in GDB
|
data/lib/gdb/type_io.rb
DELETED
@@ -1,148 +0,0 @@
|
|
1
|
-
module GDB
|
2
|
-
# Support read / write custom defined tpyes.
|
3
|
-
class TypeIO
|
4
|
-
class << self
|
5
|
-
# Read a little endian integer.
|
6
|
-
#
|
7
|
-
# @param [#read] io
|
8
|
-
# @param [Integer] byte
|
9
|
-
# @param [:signed, :unsigned] sign
|
10
|
-
# Signed or unsigned integer.
|
11
|
-
#
|
12
|
-
# @return [Integer]
|
13
|
-
# The read integer.
|
14
|
-
#
|
15
|
-
# @example
|
16
|
-
# read_integer(StringIO.new("\x80"), 1, :signed)
|
17
|
-
# #=> -128
|
18
|
-
def read_integer(io, byte, sign)
|
19
|
-
str = io.read(byte).reverse # little endian
|
20
|
-
val = str.bytes.reduce(0) { |sum, b| sum * 256 + b }
|
21
|
-
if sign == :signed && val >= (1 << (8 * byte - 1))
|
22
|
-
val -= 1 << (8 * byte)
|
23
|
-
end
|
24
|
-
val
|
25
|
-
end
|
26
|
-
|
27
|
-
# Read until +needle+ appears.
|
28
|
-
#
|
29
|
-
# @param [IO] io
|
30
|
-
# @param [String] needle
|
31
|
-
#
|
32
|
-
# @return [String]
|
33
|
-
def read_until(io, needle)
|
34
|
-
str = ''
|
35
|
-
str << io.read(1) until str.end_with?(needle)
|
36
|
-
str
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Supported built-in types.
|
41
|
-
TYPES = {
|
42
|
-
string: nil, # will be special handled
|
43
|
-
|
44
|
-
cstring: ->(io) { TypeIO.read_until(io, "\x00") }, # read a null-terminated string.
|
45
|
-
|
46
|
-
int8: ->(io) { TypeIO.read_integer(io, 1, :signed) },
|
47
|
-
int16: ->(io) { TypeIO.read_integer(io, 2, :signed) },
|
48
|
-
int32: ->(io) { TypeIO.read_integer(io, 4, :signed) },
|
49
|
-
int64: ->(io) { TypeIO.read_integer(io, 8, :signed) },
|
50
|
-
int128: ->(io) { TypeIO.read_integer(io, 16, :signed) },
|
51
|
-
|
52
|
-
uint8: ->(io) { TypeIO.read_integer(io, 1, :unsigned) },
|
53
|
-
uint16: ->(io) { TypeIO.read_integer(io, 2, :unsigned) },
|
54
|
-
uint32: ->(io) { TypeIO.read_integer(io, 4, :unsigned) },
|
55
|
-
uint64: ->(io) { TypeIO.read_integer(io, 8, :unsigned) },
|
56
|
-
uint128: ->(io) { TypeIO.read_integer(io, 16, :unsigned) },
|
57
|
-
|
58
|
-
float: ->(io) { io.read(4).unpack('F').first },
|
59
|
-
double: ->(io) { io.read(8).unpack('D').first }
|
60
|
-
}.freeze
|
61
|
-
|
62
|
-
# Instantiate a {TypeIO} object.
|
63
|
-
#
|
64
|
-
# @param [IO, #pos=, #read, #write] io
|
65
|
-
# The IO file.
|
66
|
-
def initialize(io)
|
67
|
-
@io = io.binmode
|
68
|
-
end
|
69
|
-
|
70
|
-
# Read data at specific address and cast into desired type.
|
71
|
-
#
|
72
|
-
# @param [Integer] addr
|
73
|
-
# Address to be read.
|
74
|
-
#
|
75
|
-
# @param [Integer] size
|
76
|
-
# Number of data to be read. See parameter +as+ for details.
|
77
|
-
#
|
78
|
-
# @param [Symbol] as
|
79
|
-
# The needed returned type.
|
80
|
-
# Note that the total bytes be read will be +size * sizeof(as)+.
|
81
|
-
# For example, if +as+ equals +:int32+, +size * 4+ bytes would be read,
|
82
|
-
# and returned type is array of 32 bits signed integers.
|
83
|
-
#
|
84
|
-
# Supported types are listed in {TypeIO::TYPES}, all integer-like types
|
85
|
-
# are seen as little endian. If you need big endian or other fashion things, pass a block
|
86
|
-
# instead of using parameter +as+.
|
87
|
-
#
|
88
|
-
# @yieldparam [IO] io
|
89
|
-
# If block is given, the parameter +as+ would be ignored.
|
90
|
-
# Block would be invoked +size+ times, and the returned object would be collected into
|
91
|
-
# one array and returned.
|
92
|
-
#
|
93
|
-
# This is convenient for reading non-stable size objects, e.g. c++'s string object.
|
94
|
-
# See examples for clearer usage.
|
95
|
-
#
|
96
|
-
# @yieldreturn [Object]
|
97
|
-
# Whatever object you like.
|
98
|
-
#
|
99
|
-
# @return [String, Object, Array<Object>]
|
100
|
-
# If +as+ equals to +:string+, the string with length +size+ would be returned.
|
101
|
-
# Otherwise, array of objects would be returned.
|
102
|
-
# An exception is when +size+ equals to 1, the read object would be returned
|
103
|
-
# instead of create an array with only one element.
|
104
|
-
#
|
105
|
-
# @example
|
106
|
-
# io = TypeIO.new(StringIO.new("AAAA"))
|
107
|
-
# io.read(0, 3)
|
108
|
-
# #=> "AAA"
|
109
|
-
# io.read(0, 1, as: :uint32)
|
110
|
-
# #=> 1094795585 # 0x41414141
|
111
|
-
#
|
112
|
-
# io = TypeIO.new(StringIO.new("\xef\xbe\xad\xde"))
|
113
|
-
# io.read(0, 4, as: :int8)
|
114
|
-
# #=> [-17, -66, -83, -34]
|
115
|
-
#
|
116
|
-
# io = TypeIO.new(StringIO.new("\x04ABCD\x03AAA\x00\x04meow"))
|
117
|
-
# io.read(0, 4) do |m|
|
118
|
-
# len = m.read(1).ord
|
119
|
-
# m.read(len)
|
120
|
-
# end
|
121
|
-
# #=> ['ABCD', 'AAA', '', 'meow']
|
122
|
-
def read(addr, size, as: :string)
|
123
|
-
@io.pos = addr
|
124
|
-
if block_given?
|
125
|
-
return yield @io if size == 1
|
126
|
-
Array.new(size) { yield @io }
|
127
|
-
else
|
128
|
-
raise ArgumentError, "Unsupported types #{as.inspect}" unless TYPES.key?(as)
|
129
|
-
return @io.read(size) if as == :string
|
130
|
-
read(addr, size, &TYPES[as])
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Write a string at specific address.
|
135
|
-
#
|
136
|
-
# @param [Integer] addr
|
137
|
-
# Target address.
|
138
|
-
# @param [String] str
|
139
|
-
# String to be written.
|
140
|
-
#
|
141
|
-
# @return [Integer]
|
142
|
-
# Bytes written.
|
143
|
-
def write(addr, str)
|
144
|
-
@io.pos = addr
|
145
|
-
@io.write(str)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|