38 #include <glog/logging.h>
43 #ifdef HAVE_LIB_GFLAGS
44 #include <gflags/gflags.h>
45 using namespace GFLAGS_NAMESPACE;
51 #if defined(HAVE_STACKTRACE)
55 #if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
57 static const char *TrySymbolize(
void *pc) {
58 static char symbol[4096];
59 if (
Symbolize(pc, symbol,
sizeof(symbol))) {
71 #if defined(__GNUC__) && !defined(__OPENCC__)
73 # define TEST_WITH_MODERN_GCC
74 # if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
76 # define always_inline __attribute__((always_inline))
77 # define HAVE_ALWAYS_INLINE
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__)
88 void nonstatic_func();
89 void nonstatic_func() {
94 static void static_func() {
105 EXPECT_STREQ(
"nonstatic_func", TrySymbolize((
void *)(&nonstatic_func)));
109 const char *static_func_symbol =
110 TrySymbolize(
reinterpret_cast<void *
>(&static_func));
112 #if !defined(_MSC_VER) || !defined(NDEBUG)
114 EXPECT_TRUE(strcmp(
"static_func", static_func_symbol) == 0 ||
115 strcmp(
"static_func()", static_func_symbol) == 0);
122 static void func(
int x);
132 #ifdef TEST_WITH_MODERN_GCC
135 #if !defined(_MSC_VER) || !defined(NDEBUG)
158 static void *g_pc_to_symbolize;
159 static char g_symbolize_buffer[4096];
160 static char *g_symbolize_result;
162 static void EmptySignalHandler(
int ) {}
164 static void SymbolizeSignalHandler(
int ) {
165 if (
Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
166 sizeof(g_symbolize_buffer))) {
167 g_symbolize_result = g_symbolize_buffer;
169 g_symbolize_result =
NULL;
173 const int kAlternateStackSize = 8096;
174 const char kAlternateStackFillValue = 0x55;
183 static int GetStackConsumption(
const char* alt_stack) {
185 if (StackGrowsDown(&
x)) {
186 for (
int i = 0;
i < kAlternateStackSize;
i++) {
187 if (alt_stack[
i] != kAlternateStackFillValue) {
188 return (kAlternateStackSize -
i);
192 for (
int i = (kAlternateStackSize - 1);
i >= 0;
i--) {
193 if (alt_stack[
i] != kAlternateStackFillValue) {
201 #ifdef HAVE_SIGALTSTACK
204 static const char *SymbolizeStackConsumption(
void *pc,
int *stack_consumed) {
206 g_pc_to_symbolize = pc;
213 char altstack[kAlternateStackSize];
214 memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
218 memset(&sigstk, 0,
sizeof(stack_t));
220 sigstk.ss_sp = altstack;
221 sigstk.ss_size = kAlternateStackSize;
223 CHECK_ERR(sigaltstack(&sigstk, &old_sigstk));
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;
233 sa.sa_handler = EmptySignalHandler;
234 CHECK_ERR(sigaction(SIGUSR1, &sa, &old_sa1));
237 sa.sa_handler = SymbolizeSignalHandler;
238 CHECK_ERR(sigaction(SIGUSR2, &sa, &old_sa2));
242 CHECK_ERR(kill(getpid(), SIGUSR1));
243 int stack_consumption1 = GetStackConsumption(altstack);
247 CHECK_ERR(kill(getpid(), SIGUSR2));
248 int stack_consumption2 = GetStackConsumption(altstack);
252 if (stack_consumption1 != -1 && stack_consumption2 != -1) {
253 *stack_consumed = stack_consumption2 - stack_consumption1;
255 *stack_consumed = -1;
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;
266 CHECK_ERR(sigaltstack(&old_sigstk,
NULL));
267 CHECK_ERR(sigaction(SIGUSR1, &old_sa1,
NULL));
268 CHECK_ERR(sigaction(SIGUSR2, &old_sa2,
NULL));
270 return g_symbolize_result;
275 const int kStackConsumptionUpperLimit = 4096;
278 const int kStackConsumptionUpperLimit = 2048;
285 symbol = SymbolizeStackConsumption(
reinterpret_cast<void *
>(&nonstatic_func),
289 EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
293 symbol = SymbolizeStackConsumption(
reinterpret_cast<void *
>(&static_func),
297 strcmp(
"static_func()", symbol) == 0);
299 EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
302 #ifdef TEST_WITH_MODERN_GCC
308 symbol = SymbolizeStackConsumption(
reinterpret_cast<void *
>(&
Foo::func),
313 EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
317 #endif // HAVE_SIGALTSTACK
321 inline void* always_inline inline_func() {
323 #ifdef TEST_X86_32_AND_64
324 __asm__ __volatile__(
"call 1f; 1: pop %0" :
"=r"(pc));
332 #ifdef TEST_X86_32_AND_64
333 __asm__ __volatile__(
"call 1f; 1: pop %0" :
"=r"(pc));
339 #if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
340 void *pc = non_inline_func();
341 const char *symbol = TrySymbolize(pc);
343 #if !defined(_MSC_VER) || !defined(NDEBUG)
345 CHECK_STREQ(symbol,
"non_inline_func");
347 cout <<
"Test case TestWithPCInsideNonInlineFunction passed." << endl;
352 #if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
353 void *pc = inline_func();
354 const char *symbol = TrySymbolize(pc);
356 #if !defined(_MSC_VER) || !defined(NDEBUG)
358 CHECK_STREQ(symbol, __FUNCTION__);
360 cout <<
"Test case TestWithPCInsideInlineFunction passed." << endl;
367 #if defined(HAVE_ATTRIBUTE_NOINLINE)
368 void *return_address = __builtin_return_address(0);
369 const char *symbol = TrySymbolize(return_address);
371 #if !defined(_MSC_VER) || !defined(NDEBUG)
373 CHECK_STREQ(symbol,
"main");
375 cout <<
"Test case TestWithReturnAddress passed." << endl;
379 # elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
383 #pragma intrinsic(_ReturnAddress)
387 static void func(
int x);
397 const char* ret = TrySymbolize((
void *)(&
Foo::func));
399 #if defined(HAVE_DBGHELP) && !defined(NDEBUG)
400 EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)", ret);
404 __declspec(noinline)
void TestWithReturnAddress() {
405 void *return_address =
406 #ifdef __GNUC__ // Cygwin and MinGW support
407 __builtin_return_address(0)
412 const char *symbol = TrySymbolize(return_address);
413 #if !defined(_MSC_VER) || !defined(NDEBUG)
415 CHECK_STREQ(symbol,
"main");
417 cout <<
"Test case TestWithReturnAddress passed." << endl;
420 #endif // HAVE_STACKTRACE
422 int main(
int argc,
char **argv) {
426 #if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
427 # if defined(__ELF__)
430 InstallSymbolizeCallback(
NULL);
432 TestWithPCInsideInlineFunction();
433 TestWithPCInsideNonInlineFunction();
434 TestWithReturnAddress();
436 # elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
437 TestWithReturnAddress();
439 # else // GLOG_OS_WINDOWS
440 printf(
"PASS (no symbolize_unittest support)\n");
444 printf(
"PASS (no symbolize support)\n");
446 #endif // HAVE_SYMBOLIZE