Skip to content

Instantly share code, notes, and snippets.

@Hamayama
Last active April 24, 2021 07:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hamayama/da2e08996ce0bc3412562d216172bb05 to your computer and use it in GitHub Desktop.
Save Hamayama/da2e08996ce0bc3412562d216172bb05 to your computer and use it in GitHub Desktop.
GetThreadContext test for Windows Wow64 thread
//
// 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