You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
5.0 KiB
215 lines
5.0 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#include "pfStackTrace.h" |
|
#include "pfMapFile.h" |
|
#include "pfMapFileEntry.h" |
|
#include <string.h> |
|
#include <stdio.h> |
|
|
|
#pragma optimize( "y", off ) |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
#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 = entryMap->loadAddress() + (en.section() << 12) + en.offset(); |
|
|
|
sprintf( buf+strlen(buf), "%s (0x%08X + 0x%08X)\r\n", en.name(), entryAddr, addr - 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. |
|
*/
|
|
|