// Copyright 2008 Google Inc. All Rights Reserved. // Author: hamaji@google.com (Shinichiro Hamaji) #include "utilities.h" #include #include #include #include "base/googleinit.h" #include "stacktrace.h" #include "symbolize.h" using std::string; _START_GOOGLE_NAMESPACE_ static const char* g_program_invocation_short_name = NULL; static pthread_t g_main_thread_id; // The following APIs are all internal. #ifdef HAVE_STACKTRACE #include "stacktrace.h" #include "symbolize.h" #include "base/commandlineflags.h" DEFINE_bool(symbolize_stacktrace, true, "Symbolize the stack trace in the tombstone"); typedef void DebugWriter(const char*, void*); // The %p field width for printf() functions is two characters per byte. // For some environments, add two extra bytes for the leading "0x". static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*); static void DebugWriteToStderr(const char* data, void *unused) { // This one is signal-safe. write(STDERR_FILENO, data, strlen(data)); } // Print a program counter and its symbol name. static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc, const char * const prefix) { char tmp[1024]; const char *symbol = "(unknown)"; // Symbolizes the previous address of pc because pc may be in the // next function. The overrun happens when the function ends with // a call to a function annotated noreturn (e.g. CHECK). if (Symbolize(reinterpret_cast(pc) - 1, tmp, sizeof(tmp))) { symbol = tmp; } char buf[1024]; snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix, kPrintfPointerFieldWidth, pc, symbol); writerfn(buf, arg); } // Print a program counter and the corresponding stack frame size. static void DumpPCAndFrameSize(DebugWriter *writerfn, void *arg, void *pc, int framesize, const char * const prefix) { char buf[100]; if (framesize <= 0) { snprintf(buf, sizeof(buf), "%s@ %*p (unknown)\n", prefix, kPrintfPointerFieldWidth, pc); } else { snprintf(buf, sizeof(buf), "%s@ %*p %9d\n", prefix, kPrintfPointerFieldWidth, pc, framesize); } writerfn(buf, arg); } static void DumpPC(DebugWriter *writerfn, void *arg, void *pc, const char * const prefix) { char buf[100]; snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth, pc); writerfn(buf, arg); } // Dump current stack trace as directed by writerfn static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) { // Print stack trace void* stack[32]; int depth = GetStackTrace(stack, sizeof(stack)/sizeof(*stack), skip_count+1); for (int i = 0; i < depth; i++) { #if defined(HAVE_SYMBOLIZE) if (FLAGS_symbolize_stacktrace) { DumpPCAndSymbol(writerfn, arg, stack[i], " "); } else { DumpPC(writerfn, arg, stack[i], " "); } #else DumpPC(writerfn, arg, stack[i], " "); #endif } } static void DumpStackTraceAndExit() { DumpStackTrace(1, DebugWriteToStderr, NULL); // Set the default signal handler for SIGABRT, to avoid invoking our // own signal handler installed by InstallFailedSignalHandler(). struct sigaction sig_action = {}; // Zero-clear. sigemptyset(&sig_action.sa_mask); sig_action.sa_handler = SIG_DFL; sigaction(SIGABRT, &sig_action, NULL); abort(); } #endif // HAVE_STACKTRACE namespace glog_internal_namespace_ { const char* ProgramInvocationShortName() { if (g_program_invocation_short_name != NULL) { return g_program_invocation_short_name; } else { // TODO(hamaji): Use /proc/self/cmdline and so? return "UNKNOWN"; } } bool IsGoogleLoggingInitialized() { return g_program_invocation_short_name != NULL; } bool is_default_thread() { if (g_program_invocation_short_name == NULL) { // InitGoogleLogging() not yet called, so unlikely to be in a different // thread return true; } else { return pthread_equal(pthread_self(), g_main_thread_id); } } int64 CycleClock_Now() { // TODO(hamaji): temporary impementation - it might be too slow. struct timeval tv; gettimeofday(&tv, NULL); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; } int64 UsecToCycles(int64 usec) { return usec; } static int32 g_main_thread_pid = getpid(); int32 GetMainThreadPid() { return g_main_thread_pid; } static string g_my_user_name; const string& MyUserName() { return g_my_user_name; } static void MyUserNameInitializer() { // TODO(hamaji): Probably this is not portable. const char* user = getenv("USER"); if (user != NULL) { g_my_user_name = user; } else { g_my_user_name = "invalid-user"; } } REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer()); } // namespace glog_internal_namespace_ void InitGoogleLogging(const char* argv0) { const char* slash = strrchr(argv0, '/'); #ifdef OS_WINDOWS if (!slash) slash = strrchr(argv0, '\\'); #endif g_program_invocation_short_name = slash ? slash + 1 : argv0; g_main_thread_id = pthread_self(); #ifdef HAVE_STACKTRACE InstallFailureFunction(&DumpStackTraceAndExit); #endif } _END_GOOGLE_NAMESPACE_ // Make an implementation of stacktrace compiled. #ifdef STACKTRACE_H # include STACKTRACE_H #endif