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


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:59