utilities.cc 10.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// 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
31

's avatar
committed
32 33
#include "utilities.h"

34 35 36
#include <stdio.h>
#include <stdlib.h>

37
#include <signal.h>
38 39 40
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
's avatar
committed
41
#include <time.h>
's avatar
committed
42 43 44 45 46
#if defined(HAVE_SYSCALL_H)
#include <syscall.h>                 // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h>                 // for syscall()
#endif
47 48 49
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
#endif
50 51 52 53 54 55
#ifdef HAVE_UNISTD_H
# include <unistd.h>  // For geteuid.
#endif
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
's avatar
committed
56 57 58 59 60 61 62 63 64 65

#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;

's avatar
committed
66 67
_END_GOOGLE_NAMESPACE_

's avatar
committed
68 69 70 71 72 73 74
// The following APIs are all internal.
#ifdef HAVE_STACKTRACE

#include "stacktrace.h"
#include "symbolize.h"
#include "base/commandlineflags.h"

75 76
GLOG_DEFINE_bool(symbolize_stacktrace, true,
                 "Symbolize the stack trace in the tombstone");
's avatar
committed
77

's avatar
committed
78 79
_START_GOOGLE_NAMESPACE_

's avatar
committed
80 81 82 83 84 85
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*);

86
static void DebugWriteToStderr(const char* data, void *) {
's avatar
committed
87
  // This one is signal-safe.
88 89 90
  if (write(STDERR_FILENO, data, strlen(data)) < 0) {
    // Ignore errors.
  }
's avatar
committed
91 92
}

's avatar
committed
93 94 95 96
void DebugWriteToString(const char* data, void *arg) {
  reinterpret_cast<string*>(arg)->append(data);
}

97
#ifdef HAVE_SYMBOLIZE
's avatar
committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
// 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<char *>(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);
}
114
#endif
's avatar
committed
115 116 117 118 119 120 121 122 123 124 125 126 127

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];
128
  int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
's avatar
committed
129
  for (int i = 0; i < depth; i++) {
130
#if defined(HAVE_SYMBOLIZE)
's avatar
committed
131 132 133 134 135 136 137 138 139 140 141 142 143
    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);
144

145
  // TOOD(hamaji): Use signal instead of sigaction?
146 147 148
  if (IsFailureSignalHandlerInstalled()) {
    // Set the default signal handler for SIGABRT, to avoid invoking our
    // own signal handler installed by InstallFailureSignalHandler().
149
#ifdef HAVE_SIGACTION
150 151 152 153 154
    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);
155 156
#elif defined(OS_WINDOWS)
    signal(SIGABRT, SIG_DFL);
157
#endif  // HAVE_SIGACTION
158
  }
159

's avatar
committed
160
  abort();
's avatar
committed
161
}
162

's avatar
committed
163 164
_END_GOOGLE_NAMESPACE_

165
#endif  // HAVE_STACKTRACE
's avatar
committed
166 167

_START_GOOGLE_NAMESPACE_
's avatar
committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

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);
  }
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
#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

's avatar
committed
218 219 220 221 222 223 224 225 226 227 228
int64 CycleClock_Now() {
  // TODO(hamaji): temporary impementation - it might be too slow.
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
}

int64 UsecToCycles(int64 usec) {
  return usec;
}

's avatar
committed
229 230 231 232 233
WallTime WallTime_Now() {
  // Now, cycle clock is retuning microseconds since the epoch.
  return CycleClock_Now() * 0.000001;
}

's avatar
committed
234 235 236 237 238
static int32 g_main_thread_pid = getpid();
int32 GetMainThreadPid() {
  return g_main_thread_pid;
}

239 240 241 242 243 244 245 246 247
bool PidHasChanged() {
  int32 pid = getpid();
  if (g_main_thread_pid == pid) {
    return false;
  }
  g_main_thread_pid = pid;
  return true;
}

's avatar
committed
248
pid_t GetTID() {
249 250
  // On Linux and MacOSX, we try to use gettid().
#if defined OS_LINUX || defined OS_MACOSX
's avatar
committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
#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;
  }
272
#endif  // OS_LINUX || OS_MACOSX
's avatar
committed
273 274 275 276

  // 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
277
#elif defined OS_WINDOWS && !defined OS_CYGWIN
's avatar
committed
278 279 280
  return GetCurrentThreadId();
#else
  // If none of the techniques above worked, we use pthread_self().
281
  return (pid_t)(uintptr_t)pthread_self();
's avatar
committed
282 283 284
#endif
}

285 286 287 288 289 290 291 292 293
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;
}

's avatar
committed
294 295 296 297 298 299
static string g_my_user_name;
const string& MyUserName() {
  return g_my_user_name;
}
static void MyUserNameInitializer() {
  // TODO(hamaji): Probably this is not portable.
300 301 302
#if defined(OS_WINDOWS)
  const char* user = getenv("USERNAME");
#else
's avatar
committed
303
  const char* user = getenv("USER");
304
#endif
's avatar
committed
305 306 307
  if (user != NULL) {
    g_my_user_name = user;
  } else {
308 309
#if defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H)
    struct passwd pwd;
310
    struct passwd* result = NULL;
311
    char buffer[1024] = {'\0'};
312 313 314
    uid_t uid = geteuid();
    int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result);
    if (pwuid_res == 0) {
315
      g_my_user_name = pwd.pw_name;
316
    } else {
317 318 319 320
      snprintf(buffer, sizeof(buffer), "uid%d", uid);
      g_my_user_name = buffer;
    }
#endif
321
    if (g_my_user_name.empty()) {
322 323
      g_my_user_name = "invalid-user";
    }
's avatar
committed
324
  }
325

's avatar
committed
326 327 328
}
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());

's avatar
committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
#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<const CrashReason*>(0),
                            r);
}

345
void InitGoogleLoggingUtilities(const char* argv0) {
346 347
  CHECK(!IsGoogleLoggingInitialized())
      << "You called InitGoogleLogging() twice!";
's avatar
committed
348 349 350 351 352 353 354 355 356 357 358 359
  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
}

360
void ShutdownGoogleLoggingUtilities() {
361
  CHECK(IsGoogleLoggingInitialized())
's avatar
committed
362
      << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
's avatar
committed
363
  g_program_invocation_short_name = NULL;
364 365 366 367 368
#ifdef HAVE_SYSLOG_H
  closelog();
#endif
}

369 370
}  // namespace glog_internal_namespace_

's avatar
committed
371
_END_GOOGLE_NAMESPACE_
372 373 374 375

// Make an implementation of stacktrace compiled.
#ifdef STACKTRACE_H
# include STACKTRACE_H
376 377 378 379 380 381 382 383
# if 0
// For include scanners which can't handle macro expansions.
#  include "stacktrace_libunwind-inl.h"
#  include "stacktrace_x86-inl.h"
#  include "stacktrace_x86_64-inl.h"
#  include "stacktrace_powerpc-inl.h"
#  include "stacktrace_generic-inl.h"
# endif
384
#endif