blob: a332f1a19963ec99d258cf57ce1beb10a2bfa7f9 [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
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070032#include "config.h"
Austin Schuh906616c2019-01-21 20:25:11 -080033#include "utilities.h"
34
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070035#include <cstdio>
36#include <cstdlib>
Austin Schuh906616c2019-01-21 20:25:11 -080037
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070038#include <csignal>
Austin Schuh906616c2019-01-21 20:25:11 -080039#ifdef HAVE_SYS_TIME_H
40# include <sys/time.h>
41#endif
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070042#include <ctime>
Austin Schuh906616c2019-01-21 20:25:11 -080043#if defined(HAVE_SYSCALL_H)
44#include <syscall.h> // for syscall()
45#elif defined(HAVE_SYS_SYSCALL_H)
46#include <sys/syscall.h> // for syscall()
47#endif
48#ifdef HAVE_SYSLOG_H
49# include <syslog.h>
50#endif
51#ifdef HAVE_UNISTD_H
52# include <unistd.h> // For geteuid.
53#endif
54#ifdef HAVE_PWD_H
55# include <pwd.h>
56#endif
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070057#ifdef __ANDROID__
58#include <android/log.h>
59#endif
Austin Schuh906616c2019-01-21 20:25:11 -080060
61#include "base/googleinit.h"
62
63using std::string;
64
65_START_GOOGLE_NAMESPACE_
66
67static const char* g_program_invocation_short_name = NULL;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070068
69bool IsGoogleLoggingInitialized() {
70 return g_program_invocation_short_name != NULL;
71}
Austin Schuh906616c2019-01-21 20:25:11 -080072
73_END_GOOGLE_NAMESPACE_
74
75// The following APIs are all internal.
76#ifdef HAVE_STACKTRACE
77
78#include "stacktrace.h"
79#include "symbolize.h"
80#include "base/commandlineflags.h"
81
82GLOG_DEFINE_bool(symbolize_stacktrace, true,
83 "Symbolize the stack trace in the tombstone");
84
85_START_GOOGLE_NAMESPACE_
86
87typedef void DebugWriter(const char*, void*);
88
89// The %p field width for printf() functions is two characters per byte.
90// For some environments, add two extra bytes for the leading "0x".
91static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
92
93static void DebugWriteToStderr(const char* data, void *) {
94 // This one is signal-safe.
95 if (write(STDERR_FILENO, data, strlen(data)) < 0) {
96 // Ignore errors.
97 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070098#if defined(__ANDROID__)
99 // ANDROID_LOG_FATAL as fatal error occurred and now is dumping call stack.
100 __android_log_write(ANDROID_LOG_FATAL,
101 glog_internal_namespace_::ProgramInvocationShortName(),
102 data);
103#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800104}
105
106static void DebugWriteToString(const char* data, void *arg) {
107 reinterpret_cast<string*>(arg)->append(data);
108}
109
110#ifdef HAVE_SYMBOLIZE
111// Print a program counter and its symbol name.
112static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
113 const char * const prefix) {
114 char tmp[1024];
115 const char *symbol = "(unknown)";
116 // Symbolizes the previous address of pc because pc may be in the
117 // next function. The overrun happens when the function ends with
118 // a call to a function annotated noreturn (e.g. CHECK).
119 if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
120 symbol = tmp;
121 }
122 char buf[1024];
123 snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
124 prefix, kPrintfPointerFieldWidth, pc, symbol);
125 writerfn(buf, arg);
126}
127#endif
128
129static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
130 const char * const prefix) {
131 char buf[100];
132 snprintf(buf, sizeof(buf), "%s@ %*p\n",
133 prefix, kPrintfPointerFieldWidth, pc);
134 writerfn(buf, arg);
135}
136
137// Dump current stack trace as directed by writerfn
138static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
139 // Print stack trace
140 void* stack[32];
141 int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
142 for (int i = 0; i < depth; i++) {
143#if defined(HAVE_SYMBOLIZE)
144 if (FLAGS_symbolize_stacktrace) {
145 DumpPCAndSymbol(writerfn, arg, stack[i], " ");
146 } else {
147 DumpPC(writerfn, arg, stack[i], " ");
148 }
149#else
150 DumpPC(writerfn, arg, stack[i], " ");
151#endif
152 }
153}
154
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700155#if defined(__GNUC__)
156__attribute__((noreturn))
157#elif defined(_MSC_VER)
158__declspec(noreturn)
159#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800160static void DumpStackTraceAndExit() {
161 DumpStackTrace(1, DebugWriteToStderr, NULL);
162
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700163 // TODO(hamaji): Use signal instead of sigaction?
Austin Schuh906616c2019-01-21 20:25:11 -0800164 if (IsFailureSignalHandlerInstalled()) {
165 // Set the default signal handler for SIGABRT, to avoid invoking our
166 // own signal handler installed by InstallFailureSignalHandler().
167#ifdef HAVE_SIGACTION
168 struct sigaction sig_action;
169 memset(&sig_action, 0, sizeof(sig_action));
170 sigemptyset(&sig_action.sa_mask);
171 sig_action.sa_handler = SIG_DFL;
172 sigaction(SIGABRT, &sig_action, NULL);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700173#elif defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800174 signal(SIGABRT, SIG_DFL);
175#endif // HAVE_SIGACTION
176 }
177
178 abort();
179}
180
181_END_GOOGLE_NAMESPACE_
182
183#endif // HAVE_STACKTRACE
184
185_START_GOOGLE_NAMESPACE_
186
187namespace glog_internal_namespace_ {
188
189const char* ProgramInvocationShortName() {
190 if (g_program_invocation_short_name != NULL) {
191 return g_program_invocation_short_name;
192 } else {
193 // TODO(hamaji): Use /proc/self/cmdline and so?
194 return "UNKNOWN";
195 }
196}
197
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700198#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800199struct timeval {
200 long tv_sec, tv_usec;
201};
202
203// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
204// See COPYING for copyright information.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700205static int gettimeofday(struct timeval *tv, void* /*tz*/) {
206#ifdef __GNUC__
207#pragma GCC diagnostic push
208#pragma GCC diagnostic ignored "-Wlong-long"
209#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800210#define EPOCHFILETIME (116444736000000000ULL)
211 FILETIME ft;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700212 ULARGE_INTEGER li;
Austin Schuh906616c2019-01-21 20:25:11 -0800213 uint64 tt;
214
215 GetSystemTimeAsFileTime(&ft);
216 li.LowPart = ft.dwLowDateTime;
217 li.HighPart = ft.dwHighDateTime;
218 tt = (li.QuadPart - EPOCHFILETIME) / 10;
219 tv->tv_sec = tt / 1000000;
220 tv->tv_usec = tt % 1000000;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700221#ifdef __GNUC__
222#pragma GCC diagnostic pop
223#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800224
225 return 0;
226}
227#endif
228
229int64 CycleClock_Now() {
230 // TODO(hamaji): temporary impementation - it might be too slow.
231 struct timeval tv;
232 gettimeofday(&tv, NULL);
233 return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
234}
235
236int64 UsecToCycles(int64 usec) {
237 return usec;
238}
239
240WallTime WallTime_Now() {
241 // Now, cycle clock is retuning microseconds since the epoch.
242 return CycleClock_Now() * 0.000001;
243}
244
245static int32 g_main_thread_pid = getpid();
246int32 GetMainThreadPid() {
247 return g_main_thread_pid;
248}
249
250bool PidHasChanged() {
251 int32 pid = getpid();
252 if (g_main_thread_pid == pid) {
253 return false;
254 }
255 g_main_thread_pid = pid;
256 return true;
257}
258
259pid_t GetTID() {
260 // On Linux and MacOSX, we try to use gettid().
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700261#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
Austin Schuh906616c2019-01-21 20:25:11 -0800262#ifndef __NR_gettid
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700263#ifdef GLOG_OS_MACOSX
Austin Schuh906616c2019-01-21 20:25:11 -0800264#define __NR_gettid SYS_gettid
265#elif ! defined __i386__
266#error "Must define __NR_gettid for non-x86 platforms"
267#else
268#define __NR_gettid 224
269#endif
270#endif
271 static bool lacks_gettid = false;
272 if (!lacks_gettid) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700273#if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
274 uint64_t tid64;
275 const int error = pthread_threadid_np(NULL, &tid64);
276 pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
277#else
278 pid_t tid = static_cast<pid_t>(syscall(__NR_gettid));
279#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800280 if (tid != -1) {
281 return tid;
282 }
283 // Technically, this variable has to be volatile, but there is a small
284 // performance penalty in accessing volatile variables and there should
285 // not be any serious adverse effect if a thread does not immediately see
286 // the value change to "true".
287 lacks_gettid = true;
288 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700289#endif // GLOG_OS_LINUX || GLOG_OS_MACOSX
Austin Schuh906616c2019-01-21 20:25:11 -0800290
291 // If gettid() could not be used, we use one of the following.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700292#if defined GLOG_OS_LINUX
Austin Schuh906616c2019-01-21 20:25:11 -0800293 return getpid(); // Linux: getpid returns thread ID when gettid is absent
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700294#elif defined GLOG_OS_WINDOWS && !defined GLOG_OS_CYGWIN
295 return static_cast<pid_t>(GetCurrentThreadId());
296#elif defined(HAVE_PTHREAD)
Austin Schuh906616c2019-01-21 20:25:11 -0800297 // If none of the techniques above worked, we use pthread_self().
298 return (pid_t)(uintptr_t)pthread_self();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700299#else
300 return -1;
Austin Schuh906616c2019-01-21 20:25:11 -0800301#endif
302}
303
304const char* const_basename(const char* filepath) {
305 const char* base = strrchr(filepath, '/');
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700306#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
Austin Schuh906616c2019-01-21 20:25:11 -0800307 if (!base)
308 base = strrchr(filepath, '\\');
309#endif
310 return base ? (base+1) : filepath;
311}
312
313static string g_my_user_name;
314const string& MyUserName() {
315 return g_my_user_name;
316}
317static void MyUserNameInitializer() {
318 // TODO(hamaji): Probably this is not portable.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700319#if defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800320 const char* user = getenv("USERNAME");
321#else
322 const char* user = getenv("USER");
323#endif
324 if (user != NULL) {
325 g_my_user_name = user;
326 } else {
327#if defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H)
328 struct passwd pwd;
329 struct passwd* result = NULL;
330 char buffer[1024] = {'\0'};
331 uid_t uid = geteuid();
332 int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700333 if (pwuid_res == 0 && result) {
Austin Schuh906616c2019-01-21 20:25:11 -0800334 g_my_user_name = pwd.pw_name;
335 } else {
336 snprintf(buffer, sizeof(buffer), "uid%d", uid);
337 g_my_user_name = buffer;
338 }
339#endif
340 if (g_my_user_name.empty()) {
341 g_my_user_name = "invalid-user";
342 }
343 }
344
345}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700346REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer())
Austin Schuh906616c2019-01-21 20:25:11 -0800347
348#ifdef HAVE_STACKTRACE
349void DumpStackTraceToString(string* stacktrace) {
350 DumpStackTrace(1, DebugWriteToString, stacktrace);
351}
352#endif
353
354// We use an atomic operation to prevent problems with calling CrashReason
355// from inside the Mutex implementation (potentially through RAW_CHECK).
356static const CrashReason* g_reason = 0;
357
358void SetCrashReason(const CrashReason* r) {
359 sync_val_compare_and_swap(&g_reason,
360 reinterpret_cast<const CrashReason*>(0),
361 r);
362}
363
364void InitGoogleLoggingUtilities(const char* argv0) {
365 CHECK(!IsGoogleLoggingInitialized())
366 << "You called InitGoogleLogging() twice!";
367 const char* slash = strrchr(argv0, '/');
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700368#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800369 if (!slash) slash = strrchr(argv0, '\\');
370#endif
371 g_program_invocation_short_name = slash ? slash + 1 : argv0;
Austin Schuh906616c2019-01-21 20:25:11 -0800372
373#ifdef HAVE_STACKTRACE
374 InstallFailureFunction(&DumpStackTraceAndExit);
375#endif
376}
377
378void ShutdownGoogleLoggingUtilities() {
379 CHECK(IsGoogleLoggingInitialized())
380 << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
381 g_program_invocation_short_name = NULL;
382#ifdef HAVE_SYSLOG_H
383 closelog();
384#endif
385}
386
387} // namespace glog_internal_namespace_
388
389_END_GOOGLE_NAMESPACE_
390
391// Make an implementation of stacktrace compiled.
392#ifdef STACKTRACE_H
393# include STACKTRACE_H
394# if 0
395// For include scanners which can't handle macro expansions.
396# include "stacktrace_libunwind-inl.h"
397# include "stacktrace_x86-inl.h"
398# include "stacktrace_x86_64-inl.h"
399# include "stacktrace_powerpc-inl.h"
400# include "stacktrace_generic-inl.h"
401# endif
402#endif