blob: 015579fc9c45936325075864d397e34bcbec494f [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "utilities.h"
#include "base/commandlineflags.h"
#include "glog/logging.h"
#include "stacktrace.h"
#ifdef HAVE_EXECINFO_H
# include <execinfo.h>
#endif
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE
// Obtain a backtrace, verify that the expected callers are present in the
// backtrace, and maybe print the backtrace to stdout.
//-----------------------------------------------------------------------//
void CheckStackTraceLeaf();
void CheckStackTrace4(int i);
void CheckStackTrace3(int i);
void CheckStackTrace2(int i);
void CheckStackTrace1(int i);
void CheckStackTrace(int i);
//-----------------------------------------------------------------------//
// The sequence of functions whose return addresses we expect to see in the
// backtrace.
const int BACKTRACE_STEPS = 6;
void * expected_stack[BACKTRACE_STEPS] = {
(void *) &CheckStackTraceLeaf,
(void *) &CheckStackTrace4,
(void *) &CheckStackTrace3,
(void *) &CheckStackTrace2,
(void *) &CheckStackTrace1,
(void *) &CheckStackTrace,
};
// Depending on the architecture/compiler/libraries, (not sure which)
// the current function may or may not appear in the backtrace.
// For gcc-2:
//
// stack[0] is ret addr within CheckStackTrace4
// stack[1] is ret addr within CheckStackTrace3
// stack[2] is ret addr within CheckStackTrace2
// stack[3] is ret addr within CheckStackTrace1
// stack[4] is ret addr within CheckStackTrace
//
// For gcc3-k8:
//
// stack[0] is ret addr within CheckStackTraceLeaf
// stack[1] is ret addr within CheckStackTrace4
// ...
// stack[5] is ret addr within CheckStackTrace
//-----------------------------------------------------------------------//
const int kMaxFnLen = 0x40; // assume relevant functions are only this long
void CheckRetAddrIsInFunction( void * ret_addr, void * function_start_addr)
{
CHECK_GE(ret_addr, function_start_addr);
CHECK_LE(ret_addr, (void *) ((char *) function_start_addr + kMaxFnLen));
}
//-----------------------------------------------------------------------//
void CheckStackTraceLeaf(void) {
const int STACK_LEN = 10;
void *stack[STACK_LEN];
int size;
size = GetStackTrace(stack, STACK_LEN, 0);
printf("Obtained %d stack frames.\n", size);
CHECK_LE(size, STACK_LEN);
if (1) {
#ifdef HAVE_EXECINFO_H
char **strings = backtrace_symbols(stack, size);
printf("Obtained %d stack frames.\n", size);
for (int i = 0; i < size; i++)
printf("%s %p\n", strings[i], stack[i]);
printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
free(strings);
#endif
}
for (int i = 0; i < BACKTRACE_STEPS; i++) {
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
i, expected_stack[i],
reinterpret_cast<char*>(expected_stack[i]) + kMaxFnLen, stack[i]);
CheckRetAddrIsInFunction(stack[i], expected_stack[i]);
printf("OK\n");
}
}
//-----------------------------------------------------------------------//
/* Dummy functions to make the backtrace more interesting. */
void CheckStackTrace4(int i) { for (int j = i; j >= 0; j--) CheckStackTraceLeaf(); }
void CheckStackTrace3(int i) { for (int j = i; j >= 0; j--) CheckStackTrace4(j); }
void CheckStackTrace2(int i) { for (int j = i; j >= 0; j--) CheckStackTrace3(j); }
void CheckStackTrace1(int i) { for (int j = i; j >= 0; j--) CheckStackTrace2(j); }
void CheckStackTrace(int i) { for (int j = i; j >= 0; j--) CheckStackTrace1(j); }
//-----------------------------------------------------------------------//
int main(int argc, char ** argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
CheckStackTrace(0);
printf("PASS\n");
return 0;
}
#else
int main() {
printf("PASS (no stacktrace support)\n");
return 0;
}
#endif // HAVE_STACKTRACE