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