Search code examples
c++gdbcoroutinedwarffibers

Stackful coroutines + gdb = "previous frame inner to this frame (corrupt stack)?"


I'm writing some code to debug stackful coroutines that use Boost.Context's make_fcontext and jump_fcontext, and have run into a small problem.

Normally it is not possible to backtrace past the entry of a stackful coroutine as it executes on its own stack. This means that I cannot determine from a debugger from where a coroutine was entered. This, however, is not the problem about which I am asking. I already solved this problem by adding some inline assembly and DWARF bytecode in the function I pass to make_fcontext:

__asm__ volatile (
  "mov %[caller_fcontext_t] %[somewhere]\n\t"
  ".cfi_escape /* DWARF bytecode to load caller_fcontext_t from "
  "             * somewhere and use it to load all the registers saved "
  "             * there by jump_fcontest */"
  "call %[another_function]"
  : /* stuff */ : /* stuff */ : /* stuff */)

This really does work and I can now backtrace to the point in the caller where it starts or resumes the inner coroutine - but only sometimes.

It turns out that gdb has a "sanity check": if the stack pointer moves in the "wrong" direction between call frames, gdb assumes that the stack is corrupt and stops the trace with the message "Backtrace stopped: previous frame inner to this frame (corrupt stack?)".

This gets triggered when my stacks are allocated in certain ways, but not in other ways. I even have a test with statically allocated stacks that triggers this failure when used in forward order but not when used in reverse order.

I even found the portion of gdb's source code that performs this check here: https://github.com/bminor/binutils-gdb/blob/master/gdb/frame.c#L737-L816

Now here's my actual question: How can I fix this?

Is there some assembly incantation I can write that tells GDB "trust me, I know what I'm doing"?


Solution

  • Now here's my actual question: How can I fix this?

    Is there some assembly incantation I can write that tells GDB "trust me, I know what I'm doing"?

    There currently is no way to do this. It would be a good idea, but probably would require a DWARF extension of some kind. So, it may be difficult to implement.

    You can see the evidence of this in the gdb sources: GCC had a similar issue involving -fsplit-stack, and this was worked around by simply coding the name of the offending function into gdb:

      if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
    

    A quick workaround for your personal use is to just comment out the early return here.