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