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