1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
/*
* 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
|