Repository navigation
Expand file tree
/
Copy pathcallstack.h
More file actions
178 lines (162 loc) · 7.78 KB
/
Copy pathcallstack.h
File metadata and controls
178 lines (162 loc) · 7.78 KB
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
////////////////////////////////////////////////////////////////////////////////
//
// Visual Leak Detector - CallStack Class Definitions
// Copyright (c) 2005-2014 VLD Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// See COPYING.txt for the full terms of the GNU Lesser General Public License.
//
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef VLDBUILD
#error \
"This header should only be included by Visual Leak Detector when building it from source. \
Applications should never include this header."
#endif
#include <windows.h>
#include "utility.h"
#define CALLSTACK_CHUNK_SIZE 32 // Number of frame slots in each CallStack chunk.
#define MAX_SYMBOL_NAME_LENGTH 256 // Maximum symbol name length that we will allow. Longer names will be truncated.
#define MAX_SYMBOL_NAME_SIZE ((MAX_SYMBOL_NAME_LENGTH * sizeof(WCHAR)) - 1)
////////////////////////////////////////////////////////////////////////////////
//
// The CallStack Class
//
// CallStack objects can be used for obtaining, storing, and displaying the
// call stack at a given point during program execution.
//
// The primary data structure used by the CallStack is similar in concept to
// a STL vector, but is specifically tailored for use by VLD, making it more
// efficient than a standard STL vector.
//
// Inside the CallStack are a number of "chunks" which are arranged in a
// linked list. Each chunk contains an array of frames (each frame is
// represented by a program counter address). If we run out of space when
// pushing new frames onto an existing chunk in the CallStack chunk list,
// then a new chunk is allocated and appended to the end of the list. In this
// way, the CallStack can grow dynamically as needed. New frames are always
// pushed onto the chunk at the end of the list known as the "top" chunk.
//
// IMPORTANT NOTE: This class as originally written makes two fatal assumptions:
// First: That the application will never load modules (call LoadLibrary) during the
// lifetime of the app.
// Second: That modules will never get unloaded (call to FreeLibrary)
// during the lifetime of the app.
// The result of this assumption is that
// memory allocations whose call stacks goes through dynamically loaded modules
// will be incomplete. This is manifested by stack frames that cannot be resolved
// when the stack is 'dumped' because the binaries have been unloaded from the
// process.
// To rectify this situation, it is up to the caller to resolve or format the call stacks
// into human readable form, BEFORE the callers process unloads any modules. That is
// done by calling VisualLeakDetector::ResolveCallstacks, which can be called from
// external code by the exported VLDResolveCallstacks function.
// When this happens, the call stacks are formatted, and then cached for later dumping.
// This has performance penalties, as the current implementation saves all info to heap memory,
// and it is wasteful, as some of the 'converted' memory is not a true leak, but will get
// properly de-allocated at a later time. However there is no other way to work around the
// fact that the call stacks can only get formatted when the binary is loaded in the process.
//
class CallStack
{
public:
CallStack ();
virtual ~CallStack ();
static CallStack* Create();
// Public APIs - see each function definition for details.
VOID clear ();
// Prints the call stack to one of either / or the debug output window and or
// a log file.
VOID dump (BOOL showinternalframes);
// Formats the stack frame into a human readable format, and saves it for later retrieval.
int resolve(BOOL showinternalframes);
// Formats the stack frame into a human readable format, and saves it for later retrieval.
CONST WCHAR* getResolvedCallstack(BOOL showinternalframes);
virtual DWORD getHashValue() const = 0;
virtual VOID getStackTrace (UINT32 maxdepth, const context_t& context) = 0;
bool isCrtStartupAlloc();
BOOL operator == (const CallStack &other) const;
UINT_PTR operator [] (UINT32 index) const;
VOID push_back (const UINT_PTR programcounter);
protected:
// Protected data.
UINT32 m_status; // Status flags:
#define CALLSTACK_STATUS_INCOMPLETE 0x1 // If set, the stack trace stored in this CallStack appears to be incomplete.
#define CALLSTACK_STATUS_STARTUPCRT 0x2 // If set, the stack trace is startup CRT.
#define CALLSTACK_STATUS_NOTSTARTUPCRT 0x4 // If set, the stack trace is not startup CRT.
// The chunk list is made of a linked list of Chunks.
struct chunk_t {
chunk_t* next; // Pointer to the next chunk in the chunk list.
UINT_PTR frames[CALLSTACK_CHUNK_SIZE]; // Pushed frames (program counter addresses) are stored in this array.
};
// Private data.
UINT32 m_capacity; // Current capacity limit (in frames)
UINT32 m_size; // Current size (in frames)
CallStack::chunk_t m_store; // Pointer to the underlying data store (i.e. head of the chunk list)
CallStack::chunk_t* m_topChunk; // Pointer to the chunk at the top of the stack
UINT32 m_topIndex; // Index, within the top chunk, of the top of the stack
// The string that contains the stack converted into a human readable format.
// This is always NULL if the callstack has not been 'converted'.
WCHAR* m_resolved;
int m_resolvedCapacity;
int m_resolvedLength;
bool isInternalModule( const PWSTR filename ) const;
UINT isCrtStartupFunction( LPCWSTR functionName ) const;
LPCWSTR getFunctionName(SIZE_T programCounter, DWORD64& displacement64,
SYMBOL_INFO* functionInfo, CriticalSectionLocker<DbgHelp>& locker) const;
DWORD resolveFunction(SIZE_T programCounter, IMAGEHLP_LINEW64* sourceInfo, DWORD displacement,
LPCWSTR functionName, LPWSTR stack_line, DWORD stackLineSize) const;
private:
// Don't allow this!!
CallStack(const CallStack &other);
// Don't allow this!!
CallStack& operator = (const CallStack &other);
};
////////////////////////////////////////////////////////////////////////////////
//
// The FastCallStack Class
//
// This class is a specialization of the CallStack class which provides a
// very fast stack tracing function.
//
class FastCallStack : public CallStack
{
public:
FastCallStack()
: m_hashValue(0)
{
}
virtual VOID getStackTrace (UINT32 maxdepth, const context_t& context);
virtual DWORD getHashValue() const
{
return m_hashValue;
}
private:
UINT32 m_hashValue;
};
////////////////////////////////////////////////////////////////////////////////
//
// The SafeCallStack Class
//
// This class is a specialization of the CallStack class which provides a
// more robust, but quite slow, stack tracing function.
//
class SafeCallStack : public CallStack
{
public:
virtual VOID getStackTrace (UINT32 maxdepth, const context_t& context);
virtual DWORD getHashValue() const;
};