123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- /*
- Copyright (c) 2004 Andrei Polushin
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
-
- #if !defined(_M_AMD64) && defined(_MSC_VER)
-
- /* X86_64 is currently missing some meachine-dependent code below. */
-
- #define GC_BUILD
- #include "private/msvc_dbg.h"
- #include "gc.h"
-
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
-
- #pragma pack(push, 8)
- #include <imagehlp.h>
- #pragma pack(pop)
-
- #pragma comment(lib, "dbghelp.lib")
- #pragma optimize("gy", off)
-
- typedef GC_word word;
- #define GC_ULONG_PTR word
-
- #ifdef _WIN64
- typedef GC_ULONG_PTR ULONG_ADDR;
- #else
- typedef ULONG ULONG_ADDR;
- #endif
-
- static HANDLE GetSymHandle(void)
- {
- static HANDLE symHandle = NULL;
- if (!symHandle) {
- BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
- if (bRet) {
- DWORD dwOptions = SymGetOptions();
- dwOptions &= ~SYMOPT_UNDNAME;
- dwOptions |= SYMOPT_LOAD_LINES;
- SymSetOptions(dwOptions);
- }
- }
- return symHandle;
- }
-
- static void* CALLBACK FunctionTableAccess(HANDLE hProcess,
- ULONG_ADDR dwAddrBase)
- {
- return SymFunctionTableAccess(hProcess, dwAddrBase);
- }
-
- static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
- {
- MEMORY_BASIC_INFORMATION memoryInfo;
- ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
- if (dwAddrBase) {
- return dwAddrBase;
- }
- if (VirtualQueryEx(hProcess, (void*)(GC_ULONG_PTR)dwAddress, &memoryInfo,
- sizeof(memoryInfo))) {
- char filePath[_MAX_PATH];
- char curDir[_MAX_PATH];
- char exePath[_MAX_PATH];
- DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase,
- filePath, sizeof(filePath));
-
- /* Save and restore current directory around SymLoadModule, see KB */
- /* article Q189780. */
- GetCurrentDirectoryA(sizeof(curDir), curDir);
- GetModuleFileNameA(NULL, exePath, sizeof(exePath));
- #if defined(_MSC_VER) && _MSC_VER == 1200
- /* use strcat for VC6 */
- strcat(exePath, "\\..");
- #else
- strcat_s(exePath, sizeof(exePath), "\\..");
- #endif /* _MSC_VER >= 1200 */
- SetCurrentDirectoryA(exePath);
- #ifdef _DEBUG
- GetCurrentDirectoryA(sizeof(exePath), exePath);
- #endif
- SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL,
- (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase, 0);
- SetCurrentDirectoryA(curDir);
- }
- return (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase;
- }
-
- static ULONG_ADDR CheckAddress(void* address)
- {
- ULONG_ADDR dwAddress = (ULONG_ADDR)(GC_ULONG_PTR)address;
- GetModuleBase(GetSymHandle(), dwAddress);
- return dwAddress;
- }
-
- size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
- {
- HANDLE hProcess = GetSymHandle();
- HANDLE hThread = GetCurrentThread();
- CONTEXT context;
- context.ContextFlags = CONTEXT_FULL;
- if (!GetThreadContext(hThread, &context)) {
- return 0;
- }
- /* GetThreadContext might return invalid context for the current thread. */
- #if defined(_M_IX86)
- __asm mov context.Ebp, ebp
- #endif
- return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1,
- frames, maxFrames);
- }
-
- size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread,
- CONTEXT* context, size_t skip,
- void* frames[], size_t maxFrames)
- {
- size_t frameIndex;
- DWORD machineType;
- STACKFRAME stackFrame = { 0 };
- stackFrame.AddrPC.Mode = AddrModeFlat;
- #if defined(_M_IX86)
- machineType = IMAGE_FILE_MACHINE_I386;
- stackFrame.AddrPC.Offset = context->Eip;
- stackFrame.AddrStack.Mode = AddrModeFlat;
- stackFrame.AddrStack.Offset = context->Esp;
- stackFrame.AddrFrame.Mode = AddrModeFlat;
- stackFrame.AddrFrame.Offset = context->Ebp;
- #elif defined(_M_MRX000)
- machineType = IMAGE_FILE_MACHINE_R4000;
- stackFrame.AddrPC.Offset = context->Fir;
- #elif defined(_M_ALPHA)
- machineType = IMAGE_FILE_MACHINE_ALPHA;
- stackFrame.AddrPC.Offset = (unsigned long)context->Fir;
- #elif defined(_M_PPC)
- machineType = IMAGE_FILE_MACHINE_POWERPC;
- stackFrame.AddrPC.Offset = context->Iar;
- #elif defined(_M_IA64)
- machineType = IMAGE_FILE_MACHINE_IA64;
- stackFrame.AddrPC.Offset = context->StIIP;
- #elif defined(_M_ALPHA64)
- machineType = IMAGE_FILE_MACHINE_ALPHA64;
- stackFrame.AddrPC.Offset = context->Fir;
- #elif !defined(CPPCHECK)
- # error Unknown CPU
- #endif
- for (frameIndex = 0; frameIndex < maxFrames; ) {
- BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame,
- &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
- if (!bRet) {
- break;
- }
- if (skip) {
- skip--;
- } else {
- frames[frameIndex++] = (void*)(GC_ULONG_PTR)stackFrame.AddrPC.Offset;
- }
- }
- return frameIndex;
- }
-
- size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
- {
- if (size) *moduleName = 0;
- {
- const char* sourceName;
- IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
- if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address),
- &moduleInfo)) {
- return 0;
- }
- sourceName = strrchr(moduleInfo.ImageName, '\\');
- if (sourceName) {
- sourceName++;
- } else {
- sourceName = moduleInfo.ImageName;
- }
- if (size) {
- strncpy(moduleName, sourceName, size)[size - 1] = 0;
- }
- return strlen(sourceName);
- }
- }
-
- size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
- {
- void* address = NULL;
- GetStackFrames(skip + 1, &address, 1);
- if (address) {
- return GetModuleNameFromAddress(address, moduleName, size);
- }
- return 0;
- }
-
- size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size,
- size_t* offsetBytes)
- {
- if (size) *symbolName = 0;
- if (offsetBytes) *offsetBytes = 0;
- __try {
- ULONG_ADDR dwOffset = 0;
- union {
- IMAGEHLP_SYMBOL sym;
- char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
- } u;
- u.sym.SizeOfStruct = sizeof(u.sym);
- u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
-
- if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
- &u.sym)) {
- return 0;
- } else {
- const char* sourceName = u.sym.Name;
- char undName[1024];
- if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName),
- UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
- sourceName = undName;
- } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
- sourceName = undName;
- }
- if (offsetBytes) {
- *offsetBytes = dwOffset;
- }
- if (size) {
- strncpy(symbolName, sourceName, size)[size - 1] = 0;
- }
- return strlen(sourceName);
- }
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- SetLastError(GetExceptionCode());
- }
- return 0;
- }
-
- size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size,
- size_t* offsetBytes)
- {
- void* address = NULL;
- GetStackFrames(skip + 1, &address, 1);
- if (address) {
- return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
- }
- return 0;
- }
-
- size_t GetFileLineFromAddress(void* address, char* fileName, size_t size,
- size_t* lineNumber, size_t* offsetBytes)
- {
- if (size) *fileName = 0;
- if (lineNumber) *lineNumber = 0;
- if (offsetBytes) *offsetBytes = 0;
- {
- char* sourceName;
- IMAGEHLP_LINE line = { sizeof (line) };
- GC_ULONG_PTR dwOffset = 0;
- if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
- &line)) {
- return 0;
- }
- if (lineNumber) {
- *lineNumber = line.LineNumber;
- }
- if (offsetBytes) {
- *offsetBytes = dwOffset;
- }
- sourceName = line.FileName;
- /* TODO: resolve relative filenames, found in 'source directories' */
- /* registered with MSVC IDE. */
- if (size) {
- strncpy(fileName, sourceName, size)[size - 1] = 0;
- }
- return strlen(sourceName);
- }
- }
-
- size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size,
- size_t* lineNumber, size_t* offsetBytes)
- {
- void* address = NULL;
- GetStackFrames(skip + 1, &address, 1);
- if (address) {
- return GetFileLineFromAddress(address, fileName, size, lineNumber,
- offsetBytes);
- }
- return 0;
- }
-
- size_t GetDescriptionFromAddress(void* address, const char* format,
- char* buffer, size_t size)
- {
- char*const begin = buffer;
- char*const end = buffer + size;
- size_t line_number = 0;
-
- if (size) {
- *buffer = 0;
- }
- buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
- size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
-
- if (line_number) {
- char str[128];
-
- wsprintf(str, "(%d) : ", (int)line_number);
- if (size) {
- strncpy(buffer, str, size)[size - 1] = 0;
- }
- buffer += strlen(str);
- size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
- }
-
- if (size) {
- strncpy(buffer, "at ", size)[size - 1] = 0;
- }
- buffer += strlen("at ");
- size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
-
- buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
- size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
-
- if (size) {
- strncpy(buffer, " in ", size)[size - 1] = 0;
- }
- buffer += strlen(" in ");
- size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
-
- buffer += GetModuleNameFromAddress(address, buffer, size);
- return buffer - begin;
- }
-
- size_t GetDescriptionFromStack(void* const frames[], size_t count,
- const char* format, char* description[],
- size_t size)
- {
- char*const begin = (char*)description;
- char*const end = begin + size;
- char* buffer = begin + (count + 1) * sizeof(char*);
- size_t i;
- (void)format;
- for (i = 0; i < count; ++i) {
- if (size)
- description[i] = buffer;
- size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
- buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
- }
- if (size)
- description[count] = NULL;
- return buffer - begin;
- }
-
- /* Compatibility with <execinfo.h> */
-
- int backtrace(void* addresses[], int count)
- {
- return GetStackFrames(1, addresses, count);
- }
-
- char** backtrace_symbols(void*const* addresses, int count)
- {
- size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
- char** symbols = (char**)malloc(size);
- if (symbols != NULL)
- GetDescriptionFromStack(addresses, count, NULL, symbols, size);
- return symbols;
- }
-
- #else
-
- extern int GC_quiet;
- /* ANSI C does not allow translation units to be empty. */
-
- #endif /* _M_AMD64 */
|