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