gdbdump 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +68 -4
- data/lib/gdbdump/cli.rb +1 -1
- data/lib/gdbdump/gdb.rb +6 -2
- data/lib/gdbdump/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47f96b6948a61ee96134de40f22548c97d265549
|
4
|
+
data.tar.gz: 406b7e0a333f356278bc813082cbffc599f7fcc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73adc0c34ac5e358de859b99be87e59da5558cce6fbcc1ba5ffc01d366d1c0d3fe27abe82afc1b2966dccd6b9165e09932147402a09f29172b7345fc30a0e4b3
|
7
|
+
data.tar.gz: eea4efc06c19748d84b626b6593a2afcb89ab9876f5e44c3686658bf222ce9f30d2a875de4efd4ff3db78373b5a5b532655cee35a21db5ea013d733794fe5486
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -21,7 +21,7 @@ It was verfied that gdbdump works with ruby executables built by [rbenv/ruby-bui
|
|
21
21
|
```
|
22
22
|
Usage: gdbdump [options] pid
|
23
23
|
-d, --[no-]debug print debug log (default: false)
|
24
|
-
-x, --gdbinit FILE path to ruby
|
24
|
+
-x, --gdbinit FILE path to ruby repo's .gdbinit (default: some of ruby repo's .gdbinit is pre-bundle in this gem)
|
25
25
|
--gdb PATH path to gdb command (default: gdb)
|
26
26
|
--ruby PATH path to ruby which the attached process uses (default: get from /proc/[PID]/exe)
|
27
27
|
```
|
@@ -30,7 +30,7 @@ Usage: gdbdump [options] pid
|
|
30
30
|
|
31
31
|
Default supported ruby versions: 2.1.x - 2.4.x
|
32
32
|
|
33
|
-
Ruby
|
33
|
+
Ruby repo's [.gdbinit](https://github.com/ruby/ruby/blob/trunk/.gdbinit) file defines useful helper functions and it is maintained by ruby core team. `gdbdump` uses it.
|
34
34
|
Some versions written as above of .gdbinit are bundled in this gem, but if you want to use `gdbdump` for older or newer ruby versions:
|
35
35
|
|
36
36
|
1. Download .gdbinit from ruby repo like [ruby/2.4.1/.gdbinit](https://github.com/ruby/ruby/blob/v2_4_1/.gdbinit), and specify with `-x` option
|
@@ -76,11 +76,11 @@ loop.rb:11:in `block in <main>'
|
|
76
76
|
* You can print C level backtrace with raw gdb, of course
|
77
77
|
* [sigdump](https://github.com/frsyuki/sigdump)
|
78
78
|
* sigdump enables to print ruby level backtrace with sending CONT signal to living ruby process.
|
79
|
-
* The ruby process must pre-install `sigdump` gem and `require 'sigdump/setup'` unlike gdbdump.
|
79
|
+
* The ruby process **must pre-install** `sigdump` gem and `require 'sigdump/setup'` unlike gdbdump.
|
80
80
|
* sigdump prints backtrace in signal handler, so blocks main thread, but other threads still work unlike gdbdump.
|
81
81
|
* [gdbruby](https://github.com/gunyarakun/gdbruby)
|
82
82
|
* gdbruby enables to print C level and ruby level backtrace of living ruby process and core file.
|
83
|
-
* gdbruby must follow changes of C level interfaces of CRuby to get backtrace of the core file, it rises fragility that it will be broken on newer ruby versions.
|
83
|
+
* gdbruby **must follow changes of C level interfaces of CRuby** to get backtrace of the core file, it rises fragility that it will be broken on newer ruby versions.
|
84
84
|
* gdbruby stops the process during printing backtrace as gdbdump, but it supports also core file. Using `gcore` command to get core file, it would be possible to analyze without stopping the process.
|
85
85
|
|
86
86
|
## Development
|
@@ -89,6 +89,70 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
89
89
|
|
90
90
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
91
91
|
|
92
|
+
### Investigation
|
93
|
+
|
94
|
+
Belows are my investigation notes about how to print C level and Ruby level backtrace via gdb.
|
95
|
+
|
96
|
+
#### (1) rb_print_backtrace() and rb_backtrace()
|
97
|
+
|
98
|
+
CRuby itself has [rb_print_backtrace](https://github.com/ruby/ruby/blob/26864584d269b6141a27c783cf8b751c067c7dbe/vm_dump.c#L671) function to print C level backtrace, and [rb_backtrace](https://github.com/ruby/ruby/blob/eb59047e2aabb050b23061d513f7b89dc2905670/vm_backtrace.c#L770) function to print Ruby level backtrace.
|
99
|
+
I first tried to use them.
|
100
|
+
|
101
|
+
However, they print a backtrace of only current thread. Furthermore, rb_print_backtrace supports printing outputs to only STDERR.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
def print_backtrace
|
105
|
+
run do |gdb|
|
106
|
+
gdb.cmd_exec('call write(2, "== c backtrace ==\n", 18)')
|
107
|
+
gdb.cmd_exec('call rb_print_backtrace()')
|
108
|
+
gdb.cmd_exec('call write(2, "== ruby backtrace ==\n", 21)')
|
109
|
+
gdb.cmd_exec('call rb_backtrace()')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
#### (2) bt and rb_eval_string()
|
115
|
+
|
116
|
+
I secondly tried to use GDB's `info threads` and `bt` command to print C level backtrace. This was fine.
|
117
|
+
|
118
|
+
I also tried to print Ruby level backtrace by calling [rb_eval_string](https://github.com/ruby/ruby/blob/44396dbe123511678710cfb21223c954b9ceaafb/vm_eval.c#L1474) with Ruby codes as:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
def ruby_backtrace_code
|
122
|
+
code = +%Q[File.open('#{dumpfile}', 'a') {|f|]
|
123
|
+
code << %q[
|
124
|
+
Thread.list.each {|th|
|
125
|
+
f.write %Q[ Thread #{th} status=#{th.status} priority=#{th.priority}\n]
|
126
|
+
th.backtrace.each {|bt|
|
127
|
+
f.write %Q[ #{bt}\n]
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}]
|
131
|
+
code.split("\n").map(&:strip).join('; ')
|
132
|
+
end
|
133
|
+
|
134
|
+
def print_backtrace
|
135
|
+
run do |gdb|
|
136
|
+
gdb.cmd_exec(%Q[call rb_eval_string("#{ruby_backtrace_code}")])
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
However, the debugee (target) process got stuck after `call rb_eval_string`. It seemed the ruby process will be broken if ruby codes are executed via gdb.
|
142
|
+
|
143
|
+
#### (3) rb_ps from ruby trunk's .gdbinit
|
144
|
+
|
145
|
+
I thirdly tried to use `rb_ps` function defined in [.gdbinit](https://github.com/ruby/ruby/blob/44396dbe123511678710cfb21223c954b9ceaafb/.gdbinit#L983) of ruby repository to print C level and Ruby level backtrace of all threads.
|
146
|
+
|
147
|
+
Since `.gdbinit` is maintained by ruby core team, I do not need to follow changes of C level interfaces of CRuby as long as I follow `.gdbinit`.
|
148
|
+
|
149
|
+
The drawback of this way is that
|
150
|
+
|
151
|
+
1. I have to follow changes of `.gdbinit` in newer ruby versions
|
152
|
+
2. `rb_ps` takes somewhat long time like 2.6 seconds to print backtrace.
|
153
|
+
|
154
|
+
Currently, I am taking this way.
|
155
|
+
|
92
156
|
## Contributing
|
93
157
|
|
94
158
|
Bug reports and pull requests are welcome on GitHub at https://github.com/sonots/gdbdump. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/lib/gdbdump/cli.rb
CHANGED
@@ -24,7 +24,7 @@ class Gdbdump
|
|
24
24
|
op.on('-d', '--[no-]debug', "print debug log (default: #{opts[:debug]})") {|v|
|
25
25
|
opts[:debug] = v
|
26
26
|
}
|
27
|
-
op.on('-x', '--gdbinit FILE', "path to ruby
|
27
|
+
op.on('-x', '--gdbinit FILE', "path to ruby repo's .gdbinit (default: some of ruby repo's .gdbinit are pre-bundle in this gem)") {|v|
|
28
28
|
opts[:gdbinit] = v
|
29
29
|
}
|
30
30
|
op.on('--gdb PATH', "path to gdb command (default: gdb)") {|v|
|
data/lib/gdbdump/gdb.rb
CHANGED
@@ -13,8 +13,12 @@ class Gdbdump
|
|
13
13
|
@pid = pid.to_s
|
14
14
|
@debug = debug
|
15
15
|
@gdb = gdb || 'gdb'
|
16
|
-
@ruby = ruby || Procfs.new(@pid).exe
|
17
|
-
|
16
|
+
@ruby = (ruby || Procfs.new(@pid).exe).tap do |path|
|
17
|
+
raise "ruby #{path} is not accessible" unless File.executable?(path)
|
18
|
+
end
|
19
|
+
@gdbinit = (gdbinit || File.join(ROOT, 'vendor', 'ruby', ruby_minor_version, 'gdbinit')).tap do |path|
|
20
|
+
raise "gdbinit #{path} is not readable" unless File.readable?(path)
|
21
|
+
end
|
18
22
|
@exec_options = [SUDO_CMD, @gdb, '-silent', '-nw', '-x', @gdbinit, @ruby, @pid]
|
19
23
|
end
|
20
24
|
|
data/lib/gdbdump/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gdbdump
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naotoshi Seo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|