* Add LOG_TO_STRING.
[platform/upstream/glog.git] / src / utilities.cc
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 // Author: hamaji@google.com (Shinichiro Hamaji)
3
4 #include "utilities.h"
5
6 #include <signal.h>
7 #ifdef HAVE_SYS_TIME_H
8 # include <sys/time.h>
9 #endif
10 #include <time.h>
11 #if defined(HAVE_SYSCALL_H)
12 #include <syscall.h>                 // for syscall()
13 #elif defined(HAVE_SYS_SYSCALL_H)
14 #include <sys/syscall.h>                 // for syscall()
15 #endif
16
17 #include "base/googleinit.h"
18 #include "stacktrace.h"
19 #include "symbolize.h"
20
21 using std::string;
22
23 _START_GOOGLE_NAMESPACE_
24
25 static const char* g_program_invocation_short_name = NULL;
26 static pthread_t g_main_thread_id;
27
28 // The following APIs are all internal.
29 #ifdef HAVE_STACKTRACE
30
31 #include "stacktrace.h"
32 #include "symbolize.h"
33 #include "base/commandlineflags.h"
34
35 DEFINE_bool(symbolize_stacktrace, true,
36             "Symbolize the stack trace in the tombstone");
37
38 typedef void DebugWriter(const char*, void*);
39
40 // The %p field width for printf() functions is two characters per byte.
41 // For some environments, add two extra bytes for the leading "0x".
42 static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
43
44 static void DebugWriteToStderr(const char* data, void *unused) {
45   // This one is signal-safe.
46   write(STDERR_FILENO, data, strlen(data));
47 }
48
49 void DebugWriteToString(const char* data, void *arg) {
50   reinterpret_cast<string*>(arg)->append(data);
51 }
52
53 // Print a program counter and its symbol name.
54 static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
55                             const char * const prefix) {
56   char tmp[1024];
57   const char *symbol = "(unknown)";
58   // Symbolizes the previous address of pc because pc may be in the
59   // next function.  The overrun happens when the function ends with
60   // a call to a function annotated noreturn (e.g. CHECK).
61   if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
62       symbol = tmp;
63   }
64   char buf[1024];
65   snprintf(buf, sizeof(buf), "%s@ %*p  %s\n",
66            prefix, kPrintfPointerFieldWidth, pc, symbol);
67   writerfn(buf, arg);
68 }
69
70 // Print a program counter and the corresponding stack frame size.
71 static void DumpPCAndFrameSize(DebugWriter *writerfn, void *arg, void *pc,
72                                int framesize, const char * const prefix) {
73   char buf[100];
74   if (framesize <= 0) {
75     snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)\n",
76              prefix, kPrintfPointerFieldWidth, pc);
77   } else {
78     snprintf(buf, sizeof(buf), "%s@ %*p  %9d\n",
79              prefix, kPrintfPointerFieldWidth, pc, framesize);
80   }
81   writerfn(buf, arg);
82 }
83
84 static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
85                    const char * const prefix) {
86   char buf[100];
87   snprintf(buf, sizeof(buf), "%s@ %*p\n",
88            prefix, kPrintfPointerFieldWidth, pc);
89   writerfn(buf, arg);
90 }
91
92 // Dump current stack trace as directed by writerfn
93 static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
94   // Print stack trace
95   void* stack[32];
96   int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
97   for (int i = 0; i < depth; i++) {
98 #if defined(HAVE_SYMBOLIZE)
99     if (FLAGS_symbolize_stacktrace) {
100       DumpPCAndSymbol(writerfn, arg, stack[i], "    ");
101     } else {
102       DumpPC(writerfn, arg, stack[i], "    ");
103     }
104 #else
105     DumpPC(writerfn, arg, stack[i], "    ");
106 #endif
107   }
108 }
109
110 static void DumpStackTraceAndExit() {
111   DumpStackTrace(1, DebugWriteToStderr, NULL);
112
113   // Set the default signal handler for SIGABRT, to avoid invoking our
114   // own signal handler installed by InstallFailedSignalHandler().
115   struct sigaction sig_action = {};  // Zero-clear.
116   sigemptyset(&sig_action.sa_mask);
117   sig_action.sa_handler = SIG_DFL;
118   sigaction(SIGABRT, &sig_action, NULL);
119
120   abort();
121 }
122
123 #endif  // HAVE_STACKTRACE
124
125 namespace glog_internal_namespace_ {
126
127 const char* ProgramInvocationShortName() {
128   if (g_program_invocation_short_name != NULL) {
129     return g_program_invocation_short_name;
130   } else {
131     // TODO(hamaji): Use /proc/self/cmdline and so?
132     return "UNKNOWN";
133   }
134 }
135
136 bool IsGoogleLoggingInitialized() {
137   return g_program_invocation_short_name != NULL;
138 }
139
140 bool is_default_thread() {
141   if (g_program_invocation_short_name == NULL) {
142     // InitGoogleLogging() not yet called, so unlikely to be in a different
143     // thread
144     return true;
145   } else {
146     return pthread_equal(pthread_self(), g_main_thread_id);
147   }
148 }
149
150 int64 CycleClock_Now() {
151   // TODO(hamaji): temporary impementation - it might be too slow.
152 #ifdef OS_WINDOWS
153   SYSTEMTIME now;
154   GetSystemTime(&now);
155   return (static_cast<int64>(now.wSecond) * 1000000 +
156           static_cast<int64>(now.wMilliseconds) * 1000);
157 #else
158   struct timeval tv;
159   gettimeofday(&tv, NULL);
160   return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
161 #endif
162 }
163
164 int64 UsecToCycles(int64 usec) {
165   return usec;
166 }
167
168 WallTime WallTime_Now() {
169   // Now, cycle clock is retuning microseconds since the epoch.
170   return CycleClock_Now() * 0.000001;
171 }
172
173 static int32 g_main_thread_pid = getpid();
174 int32 GetMainThreadPid() {
175   return g_main_thread_pid;
176 }
177
178 pid_t GetTID() {
179   // On Linux and FreeBSD, we try to use gettid().
180 #if defined OS_LINUX || defined OS_FREEBSD || defined OS_MACOSX
181 #ifndef __NR_gettid
182 #ifdef OS_MACOSX
183 #define __NR_gettid SYS_gettid
184 #elif ! defined __i386__
185 #error "Must define __NR_gettid for non-x86 platforms"
186 #else
187 #define __NR_gettid 224
188 #endif
189 #endif
190   static bool lacks_gettid = false;
191   if (!lacks_gettid) {
192     pid_t tid = syscall(__NR_gettid);
193     if (tid != -1) {
194       return tid;
195     }
196     // Technically, this variable has to be volatile, but there is a small
197     // performance penalty in accessing volatile variables and there should
198     // not be any serious adverse effect if a thread does not immediately see
199     // the value change to "true".
200     lacks_gettid = true;
201   }
202 #endif  // OS_LINUX || OS_FREEBSD
203
204   // If gettid() could not be used, we use one of the following.
205 #if defined OS_LINUX
206   return getpid();  // Linux:  getpid returns thread ID when gettid is absent
207 #elif defined OS_WINDOWS || defined OS_CYGWIN
208   return GetCurrentThreadId();
209 #else
210   // If none of the techniques above worked, we use pthread_self().
211   return (pid_t)pthread_self();
212 #endif
213 }
214
215 const char* const_basename(const char* filepath) {
216   const char* base = strrchr(filepath, '/');
217 #ifdef OS_WINDOWS  // Look for either path separator in Windows
218   if (!base)
219     base = strrchr(filepath, '\\');
220 #endif
221   return base ? (base+1) : filepath;
222 }
223
224 static string g_my_user_name;
225 const string& MyUserName() {
226   return g_my_user_name;
227 }
228 static void MyUserNameInitializer() {
229   // TODO(hamaji): Probably this is not portable.
230   const char* user = getenv("USER");
231   if (user != NULL) {
232     g_my_user_name = user;
233   } else {
234     g_my_user_name = "invalid-user";
235   }
236 }
237 REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
238
239 #ifdef HAVE_STACKTRACE
240 void DumpStackTraceToString(string* stacktrace) {
241   DumpStackTrace(1, DebugWriteToString, stacktrace);
242 }
243 #endif
244
245 // We use an atomic operation to prevent problems with calling CrashReason
246 // from inside the Mutex implementation (potentially through RAW_CHECK).
247 static const CrashReason* g_reason = 0;
248
249 void SetCrashReason(const CrashReason* r) {
250   sync_val_compare_and_swap(&g_reason,
251                             reinterpret_cast<const CrashReason*>(0),
252                             r);
253 }
254
255 }  // namespace glog_internal_namespace_
256
257 void InitGoogleLogging(const char* argv0) {
258   const char* slash = strrchr(argv0, '/');
259 #ifdef OS_WINDOWS
260   if (!slash)  slash = strrchr(argv0, '\\');
261 #endif
262   g_program_invocation_short_name = slash ? slash + 1 : argv0;
263   g_main_thread_id = pthread_self();
264
265 #ifdef HAVE_STACKTRACE
266   InstallFailureFunction(&DumpStackTraceAndExit);
267 #endif
268 }
269
270 _END_GOOGLE_NAMESPACE_
271
272 // Make an implementation of stacktrace compiled.
273 #ifdef STACKTRACE_H
274 # include STACKTRACE_H
275 #endif