123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /*
- * Copyright (c) 2006 Michael Eddington
- * 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.
- */
- #include "StackTrace.h"
- #include "MapFile.h"
- #include "MapFileEntry.h"
- #include <string.h>
- #include <stdio.h>
- //-----------------------------------------------------------------------------
- static const char* internalFunctions[] = {
- "__duma_malloc",
- "__duma_calloc",
- "__duma_realloc",
- "__duma_valloc",
- "__duma_allocate",
- "_printStackTrace",
- 0
- };
- #define MAX_DEPTH 32
- //-----------------------------------------------------------------------------
- namespace dev
- {
- static int IsInternalFunction(const char* func)
- {
- for(int i=0; internalFunctions[i]; i++)
- {
- if(!strcmp(func, internalFunctions[i]))
- return 1;
- }
- return 0;
- }
- /*
- EBP points to stack frame (at least 2 DWORDs) which looks something like this:
- DWORD[EBP+4] = return address (=calling function)
- DWORD[EBP+0] = calling function stack frame
- So we
- 1) get the EBP to EBX
- 2) take calling function address to EAX
- 3) parent stack frame to EBX and
- 4) loop 2,3,4 until desired level in calling stack is reached.
- Beware that compiler does not always make stack frame (at least if s.c. "omit stack frame"
- optimization is enabled), so at least I'd use this code only in debug build.
- */
- static long getCaller( int index )
- {
- #if defined(_DEBUG) && defined(_MSC_VER) && defined(_M_IX86)
- // Changed a couple things here to prevent some
- // access violations, esp with release code that
- // doesn't always have a stack frame.
- //
- // 1. Check next frame to see if we are below 10000
- // 2. If we are forcing a stop make the return addr 0
- 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]
- cmp ebx, 10000
- jb StackTrace_getCaller_stop
- dec ecx
- jnz StackTrace_getCaller_next
- jmp StackTrace_getCaller_end
- StackTrace_getCaller_stop:
- mov eax, 0
- StackTrace_getCaller_end:
- mov caller, eax
- }
- return caller;
- #else
- return 0;
- #endif
- }
- int StackTrace::printStackTrace( MapFile** map, int maps,
- int initLevel, int maxDepth, char* buffer, int bufferSize )
- {
- if ( maxDepth > MAX_DEPTH )
- maxDepth = MAX_DEPTH;
- // list callers
- long callersAddr[MAX_DEPTH];
- MapFileEntry* callersEntry[MAX_DEPTH];
- int callers;
- int i;
- int entry;
- long addr = -1;
- int flag = 0;
- int j;
- for (callers = 0, i = initLevel ; i < maxDepth && addr ; i++)
- {
- addr = getCaller( i );
- callersEntry[callers] = NULL;
- for (entry = -1, j = 0 ; j < maps ; ++j )
- {
- entry = map[j]->findEntry( addr );
- if ( entry != -1 )
- {
- callersEntry[callers] = map[j]->getEntry(entry);
- break;
- }
- }
- if(entry == -1)
- continue;
- callersAddr[callers] = addr;
- callers++;
- }
- // output call stack
- if ( bufferSize > 0 )
- *buffer = 0;
- int needed = 0;
- for ( i = 1 ; i <= callers ; ++i )
- {
- addr = callersAddr[callers-i];
- if(IsInternalFunction(callersEntry[callers-i]->name()))
- continue;
- // 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 ( callersEntry[callers-i] == NULL )
- sprintf( buf+strlen(buf), "0x%x\n", addr );
- else
- sprintf( buf+strlen(buf), "%s (%x)\n", callersEntry[callers-i]->name(), addr );
- // append temporary buf to output buffer if space left
- needed += (int)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
|