This is the mail archive of the
gdb@sources.redhat.com
mailing list for the GDB project.
Stack Frame Unwinding
- From: Steven Johnson <sjohnson at sakuraindustries dot com>
- To: gdb at sources dot redhat dot com
- Date: Thu, 19 May 2005 11:29:05 -1100
- Subject: Stack Frame Unwinding
I had previous discussions on this list about this "feature" of GDB and
its effect on an ARM Embedded Target.
Well now, ive been trying to use CVS_HEAD of GDB on a powrpc embedded
target. Ive been using GDB for years for powerpc targets, and all of
the things i used to be able to rely upon, i can no longer. To the
extent that to get my target initialised and running a progrm reliably
ive had to introduce "monitor" commands to get around the current
"sledge hammer" stack unwinding approach in GDB.
Im using a PowerPC:MPC860 variant. They have tons of registers.
One of them is the "DER" or Debug Enable Register.
It is outside the program's ABI. It is a special purpose register, and
amounts to a peripheral register inside the powerpc. there are lots of
these in powerpc, usually far more than the base registers, they control
things like caches, debug engines, timers, etc. If i tell GDB to write
one, before it does, it "stack unwinds" which causes GDB to dereference
the value in another register, and then scan through memory.
What for. The DER and these other SPR's are not program registers, it
can not have a "place" on the stack, depending on where our "frame" is
in the stack. This is crazy. It slows things down for no valid reason,
and doesnt achieve anything.
Also, for embedded targets, especially those that use JTAG for
connection (dare i say all (or at least most) modern processors used in
the embedded space use this as the "preffered" option for debuggin".
When you "connect" with GDB to those targets, you hav access to the raw
hardware, straight after a reset. Not some nice clean envirmonment a
"debug stub" has set up for you. The obvious advantage with this, is
that many many times the presence of a "debug stub" actually changes the
behaviour of your program, so your program might work with the stub
there, compile it up for a release build, and it fails to run. But you
cant debug it, because there is no stub. So for many years stubs have
been seen as a poor mans tool, compared to expensive "in circuit
emulators" well "jtag" debugging gives most of the advantages of "in
circuit emulators" but they dont carry the traditionaly high cost. Well
with these tools, after a target reset, there is no stack, there is no
stack pointer worth anything. It just doesnt exist. I have had
situations wher GDB has said "lets unwind the stack" and it has merilly
gone and itterated through memory, 4 bytes at a time, never finding
anything that tells it to terminate its stack frame unwinding, so it
just keeps going and going and going (an hour later i killed it out of
chronic frustration). Why, because after a reset, memory is crap, and
there is no stack frame. For me recently, this was happening 2 or 3
times out of every 5 resets.
I know this is a boundary condition, but it is a very real boundary
condition, that will effect the debugging of every embedded target that
has a good solid hold over the target CPU (like a jtag interface).
I think the whole brute force, everytime we touch a memory address, or
write a register we will force a stack unwind, because maybe it has
changed, needs to be rethought. It is unusable for any embedded
development i have been involved with the way it is at the moment. At
the very least, there needs to be a switch that says "Dont unwind the
stack frame, use a dummy emtpy stack frame for the purposes of GDB".
And for remote targets, this should be enabled by default. Maybe it
should change automatically after the first target "load" but that is up
for debate. There needs to be a way to prevent GDB accessing memory
when the known result is that the memory is crap, and GDB isnt going to
get any useful information anyway.
Further, it just simply shouldnt do it at all, unless the register is a
part of the ABI. (Eg, SPR's on the PowerPC should never force a stack
frame unwind.)
It does not seem that when this was concieved the effect it has on
embedded targets, like ive described, was considered much at all.
I have spent the last 2 days trying to find an elegant way to introduce
such a switch, and i just cant see one. It is just in so many places
(it seems) that i couldnt find a nice place to put the switch, without
fear of missing some places, or producing unwanted side effects. Also, i
couldnt for the life of me work out what one would do to produce an
"empty" or "default nothing in there" stack frame, so that GDB was
satisfied with its "GDB always must have a stack frame" necessity. Its
fine for GDB to always need a stack frame, but this is a new
requirement, and some thought should have been given to debug targets
that in actuallity dont always have a stack frame. Such a rule is
actually false for embedded targets, and GDB should have some way of
satisfying its own internal requirements without imposing those on an
external target.
Even though the remote serial protocol hasnt changes, i believe GDB's
use of it in this context has broken backwards compatibility, becuase
things you could rely on before, you can no longer rely on. (Like GDB
not accessing memory, unless you gave it a specific command to access
memory, and then it only accessed what you told it to, and didnt make a
running rampage through random memory in a random way)
As it stands, the stack unwinder for an embedded target, at certain
points in debugging can serve no good purpose "garbage in, garbage
out". Another example is programs that are completely written in
assembler, they do not need to behave to anyones "rules" of what
constitutes a valid stack frame, and so it is unlikely GDB is going to
make much sense of them either. This is another reason why "Brute
force, stack unwinding needs to be able to be disabled".
The only way ive been able to proceed to use GDB is to introduce
mechanisms into the remote handler, that allow me to byspass the GDB
register and memory writing mechanisms, so i can write memory and
registers directly, just like GDB used to do. This is highly sub
optimal. At the stage i am at with this, i am not sure, that some other
necessary operations, will incur unnecessary stack unwinding.
Also, dont get me wrong, i can see the point of it, probably for 95% of
the cases when you are in the "middle" of debugging a high level
language, it is just there are numerous cases where its not appropriate
as well.
This email is to serve two purposes,
1. Discuss my experiences with the stack unwinder, and
2. Hopefully trigger some meaningful debate on ways we might proceed to
make GDB even better.
If a clear way forward can be identified, that the majority, and
especially the maintainers are happy with, i am more than capable and
happy to implement it (im not asking someone to do this for me, i
understand it is free software). There is just no point me doing
anything about this unilateraly as its likely to be rejected. (It not
being a simple thing).
Best Regards,
Steven Johnson