blob: f3eebeae9888677e61b027251addb25f964a4420 [file] [log] [blame]
/*
* Copyright (c) 2012 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* This tests execises __builtin_dwarf_cfa()
*
* NOTE: because of fun pointer casting we need to disable -pedantic.
* NOTE: because of aggressive inlining we need to disable -O2.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unwind.h>
#include "native_client/tests/toolchain/utils.h"
int main(int argc, char* argv[]);
const int MAGIC_MARKER = 0x73537353;
const int NUM_ITERS = 5;
int PointerDelta(void* a, void* b) {
return (char*) a - (char*) b;
}
void DumpMemory(const unsigned char* cp, int n) {
for (int i = 0; i < n; ++i) {
if (i % 8 == 0) printf("%p: %08x %08x ", cp, *(int*)cp, *(int*)(cp+4));
printf("%02x ", *cp);
++cp;
if (i % 8 == 7) printf("\n");
}
}
void* GetReturnAddress(void* frame_end) {
#if defined(__native_client__)
#if defined(__arm__)
return ((void**)frame_end)[-1];
#elif defined(__mips__)
return ((void**)frame_end)[-1];
#elif defined(__i386__)
return ((void**)frame_end)[-1];
#elif defined(__x86_64__)
/* NOTE: a call pushes 64 bits but we only care about the first 32 */
return ((void**)frame_end)[-2];
#else
#error "unknown arch"
#endif
#else /* !defined(__native_client__) */
// NOTE: we also want to compile this file with local compilers like so
// g++ tests/toolchain/stack_frame.cc -m32
// g++ tests/toolchain/stack_frame.cc -m64
// arm-none-linux-gnueabihf-g++
// tests/toolchain/stack_frame.cc
// -Wl,-T -Wl,toolchain/linux_x86_linux_arm/arm_trusted/ld_script_arm_trusted
#if defined(__arm__)
return ((void**)frame_end)[-1];
#elif defined(__i386__)
return ((void**)frame_end)[-1];
#elif defined(__x86_64__)
return ((void**)frame_end)[-1];
#else
#error "unknown arch"
#endif
#endif
}
void recurse(int n, unsigned char* old_cfa) {
int i;
int array[16];
unsigned char* cfa = (unsigned char*) __builtin_dwarf_cfa();
int* start = &array[0];
int* end = &array[16];
int frame_size = PointerDelta(old_cfa, cfa);
void* return_address = GetReturnAddress(old_cfa);
for (i = 0; i < 16; ++i) {
array[i] = MAGIC_MARKER;
}
/* NOTE: we dump the frame for this invocation at the beginning of the next */
printf("frame [%p, %p[\n", cfa, old_cfa);
printf("framesize %d\n", frame_size);
printf("return %p\n", return_address);
DumpMemory(cfa, frame_size);
// TODO(sehr): change those to 16
ASSERT(frame_size % 8 == 0, "ERRRO: bad frame size");
ASSERT((int) cfa % 8 == 0, "ERRRO: bad frame pointer");
if (n == NUM_ITERS) {
// main()'s stackframe may be non-standard due to the startup code
} else if (n == NUM_ITERS - 1) {
// first stack frame for recurse() - return address inside main()
ASSERT(FUNPTR2PTR(main) < return_address,
"ERROR: return address is not within main()");
} else {
// recurse() calling itself
ASSERT(FUNPTR2PTR(recurse) < return_address &&
return_address < FUNPTR2PTR(main),
"ERROR: return address is not within recurse()");
}
if (n == 0) {
return;
}
printf("========================\n");
printf("recurse level %d\n", n);
printf("array %p %p\n", start, end);
recurse(n - 1, cfa);
/* NOTE: this print statement also prevents this function
* from tail recursing into itself.
* On gcc this behavior can also be controlled using
* -foptimize-sibling-calls
*/
printf("recurse <- %d\n", n);
}
int main(int argc, char* argv[]) {
printf("&main: %p\n", FUNPTR2PTR(main));
printf("&recurse: %p\n", FUNPTR2PTR(recurse));
ASSERT(FUNPTR2PTR(recurse) < FUNPTR2PTR(main),
"ERROR: this test assumes that main() follows recurse()\n");
unsigned char* cfa = (unsigned char*) __builtin_dwarf_cfa();
recurse(NUM_ITERS, cfa);
return 55;
}