1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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
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.
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.
30 // Author: Satoru Takabayashi
32 // Unit tests for functions in symbolize.cc.
34 #include "utilities.h"
39 #include "glog/logging.h"
40 #include "symbolize.h"
41 #include "googletest.h"
44 #ifdef HAVE_LIB_GFLAGS
45 #include <gflags/gflags.h>
46 using namespace GFLAGS_NAMESPACE;
50 using namespace GOOGLE_NAMESPACE;
52 #if defined(HAVE_STACKTRACE) && defined(__ELF__)
56 // This unit tests make sense only with GCC.
57 // Uses lots of GCC specific features.
58 #if defined(__GNUC__) && !defined(__OPENCC__)
60 # define TEST_WITH_MODERN_GCC
61 # if __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
63 # define always_inline __attribute__((always_inline))
64 # define HAVE_ALWAYS_INLINE
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__)
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))) {
83 // Make them C linkage to avoid mangled names.
85 void nonstatic_func() {
90 static void static_func() {
96 TEST(Symbolize, Symbolize) {
97 // We do C-style cast since GCC 2.95.3 doesn't allow
98 // reinterpret_cast<void *>(&func).
100 // Compilers should give us pointers to them.
101 EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
102 EXPECT_STREQ("static_func", TrySymbolize((void *)(&static_func)));
104 EXPECT_TRUE(NULL == TrySymbolize(NULL));
108 static void func(int x);
111 void ATTRIBUTE_NOINLINE Foo::func(int x) {
116 // With a modern GCC, Symbolize() should return demangled symbol
117 // names. Function parameters should be omitted.
118 #ifdef TEST_WITH_MODERN_GCC
119 TEST(Symbolize, SymbolizeWithDemangling) {
121 EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
125 // Tests that verify that Symbolize footprint is within some limit.
127 // To measure the stack footprint of the Symbolize function, we create
128 // a signal handler (for SIGUSR1 say) that calls the Symbolize function
129 // on an alternate stack. This alternate stack is initialized to some
130 // known pattern (0x55, 0x55, 0x55, ...). We then self-send this signal,
131 // and after the signal handler returns, look at the alternate stack
132 // buffer to see what portion has been touched.
134 // This trick gives us the the stack footprint of the signal handler.
135 // But the signal handler, even before the call to Symbolize, consumes
136 // some stack already. We however only want the stack usage of the
137 // Symbolize function. To measure this accurately, we install two signal
138 // handlers: one that does nothing and just returns, and another that
139 // calls Symbolize. The difference between the stack consumption of these
140 // two signals handlers should give us the Symbolize stack foorprint.
142 static void *g_pc_to_symbolize;
143 static char g_symbolize_buffer[4096];
144 static char *g_symbolize_result;
146 static void EmptySignalHandler(int signo) {}
148 static void SymbolizeSignalHandler(int signo) {
149 if (Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
150 sizeof(g_symbolize_buffer))) {
151 g_symbolize_result = g_symbolize_buffer;
153 g_symbolize_result = NULL;
157 const int kAlternateStackSize = 8096;
158 const char kAlternateStackFillValue = 0x55;
160 // These helper functions look at the alternate stack buffer, and figure
161 // out what portion of this buffer has been touched - this is the stack
162 // consumption of the signal handler running on this alternate stack.
163 static ATTRIBUTE_NOINLINE bool StackGrowsDown(int *x) {
167 static int GetStackConsumption(const char* alt_stack) {
169 if (StackGrowsDown(&x)) {
170 for (int i = 0; i < kAlternateStackSize; i++) {
171 if (alt_stack[i] != kAlternateStackFillValue) {
172 return (kAlternateStackSize - i);
176 for (int i = (kAlternateStackSize - 1); i >= 0; i--) {
177 if (alt_stack[i] != kAlternateStackFillValue) {
185 #ifdef HAVE_SIGALTSTACK
187 // Call Symbolize and figure out the stack footprint of this call.
188 static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
190 g_pc_to_symbolize = pc;
192 // The alt-signal-stack cannot be heap allocated because there is a
193 // bug in glibc-2.2 where some signal handler setup code looks at the
194 // current stack pointer to figure out what thread is currently running.
195 // Therefore, the alternate stack must be allocated from the main stack
197 char altstack[kAlternateStackSize];
198 memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
200 // Set up the alt-signal-stack (and save the older one).
202 memset(&sigstk, 0, sizeof(stack_t));
204 sigstk.ss_sp = altstack;
205 sigstk.ss_size = kAlternateStackSize;
207 CHECK_ERR(sigaltstack(&sigstk, &old_sigstk));
209 // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
211 memset(&sa, 0, sizeof(struct sigaction));
212 struct sigaction old_sa1, old_sa2;
213 sigemptyset(&sa.sa_mask);
214 sa.sa_flags = SA_ONSTACK;
216 // SIGUSR1 maps to EmptySignalHandler.
217 sa.sa_handler = EmptySignalHandler;
218 CHECK_ERR(sigaction(SIGUSR1, &sa, &old_sa1));
220 // SIGUSR2 maps to SymbolizeSignalHanlder.
221 sa.sa_handler = SymbolizeSignalHandler;
222 CHECK_ERR(sigaction(SIGUSR2, &sa, &old_sa2));
224 // Send SIGUSR1 signal and measure the stack consumption of the empty
226 CHECK_ERR(kill(getpid(), SIGUSR1));
227 int stack_consumption1 = GetStackConsumption(altstack);
229 // Send SIGUSR2 signal and measure the stack consumption of the symbolize
231 CHECK_ERR(kill(getpid(), SIGUSR2));
232 int stack_consumption2 = GetStackConsumption(altstack);
234 // The difference between the two stack consumption values is the
235 // stack footprint of the Symbolize function.
236 if (stack_consumption1 != -1 && stack_consumption2 != -1) {
237 *stack_consumed = stack_consumption2 - stack_consumption1;
239 *stack_consumed = -1;
242 // Log the stack consumption values.
243 LOG(INFO) << "Stack consumption of empty signal handler: "
244 << stack_consumption1;
245 LOG(INFO) << "Stack consumption of symbolize signal handler: "
246 << stack_consumption2;
247 LOG(INFO) << "Stack consumption of Symbolize: " << *stack_consumed;
249 // Now restore the old alt-signal-stack and signal handlers.
250 CHECK_ERR(sigaltstack(&old_sigstk, NULL));
251 CHECK_ERR(sigaction(SIGUSR1, &old_sa1, NULL));
252 CHECK_ERR(sigaction(SIGUSR2, &old_sa2, NULL));
254 return g_symbolize_result;
257 // Symbolize stack consumption should be within 2kB.
258 const int kStackConsumptionUpperLimit = 2048;
260 TEST(Symbolize, SymbolizeStackConsumption) {
264 symbol = SymbolizeStackConsumption((void *)(&nonstatic_func),
266 EXPECT_STREQ("nonstatic_func", symbol);
267 EXPECT_GT(stack_consumed, 0);
268 EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
270 symbol = SymbolizeStackConsumption((void *)(&static_func),
272 EXPECT_STREQ("static_func", symbol);
273 EXPECT_GT(stack_consumed, 0);
274 EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
277 #ifdef TEST_WITH_MODERN_GCC
278 TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
283 symbol = SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed);
285 EXPECT_STREQ("Foo::func()", symbol);
286 EXPECT_GT(stack_consumed, 0);
287 EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
291 #endif // HAVE_SIGALTSTACK
293 // x86 specific tests. Uses some inline assembler.
295 inline void* always_inline inline_func() {
296 register void *pc = NULL;
297 #ifdef TEST_X86_32_AND_64
298 __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
303 void* ATTRIBUTE_NOINLINE non_inline_func() {
304 register void *pc = NULL;
305 #ifdef TEST_X86_32_AND_64
306 __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
311 void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
312 #if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
313 void *pc = non_inline_func();
314 const char *symbol = TrySymbolize(pc);
315 CHECK(symbol != NULL);
316 CHECK_STREQ(symbol, "non_inline_func");
317 cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
321 void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
322 #if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
323 void *pc = inline_func(); // Must be inlined.
324 const char *symbol = TrySymbolize(pc);
325 CHECK(symbol != NULL);
326 CHECK_STREQ(symbol, __FUNCTION__);
327 cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
332 // Test with a return address.
333 void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
334 #if defined(HAVE_ATTRIBUTE_NOINLINE)
335 void *return_address = __builtin_return_address(0);
336 const char *symbol = TrySymbolize(return_address);
337 CHECK(symbol != NULL);
338 CHECK_STREQ(symbol, "main");
339 cout << "Test case TestWithReturnAddress passed." << endl;
343 int main(int argc, char **argv) {
344 FLAGS_logtostderr = true;
345 InitGoogleLogging(argv[0]);
346 InitGoogleTest(&argc, argv);
347 #ifdef HAVE_SYMBOLIZE
348 // We don't want to get affected by the callback interface, that may be
349 // used to install some callback function at InitGoogle() time.
350 InstallSymbolizeCallback(NULL);
352 TestWithPCInsideInlineFunction();
353 TestWithPCInsideNonInlineFunction();
354 TestWithReturnAddress();
355 return RUN_ALL_TESTS();
363 #ifdef HAVE_SYMBOLIZE
364 printf("PASS (no symbolize_unittest support)\n");
366 printf("PASS (no symbolize support)\n");
370 #endif // HAVE_STACKTRACE