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