/thirdparty/breakpad/third_party/glog/src/utilities.cc
C++ | 346 lines | 234 code | 51 blank | 61 comment | 25 complexity | 423caa7488948002bb742d14a8097dce MD5 | raw file
1// Copyright (c) 2008, 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: Shinichiro Hamaji 31 32#include "utilities.h" 33 34#include <stdio.h> 35#include <stdlib.h> 36 37#include <signal.h> 38#ifdef HAVE_SYS_TIME_H 39# include <sys/time.h> 40#endif 41#include <time.h> 42#if defined(HAVE_SYSCALL_H) 43#include <syscall.h> // for syscall() 44#elif defined(HAVE_SYS_SYSCALL_H) 45#include <sys/syscall.h> // for syscall() 46#endif 47#ifdef HAVE_SYSLOG_H 48# include <syslog.h> 49#endif 50 51#include "base/googleinit.h" 52 53using std::string; 54 55_START_GOOGLE_NAMESPACE_ 56 57static const char* g_program_invocation_short_name = NULL; 58static pthread_t g_main_thread_id; 59 60_END_GOOGLE_NAMESPACE_ 61 62// The following APIs are all internal. 63#ifdef HAVE_STACKTRACE 64 65#include "stacktrace.h" 66#include "symbolize.h" 67#include "base/commandlineflags.h" 68 69GLOG_DEFINE_bool(symbolize_stacktrace, true, 70 "Symbolize the stack trace in the tombstone"); 71 72_START_GOOGLE_NAMESPACE_ 73 74typedef void DebugWriter(const char*, void*); 75 76// The %p field width for printf() functions is two characters per byte. 77// For some environments, add two extra bytes for the leading "0x". 78static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*); 79 80static void DebugWriteToStderr(const char* data, void *unused) { 81 // This one is signal-safe. 82 if (write(STDERR_FILENO, data, strlen(data)) < 0) { 83 // Ignore errors. 84 } 85} 86 87void DebugWriteToString(const char* data, void *arg) { 88 reinterpret_cast<string*>(arg)->append(data); 89} 90 91#ifdef HAVE_SYMBOLIZE 92// Print a program counter and its symbol name. 93static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc, 94 const char * const prefix) { 95 char tmp[1024]; 96 const char *symbol = "(unknown)"; 97 // Symbolizes the previous address of pc because pc may be in the 98 // next function. The overrun happens when the function ends with 99 // a call to a function annotated noreturn (e.g. CHECK). 100 if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) { 101 symbol = tmp; 102 } 103 char buf[1024]; 104 snprintf(buf, sizeof(buf), "%s@ %*p %s\n", 105 prefix, kPrintfPointerFieldWidth, pc, symbol); 106 writerfn(buf, arg); 107} 108#endif 109 110static void DumpPC(DebugWriter *writerfn, void *arg, void *pc, 111 const char * const prefix) { 112 char buf[100]; 113 snprintf(buf, sizeof(buf), "%s@ %*p\n", 114 prefix, kPrintfPointerFieldWidth, pc); 115 writerfn(buf, arg); 116} 117 118// Dump current stack trace as directed by writerfn 119static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) { 120 // Print stack trace 121 void* stack[32]; 122 int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1); 123 for (int i = 0; i < depth; i++) { 124#if defined(HAVE_SYMBOLIZE) 125 if (FLAGS_symbolize_stacktrace) { 126 DumpPCAndSymbol(writerfn, arg, stack[i], " "); 127 } else { 128 DumpPC(writerfn, arg, stack[i], " "); 129 } 130#else 131 DumpPC(writerfn, arg, stack[i], " "); 132#endif 133 } 134} 135 136static void DumpStackTraceAndExit() { 137 DumpStackTrace(1, DebugWriteToStderr, NULL); 138 139 // Set the default signal handler for SIGABRT, to avoid invoking our 140 // own signal handler installed by InstallFailedSignalHandler(). 141 struct sigaction sig_action; 142 memset(&sig_action, 0, sizeof(sig_action)); 143 sigemptyset(&sig_action.sa_mask); 144 sig_action.sa_handler = SIG_DFL; 145 sigaction(SIGABRT, &sig_action, NULL); 146 147 abort(); 148} 149 150_END_GOOGLE_NAMESPACE_ 151 152#endif // HAVE_STACKTRACE 153 154_START_GOOGLE_NAMESPACE_ 155 156namespace glog_internal_namespace_ { 157 158const char* ProgramInvocationShortName() { 159 if (g_program_invocation_short_name != NULL) { 160 return g_program_invocation_short_name; 161 } else { 162 // TODO(hamaji): Use /proc/self/cmdline and so? 163 return "UNKNOWN"; 164 } 165} 166 167bool IsGoogleLoggingInitialized() { 168 return g_program_invocation_short_name != NULL; 169} 170 171bool is_default_thread() { 172 if (g_program_invocation_short_name == NULL) { 173 // InitGoogleLogging() not yet called, so unlikely to be in a different 174 // thread 175 return true; 176 } else { 177 return pthread_equal(pthread_self(), g_main_thread_id); 178 } 179} 180 181#ifdef OS_WINDOWS 182struct timeval { 183 long tv_sec, tv_usec; 184}; 185 186// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd 187// See COPYING for copyright information. 188static int gettimeofday(struct timeval *tv, void* tz) { 189#define EPOCHFILETIME (116444736000000000ULL) 190 FILETIME ft; 191 LARGE_INTEGER li; 192 uint64 tt; 193 194 GetSystemTimeAsFileTime(&ft); 195 li.LowPart = ft.dwLowDateTime; 196 li.HighPart = ft.dwHighDateTime; 197 tt = (li.QuadPart - EPOCHFILETIME) / 10; 198 tv->tv_sec = tt / 1000000; 199 tv->tv_usec = tt % 1000000; 200 201 return 0; 202} 203#endif 204 205int64 CycleClock_Now() { 206 // TODO(hamaji): temporary impementation - it might be too slow. 207 struct timeval tv; 208 gettimeofday(&tv, NULL); 209 return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec; 210} 211 212int64 UsecToCycles(int64 usec) { 213 return usec; 214} 215 216WallTime WallTime_Now() { 217 // Now, cycle clock is retuning microseconds since the epoch. 218 return CycleClock_Now() * 0.000001; 219} 220 221static int32 g_main_thread_pid = getpid(); 222int32 GetMainThreadPid() { 223 return g_main_thread_pid; 224} 225 226bool PidHasChanged() { 227 int32 pid = getpid(); 228 if (g_main_thread_pid == pid) { 229 return false; 230 } 231 g_main_thread_pid = pid; 232 return true; 233} 234 235pid_t GetTID() { 236 // On Linux and FreeBSD, we try to use gettid(). 237#if defined OS_LINUX || defined OS_FREEBSD || defined OS_MACOSX 238#ifndef __NR_gettid 239#ifdef OS_MACOSX 240#define __NR_gettid SYS_gettid 241#elif ! defined __i386__ 242#error "Must define __NR_gettid for non-x86 platforms" 243#else 244#define __NR_gettid 224 245#endif 246#endif 247 static bool lacks_gettid = false; 248 if (!lacks_gettid) { 249 pid_t tid = syscall(__NR_gettid); 250 if (tid != -1) { 251 return tid; 252 } 253 // Technically, this variable has to be volatile, but there is a small 254 // performance penalty in accessing volatile variables and there should 255 // not be any serious adverse effect if a thread does not immediately see 256 // the value change to "true". 257 lacks_gettid = true; 258 } 259#endif // OS_LINUX || OS_FREEBSD 260 261 // If gettid() could not be used, we use one of the following. 262#if defined OS_LINUX 263 return getpid(); // Linux: getpid returns thread ID when gettid is absent 264#elif defined OS_WINDOWS || defined OS_CYGWIN 265 return GetCurrentThreadId(); 266#else 267 // If none of the techniques above worked, we use pthread_self(). 268 return (pid_t)(uintptr_t)pthread_self(); 269#endif 270} 271 272const char* const_basename(const char* filepath) { 273 const char* base = strrchr(filepath, '/'); 274#ifdef OS_WINDOWS // Look for either path separator in Windows 275 if (!base) 276 base = strrchr(filepath, '\\'); 277#endif 278 return base ? (base+1) : filepath; 279} 280 281static string g_my_user_name; 282const string& MyUserName() { 283 return g_my_user_name; 284} 285static void MyUserNameInitializer() { 286 // TODO(hamaji): Probably this is not portable. 287#if defined(OS_WINDOWS) 288 const char* user = getenv("USERNAME"); 289#else 290 const char* user = getenv("USER"); 291#endif 292 if (user != NULL) { 293 g_my_user_name = user; 294 } else { 295 g_my_user_name = "invalid-user"; 296 } 297} 298REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer()); 299 300#ifdef HAVE_STACKTRACE 301void DumpStackTraceToString(string* stacktrace) { 302 DumpStackTrace(1, DebugWriteToString, stacktrace); 303} 304#endif 305 306// We use an atomic operation to prevent problems with calling CrashReason 307// from inside the Mutex implementation (potentially through RAW_CHECK). 308static const CrashReason* g_reason = 0; 309 310void SetCrashReason(const CrashReason* r) { 311 sync_val_compare_and_swap(&g_reason, 312 reinterpret_cast<const CrashReason*>(0), 313 r); 314} 315 316void InitGoogleLoggingUtilities(const char* argv0) { 317 CHECK(!IsGoogleLoggingInitialized()) 318 << "You called InitGoogleLogging() twice!"; 319 const char* slash = strrchr(argv0, '/'); 320#ifdef OS_WINDOWS 321 if (!slash) slash = strrchr(argv0, '\\'); 322#endif 323 g_program_invocation_short_name = slash ? slash + 1 : argv0; 324 g_main_thread_id = pthread_self(); 325 326#ifdef HAVE_STACKTRACE 327 InstallFailureFunction(&DumpStackTraceAndExit); 328#endif 329} 330 331void ShutdownGoogleLoggingUtilities() { 332 CHECK(IsGoogleLoggingInitialized()) 333 << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!"; 334#ifdef HAVE_SYSLOG_H 335 closelog(); 336#endif 337} 338 339} // namespace glog_internal_namespace_ 340 341_END_GOOGLE_NAMESPACE_ 342 343// Make an implementation of stacktrace compiled. 344#ifdef STACKTRACE_H 345# include STACKTRACE_H 346#endif