blob: 3076835426cda44e6613c0bcfeae305c560b173f [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2012 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.
*/
/* test wrapping functionality using a library w/ exported routines
* so they're easy for the client to locate
*/
/***************************************************************************/
#ifndef ASM_CODE_ONLY /* C code */
#include "tools.h"
#include <setjmp.h>
jmp_buf mark;
int EXPORT makes_tailcall(int x); /* in asm */
int EXPORT
runlots(int *x)
{
if (*x == 1024)
print("in runlots 1024\n");
(*x)++;
return *x;
}
int EXPORT
preonly(int *x)
{
print("in preonly\n");
*x = 6;
return -1;
}
int EXPORT
postonly(int *x)
{
print("in postonly\n");
*x = 6;
return -1;
}
int EXPORT
replaceme(int *x)
{
print("in replaceme\n");
*x = 5;
return -1;
}
int EXPORT
replaceme2(int *x)
{
print("in replaceme2\n");
*x = 5;
return -1;
}
static int
replace_callsite_callee(int *x)
{
*x = 5;
return -1;
}
int EXPORT
replace_callsite(int *x)
{
int y = replace_callsite_callee(x);
/* just putting in stuff to prevent tailcall */
if (y == *x)
*x = y + 1;
return y;
}
int EXPORT
skipme(int *x)
{
print("in skipme\n");
*x = 4;
return -1;
}
int EXPORT
level2(int x)
{
print("in level2 %d\n", x);
return x;
}
int EXPORT
level1(int x, int y)
{
print("in level1 %d %d\n", x, y);
makes_tailcall(x+y);
return x;
}
int EXPORT
level0(int x)
{
print("in level0 %d\n", x);
print("level1 returned %d\n", level1(x, x*2));
return x;
}
void *level2_ptr;
/***************************************************************************
* test longjmp
*/
void EXPORT
long3(void)
{
print("long3 A\n");
#ifdef WINDOWS
/* test SEH */
__try {
*(int *)4 = 42;
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
longjmp(mark, 1);
}
#else
longjmp(mark, 1);
#endif
print(" long3 B\n");
}
void EXPORT
long2(void)
{
print("long2 A\n");
long3();
print(" long2 B\n");
}
void EXPORT
long1(void)
{
print("long1 A\n");
long2();
print(" long1 B\n");
}
void EXPORT
long0(void)
{
print("long0 A\n");
long1();
print(" long0 B\n");
}
void EXPORT
longstart(void)
{
long0();
}
void EXPORT
longdone(void)
{
print("longdone\n");
}
void
run_tests(void)
{
int x = 3;
int res;
level2_ptr = (void *) level2;
print("thread.appdll process init\n");
print("level0 returned %d\n", level0(37));
res = skipme(&x);
print("skipme returned %d and x=%d\n", res, x);
res = replaceme(&x);
print("replaceme returned %d and x=%d\n", res, x);
res = replaceme2(&x);
print("replaceme2 returned %d and x=%d\n", res, x);
res = replace_callsite(&x);
print("replace_callsite returned %d and x=%d\n", res, x);
preonly(&x);
postonly(&x);
skipme(&x);
postonly(&x);
/* test delayed flushing that doesn't flush until 1024 executions */
x = 0;
for (res = 0; res < 2048; res++)
runlots(&x);
/* test longjmp recovery on pre not post so we call from non-wrapped routine */
if (setjmp(mark) == 0)
longstart();
longdone();
}
#ifdef WINDOWS
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD reason_for_call, LPVOID Reserved)
{
switch (reason_for_call) {
case DLL_PROCESS_ATTACH:
run_tests();
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
#else
int __attribute__((constructor))
so_init(void)
{
run_tests();
return 0;
}
#endif
#else /* asm code *************************************************************/
#include "asm_defines.asm"
START_FILE
# if defined(UNIX) && defined(X64)
/* to work on x64 w/o ld reloc problems we use a stored address
* so we're not testing tailcall on x64 linux.
* (if we use indirect jump, drwrap misses the post-makes_tailcall:
* it doesn't handle indirect-jump tailcalls)
*/
DECL_EXTERN(level2_ptr)
# else
DECL_EXTERN(level2)
# endif
#define FUNCNAME makes_tailcall
DECLARE_EXPORTED_FUNC(FUNCNAME)
GLOBAL_LABEL(FUNCNAME:)
# if defined(UNIX) && defined(X64)
push REG_XBP /* Needed only to maintain 16-byte alignment. */
call PTRSZ SYMREF(level2_ptr)
pop REG_XBP
ret
# else
jmp level2
# endif
ret /* won't get here */
END_FUNC(FUNCNAME)
END_FILE
#endif /* ASM_CODE_ONLY */