Add __attribute__((noinline)) for StackGrowsDown. This is necessary for recent GCC...
[platform/upstream/glog.git] / src / symbolize_unittest.cc
1 // Copyright 2006 Google Inc. All Rights Reserved.
2 // Author: Satoru Takabayashi
3 //
4 // Unit tests for functions in symbolize.cc.
5
6 #include <signal.h>
7 #include <iostream>
8
9 #include "glog/logging.h"
10 #include "symbolize.h"
11 #include "googletest.h"
12 #include "config.h"
13 #include "utilities.h"
14
15 using namespace std;
16 using namespace GOOGLE_NAMESPACE;
17
18 #if defined(HAVE_STACKTRACE) && defined(__ELF__)
19
20 #define always_inline
21
22 // This unit tests make sense only with GCC.
23 // Uses lots of GCC specific features.
24 #if defined(__GNUC__) && !defined(__OPENCC__)
25 #  if __GNUC__ >= 4
26 #    define TEST_WITH_MODERN_GCC
27 #    if __i386__  // always_inline isn't supported for x86_64 with GCC 4.1.0.
28 #      undef always_inline
29 #      define always_inline __attribute__((always_inline))
30 #      define HAVE_ALWAYS_INLINE
31 #    endif  // __i386__
32 #  else
33 #  endif  // __GNUC__ >= 4
34 #  if defined(__i386__) || defined(__x86_64__)
35 #    define TEST_X86_32_AND_64 1
36 #  endif  // defined(__i386__) || defined(__x86_64__)
37 #endif
38
39 // A wrapper function for Symbolize() to make the unit test simple.
40 static const char *TrySymbolize(void *pc) {
41   static char symbol[4096];
42   if (Symbolize(pc, symbol, sizeof(symbol))) {
43     return symbol;
44   } else {
45     return NULL;
46   }
47 }
48
49 // Make them C linkage to avoid mangled names.
50 extern "C" {
51 void nonstatic_func() {
52   volatile int a = 0;
53   ++a;
54 }
55
56 static void static_func() {
57   volatile int a = 0;
58   ++a;
59 }
60 }
61
62 TEST(Symbolize, Symbolize) {
63   // We do C-style cast since GCC 2.95.3 doesn't allow
64   // reinterpret_cast<void *>(&func).
65
66   // Compilers should give us pointers to them.
67   EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
68   EXPECT_STREQ("static_func", TrySymbolize((void *)(&static_func)));
69
70   EXPECT_TRUE(NULL == TrySymbolize(NULL));
71 }
72
73 struct Foo {
74   static void func(int x);
75 };
76
77 void ATTRIBUTE_NOINLINE Foo::func(int x) {
78   volatile int a = x;
79   ++a;
80 }
81
82 // With a modern GCC, Symbolize() should return demangled symbol
83 // names.  Function parameters should be omitted.
84 #ifdef TEST_WITH_MODERN_GCC
85 TEST(Symbolize, SymbolizeWithDemangling) {
86   Foo::func(100);
87   EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
88 }
89 #endif
90
91 // Tests that verify that Symbolize footprint is within some limit.
92
93 // To measure the stack footprint of the Symbolize function, we create
94 // a signal handler (for SIGUSR1 say) that calls the Symbolize function
95 // on an alternate stack. This alternate stack is initialized to some
96 // known pattern (0x55, 0x55, 0x55, ...). We then self-send this signal,
97 // and after the signal handler returns, look at the alternate stack
98 // buffer to see what portion has been touched.
99 //
100 // This trick gives us the the stack footprint of the signal handler.
101 // But the signal handler, even before the call to Symbolize, consumes
102 // some stack already. We however only want the stack usage of the
103 // Symbolize function. To measure this accurately, we install two signal
104 // handlers: one that does nothing and just returns, and another that
105 // calls Symbolize. The difference between the stack consumption of these
106 // two signals handlers should give us the Symbolize stack foorprint.
107
108 static void *g_pc_to_symbolize;
109 static char g_symbolize_buffer[4096];
110 static char *g_symbolize_result;
111
112 static void EmptySignalHandler(int signo) {}
113
114 static void SymbolizeSignalHandler(int signo) {
115   if (Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
116                 sizeof(g_symbolize_buffer))) {
117     g_symbolize_result = g_symbolize_buffer;
118   } else {
119     g_symbolize_result = NULL;
120   }
121 }
122
123 const int kAlternateStackSize = 8096;
124 const char kAlternateStackFillValue = 0x55;
125
126 // These helper functions look at the alternate stack buffer, and figure
127 // out what portion of this buffer has been touched - this is the stack
128 // consumption of the signal handler running on this alternate stack.
129 static ATTRIBUTE_NOINLINE bool StackGrowsDown(int *x) {
130   int y;
131   return &y < x;
132 }
133 static int GetStackConsumption(const char* alt_stack) {
134   int x;
135   if (StackGrowsDown(&x)) {
136     for (int i = 0; i < kAlternateStackSize; i++) {
137       if (alt_stack[i] != kAlternateStackFillValue) {
138         return (kAlternateStackSize - i);
139       }
140     }
141   } else {
142     for (int i = (kAlternateStackSize - 1); i >= 0; i--) {
143       if (alt_stack[i] != kAlternateStackFillValue) {
144         return i;
145       }
146     }
147   }
148   return -1;
149 }
150
151 #ifdef HAVE_SIGALTSTACK
152
153 // Call Symbolize and figure out the stack footprint of this call.
154 static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
155
156   g_pc_to_symbolize = pc;
157
158   // The alt-signal-stack cannot be heap allocated because there is a
159   // bug in glibc-2.2 where some signal handler setup code looks at the
160   // current stack pointer to figure out what thread is currently running.
161   // Therefore, the alternate stack must be allocated from the main stack
162   // itself.
163   char altstack[kAlternateStackSize];
164   memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
165
166   // Set up the alt-signal-stack (and save the older one).
167   stack_t sigstk = {};  // Zero-clear.
168   stack_t old_sigstk;
169   sigstk.ss_sp = altstack;
170   sigstk.ss_size = kAlternateStackSize;
171   sigstk.ss_flags = 0;
172   CHECK_ERR(sigaltstack(&sigstk, &old_sigstk));
173
174   // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
175   struct sigaction sa = {};  // Zero-clear;
176   struct sigaction old_sa1, old_sa2;
177   sigemptyset(&sa.sa_mask);
178   sa.sa_flags = SA_ONSTACK;
179
180   // SIGUSR1 maps to EmptySignalHandler.
181   sa.sa_handler = EmptySignalHandler;
182   CHECK_ERR(sigaction(SIGUSR1, &sa, &old_sa1));
183
184   // SIGUSR2 maps to SymbolizeSignalHanlder.
185   sa.sa_handler = SymbolizeSignalHandler;
186   CHECK_ERR(sigaction(SIGUSR2, &sa, &old_sa2));
187
188   // Send SIGUSR1 signal and measure the stack consumption of the empty
189   // signal handler.
190   CHECK_ERR(kill(getpid(), SIGUSR1));
191   int stack_consumption1 = GetStackConsumption(altstack);
192
193   // Send SIGUSR2 signal and measure the stack consumption of the symbolize
194   // signal handler.
195   CHECK_ERR(kill(getpid(), SIGUSR2));
196   int stack_consumption2 = GetStackConsumption(altstack);
197
198   // The difference between the two stack consumption values is the
199   // stack footprint of the Symbolize function.
200   if (stack_consumption1 != -1 && stack_consumption2 != -1) {
201     *stack_consumed = stack_consumption2 - stack_consumption1;
202   } else {
203     *stack_consumed = -1;
204   }
205
206   // Log the stack consumption values.
207   LOG(INFO) << "Stack consumption of empty signal handler: "
208             << stack_consumption1;
209   LOG(INFO) << "Stack consumption of symbolize signal handler: "
210             << stack_consumption2;
211   LOG(INFO) << "Stack consumption of Symbolize: " << *stack_consumed;
212
213   // Now restore the old alt-signal-stack and signal handlers.
214   CHECK_ERR(sigaltstack(&old_sigstk, NULL));
215   CHECK_ERR(sigaction(SIGUSR1, &old_sa1, NULL));
216   CHECK_ERR(sigaction(SIGUSR2, &old_sa2, NULL));
217
218   return g_symbolize_result;
219 }
220
221 // Symbolize stack consumption should be within 2kB.
222 const int kStackConsumptionUpperLimit = 2048;
223
224 TEST(Symbolize, SymbolizeStackConsumption) {
225   int stack_consumed;
226   const char* symbol;
227
228   symbol = SymbolizeStackConsumption((void *)(&nonstatic_func),
229                                      &stack_consumed);
230   EXPECT_STREQ("nonstatic_func", symbol);
231   EXPECT_GT(stack_consumed, 0);
232   EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
233
234   symbol = SymbolizeStackConsumption((void *)(&static_func),
235                                      &stack_consumed);
236   EXPECT_STREQ("static_func", symbol);
237   EXPECT_GT(stack_consumed, 0);
238   EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
239 }
240
241 #ifdef TEST_WITH_MODERN_GCC
242 TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
243   Foo::func(100);
244   int stack_consumed;
245   const char* symbol;
246
247   symbol = SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed);
248
249   EXPECT_STREQ("Foo::func()", symbol);
250   EXPECT_GT(stack_consumed, 0);
251   EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
252 }
253 #endif
254
255 #endif  // HAVE_SIGALTSTACK
256
257 // x86 specific tests.  Uses some inline assembler.
258 extern "C" {
259 inline void* always_inline inline_func() {
260   register void *pc = NULL;
261 #ifdef TEST_X86_32_AND_64
262   __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
263 #endif
264   return pc;
265 }
266
267 void* ATTRIBUTE_NOINLINE non_inline_func() {
268   register void *pc = NULL;
269 #ifdef TEST_X86_32_AND_64
270   __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
271 #endif
272   return pc;
273 }
274
275 void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
276 #if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
277   void *pc = non_inline_func();
278   const char *symbol = TrySymbolize(pc);
279   CHECK(symbol != NULL);
280   CHECK_STREQ(symbol, "non_inline_func");
281   cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
282 #endif
283 }
284
285 void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
286 #if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
287   void *pc = inline_func();  // Must be inlined.
288   const char *symbol = TrySymbolize(pc);
289   CHECK(symbol != NULL);
290   CHECK_STREQ(symbol, __FUNCTION__);
291   cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
292 #endif
293 }
294 }
295
296 // Test with a return address.
297 void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
298 #if defined(HAVE_ATTRIBUTE_NOINLINE)
299   void *return_address = __builtin_return_address(0);
300   const char *symbol = TrySymbolize(return_address);
301   CHECK(symbol != NULL);
302   CHECK_STREQ(symbol, "main");
303   cout << "Test case TestWithReturnAddress passed." << endl;
304 #endif
305 }
306
307 int main(int argc, char **argv) {
308   FLAGS_logtostderr = true;
309   InitGoogleLogging(argv[0]);
310   // We don't want to get affected by the callback interface, that may be
311   // used to install some callback function at InitGoogle() time.
312   InstallSymbolizeCallback(NULL);
313
314   // Symbolize() now only supports ELF binaries.
315   // The test makes sense only if __ELF__ is defined.
316 #ifndef __ELF__
317   return 0;
318 #else
319   TestWithPCInsideInlineFunction();
320   TestWithPCInsideNonInlineFunction();
321   TestWithReturnAddress();
322   return RUN_ALL_TESTS();
323 #endif
324 }
325
326 #else
327 int main() {
328   printf("PASS (no symbolize support)\n");
329   return 0;
330 }
331 #endif  // HAVE_STACKTRACE