// test : test program for multithreaded stack walk // #include #include #include #ifndef _WIN64 CRITICAL_SECTION g_cs; BOOL CALLBACK cbEnumSym( PSYMBOL_INFO si, ULONG size, PVOID context ) { // printf("%s ", si->Name); return TRUE; } BOOL CALLBACK cbEnumMods( PSTR name, DWORD64 base, PVOID context ) { HANDLE hp = (HANDLE)context; SymEnumSymbols(hp, base, "*", cbEnumSym, NULL); return TRUE; } BOOL cbSymbol( HANDLE hProcess, ULONG ActionCode, ULONG64 CallbackData, ULONG64 UserContext ) { PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl; PIMAGEHLP_CBA_READ_MEMORY prm; IMAGEHLP_MODULE64 mi; PUCHAR p; ULONG i; idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD64) CallbackData; switch ( ActionCode ) { case CBA_DEBUG_INFO: printf("%s", (LPSTR)CallbackData); break; #if 0 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: if (fControlC) { fControlC = 0; return TRUE; } break; #endif case CBA_DEFERRED_SYMBOL_LOAD_START: printf("loading symbols for %s\n", idsl->FileName); break; case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: if (idsl->FileName && *idsl->FileName) printf( "*** Error: could not load symbols for %s\n", idsl->FileName ); else printf( "*** Error: could not load symbols [MODNAME UNKNOWN]\n"); break; case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: printf("loaded symbols for %s\n", idsl->FileName); SymEnumSymbols(hProcess, idsl->BaseOfImage, "*", cbEnumSym, NULL); break; case CBA_SYMBOLS_UNLOADED: printf("unloaded symbols for %s\n", idsl->FileName); break; #if 1 case CBA_READ_MEMORY: prm = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData; return ReadProcessMemory(GetCurrentProcess(), (LPCVOID)prm->addr, prm->buf, prm->bytes, prm->bytesread); #endif default: return FALSE; } return FALSE; } BOOL CALLBACK MyReadProcessMemory( HANDLE hProcess, // handle to the process DWORD lpBaseAddress, // base of memory area LPVOID lpBuffer, // data buffer DWORD nSize, // number of bytes to read LPDWORD lpNumberOfBytesRead) // number of bytes read { DWORD i = 0; BOOL fRet = FALSE; if (nSize == 0) { fRet = TRUE; goto Exit; } // // Try to read as much as possible // __try { for (i = 0; i < nSize; i++) { ((PBYTE)lpBuffer)[i] = *((PBYTE)lpBaseAddress + i); } } __except(EXCEPTION_EXECUTE_HANDLER) { // // We have a partial read in this case // } if (lpNumberOfBytesRead) { *lpNumberOfBytesRead = i; } fRet = (i > 0); Exit: return fRet; } VOID GetStack() { BOOL fRet = FALSE; HANDLE hProcess = GetCurrentProcess(); HANDLE hThread = GetCurrentThread(); DWORD dwStackDepth = 0; DWORD i = 0; DWORD dwStackAddr[16]; CONTEXT Context; STACKFRAME StackFrame; // // First initialize data used by the // stack walker // ZeroMemory(&Context, sizeof(CONTEXT)); Context.ContextFlags = CONTEXT_FULL; ZeroMemory(&StackFrame, sizeof(STACKFRAME)); fRet = GetThreadContext(hThread, &Context); if (!fRet) { printf("Could not get the thread context -0x%x\n", GetLastError()); goto Exit; } // // Fill in our stack frame // StackFrame.AddrStack.Mode = AddrModeFlat; StackFrame.AddrFrame.Mode = AddrModeFlat; StackFrame.AddrPC.Mode = AddrModeFlat; __asm { mov StackFrame.AddrStack.Offset, esp; mov StackFrame.AddrFrame.Offset, ebp; mov StackFrame.AddrPC.Offset, offset DummyLabel; DummyLabel: } // // Start walking the stack. // while (dwStackDepth < 16) { fRet = StackWalk( IMAGE_FILE_MACHINE_I386, // MachineType hProcess, // Current process hThread, // Current thread &StackFrame, // StackFrame &Context, // ContextRecord - can be NULL for x86 &MyReadProcessMemory, // use our own read process memory &SymFunctionTableAccess, // FunctionTableAccessRoutine &SymGetModuleBase, // GetModuleBaseRoutine NULL); // TranslateAddressProc if (!fRet) { break; } dwStackAddr[dwStackDepth] = StackFrame.AddrPC.Offset; dwStackDepth++; } EnterCriticalSection(&g_cs); printf("\nThread: 0x%x\n", GetCurrentThreadId()); for (i = 0; i < dwStackDepth; i++) { printf("\t-0x%x\n", dwStackAddr[i]); } LeaveCriticalSection(&g_cs); SymEnumerateModules64(hProcess, cbEnumMods, hProcess); Exit: fflush(stdout); return; } VOID Dummy2() { ULONG ul = (GetCurrentThreadId() % 2); if (ul == 0) { GetStack(); } else return; } VOID Dummy1() { ULONG ul = (GetCurrentThreadId() % 5); if (ul == 0 || ul == 4) { Dummy2(); } else { GetStack(); } GetStack(); } DWORD WINAPI DwThreadFn( LPVOID pvParam) { ULONG ul = (GetCurrentThreadId() % 7); if (ul == 3 || ul == 1 || ul == 5 || ul == 6) { GetStack(); Dummy1(); } else { Dummy2(); } GetStack(); return 0; } #define THREAD_COUNT MAXIMUM_WAIT_OBJECTS int __cdecl main(int argc, char* argv[]) { int i = 0; HANDLE rghThread[THREAD_COUNT] = {0}; InitializeCriticalSection(&g_cs); #if 0 if (argc < 2 || argv[1] == NULL) { printf("usage: s.exe \n"); goto Exit; } #endif printf("Starting test!\n"); // // Initialize the symbols handler // SymSetOptions(SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG); if (!SymInitialize( GetCurrentProcess(), // hProcess NULL, // UserSearchPath TRUE)) { printf("Cannot initialize the symbols - 0x%x!\n", GetLastError()); goto Exit; } SymRegisterCallback64(GetCurrentProcess(), cbSymbol, 0); printf("Creating %u threads!\n", THREAD_COUNT); for (i = 0; i < THREAD_COUNT; i++) { rghThread[i] = CreateThread( NULL, 0, &DwThreadFn, NULL, CREATE_SUSPENDED, NULL); if (!rghThread[i]) { printf("Cannot create thread - 0x%x", GetLastError()); } else printf("Created thread %x\n", rghThread[i]); } // // Now resume all threads // for (i = 0; i < THREAD_COUNT; i++) { ResumeThread(rghThread[i]); } // // Wait for the threads to finish // WaitForMultipleObjects(THREAD_COUNT, rghThread, TRUE, INFINITE); for (i = 0; i < THREAD_COUNT; i++) { CloseHandle(rghThread[i]); } printf("Test finished!\n"); Exit: DeleteCriticalSection(&g_cs); return 0; } #else int __cdecl main(int argc, char* argv[]) { printf("storm.exe is not implemented for 64 bit platforms.\n"); return 0; } #endif // #ifndef _WIN64