/thirdparty/breakpad/third_party/glog/src/symbolize_unittest.cc

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