* Copyright (c) 2015-2019 Google, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef ASM_CODE_ONLY
# include "tools.h"
# include "mangle_asynch-shared.h"
# include <setjmp.h>
# include <signal.h>
# include <pthread.h>
volatile bool test_ready = false;
volatile bool test_done = false;
volatile int loop_inc = 1;
void
test_asm();
static SIGJMP_BUF mark;
static void
handle_signal(int signal, siginfo_t *siginfo, ucontext_t *ucxt)
{
# ifdef X86_64
if (signal == SIGILL) {
sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt);
if (sc->LOOP_COUNT_REG_SIG != LOOP_COUNT)
print("ERROR: incorrect result!\n");
SIGLONGJMP(mark, 1);
} else if (signal != SIGUSR2) {
print("Unexpected signal!\n");
}
# endif
}
static void *
thread_routine(void *arg)
{
# ifdef X86_64
pthread_t main_thread = *(pthread_t *)arg;
while (!test_ready) {
}
struct timespec sleeptime;
sleeptime.tv_sec = 0;
sleeptime.tv_nsec = 1000 * 1111;
while (!test_done) {
pthread_kill(main_thread, SIGUSR2);
nanosleep(&sleeptime, NULL);
}
# endif
return NULL;
}
int
main(int argc, const char *argv[])
{
# define NUM_THREADS 8
pthread_t thread[NUM_THREADS];
void *retval;
pthread_t main_thread = pthread_self();
for (int i = 0; i < NUM_THREADS; ++i) {
if (pthread_create(&thread[i], NULL, thread_routine, &main_thread) != 0) {
perror("Failed to create thread");
exit(1);
}
}
intercept_signal(SIGILL, (handler_3_t)&handle_signal, false);
intercept_signal(SIGUSR2, (handler_3_t)&handle_signal, false);
* signals.
*/
if (SIGSETJMP(mark) == 0) {
test_asm();
}
for (int i = 0; i < NUM_THREADS; ++i) {
if (pthread_join(thread[i], &retval) != 0)
perror("Failed to join thread");
}
print("Test finished\n");
return 0;
}
#else
# include "asm_defines.asm"
# include "mangle_asynch-shared.h"
START_FILE
#ifdef X64
# define FRAME_PADDING 0
#else
# define FRAME_PADDING 0
#endif
DECL_EXTERN(test_ready)
DECL_EXTERN(test_done)
DECL_EXTERN(loop_inc)
#define FUNCNAME test_asm
DECLARE_FUNC_SEH(FUNCNAME)
GLOBAL_LABEL(FUNCNAME:)
#ifdef X86
#ifdef X64
PUSH_CALLEE_SAVED_REGS()
sub REG_XSP, FRAME_PADDING
END_PROLOG
jmp test
test:
mov BYTE SYMREF(test_ready), HEX(1)
mov LOOP_TEST_REG_ASM, LOOP_COUNT
mov LOOP_COUNT_REG_ASM, 0
loop:
add LOOP_COUNT_REG_ASM, PTRSZ SYMREF(loop_inc)
sub LOOP_TEST_REG_ASM, 1
cmp LOOP_TEST_REG_ASM, 0
jnz loop
jmp epilog
epilog:
mov BYTE SYMREF(test_done), HEX(1)
* add within the loop from re-execution due to translating back.
*/
ud2
add REG_XSP, FRAME_PADDING
POP_CALLEE_SAVED_REGS()
#endif
ret
#elif defined(ARM)
bx lr
#elif defined(AARCH64)
ret
#endif
END_FUNC(FUNCNAME)
#undef FUNCNAME
END_FILE
#endif