2

I have a ruby program that spawns two threads. Rarely, it appears to be hanging on the main thread, and I'm trying to use gdb to figure out why.

Using the blog post here, I have used gdb to attach to to the process, and call rb_backtrace() to get the backtrace.

Problem is, the backtrace is always from one of the spawned worker threads, not the main thread where I experience the hang.

Is there a way to get a backtrace from a particular thread?

I have tried using the gdb commands info threads and thread 2 to change the active thread, but it has no effect. I have also tried using a ruby_eval definition in gdb as described here, but any time I try to evaluate a line of ruby code, I get the error No symbol table is loaded. Use the "file" command. Because I am working on an embedded system, I can't easily recompile ruby with gdb symbols.

davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • "I get the error No symbol table is loaded" -- likely means you didn't invoke GDB correctly, or the binary is stripped. – Employed Russian Feb 26 '18 at 15:29
  • It's an embedded system so the binary may be stripped. I have tried invoking by `gdb /usr/bin/ruby -p XXX` or just `gdb -p XXX` – davidgyoung Feb 26 '18 at 15:50

1 Answers1

2

rb_backtrace() refers to a global ruby_current_thread variable that you can override:

# Make a note of the old thread pointer so you can put it back.
(gdb) p ruby_current_thread
$1 = (rb_thread_t *) 0x5619dfe485e0

(gdb) set ruby_current_thread = 0x5619efb7d3a0

(gdb) p ruby_current_thread
$2 = (rb_thread_t *) 0x5619efb7d3a0

# Write the backtrace to stderr
(gdb) call (void) rb_backtrace()

The ruby thread pointer (0x5619efb7d3a0 above) can be found in the GDB backtrace of the native thread you're interested in, eg.

#7  0x00005619de86cf96 in vm_exec (th=th@entry=0x5619efb7d3a0) at vm.c:1693

Do set ruby_current_thread back to its original value before the letting the process resume. Tested on Ruby 2.3.8.

  • Starting in version 2.5 this variable is called `ruby_current_execution_context_ptr` instead of ruby_current_thread – Segfault Jan 17 '22 at 21:07