Mail Archives: djgpp/1996/09/05/13:47:46
> When a djgpp program crashes, it prints a nice stack trace which is very handy
> for debugging. Is there anyway to generate this without actually crashing, ie:
> if you want to find out how a particular procedure got called then insert a
> line that generates the stacktrace? Or is this a CWSDPMI thing?
/* Name : stak_dmp.c
*
* Notes: This file contains some simple routines that I use to help
* debug programs. I use the IsPointerValid() function a lot
* in assert() statements, and I modified my assert() macro to
* call stack_trace(), then call exit(), rather than call abort().
*/
#include <stdio.h>
/*****************************************************************************/
/* Name : IsFarPointerValid()
*
* Notes: This function is used to determin, in advance, if accessing the
* specified pointer and selector will cause a GP fault.
*
* This code was taken from an older (1993ish) issue of
* _PC_Techniques_. I only typed it in and GCCized it.
*/
int IsFarPointerValid( void * ptr, unsigned short selector )
{
int retVal;
asm(
"xor %%eax,%%eax\n" /* assume failure */
"lar %%edx,%%ebx\n" /* validate the specified selctor */
"jnz fbail\n"
"lsl %%edx,%%ebx\n" /* get the selector segment limit.. */
"jnz fbail\n" /* ..or an error if the selector.. */
/* ..can't be read. */
"cmp %%ecx,%%ebx\n" /* make sure the offset is less.. */
"jbe fbail\n" /* ..than the limit */
"verw %%edx\n" /* make sure the selector is.. */
"jnz fbail\n" /* ..writable (i.e., data) */
"inc %%eax\n" /* ptr must be valid to get here. */
"fbail:\n" /* bail out point for failure. */
: "=eax" (retVal)
: "edx" (selector), "ecx" (ptr)
: "ebx" );
return( retVal );
}
/*****************************************************************************/
/* Name : IsPointerValid()
*
* Notes: This function works exactly like IsFarPointerValid(), except that
* it uses the current %ds as the selector.
*/
int IsPointerValid( void * ptr )
{
int retVal;
asm(
"xor %%edx,%%edx\n\t"
"mov %%ds,%%dx\n\t"
"xor %%eax,%%eax\n\t" /* assume failure */
"lar %%edx,%%ebx\n\t" /* validate the specified selctor */
"jnz bail\n\t"
"lsl %%edx,%%ebx\n\t" /* get the selector segment limit.. */
"jnz bail\n\t" /* ..or an error if the selector.. */
/* ..can't be read. */
"cmp %%ecx,%%ebx\n\t" /* make sure the offset is less.. */
"jbe bail\n\t" /* ..than the limit */
"verw %%edx\n\t" /* make sure the selector is.. */
"jnz bail\n\t" /* ..writable (i.e., data) */
"inc %%eax\n\t" /* ptr must be valid to get here. */
"bail:\n" /* bail out point for failure. */
: "=eax" (retVal)
: "ecx" (ptr)
: "ebx" );
return( retVal );
}
/*****************************************************************************/
/* Name : GetSS()
*
* Notes: Returns the current stack segment selector.
*
*/
__inline__ short GetSS( void )
{
short ss;
asm( "movw %%ss,%w0\n" : "=r" (ss) );
return( ss );
}
/*****************************************************************************/
/* Name : stack_trace()
*
* Notes: This code is used to print a symify compatible stack trace. It
* is based on some code posted to the DJGPP mailing list sometime
* ago. Search the archive at http://www.delorie.com/djgpp if you
* really want to see the original. My major addition is the calls
* to IsFarPointerValid(). I did this to prevent a crash in programs
* compiled with GCC's -fomit-frame-pointer option.
*/
void stack_trace( FILE * file )
{
long * bp;
if ( file == NULL )
{
file = stderr;
}
/* Get the frame pointer for this subroutine. */
bp = (long *) & bp + 1;
/* Loop until we run out of frame pointers. */
while( bp[0] != NULL )
{
if ( ! IsFarPointerValid( bp, GetSS() ) ||
! IsFarPointerValid( bp + 1, GetSS() ) )
{
break;
}
/* Print the return address for the current frame. */
fprintf( file, " 0x%08lx\n", bp[1] );
/* Follow the link to the next frame. */
bp = (long *) bp[0];
}
}
--
"Harshaw conceded that man, a social animal, could not avoid government, any
more than an individual could escape bondage to his bowels."
-- Stranger In A Strange Land
See my bowels at http://www.cs.pdx.edu/~idr
- Raw text -