#include "pfStackTrace.h" #include "pfMapFile.h" #include "pfMapFileEntry.h" #include #include #pragma optimize( "y", off ) extern "C" struct IMAGE_DOS_HEADER __ImageBase; //----------------------------------------------------------------------------- #define MAX_DEPTH 32 //----------------------------------------------------------------------------- namespace dev { static long getCallerFromStack( unsigned long stackPtr, int index ) { #if /*defined(_DEBUG) && */defined(_MSC_VER) && defined(_M_IX86) long caller = 0; __asm { mov ebx, stackPtr mov ecx, index inc ecx xor eax, eax StackTrace_getCaller_next: mov eax, [ebx+4] mov ebx, [ebx] test eax,eax jz StackTrace_getCallerFromStack_done dec ecx jnz StackTrace_getCaller_next StackTrace_getCallerFromStack_done: mov caller, eax } return caller; #else return 0; #endif } static long getCaller( int index ) { #if /*defined(_DEBUG) && */defined(_MSC_VER) && defined(_M_IX86) long caller = 0; __asm { mov ebx, ebp mov ecx, index inc ecx xor eax, eax StackTrace_getCaller_next: mov eax, [ebx+4] mov ebx, [ebx] test eax,eax jz StackTrace_getCaller_done dec ecx jnz StackTrace_getCaller_next StackTrace_getCaller_done: mov caller, eax } return caller; #else return 0; #endif } int StackTrace::printStackTrace( MapFile** map, int maps, int initLevel, int maxDepth, char* buffer, int bufferSize, unsigned long stackPtr, unsigned long opPtr ) { if ( maxDepth > MAX_DEPTH ) maxDepth = MAX_DEPTH; bool sucks = false; // list callers long callersAddr[MAX_DEPTH]; int callers = 0; int i; for ( i = initLevel ; i < maxDepth ; ++i ) { long addr; if( stackPtr != 0 ) { if( i == initLevel ) addr = opPtr; else addr = getCallerFromStack( stackPtr, i - initLevel - 1 ); } else addr = getCaller( i ); callersAddr[callers++] = addr; // end tracing here if the entry is not in a map file if( map != 0 ) { int entry = -1; for ( int j = 0 ; j < maps ; ++j ) { entry = map[j]->findEntry( addr ); if ( -1 != entry ) break; } if ( -1 == entry ) { sucks = true; break; } } } int needed = 0; if ( bufferSize > 0 ) *buffer = 0; sprintf( buffer, "Call stack (%d levels%s):\r\n", callers - initLevel, sucks ? ", truncated" : "" ); needed = strlen( buffer ); // output call stack for ( i = initLevel ; i < callers ; ++i ) { long addr = callersAddr[callers-i-1]; // find entry info int entry = -1; const MapFile* entryMap = 0; for ( int j = 0 ; j < maps ; ++j ) { entry = map[j]->findEntry( addr ); if ( -1 != entry ) { entryMap = map[j]; break; } } // format entry to tempory buf char buf[MapFileEntry::MAX_NAME+MAX_DEPTH+20]; // name + margin + hex number buf[0] = 0; for ( int k = initLevel-1 ; k < i ; ++k ) strcat( buf, " " ); if ( !entryMap ) sprintf( buf+strlen(buf), "0x%08X\r\n", addr ); else { const MapFileEntry &en = entryMap->getEntry( entry ); long entryAddr = en.rvabase(); long stackAddr = addr; #ifdef WIN32 stackAddr -= (long)&__ImageBase; stackAddr += entryMap->loadAddress(); #endif sprintf( buf+strlen(buf), "%s (0x%08X + 0x%08X)\r\n", en.name(), entryAddr, stackAddr - entryAddr ); } // append temporary buf to output buffer if space left needed += strlen( buf ); if ( needed < bufferSize ) strcat( buffer, buf ); } // terminate output buffer if ( needed < bufferSize ) buffer[needed] = 0; else if ( bufferSize > 0 ) buffer[bufferSize-1] = 0; return needed; } } // dev /* * Copyright (c) 2001 Jani Kajala * * Permission to use, copy, modify, distribute and sell this * software and its documentation for any purpose is hereby * granted without fee, provided that the above copyright notice * appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation. * Jani Kajala makes no representations about the suitability * of this software for any purpose. It is provided "as is" * without express or implied warranty. */