Skip to content
Advertisement

Weird Backtrace After a Call Instruction Targeting Signal Functions

I tried to trace evince-3.28.4 execution using GDB. There is a callq instruction at some point in libdl, which is shown below (i.e., at _dl_lookup_symbol_x+840):

JavaScript

When the execution reaches here, the backtrace is as follows:

JavaScript

But when I enter ni (to jump to the next assembly instruction), it turns into this:

JavaScript

As can be seen, after a simple call and return, 4 elements are popped off the stack. Perhaps there is something special about the <_dl_signal_cexception(), __GI__dl_catch_exception()> pair. The stack is changed by some means other than call or return. It seems that _dl_signal_cexception() finally leads to a __longjmp() function at ../sysdeps/x86_64/__longjmp.S which modifies the backtrace. Can someone describe the process?

Advertisement

Answer

As can be seen, after a simple call and return, 4 elements are popped off the stack. Perhaps there is something special about the _dl_signal_cexception() __GI__dl_catch_exception()pair. The stack is changed by some means other than call or return.

Correct: the _dl_signal_exception doesn’t return, it uses longjmp to transfer control not to its caller, but to its callers callers … caller.

It seems that _dl_signal_cexception() finally leads to a __longjmp()

Correct.

Can someone describe the process?

You appear to not understand what longjmp does. Reading its man page and/or this example should help.

Update:

this approach for transition in control flow is somehow insane even compared to simple gotos … any other cases that I should consider?

Other “interesting” control transfers are via makecontext, setcontext and swapcontext family of functions, and (in C++) throw and catch are pretty much equivalent to setjmp and longjmp.

Advertisement