~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to msvc_dbg.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2004 Andrei Polushin
 
3
 
 
4
  Permission is hereby granted, free of charge,  to any person obtaining a copy
 
5
  of this software and associated documentation files (the "Software"), to deal
 
6
  in the Software without restriction,  including without limitation the rights
 
7
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
8
  copies of the Software, and to permit persons to whom the Software is
 
9
  furnished to do so, subject to the following conditions:
 
10
 
 
11
  The above copyright notice and this permission notice shall be included in
 
12
  all copies or substantial portions of the Software.
 
13
 
 
14
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
16
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
17
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
18
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
19
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
20
  THE SOFTWARE.
 
21
*/
 
22
#ifndef _M_AMD64
 
23
 
 
24
/* X86_64 is ccurrently missing some meachine-dependent code below. */
 
25
 
 
26
#include "private/msvc_dbg.h"
 
27
 
 
28
#define WIN32_LEAN_AND_MEAN
 
29
#include <windows.h>
 
30
 
 
31
#pragma pack(push, 8)
 
32
#include <imagehlp.h>
 
33
#pragma pack(pop)
 
34
 
 
35
#pragma comment(lib, "dbghelp.lib")
 
36
#pragma optimize("gy", off)
 
37
 
 
38
#ifdef _WIN64
 
39
        typedef ULONG_PTR ULONG_ADDR;
 
40
#else
 
41
        typedef ULONG     ULONG_ADDR;
 
42
#endif
 
43
 
 
44
static HANDLE GetSymHandle()
 
45
{
 
46
        static HANDLE symHandle = NULL;
 
47
        if (!symHandle) {
 
48
                BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
 
49
                if (bRet) {
 
50
                        DWORD dwOptions = SymGetOptions();
 
51
                        dwOptions &= ~SYMOPT_UNDNAME;
 
52
                        dwOptions |= SYMOPT_LOAD_LINES;
 
53
                        SymSetOptions(dwOptions);
 
54
                }
 
55
        }
 
56
        return symHandle;
 
57
}
 
58
 
 
59
static void* CALLBACK FunctionTableAccess(HANDLE hProcess, ULONG_ADDR dwAddrBase)
 
60
{
 
61
        return SymFunctionTableAccess(hProcess, dwAddrBase);
 
62
}
 
63
 
 
64
static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
 
65
{
 
66
        MEMORY_BASIC_INFORMATION memoryInfo;
 
67
        ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
 
68
        if (dwAddrBase) {
 
69
                return dwAddrBase;
 
70
        }
 
71
        if (VirtualQueryEx(hProcess, (void*)(ULONG_PTR)dwAddress, &memoryInfo, sizeof(memoryInfo))) {
 
72
                char filePath[_MAX_PATH];
 
73
                char curDir[_MAX_PATH];
 
74
                char exePath[_MAX_PATH];
 
75
                DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase, filePath, sizeof(filePath));
 
76
 
 
77
                // Save and restore current directory around SymLoadModule, see KB article Q189780
 
78
                GetCurrentDirectoryA(sizeof(curDir), curDir);
 
79
                GetModuleFileNameA(NULL, exePath, sizeof(exePath));
 
80
#if defined(_MSC_VER) && _MSC_VER == 1200
 
81
                /* use strcat for VC6 */
 
82
                strcat(exePath, "\\..");
 
83
#else
 
84
                strcat_s(exePath, sizeof(exePath), "\\..");
 
85
#endif /* _MSC_VER >= 1200 */
 
86
                SetCurrentDirectoryA(exePath);
 
87
#ifdef _DEBUG
 
88
                GetCurrentDirectoryA(sizeof(exePath), exePath);
 
89
#endif
 
90
                SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL, (ULONG_ADDR)(ULONG_PTR)memoryInfo.AllocationBase, 0);
 
91
                SetCurrentDirectoryA(curDir);
 
92
        }
 
93
        return (ULONG_ADDR)(ULONG_PTR)memoryInfo.AllocationBase;
 
94
}
 
95
 
 
96
static ULONG_ADDR CheckAddress(void* address)
 
97
{
 
98
        ULONG_ADDR dwAddress = (ULONG_ADDR)(ULONG_PTR)address;
 
99
        GetModuleBase(GetSymHandle(), dwAddress);
 
100
        return dwAddress;
 
101
}
 
102
 
 
103
size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
 
104
{
 
105
        HANDLE hProcess = GetSymHandle();
 
106
        HANDLE hThread = GetCurrentThread();
 
107
        CONTEXT context;
 
108
        context.ContextFlags = CONTEXT_FULL;
 
109
        if (!GetThreadContext(hThread, &context)) {
 
110
                return 0;
 
111
        }
 
112
        // GetThreadContext might return invalid context for the current thread
 
113
#if defined(_M_IX86)
 
114
    __asm mov context.Ebp, ebp
 
115
#endif
 
116
        return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1, frames, maxFrames);
 
