2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
8 * This tests execises __builtin_dwarf_cfa()
10 * NOTE: because of fun pointer casting we need to disable -pedantic.
11 * NOTE: because of aggressive inlining we need to disable -O2.
17 #include "native_client/tests/toolchain/utils.h"
19 int main(int argc, char* argv[]);
20 const int MAGIC_MARKER = 0x73537353;
21 const int NUM_ITERS = 5;
24 int PointerDelta(void* a, void* b) {
25 return (char*) a - (char*) b;
29 void DumpMemory(const unsigned char* cp, int n) {
30 for (int i = 0; i < n; ++i) {
31 if (i % 8 == 0) printf("%p: %08x %08x ", cp, *(int*)cp, *(int*)(cp+4));
34 if (i % 8 == 7) printf("\n");
39 void* GetReturnAddress(void* frame_end) {
40 #if defined(__native_client__)
43 return ((void**)frame_end)[-1];
44 #elif defined(__mips__)
45 return ((void**)frame_end)[-1];
46 #elif defined(__i386__)
47 return ((void**)frame_end)[-1];
48 #elif defined(__x86_64__)
49 /* NOTE: a call pushes 64 bits but we only care about the first 32 */
50 return ((void**)frame_end)[-2];
55 #else /* !defined(__native_client__) */
56 // NOTE: we also want to compile this file with local compilers like so
57 // g++ tests/toolchain/stack_frame.cc -m32
58 // g++ tests/toolchain/stack_frame.cc -m64
59 // arm-none-linux-gnueabihf-g++
60 // tests/toolchain/stack_frame.cc
61 // -Wl,-T -Wl,toolchain/linux_x86_linux_arm/arm_trusted/ld_script_arm_trusted
63 return ((void**)frame_end)[-1];
64 #elif defined(__i386__)
65 return ((void**)frame_end)[-1];
66 #elif defined(__x86_64__)
67 return ((void**)frame_end)[-1];
76 void recurse(int n, unsigned char* old_cfa) {
79 unsigned char* cfa = (unsigned char*) __builtin_dwarf_cfa();
80 int* start = &array[0];
81 int* end = &array[16];
82 int frame_size = PointerDelta(old_cfa, cfa);
83 void* return_address = GetReturnAddress(old_cfa);
84 for (i = 0; i < 16; ++i) {
85 array[i] = MAGIC_MARKER;
88 /* NOTE: we dump the frame for this invocation at the beginning of the next */
89 printf("frame [%p, %p[\n", cfa, old_cfa);
90 printf("framesize %d\n", frame_size);
91 printf("return %p\n", return_address);
92 DumpMemory(cfa, frame_size);
94 // TODO(sehr): change those to 16
95 ASSERT(frame_size % 8 == 0, "ERRRO: bad frame size");
96 ASSERT((int) cfa % 8 == 0, "ERRRO: bad frame pointer");
99 // main()'s stackframe may be non-standard due to the startup code
100 } else if (n == NUM_ITERS - 1) {
101 // first stack frame for recurse() - return address inside main()
102 ASSERT(FUNPTR2PTR(main) < return_address,
103 "ERROR: return address is not within main()");
105 // recurse() calling itself
106 ASSERT(FUNPTR2PTR(recurse) < return_address &&
107 return_address < FUNPTR2PTR(main),
108 "ERROR: return address is not within recurse()");
115 printf("========================\n");
116 printf("recurse level %d\n", n);
117 printf("array %p %p\n", start, end);
120 /* NOTE: this print statement also prevents this function
121 * from tail recursing into itself.
122 * On gcc this behavior can also be controlled using
123 * -foptimize-sibling-calls
125 printf("recurse <- %d\n", n);
129 int main(int argc, char* argv[]) {
130 printf("&main: %p\n", FUNPTR2PTR(main));
131 printf("&recurse: %p\n", FUNPTR2PTR(recurse));
132 ASSERT(FUNPTR2PTR(recurse) < FUNPTR2PTR(main),
133 "ERROR: this test assumes that main() follows recurse()\n");
135 unsigned char* cfa = (unsigned char*) __builtin_dwarf_cfa();
136 recurse(NUM_ITERS, cfa);