[comp.sys.m68k] stack backtrace on a 68010

peters@ti-csl.UUCP (04/07/87)

I am trying to construct a stack backtrace routine to run on a 68010
system we are building (Internal use only.  This is not a product 
announcement.).  I'm after the sort of thing that adb will give
you when you use the $c command.  Unfortunately, all of our Unix
source is for the Vax, so I can't just lift the algorithm from adb.

At any given point in time, the frame pointer (in our case, A6) is pointing
at the previous value of A6, conveniently stored on the stack.
Continuing to unwind the stack, you find the return address of the jsr,
right next to where A6 is pointing now .  Then the fun begins.
Next in line is the top of the previous routine's stack.  The bottom of
the frame can be determined from the place A6 is pointing right now.
Great, we've got the top of the stack and the bottom of the frame for
the previous routine.  Next you need to find the bottom of the stack
(or the top of the frame) so you can distinguish the stack (parameters
to the next routine) from the local variables (the frame of this
routine).  Easier said than done--at least I haven't figured out how to
do it yet.  I just keep bumping into this glob that's part frame and part
stack (and I don't know how much of each).

If anyone out there would care to enlighten me on this subject, I would
be in your debt (figuratively speaking, of course).

peters@ti-csl.UUCP (04/07/87)

Almost forgot the signature.....

-- 
Patrick Peters                 UUCP:    ut-sally!im4u!ti-csl!tifsie!pat 
Texas Instruments                          sun!texsun!ti-csl!tifsie!pat
PO Box 655012  M/S 3635                   uiucdcs!convex!smu!tifsie!pat
Dallas, TX 75265               Voice:   (214)995-2786    

terryl@tekcrl.UUCP (04/07/87)

In article <18534@ti-csl.CSNET> peters@ti-csl.CSNET (Pat Peters) writes:
>
>I am trying to construct a stack backtrace routine to run on a 68010
>system we are building (Internal use only.  This is not a product 
>announcement.).  I'm after the sort of thing that adb will give
>you when you use the $c command.  Unfortunately, all of our Unix
>source is for the Vax, so I can't just lift the algorithm from adb.
>
> ....Delete many lines about A6, etc.....
>

     Well, unfortunately, you don't say what system, or more importantly,
what compiler you are using. I'll describe things the way the MIT C compiler
works for a 68k machine:

     As you commented, A6 always points to the TOP of the stack frame (where
TOP is defined as a HIGHER address than the BOTTOM of the stack frame, where
stack frames grow DOWNWARDS) of the current procedure. At the TOP of the stack
frame (i.e. what A6 points to) is the previous value of A6 (i.e. the TOP of the
previous stack frame of the procedure that called the current procedure). Above
the TOP of the stack frame is the return address of the procdeure that called
the current procedure; above this is the arguments to the current procedure,
and above that are the local variables and temporaries of the previous proce-
dure. Believing that a picture is worth more than a thousand words, here is
a graphical representation:

				+-------------------------------+
	(Higher addresses)	| Top of previous stack frame	|
				| Local variables, temporaries	|
				| and saved registers of pre-	|
				| vious stack frame.		|
				| Arguments to next frame.	|
				| Return address to return to	|
				| after next procedure is	|
				| finished.			|
				|-------------------------------|
				| Previous value of A6 (i.e. the|
				| address of the top of the pre-|
				| vious stack frame).		|
				| Local variables, etc.		|
	(Lower addresses)	+-------------------------------+

     So now what you need to do a complete C stack trace back is: The current
value of A6 (so you can find the current value of the TOP of the current stack
frame), and the Program Counter (so you can tell what procedure you are in).
Everything else can be found from the above description. A6 points to the TOP
of the previous stack frame; at A6+4 is the return address, so now you can find
what procedure called this procedure. Keep following this chain until you find
the end of the stack frames (unfortunately, this is not compiler specific but
system specific. For our 68k systems, in the C runtime startup, we put a zero
value into A6, so when we have a zero value for the TOP of the previous stack
frame, we know we are done).

     Well, what about arguments to routines, you ask??? Well, again, this is
compiler specific. There is no way to explicitly know how many arguments are
passed to a routine, unlike the VAX where the calling convention says you have
to specify it. Luckily, some compilers help us out on this respect. Speci-
fically, the MIT C compiler always returns to an add-type instruction to pop
off the arguments, so if you look up the instruction to return to, you can
find out how many bytes were passed as arguments. Even luckier, the MIT C
compiler also pushes ALL non-floating point and structure arguments as a four-
byte quantity; it pushes floating point arguments as doubles, and structures
as-is. So without more knowledge about what kind of arguments were pushed,
you can only make a guess, usually that all arguments are simple four-byte
non-floating point, non-structure type arguments.

     Also note that arguments to routines are actually part of the calling
routine's stack frame, and are not part of the called routine's stack frame.

     Hope this helps soemwhat.

				Terry Laskodi
				     of
				Tektronix

peters@ti-csl.UUCP (04/08/87)

in article <755@killer.UUCP>, jfh@killer.UUCP (John Haugh) says:
> 
> In article <18534@ti-csl.CSNET>, peters@ti-csl.CSNET (Pat Peters) writes:
>> 
>> I am trying to construct a stack backtrace routine to run on a 68010
>> system we are building....
> 
> The stack on a M68000 looks something like this:
> 
> SP + a bunch:	<ARG N>
> 		.
> 		.
> 		<ARG 0>
> 		<RETURN ADDRESS>
> FP:		<SAVED FRAME POINTER>
.....
> Take that return address and find the instruction after the
> jsr instruction.  (Easy - it is at the return address.)  Decode this
> instruction to figure out how many arguments there were. 

Nice thought (in fact one I already had) but, 

1.	Inconvenient because the compiler will use several (I believe at
	least three different) ways of unwinding the stack.  They
	are documented, however.

2.	I've seen the compiler decide to unwind the stack at some time 
	other than on return (the instruction at the return address may
	not be the one that restores the stack pointer).

In case you're wondering, we use Green Hills C.  The optimizer does some
wonderful (but strange) things to the code.  There is an option that will
force generation of stack frames (put in specifically to facilitate back
tracing the stack), but I don't see anywhere in the manual where they
promise that the instruction pointed to by the return address is the one
(of three types) that will restore the stack pointer.

-- 
Patrick Peters                 UUCP:    ut-sally!im4u!ti-csl!tifsie!pat 
Texas Instruments                          sun!texsun!ti-csl!tifsie!pat
PO Box 655012  M/S 3635                   uiucdcs!convex!smu!tifsie!pat
Dallas, TX 75265               Voice:   (214)995-2786    

kent@rose4.Rosemount.COM (Kent Schnaith) (04/09/87)

Use the return address and look at the instruction, it should
be addl #N,a7 or something.  Its pretty easy to decode the instruction
since only a few combinations may be used.  N is the size of the
paramters passed.  Assuming your compiler works like ours of course.