Examining copied stack contents

Martin Schröder
2010-07-03T10:48:31Z

Hello everyone.

I'm currently implementing a high-level debugger based on GDB for a
coroutine-based simulation framework. The platform is GNU/Linux on x86.

That framework implements coroutines by using the C/C++ setjmp/longjmp
instructions and by copying the call stack that is used by each
coroutine to dynamically allocated memory on the heap. It's this latter
aspect that gives me terrible headaches in GDB.

My question is simply: Is it possible to point GDB to the copied
contents of the call stack and tell it to print out the information
contained therein?

The documentation [1] does contain the following note:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
frame addr
f addr
Select the frame at address addr. This is useful mainly if the chaining
of stack frames has been damaged by a bug, making it impossible for gdb
to assign numbers properly to all frames. In addition, this can be
useful when your program has multiple stacks and switches between them.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Additionally, the docs about the "info frame" command also say that it
accepts memory addresses as arguments.

Unfortunately, this does not seem to work as well as I anticipated. I
tried several versions of the GDB, from 6.8 to the newest 7.1, but they
all exhibit the same issues.

When I stop the program directly after the call stack was saved, the
situation presents itself as follows:

The stack pointer register is at 0xbfffeec0. The first two stack frames
return the following data:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(gdb) info frame 0
Stack frame at 0xbfffeef0:
eip = 0x805a972 in [CODE LINE]; saved eip 0x805a588
called by frame at 0xbfffef30
source language c++.
Arglist at 0xbfffeee8, args: this=0x80b3238
Locals at 0xbfffeee8, Previous frame's sp is 0xbfffeef0
Saved registers:
ebp at 0xbfffeee8, eip at 0xbfffeeec

(gdb) info frame 1
Stack frame at 0xbfffef30:
eip = 0x805a588 in [CODE LINE]; saved eip 0x806b2a6
called by frame at 0xbfffef70, caller of frame at 0xbfffeef0
source language c++.
Arglist at 0xbfffef28, args: this=0x80b2bd8
Locals at 0xbfffef28, Previous frame's sp is 0xbfffef30
Saved registers:
ebx at 0xbfffef20, ebp at 0xbfffef28, esi at 0xbfffef24, eip at
0xbfffef2c
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The program copied the whole stack (including a bit of safety margin)
beginning with the address 0xbfffeedf to the address 0x80b39c8.

Now, if I tell GDB to print information about the stack frame located at
0xbfffeef0, it does so correctly:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(gdb) info frame 0xbfffeef0
Stack frame at 0xbfffeef0:
eip = 0x805a972 in [CODE LINE]; saved eip 0x805a588
called by frame at 0xbfffef30
source language c++.
Arglist at 0xbfffeee8, args: this=0x80b3238
Locals at 0xbfffeee8, Previous frame's sp is 0xbfffeef0
Saved registers:
ebp at 0xbfffeee8, eip at 0xbfffeeec

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

But if I point it to the exact copy of that frame, beginning with
0x80b39d9, I get the following "fail safe" information that the GDB also
prints when I point it to *any* arbitrary address:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(gdb) info frame 0x80b39d9
Stack frame at 0x80b39d9:
eip = 0x0; saved eip 0x80b39c8
called by frame at 0xbfffeef0
Arglist at 0xbfffeebc, args:
Locals at 0xbfffeebc, Previous frame's sp is 0xbfffeec4
Saved registers:
eip at 0xbfffeec0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

But if I examine the memory ranges, they are absolutely identical:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(gdb) x/8x 0x80b39d9
0x80b39d9: 0x080b3238 0x080b2bd8 0x080b2ca4 0x080b2ca4
0x80b39e9: 0x0021a73c 0x080b2bc8 0x080b3238 0x00000000
(gdb) x/8x 0xbfffeef0
0xbfffeef0: 0x080b3238 0x080b2bd8 0x080b2ca4 0x080b2ca4
0xbfffef00: 0x0021a73c 0x080b2bc8 0x080b3238 0x00000000
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Obviously, the GDB doesn't even attempt to interpret the given address
as a stack frame. I am aware that the GDB needs debugging symbols to
make any sense out of the stack (after all, the frame size depends on
the actual call they represent); and also that the addresses inside the
copied stack can't be followed, because they still point to the original
memory addresses.

But I'm also aware that the GDB *should be* able to do what I want it to
do. For one, the documentation explicitly mentions that the feature
works with programs that utilize multiple stacks. Furthermore, the GDB
is also able to debug Multi-Threaded programs, which also need to save
the call stack to dynamic heap memory.

So, my question is: Is it possible to examine the copied stack? And if
yes, what do I need to give to the GDB to allow it?

Thanks in advance,
Martin SchrÃ¶der.

[1] - http://sourceware.org/gdb/current/onlinedocs/gdb/Selection.html