File: StackTrace.cpp

package info (click to toggle)
duma 2.5.21-11
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,460 kB
  • sloc: ansic: 5,512; cpp: 2,205; makefile: 441; javascript: 191; sh: 129
file content (187 lines) | stat: -rw-r--r-- 4,108 bytes parent folder | download | duplicates (2)
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