www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/09/05/13:47:46

From: idr AT cs DOT pdx DOT edu (Ian D Romanick)
Message-Id: <199609051735.KAA21363@sirius.cs.pdx.edu>
Subject: Re: Stack Trace
To: mikeday AT melbpc DOT org DOT au (Michael Day)
Date: Thu, 5 Sep 1996 10:35:20 -0700 (PDT)
Cc: djgpp AT delorie DOT com
In-Reply-To: <mikeday.9.0004B0A0@melbpc.org.au> from "Michael Day" at Sep 5, 96 12:32:22 pm
MIME-Version: 1.0

> 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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019