// Copyright (c) 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: Shinichiro Hamaji #include "utilities.h" #include #include #include #ifdef HAVE_SYS_TIME_H # include #endif #include #if defined(HAVE_SYSCALL_H) #include // for syscall() #elif defined(HAVE_SYS_SYSCALL_H) #include // for syscall() #endif #ifdef HAVE_SYSLOG_H # include #endif #include "base/googleinit.h" using std::string; _START_GOOGLE_NAMESPACE_ static const char* g_program_invocation_short_name = NULL; static pthread_t g_main_thread_id; _END_GOOGLE_NAMESPACE_ // The following APIs are all internal. #ifdef HAVE_STACKTRACE #include "stacktrace.h" #include "symbolize.h" #include "base/commandlineflags.h" GLOG_DEFINE_bool(symbolize_stacktrace, true, "Symbolize the stack trace in the tombstone"); _START_GOOGLE_NAMESPACE_ 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 *) { // This one is signal-safe. if (write(STDERR_FILENO, data, strlen(data)) < 0) { // Ignore errors. } } void DebugWriteToString(const char* data, void *arg) { reinterpret_cast(arg)->append(data); } #ifdef HAVE_SYMBOLIZE // 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); } #endif 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, ARRAYSIZE(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); // TOOD(hamaji): Use signal instead of sigaction? #ifdef HAVE_SIGACTION if (IsFailureSignalHandlerInstalled()) { // Set the default signal handler for SIGABRT, to avoid invoking our // own signal handler installed by InstallFailureSignalHandler(). struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); sig_action.sa_handler = SIG_DFL; sigaction(SIGABRT, &sig_action, NULL); } #endif // HAVE_SIGACTION abort(); } _END_GOOGLE_NAMESPACE_ #endif // HAVE_STACKTRACE _START_GOOGLE_NAMESPACE_ 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); } } #ifdef OS_WINDOWS struct timeval { long tv_sec, tv_usec; }; // Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd // See COPYING for copyright information. static int gettimeofday(struct timeval *tv, void* tz) { #define EPOCHFILETIME (116444736000000000ULL) FILETIME ft; LARGE_INTEGER li; uint64 tt; GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; tt = (li.QuadPart - EPOCHFILETIME) / 10; tv->tv_sec = tt / 1000000; tv->tv_usec = tt % 1000000; return 0; } #endif 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; } WallTime WallTime_Now() { // Now, cycle clock is retuning microseconds since the epoch. return CycleClock_Now() * 0.000001; } static int32 g_main_thread_pid = getpid(); int32 GetMainThreadPid() { return g_main_thread_pid; } bool PidHasChanged() { int32 pid = getpid(); if (g_main_thread_pid == pid) { return false; } g_main_thread_pid = pid; return true; } pid_t GetTID() { // On Linux and MacOSX, we try to use gettid(). #if defined OS_LINUX || defined OS_MACOSX #ifndef __NR_gettid #ifdef OS_MACOSX #define __NR_gettid SYS_gettid #elif ! defined __i386__ #error "Must define __NR_gettid for non-x86 platforms" #else #define __NR_gettid 224 #endif #endif static bool lacks_gettid = false; if (!lacks_gettid) { pid_t tid = syscall(__NR_gettid); if (tid != -1) { return tid; } // Technically, this variable has to be volatile, but there is a small // performance penalty in accessing volatile variables and there should // not be any serious adverse effect if a thread does not immediately see // the value change to "true". lacks_gettid = true; } #endif // OS_LINUX || OS_MACOSX // If gettid() could not be used, we use one of the following. #if defined OS_LINUX return getpid(); // Linux: getpid returns thread ID when gettid is absent #elif defined OS_WINDOWS || defined OS_CYGWIN return GetCurrentThreadId(); #else // If none of the techniques above worked, we use pthread_self(). return (pid_t)(uintptr_t)pthread_self(); #endif } const char* const_basename(const char* filepath) { const char* base = strrchr(filepath, '/'); #ifdef OS_WINDOWS // Look for either path separator in Windows if (!base) base = strrchr(filepath, '\\'); #endif return base ? (base+1) : filepath; } static string g_my_user_name; const string& MyUserName() { return g_my_user_name; } static void MyUserNameInitializer() { // TODO(hamaji): Probably this is not portable. #if defined(OS_WINDOWS) const char* user = getenv("USERNAME"); #else const char* user = getenv("USER"); #endif if (user != NULL) { g_my_user_name = user; } else { g_my_user_name = "invalid-user"; } } REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer()); #ifdef HAVE_STACKTRACE void DumpStackTraceToString(string* stacktrace) { DumpStackTrace(1, DebugWriteToString, stacktrace); } #endif // We use an atomic operation to prevent problems with calling CrashReason // from inside the Mutex implementation (potentially through RAW_CHECK). static const CrashReason* g_reason = 0; void SetCrashReason(const CrashReason* r) { sync_val_compare_and_swap(&g_reason, reinterpret_cast(0), r); } void InitGoogleLoggingUtilities(const char* argv0) { CHECK(!IsGoogleLoggingInitialized()) << "You called InitGoogleLogging() twice!"; 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 } void ShutdownGoogleLoggingUtilities() { CHECK(IsGoogleLoggingInitialized()) << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!"; g_program_invocation_short_name = NULL; #ifdef HAVE_SYSLOG_H closelog(); #endif } } // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_ // Make an implementation of stacktrace compiled. #ifdef STACKTRACE_H # include STACKTRACE_H #endif