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.

218 lines
5.4 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.
*/
/*
* This test verifies that Pin properly saves and restores the applicaton's
* XMM registers when emulating a delivered signal. The application's main thread
* simply does some string copy operations using the XMM registers while ALRM
* signals are handled. The signal handler also uses the XMM registers to do some
* string compares. If Pin doesn't properly save/restore the XMM registers, the
* handler will mess up the main thread's copy operations.
*
*********************************************************************************
*
* I have observed that this test occasionally fails on vs-lin64-4 (running SUSE10
* on Intel64). I can only make the problem occur on heavy load, for example
* while running the signal tests with "make -j8". However, the problem appears
* to be unrelated to Pin, since I can make the same failure occur with the native
* version of this test.
*
* Occasionally, the kernel enters the signal handler with an empty FP register
* state saved in the signal context. (I.e. all FP registers are reset as
* though an FINIT instruction had been exectued.) When the signal handler
* returns, the empty FP state is restored, which corrupts the XMM registers
* in the test's loop. This is clearly not a Pin bug since it happens in a
* native test.
*
* The IsBadKernel() function below disables this test on kernels that are known
* to have this bug.
*/
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/utsname.h>
#define SIGCOUNT 100
#define SIZEBIG 4096
#define SIZESMALL 32
#define ALIGN 16
volatile unsigned SigCount = 0;
char *SigBuf1;
char *SigBuf2;
static void XmmCheck();
static void CheckBuf(const char *, size_t);
static char *Allocate(size_t, size_t);
static void Handle1(int);
static void Handle2(int, siginfo_t *, void *);
static int IsBadKernel();
extern void CopyWithXmmDelay(char *, char *, int);
extern void CopyWithXmm(char *, char *, int);
int main()
{
struct sigaction sigact;
struct itimerval itval;
int i;
if (IsBadKernel())
return 0;
SigBuf1 = Allocate(SIZESMALL, ALIGN);
SigBuf2 = Allocate(SIZESMALL, ALIGN);
for (i = 0; i < SIZESMALL; i++)
SigBuf1[i] = (char)i;
sigact.sa_handler = Handle1;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
if (sigaction(SIGALRM, &sigact, 0) == -1)
{
fprintf(stderr, "Unable to set up handler\n");
return 1;
}
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_usec = 10000;
itval.it_value.tv_sec = 0;
itval.it_value.tv_usec = 10000;
if (setitimer(ITIMER_REAL, &itval, 0) == -1)
{
fprintf(stderr, "Unable to set up timer\n");
return 1;
}
XmmCheck();
itval.it_value.tv_sec = 0;
itval.it_value.tv_usec = 0;
if (setitimer(ITIMER_REAL, &itval, 0) == -1)
{
fprintf(stderr, "Unable to disable timer\n");
return 1;
}
return 0;
}
static void XmmCheck()
{
char *p1;
char *p2;
int i;
p1 = Allocate(SIZEBIG, ALIGN);
p2 = Allocate(SIZEBIG, ALIGN);
memset(p2, 0, SIZEBIG);
printf("src = %p - %p\n", p1, p1+SIZEBIG);
printf("dst = %p - %p\n", p2, p2+SIZEBIG);
for (i = 0; i < SIZEBIG; i++)
p1[i] = "abcdefghijklmnopqrstuvwxyz"[i%26];
while (SigCount < SIGCOUNT)
{
CopyWithXmmDelay(p2, p1, SIZEBIG);
CheckBuf(p2, SIZEBIG);
}
}
static void CheckBuf(const char *p, size_t size)
{
int i;
char c;
int ok;
ok = 1;
for (i = 0; i < size; i++)
{
c = "abcdefghijklmnopqrstuvwxyz"[i%26];
if (p[i] != c)
{
fprintf(stderr, "Element %d wrong: is '%c' (%d) should be '%c' (%d)\n", i, p[i], (int)p[i], c, (int)c);
ok = 0;
}
}
if (!ok)
exit(1);
}
static char *Allocate(size_t size, size_t align)
{
char *p;
size_t low;
p = malloc(size + (align-1));
low = (size_t)p % align;
if (low)
return p + (align-low);
else
return p;
}
static void Handle1(int sig)
{
SigCount++;
CopyWithXmm(SigBuf2, SigBuf1, SIZESMALL);
/*
* After a while, switch to using a "siginfo" handler. This exercises different
* signal emulation paths within Pin.
*/
if (SigCount > SIGCOUNT/2)
{
struct sigaction sigact;
sigact.sa_sigaction = Handle2;
sigact.sa_flags = SA_SIGINFO;
sigemptyset(&sigact.sa_mask);
if (sigaction(SIGALRM, &sigact, 0) == -1)
{
fprintf(stderr, "Unable to reset handler\n");
exit(1);
}
}
}
static void Handle2(int sig, siginfo_t *i, void *v)
{
SigCount++;
CopyWithXmm(SigBuf2, SigBuf1, SIZESMALL);
}
/*
* Returns True if the kernel version is known to be one that causes this test to fail.
*/
static int IsBadKernel()
{
struct utsname info;
if (uname(&info) == -1)
return 1;
if (strncmp(info.release, "2.6.16", sizeof("2.6.16")-1) == 0)
return 1;
return 0;
}