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.
173 lines
3.7 KiB
173 lines
3.7 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 checks that we can get precise register state in a signal handler
|
|
* if a string instruction faults midway through a REP prefix.
|
|
*/
|
|
|
|
// features.h does not exist on FreeBSD
|
|
#ifdef TARGET_LINUX
|
|
// features initializes the system's state, including the state of __USE_GNU
|
|
#include <features.h>
|
|
#endif
|
|
|
|
// If __USE_GNU is defined, we don't need to do anything.
|
|
// If we defined it ourselves, we need to undefine it later.
|
|
#ifndef __USE_GNU
|
|
#define __USE_GNU
|
|
#define APP_UNDEF_USE_GNU
|
|
#endif
|
|
|
|
#if defined(TARGET_MAC)
|
|
# include <sys/ucontext.h>
|
|
#else
|
|
# include <ucontext.h>
|
|
#endif
|
|
|
|
// If we defined __USE_GNU ourselves, we need to undefine it here.
|
|
#ifdef APP_UNDEF_USE_GNU
|
|
#undef __USE_GNU
|
|
#undef APP_UNDEF_USE_GNU
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <sys/mman.h>
|
|
|
|
|
|
#ifndef MAP_ANONYMOUS
|
|
#ifdef MAP_ANON
|
|
#define MAP_ANONYMOUS MAP_ANON
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(TARGET_IA32)
|
|
# define REG_CX REG_ECX
|
|
#elif defined(TARGET_IA32E)
|
|
# define REG_CX REG_RCX
|
|
#else
|
|
# error "No target defined"
|
|
#endif
|
|
|
|
extern void CopyWithMovsb(void *, void *, size_t);
|
|
|
|
|
|
static void *Map1Page();
|
|
static void *Map2Pages();
|
|
static int SetupHandler();
|
|
static void HandleSegv(int, siginfo_t *, void *);
|
|
|
|
|
|
size_t PageSize;
|
|
|
|
int main()
|
|
{
|
|
void *ptr1;
|
|
void *ptr2;
|
|
|
|
PageSize = getpagesize();
|
|
ptr1 = Map1Page();
|
|
ptr2 = Map2Pages();
|
|
if (!ptr1 || !ptr2)
|
|
return 1;
|
|
|
|
if (!SetupHandler())
|
|
return 1;
|
|
|
|
CopyWithMovsb(ptr2, ptr1, 2*PageSize);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void *Map1Page()
|
|
{
|
|
char *ptr;
|
|
|
|
ptr = mmap(0, 2*PageSize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANONYMOUS), -1, 0);
|
|
if (ptr == MAP_FAILED)
|
|
{
|
|
fprintf(stderr, "mmap failed\n");
|
|
return 0;
|
|
}
|
|
|
|
if (mprotect(ptr + PageSize, PageSize, PROT_NONE) == -1)
|
|
{
|
|
fprintf(stderr, "mprotect failed\n");
|
|
return 0;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
|
|
static void *Map2Pages()
|
|
{
|
|
char *ptr;
|
|
|
|
ptr = mmap(0, 2*PageSize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANONYMOUS), -1, 0);
|
|
if (ptr == MAP_FAILED)
|
|
{
|
|
fprintf(stderr, "mmap failed\n");
|
|
return 0;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
|
|
static int SetupHandler()
|
|
{
|
|
struct sigaction act;
|
|
|
|
act.sa_sigaction = HandleSegv;
|
|
act.sa_flags = SA_SIGINFO;
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
// FreeBSD 6 (and macOS* - from what I read) send sigbus instead of sigsegv on the failure we catch
|
|
// here, however, FreeBSD 8 and Linux send sigsegv. therefore - we catch both...
|
|
|
|
if (sigaction(SIGBUS, &act, 0) == -1)
|
|
{
|
|
fprintf(stderr, "sigaction failed\n");
|
|
return 0;
|
|
}
|
|
|
|
if (sigaction(SIGSEGV, &act, 0) == -1)
|
|
{
|
|
fprintf(stderr, "sigaction failed\n");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void HandleSegv(int sig, siginfo_t *info, void *vctxt)
|
|
{
|
|
ucontext_t *ctxt = vctxt;
|
|
#if defined(TARGET_BSD)
|
|
size_t cx = ctxt->uc_mcontext.mc_rcx;
|
|
#elif defined(TARGET_MAC) && defined(TARGET_IA32E)
|
|
size_t cx = ctxt->uc_mcontext->__ss.__rcx;
|
|
#elif defined(TARGET_MAC) && defined(TARGET_IA32)
|
|
size_t cx = ctxt->uc_mcontext->__ss.__ecx;
|
|
#else
|
|
size_t cx = ctxt->uc_mcontext.gregs[REG_CX];
|
|
#endif
|
|
if (cx != PageSize)
|
|
{
|
|
fprintf(stderr, "%%ecx is %lx, expected %lx\n", (long)cx, (long)PageSize);
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
}
|