117
}
 
118
 
 
119
size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames)
 
120
{
 
121
        size_t frameIndex;
 
122
        DWORD machineType;
 
123
        STACKFRAME stackFrame = { 0 };
 
124
        stackFrame.AddrPC.Mode      = AddrModeFlat;
 
125
#if defined(_M_IX86)
 
126
        machineType                 = IMAGE_FILE_MACHINE_I386;
 
127
        stackFrame.AddrPC.Offset    = context->Eip;
 
128
        stackFrame.AddrStack.Mode   = AddrModeFlat;
 
129
        stackFrame.AddrStack.Offset = context->Esp;
 
130
        stackFrame.AddrFrame.Mode   = AddrModeFlat;
 
131
        stackFrame.AddrFrame.Offset = context->Ebp;
 
132
#elif defined(_M_MRX000)
 
133
        machineType                 = IMAGE_FILE_MACHINE_R4000;
 
134
        stackFrame.AddrPC.Offset    = context->Fir;
 
135
#elif defined(_M_ALPHA)
 
136
        machineType                 = IMAGE_FILE_MACHINE_ALPHA;
 
137
        stackFrame.AddrPC.Offset    = (unsigned long)context->Fir;
 
138
#elif defined(_M_PPC)
 
139
        machineType                 = IMAGE_FILE_MACHINE_POWERPC;
 
140
        stackFrame.AddrPC.Offset    = context->Iar;
 
141
#elif defined(_M_IA64)
 
142
        machineType                 = IMAGE_FILE_MACHINE_IA64;
 
143
        stackFrame.AddrPC.Offset    = context->StIIP;
 
144
#elif defined(_M_ALPHA64)
 
145
        machineType                 = IMAGE_FILE_MACHINE_ALPHA64;
 
146
        stackFrame.AddrPC.Offset    = context->Fir;
 
147
#else
 
148
#error Unknown CPU
 
149
#endif
 
150
        for (frameIndex = 0; frameIndex < maxFrames; ) {
 
151
                BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame, &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
 
152
                if (!bRet) {
 
153
                        break;
 
154
                }
 
155
                if (skip) {
 
156
                        skip--;
 
157
                } else {
 
158
                        frames[frameIndex++] = (void*)(ULONG_PTR)stackFrame.AddrPC.Offset;
 
159
                }
 
160
        }
 
161
        return frameIndex;
 
162
}
 
163
 
 
164
size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
 
165
{
 
166
        if (size) *moduleName = 0;
 
167
        {
 
168
                const char* sourceName;
 
169
                IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
 
170
                if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address), &moduleInfo)) {
 
171
                        return 0;
 
172
                }
 
173
                sourceName = strrchr(moduleInfo.ImageName, '\\');
 
174
                if (sourceName) {
 
175
                        sourceName++;
 
176
                } else {
 
177
                        sourceName = moduleInfo.ImageName;
 
178
                }
 
179
                if (size) {
 
180
                        strncpy(moduleName, sourceName, size)[size - 1] = 0;
 
181
                }
 
182
                return strlen(sourceName);
 
183
        }
 
184
}
 
185
 
 
186
size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
 
187
{
 
188
        void* address = NULL;
 
189
        GetStackFrames(skip + 1, &address, 1);
 
190
        if (address) {
 
191
                return GetModuleNameFromAddress(address, moduleName, size);
 
192
        }
 
193
        return 0;
 
194
}
 
195
 
 
196
size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes)
 
197
{
 
198
        if (size) *symbolName = 0;
 
199
        if (offsetBytes) *offsetBytes = 0;
 
200
        __try {
 
201
                ULONG_ADDR dwOffset = 0;
 
202
                union {
 
203
                        IMAGEHLP_SYMBOL sym;
 
204
                        char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
 
205
                } u;
 
206
                u.sym.SizeOfStruct  = sizeof(u.sym);
 
207
                u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
 
208
 
 
209
                if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset, &u.sym)) {
 
210
                        return 0;
 
211
                } else {
 
212
                        const char* sourceName = u.sym.Name;
 
213
                        char undName[1024];
 
214
                        if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName), UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
 
215
                                sourceName = undName;
 
216
                        } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
 
217
                                sourceName = undName;
 
218
                        }
 
219
                        if (offsetBytes) {
 
220
                                *offsetBytes = dwOffset;
 
221
                        }
 
222
                        if (size) {
 
223
                                strncpy(symbolName, sourceName, size)[size - 1] = 0;
 
224
                        }
 
