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