Getting a backtrace of other thread
Asked Answered
R

3

21

In Linux, to get a backtrace you can use backtrace() library call, but it only returns backtrace of current thread. Is there any way to get a backtrace of some other thread, assuming I know it's TID (or pthread_t) and I can guarantee it sleeps?

It seems that libunwind (http://www.nongnu.org/libunwind/) project can help. The problem is that it is not supported by CentOS, so I prefer not to use it.

Any other ideas? Thanks.

Rihana answered 19/6, 2011 at 11:45 Comment(0)
M
10

Signal Handling with the help of backtrace can solve your purpose.

I mean if you have a PID of the Thread, you can raise a signal for that thread. and in the handler you can use the backtrace. since the handler would be executing in that partucular thread, the backtrace there would be the output what you are needed.

Marishamariska answered 20/6, 2011 at 6:44 Comment(5)
This is not precisely what I was looking for, but this is a nice idea. I think I can use it. Thanks!Rihana
@Alexander is this solution working for you when malloc or free like calls are call stack..? and are you able to call backtrace() in this case from Signal handler? i am getting crash.Marishamariska
Eventually, I decided to work with libunwind. This solution is way too complicated for my circumstances and I decided to abandon it. Anyway, please post here if you make it work somehow.Rihana
@Alex - did you get libunwind to do this for you? I am looking to solve a similar problem, and wondered what your experience was with this. Can you post code that does this?Samoyed
I didn't get trying it yet. I am negotiating it's inclusion with my management, so it may happen one day, but not yet.Rihana
T
13

I implemented that myself here.

Initially, I wanted to implement something similar as suggested here, i.e. getting somehow the top frame pointer of the thread and unwinding it manually (the linked source is derived from Apples backtrace implementation, thus might be Apple-specific, but the idea is generic).

However, to have that safe (and the source above is not and may even be broken anyway), you must suspend the thread while you access its stack. I searched around for different ways to suspend a thread and found this, this and this. Basically, there is no really good way. The common hack, also used by the Hotspot JAVA VM, is to use signals and sending a custom signal to your thread via pthread_kill.

So, as I would need such signal-hack anyway, I can have it a bit simpler and just use backtrace inside the called signal handler which is executed in the target thread (as also suggested here by sandeep). This is basically what my implementation is doing.

If you are also interested in printing the backtrace, i.e. get some useful debugging information (function name, source code filename, source code line number, ...), read here about an extended backtrace_symbols based on libbfd. Or just see the source here.

Twayblade answered 6/4, 2012 at 22:29 Comment(7)
Albert, I have a scenario where I need to get the call stack of main thread from background thread. The idea behind is that If there is hang in the UI thread more than 2 seconds, the background thread that monitors UI thread every 200ms will collect the call stack. I was wondering your solution might also address this one? Thanks much for in advance.Cressy
@ilkerAcar: Yes, the function int GetCallstack(ThreadId threadId, void **buffer, int size) in my implementation can be called from any thread. Just pass the main thread id.Twayblade
Btw., I am also doing this in some project, see startMainLockDetector() here.Twayblade
@Twayblade Excuse me, but would you mind giving me a hand on HOWTO get the correct frame pointer? Thanks.Ferrel
Hi. Is there a chance that sigsuspend would block forever because the reply comes too fast?Curvet
@hsfzxjy: Oh yes I think you are right. You probably want to reimplement that in a different way, not using sigsuspend, or having some other spinlock or so.Twayblade
@Twayblade I think the right approach is to use sigprocmask before pthread_kill and after sigsuspend to ensure no SIGUSR2 is delivered in this critical section.Curvet
M
10

Signal Handling with the help of backtrace can solve your purpose.

I mean if you have a PID of the Thread, you can raise a signal for that thread. and in the handler you can use the backtrace. since the handler would be executing in that partucular thread, the backtrace there would be the output what you are needed.

Marishamariska answered 20/6, 2011 at 6:44 Comment(5)
This is not precisely what I was looking for, but this is a nice idea. I think I can use it. Thanks!Rihana
@Alexander is this solution working for you when malloc or free like calls are call stack..? and are you able to call backtrace() in this case from Signal handler? i am getting crash.Marishamariska
Eventually, I decided to work with libunwind. This solution is way too complicated for my circumstances and I decided to abandon it. Anyway, please post here if you make it work somehow.Rihana
@Alex - did you get libunwind to do this for you? I am looking to solve a similar problem, and wondered what your experience was with this. Can you post code that does this?Samoyed
I didn't get trying it yet. I am negotiating it's inclusion with my management, so it may happen one day, but not yet.Rihana
F
1

gdb provides these facilities for debugging multi-thread programs:

  • automatic notification of new threads
  • ‘thread thread-id’, a command to switch among threads
  • ‘info threads’, a command to inquire about existing threads
  • ‘thread apply [thread-id-list] [all] args’, a command to apply a command to a list of threads
  • thread-specific breakpoints
  • ‘set print thread-events’, which controls printing of messages on thread start and exit.
  • ‘set libthread-db-search-path path’, which lets the user specify which libthread_db to use if the default choice isn't compatible with the program.

So just goto required thread in GDB by cmd: 'thread thread-id'. Then do 'bt' in that thread context to print the thread backtrace.

Firth answered 3/11, 2016 at 6:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.