225
                        return strlen(sourceName);
 
226
                }
 
227
        } __except (EXCEPTION_EXECUTE_HANDLER) {
 
228
                SetLastError(GetExceptionCode());
 
229
        }
 
230
        return 0;
 
231
}
 
232
 
 
233
size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes)
 
234
{
 
235
        void* address = NULL;
 
236
        GetStackFrames(skip + 1, &address, 1);
 
237
        if (address) {
 
238
                return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
 
239
        }
 
240
        return 0;
 
241
}
 
242
 
 
243
size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes)
 
244
{
 
245
        if (size) *fileName = 0;
 
246
        if (lineNumber) *lineNumber = 0;
 
247
        if (offsetBytes) *offsetBytes = 0;
 
248
        {
 
249
                char* sourceName;
 
250
                IMAGEHLP_LINE line = { sizeof (line) };
 
251
                ULONG_PTR dwOffset = 0;
 
252
                if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset, &line)) {
 
253
                        return 0;
 
254
                }
 
255
                if (lineNumber) {
 
256
                        *lineNumber = line.LineNumber;
 
257
                }
 
258
                if (offsetBytes) {
 
259
                        *offsetBytes = dwOffset;
 
260
                }
 
261
                sourceName = line.FileName;
 
262
                // TODO: resolve relative filenames, found in 'source directories' registered with MSVC IDE.
 
263
                if (size) {
 
264
                        strncpy(fileName, sourceName, size)[size - 1] = 0;
 
265
                }
 
266
                return strlen(sourceName);
 
267
        }
 
268
}
 
269
 
 
270
size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes)
 
271
{
 
272
        void* address = NULL;
 
273
        GetStackFrames(skip + 1, &address, 1);
 
274
        if (address) {
 
275
                return GetFileLineFromAddress(address, fileName, size, lineNumber, offsetBytes);
 
276
        }
 
277
        return 0;
 
278
}
 
279
 
 
280
size_t GetDescriptionFromAddress(void* address, const char* format, char* buffer, size_t size)
 
281
{
 
282
        char*const begin = buffer;
 
283
        char*const end = buffer + size;
 
284
        size_t line_number = 0;
 
285
        char   str[128];
 
286
 
 
287
        if (size) {
 
288
                *buffer = 0;
 
289
        }
 
290
        buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
 
291
        size = end < buffer ? 0 : end - buffer;
 
292
 
 
293
        if (line_number) {
 
294
                wsprintf(str, "(%d) : ", line_number);
 
295
                if (size) {
 
296
                        strncpy(buffer, str, size)[size - 1] = 0;
 
297
                }
 
298
                buffer += strlen(str);
 
299
                size = end < buffer ? 0 : end - buffer;
 
300
        }
 
301
 
 
302
        if (size) {
 
303
                strncpy(buffer, "at ", size)[size - 1] = 0;
 
304
        }
 
305
        buffer += strlen("at ");
 
306
        size = end < buffer ? 0 : end - buffer;
 
307
 
 
308
        buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
 
309
        size = end < buffer ? 0 : end - buffer;
 
310
 
 
311
        if (size) {
 
312
                strncpy(buffer, " in ", size)[size - 1] = 0;
 
313
        }
 
314
        buffer += strlen(" in ");
 
315
        size = end < buffer ? 0 : end - buffer;
 
316
        
 
317
        buffer += GetModuleNameFromAddress(address, buffer, size);
 
318
        size = end < buffer ? 0 : end - buffer;
 
319
        
 
320
        return buffer - begin;
 
321
}
 
322
 
 
323
size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size)
 
324
{
 
325
        char*const begin = (char*)description;
 
326
        char*const end = begin + size;
 
327
        char* buffer = begin + (count + 1) * sizeof(char*);
 
328
        size_t i;
 
329
        for (i = 0; i < count; ++i) {
 
330
                if (description) description[i] = buffer;
 
331
                size = end < buffer ? 0 : end - buffer;
 
332
                buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
 
333
        }
 
334
        if (description) description[count] = NULL;
 
335
        return buffer - begin;
 
336
}
 
337
 
 
338
/* Compatibility with <execinfo.h> */
 
339
 
 
340
int backtrace(void* addresses[], int count)
 
341
{
 
342
        return GetStackFrames(1, addresses, count);
 
343
}
 
344
 
 
345
char** backtrace_symbols(void*const* addresses, int count)
 
346
{
 
347
        size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
 
348
        char** symbols = (char**)malloc(size);
 
349
        GetDescriptionFromStack(addresses, count, NULL, symbols, size);
 
350
        return symbols;
 
351
}
 
352
 
 
353
#endif /* !_M_AMD64 */