1 /*
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.
5 */
6
7 /*
8 * This tests execises __builtin_dwarf_cfa()
9 *
10 * NOTE: because of fun pointer casting we need to disable -pedantic.
11 * NOTE: because of aggressive inlining we need to disable -O2.
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unwind.h>
17 #include "native_client/tests/toolchain/utils.h"
18
19 int main(int argc, char* argv[]);
20 const int MAGIC_MARKER = 0x73537353;
21 const int NUM_ITERS = 5;
22
23
PointerDelta(void * a,void * b)24 int PointerDelta(void* a, void* b) {
25 return (char*) a - (char*) b;
26 }
27
28
DumpMemory(const unsigned char * cp,int n)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));
32 printf("%02x ", *cp);
33 ++cp;
34 if (i % 8 == 7) printf("\n");
35 }
36 }
37
38
GetReturnAddress(void * frame_end)39 void* GetReturnAddress(void* frame_end) {
40 #if defined(__native_client__)
41
42 #if defined(__arm__)
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];
51 #else
52 #error "unknown arch"
53 #endif
54
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
62 #if defined(__arm__)
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];
68 #else
69 #error "unknown arch"
70 #endif
71
72 #endif
73 }
74
75
recurse(int n,unsigned char * old_cfa)76 void recurse(int n, unsigned char* old_cfa) {
77 int i;
78 int array[16];
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;
86 }
87
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);
93
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");
97
98 if (n == NUM_ITERS) {
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()");
104 } else {
105 // recurse() calling itself
106 ASSERT(FUNPTR2PTR(recurse) < return_address &&
107 return_address < FUNPTR2PTR(main),
108 "ERROR: return address is not within recurse()");
109 }
110
111 if (n == 0) {
112 return;
113 }
114
115 printf("========================\n");
116 printf("recurse level %d\n", n);
117 printf("array %p %p\n", start, end);
118
119 recurse(n - 1, cfa);
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
124 */
125 printf("recurse <- %d\n", n);
126 }
127
128
main(int argc,char * argv[])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");
134
135 unsigned char* cfa = (unsigned char*) __builtin_dwarf_cfa();
136 recurse(NUM_ITERS, cfa);
137 return 55;
138 }
139