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.
115 lines
3.3 KiB
115 lines
3.3 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*
|
|
* Test that we can read / write a thread's MXCSR register via the Windows CONTEXT.MxCsr field.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
|
|
const unsigned MXCSR_INITIAL = 0x1f80; // All exceptions masked
|
|
const unsigned MXCSR_NEW = 0x1d80; // Enable divide-by-zero exceptions
|
|
|
|
volatile bool TestThreadReady = false;
|
|
volatile bool MxcsrChanged = false;
|
|
|
|
extern "C" void SetMxcsr(unsigned);
|
|
extern "C" unsigned GetMxcsr();
|
|
|
|
static DWORD WINAPI TestThread(LPVOID);
|
|
|
|
|
|
int main()
|
|
{
|
|
HANDLE thd = CreateThread(0, 0, TestThread, 0, 0, 0);
|
|
if (!thd)
|
|
{
|
|
std::cerr << "Unable to create thread" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
while (!TestThreadReady)
|
|
Sleep(0);
|
|
|
|
if (SuspendThread(thd) == -1)
|
|
{
|
|
std::cerr << "Error from SuspendThread()" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
CONTEXT ctxt;
|
|
std::memset(&ctxt, 0, sizeof(ctxt));
|
|
|
|
// Must specify CONTEXT_CONTROL here to avoid Windows bug on Vista and earlier (?).
|
|
// On those systems, the SetThreadContext() call below will try to write the CONTROL
|
|
// registers even though we don't specify CONTEXT_CONTROL in that call. Therefore,
|
|
// we read the CONTROL registers here in case the SetThreadContext() call tries to
|
|
// write them back.
|
|
//
|
|
ctxt.ContextFlags = (CONTEXT_FLOATING_POINT | CONTEXT_CONTROL);
|
|
if (GetThreadContext(thd, &ctxt) == 0)
|
|
{
|
|
std::cerr << "Error from GetThreadContext()" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
if (ctxt.MxCsr != MXCSR_INITIAL)
|
|
{
|
|
std::cout << "Read incorrect initial MXCSR value (0x" << std::hex << ctxt.MxCsr << ")" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
ctxt.ContextFlags = CONTEXT_FLOATING_POINT;
|
|
ctxt.MxCsr = MXCSR_NEW;
|
|
if (SetThreadContext(thd, &ctxt) == 0)
|
|
{
|
|
std::cerr << "Error from SetThreadContext()" << std::endl;
|
|
return 1;
|
|
}
|
|
if (ResumeThread(thd) == -1)
|
|
{
|
|
std::cerr << "Error from ResumeThread()" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
MxcsrChanged = true;
|
|
WaitForSingleObject(thd, INFINITE);
|
|
|
|
DWORD ret = 1;
|
|
GetExitCodeThread(thd, &ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static DWORD WINAPI TestThread(LPVOID)
|
|
{
|
|
SetMxcsr(MXCSR_INITIAL);
|
|
TestThreadReady = true;
|
|
|
|
// Wait for the main thread to change our MXCSR value. Note that we do not call Sleep here
|
|
// because we want to force Pin to suspend us outside of a system call. When the thread is
|
|
// suspended inside a system call, Pin executes the SetThreadContext() syscall directly (instead
|
|
// of emulating it). The test would still be valid in that case, but it's a better test
|
|
// if it exercises the emulation support in Pin.
|
|
//
|
|
while (!MxcsrChanged);
|
|
|
|
unsigned mxcsr = GetMxcsr();
|
|
if (mxcsr != MXCSR_NEW)
|
|
{
|
|
std::cout << "New MXCSR value (0x" << std::hex << mxcsr << ") is wrong" << std::endl;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|