gdbdump 0.9.2 → 0.9.3
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/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
|