You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
7.1 KiB
360 lines
7.1 KiB
// test : test program for multithreaded stack walk
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <dbghelp.h>
|
|
|
|
#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 <sympath>\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
|