Last active
April 24, 2021 07:01
-
-
Save Hamayama/da2e08996ce0bc3412562d216172bb05 to your computer and use it in GitHub Desktop.
GetThreadContext test for Windows Wow64 thread
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// thread32.c | |
// 2019-2-16 v1.03 | |
// | |
// Description: | |
// GetThreadContext test for Windows Wow64 thread. | |
// | |
// Original source: | |
// https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/aa176c36-6624-4776-9380-1c9cf37a314e/getthreadcontext-returns-stale-register-values-on-wow64?forum=windowscompatibility | |
// (GetThreadContext returns stale register values on WOW64) | |
// | |
// Modify: | |
// - Modified for MSYS2/MinGW-w64 32bit environment. | |
// (gcc version 7.3.0 (Rev2, Built by MSYS2 project)) | |
// - Added Wow64 workaround. | |
// (This doesn't work when the thread is already waiting. | |
// (See also https://github.com/ivmai/bdwgc/issues/262 )) | |
// | |
// Compile: | |
// gcc -g -O2 -o thread32.exe thread32.c | |
// | |
#include <windows.h> | |
#include <stdio.h> | |
#define LOOP_NUM 1000000 | |
#define USE_WOW64_WORKAROUND | |
#define USE_RESUME_SUSPEND_REPEAT | |
#define USE_CONTEXT_EXCEPTION_ACTIVE | |
//#define USE_CONTEXT_SERVICE_ACTIVE | |
#define CONTEXT_EXCEPTION_ACTIVE 0x08000000 | |
#define CONTEXT_SERVICE_ACTIVE 0x10000000 | |
#define CONTEXT_EXCEPTION_REQUEST 0x40000000 | |
#define CONTEXT_EXCEPTION_REPORTING 0x80000000 | |
volatile DWORD savedEsp; | |
volatile DWORD prevEsp; | |
volatile DWORD stackSize; | |
void __attribute__ ((noinline)) SwitchToThreadWithStack(DWORD stackSize0) | |
{ | |
stackSize = stackSize0; | |
__asm__ __volatile__ | |
( | |
"sub %2, %%esp \n\t" // esp -= stackSize; | |
"mov %%esp, %0 \n\t" // savedEsp = esp; | |
"call _SwitchToThread@0 \n\t" // SwitchToThread(); | |
"movl $0, %0 \n\t" // savedEsp = 0; | |
"mov %%esp, %1 \n\t" // prevEsp = esp; | |
"add %2, %%esp \n\t" // esp += stackSize; | |
: "=m" (savedEsp), "=m" (prevEsp) // out: %0=savedEsp, %1=prevEsp | |
: "m" (stackSize) // in: %2=stackSize | |
); | |
} | |
DWORD WINAPI ThreadProc(LPVOID lpParameter) | |
{ | |
for (;;) { | |
SwitchToThreadWithStack(8); | |
SwitchToThreadWithStack(32); | |
SwitchToThreadWithStack(4); | |
SwitchToThreadWithStack(16); | |
} | |
return 0; | |
} | |
int main(void) | |
{ | |
HANDLE hThread; | |
CONTEXT context; | |
int total_call = 0; | |
int loss_occur = 0; | |
int repeat_count = 0; | |
int repeat_sum = 0; | |
hThread = CreateThread(NULL, 0, &ThreadProc, NULL, 0, NULL); | |
if (hThread == NULL) { | |
printf("ERROR: CreateThread failed.\n"); | |
return 1; | |
} | |
for (total_call = 0; total_call < LOOP_NUM; total_call++) { | |
repeat: | |
if (SuspendThread(hThread) == (DWORD)-1) { | |
printf("ERROR: SuspendThread failed.\n"); | |
return 1; | |
} | |
repeat2: | |
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST; | |
if (!GetThreadContext(hThread, &context)) { | |
printf("ERROR: GetThreadContext failed.\n"); | |
return 1; | |
} | |
//printf("%x\n", context.ContextFlags); | |
//fflush(stdout); | |
#if defined(USE_WOW64_WORKAROUND) | |
/* Wow64 workaround */ | |
if ((context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) | |
&& (context.ContextFlags & (0 | |
# if defined(USE_CONTEXT_EXCEPTION_ACTIVE) | |
| CONTEXT_EXCEPTION_ACTIVE | |
# endif /* USE_CONTEXT_EXCEPTION_ACTIVE */ | |
# if defined(USE_CONTEXT_SERVICE_ACTIVE) | |
| CONTEXT_SERVICE_ACTIVE | |
# endif /* USE_CONTEXT_SERVICE_ACTIVE */ | |
))) { | |
# if defined(USE_RESUME_SUSPEND_REPEAT) | |
if (ResumeThread(hThread) == (DWORD)-1) { | |
printf("ERROR: ResumeThread failed !\n"); | |
return 1; | |
} | |
# endif /* USE_RESUME_SUSPEND_REPEAT */ | |
SwitchToThread(); | |
//Sleep(0); | |
//Sleep(1); | |
repeat_count++; | |
# if defined(USE_RESUME_SUSPEND_REPEAT) | |
goto repeat; | |
# else /* !USE_RESUME_SUSPEND_REPEAT */ | |
goto repeat2; | |
# endif /* !USE_RESUME_SUSPEND_REPEAT */ | |
} | |
#endif /* USE_WOW64_WORKAROUND */ | |
/* collect data */ | |
if (repeat_count > 0) loss_occur++; | |
repeat_sum += repeat_count; | |
//printf("%d %d %d %d\n", total_call, loss_occur, repeat_sum, repeat_count); | |
//fflush(stdout); | |
repeat_count = 0; | |
/* check error */ | |
if (savedEsp != 0 && prevEsp != 0 && context.Esp > savedEsp) { | |
if (context.Esp <= prevEsp) { | |
printf("ERROR: Stale ESP ! (Context ESP: 0x%x, Saved ESP: 0x%x, Previous ESP: 0x%x)\n", context.Esp, savedEsp, prevEsp); | |
return 1; | |
} else { | |
printf("ERROR: Unknown ESP.\n"); | |
return 1; | |
} | |
} | |
if (ResumeThread(hThread) == (DWORD)-1) { | |
printf("ERROR: ResumeThread failed.\n"); | |
return 1; | |
} | |
SwitchToThread(); | |
} | |
printf("total_call=%d loss_occur=%d repeat_sum=%d\n", total_call, loss_occur, repeat_sum); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment