Class: Gdbdump::GDB
- Inherits:
-
Object
- Object
- Gdbdump::GDB
- Defined in:
- lib/gdbdump/gdb.rb
Overview
GDB.new(pid: 999, debug: true).run do |gdb|
puts gdb.cmd_exec('bt')
end
Constant Summary collapse
- COMMAND_READ_BUFFER_SIZE =
1024
- SUDO_CMD =
'sudo'
Instance Method Summary collapse
- #cmd_exec(cmd) ⇒ Object
- #get_response ⇒ Object
-
#initialize(ruby: nil, pid_or_core:, debug: false, gdbinit: nil, gdb: nil) ⇒ GDB
constructor
A new instance of GDB.
- #print_backtrace ⇒ Object
- #run ⇒ Object
Constructor Details
#initialize(ruby: nil, pid_or_core:, debug: false, gdbinit: nil, gdb: nil) ⇒ GDB
Returns a new instance of GDB.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/gdbdump/gdb.rb', line 12 def initialize(ruby: nil, pid_or_core:, debug: false, gdbinit: nil, gdb: nil) if pid_or_core =~ /\A\d+\z/ @pid = pid_or_core.to_s @ruby = ruby || Procfs.new(@pid).exe else @core = pid_or_core raise "core #{@core} is not readable" unless File.readable?(@core) @ruby = ruby || raise("With core file, ruby path is required") end @pid_or_core = pid_or_core raise "ruby #{@ruby} is not accessible" unless File.executable?(@ruby) @gdbinit = gdbinit || File.join(ROOT, 'vendor', 'ruby', ruby_minor_version, 'gdbinit') raise "gdbinit #{@gdbinit} is not readable" unless File.readable?(@gdbinit) @debug = debug @gdb = gdb || 'gdb' @exec_options = [@gdb, '-silent', '-nw', '-x', @gdbinit, @ruby, @pid_or_core] @exec_options.unshift(SUDO_CMD) if @pid # sudo is required to ptrace a living process log('C', @exec_options.join(' ')) end |
Instance Method Details
#cmd_exec(cmd) ⇒ Object
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/gdbdump/gdb.rb', line 68 def cmd_exec(cmd) log('C', cmd) if cmd send_cmd = cmd.empty? ? cmd : "#{cmd}\n" r = @stdin.syswrite(send_cmd) raise "failed to send: [#{cmd}]" if r < send_cmd.length end get_response end |
#get_response ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/gdbdump/gdb.rb', line 79 def get_response out = +'' loop do begin buf = @stdout.sysread(COMMAND_READ_BUFFER_SIZE) rescue EOFError break end break if buf =~ /\(gdb\) $/ out << buf end log('O', out) err = +'' loop do begin buf = @stderr.read_nonblock(COMMAND_READ_BUFFER_SIZE) rescue Errno::EAGAIN, Errno::EWOULDBLOCK break rescue EOFError break end err << buf if buf end log('E', err) [out, err] end |
#print_backtrace ⇒ Object
43 44 45 46 47 48 49 |
# File 'lib/gdbdump/gdb.rb', line 43 def print_backtrace run do |gdb| out, err = gdb.cmd_exec('rb_ps') $stdout.puts out $stderr.puts err unless err.empty? end end |
#run ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/gdbdump/gdb.rb', line 51 def run @stdin, @stdout, @stderr = Open3.popen3(*@exec_options) if get_response =~ /ptrace: Operation not permitted/ raise 'root privilege is required' end prepare begin yield(self) detach ensure Process.kill('CONT', @pid.to_i) if @pid @stdin.close @stdout.close @stderr.close end end |