Initial windows support. Now we don't have the stacktrace and several unittests.
[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
12 #include "base/googleinit.h"
13 #include "stacktrace.h"
14 #include "symbolize.h"
15
16 using std::string;
17
18 _START_GOOGLE_NAMESPACE_
19
20 static const char* g_program_invocation_short_name = NULL;
21 static pthread_t g_main_thread_id;
22
23 // The following APIs are all internal.
24 #ifdef HAVE_STACKTRACE
25
26 #include "stacktrace.h"
27 #include "symbolize.h"
28 #include "base/commandlineflags.h"
29
30 DEFINE_bool(symbolize_stacktrace, true,
31             "Symbolize the stack trace in the tombstone");
32
33 typedef void DebugWriter(const char*, void*);
34
35 // The %p field width for printf() functions is two characters per byte.
36 // For some environments, add two extra bytes for the leading "0x".
37 static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
38
39 static void DebugWriteToStderr(const char* data, void *unused) {
40   // This one is signal-safe.
41   write(STDERR_FILENO, data, strlen(data));
42 }
43
44 // Print a program counter and its symbol name.
45 static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
46                             const char * const prefix) {
47   char tmp[1024];
48   const char *symbol = "(unknown)";
49   // Symbolizes the previous address of pc because pc may be in the
50   // next function.  The overrun happens when the function ends with
51   // a call to a function annotated noreturn (e.g. CHECK).
52   if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
53       symbol = tmp;
54   }
55   char buf[1024];
56   snprintf(buf, sizeof(buf), "%s@ %*p  %s\n",
57            prefix, kPrintfPointerFieldWidth, pc, symbol);
58   writerfn(buf, arg);
59 }
60
61 // Print a program counter and the corresponding stack frame size.
62 static void DumpPCAndFrameSize(DebugWriter *writerfn, void *arg, void *pc,
63                                int framesize, const char * const prefix) {
64   char buf[100];
65   if (framesize <= 0) {
66     snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)\n",
67              prefix, kPrintfPointerFieldWidth, pc);
68   } else {
69     snprintf(buf, sizeof(buf), "%s@ %*p  %9d\n",
70              prefix, kPrintfPointerFieldWidth, pc, framesize);
71   }
72   writerfn(buf, arg);
73 }
74
75 static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
76                    const char * const prefix) {
77   char buf[100];
78   snprintf(buf, sizeof(buf), "%s@ %*p\n",
79            prefix, kPrintfPointerFieldWidth, pc);
80   writerfn(buf, arg);
81 }
82
83 // Dump current stack trace as directed by writerfn
84 static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
85   // Print stack trace
86   void* stack[32];
87   int depth = GetStackTrace(stack, sizeof(stack)/sizeof(*stack), skip_count+1);
88   for (int i = 0; i < depth; i++) {
89 #if defined(HAVE_SYMBOLIZE)
90     if (FLAGS_symbolize_stacktrace) {
91       DumpPCAndSymbol(writerfn, arg, stack[i], "    ");
92     } else {
93       DumpPC(writerfn, arg, stack[i], "    ");
94     }
95 #else
96     DumpPC(writerfn, arg, stack[i], "    ");
97 #endif
98   }
99 }
100
101 static void DumpStackTraceAndExit() {
102   DumpStackTrace(1, DebugWriteToStderr, NULL);
103
104   // Set the default signal handler for SIGABRT, to avoid invoking our
105   // own signal handler installed by InstallFailedSignalHandler().
106   struct sigaction sig_action = {};  // Zero-clear.
107   sigemptyset(&sig_action.sa_mask);
108   sig_action.sa_handler = SIG_DFL;
109   sigaction(SIGABRT, &sig_action, NULL);
110
111   abort();
112 }
113
114 #endif  // HAVE_STACKTRACE
115
116 namespace glog_internal_namespace_ {
117
118 const char* ProgramInvocationShortName() {
119   if (g_program_invocation_short_name != NULL) {
120     return g_program_invocation_short_name;
121   } else {
122     // TODO(hamaji): Use /proc/self/cmdline and so?
123     return "UNKNOWN";
124   }
125 }
126
127 bool IsGoogleLoggingInitialized() {
128   return g_program_invocation_short_name != NULL;
129 }
130
131 bool is_default_thread() {
132   if (g_program_invocation_short_name == NULL) {
133     // InitGoogleLogging() not yet called, so unlikely to be in a different
134     // thread
135     return true;
136   } else {
137     return pthread_equal(pthread_self(), g_main_thread_id);
138   }
139 }
140
141 int64 CycleClock_Now() {
142   // TODO(hamaji): temporary impementation - it might be too slow.
143 #ifdef OS_WINDOWS
144   SYSTEMTIME now;
145   GetSystemTime(&now);
146   return (static_cast<int64>(now.wSecond) * 1000000 +
147           static_cast<int64>(now.wMilliseconds) * 1000);
148 #else
149   // TODO(hamaji): temporary impementation - it might be too slow.
150   struct timeval tv;
151   gettimeofday(&tv, NULL);
152   return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
153 #endif
154 }
155
156 int64 UsecToCycles(int64 usec) {
157   return usec;
158 }
159
160 static int32 g_main_thread_pid = getpid();
161 int32 GetMainThreadPid() {
162   return g_main_thread_pid;
163 }
164
165 const char* const_basename(const char* filepath) {
166   const char* base = strrchr(filepath, '/');
167 #ifdef OS_WINDOWS  // Look for either path separator in Windows
168   if (!base)
169     base = strrchr(filepath, '\\');
170 #endif
171   return base ? (base+1) : filepath;
172 }
173
174 static string g_my_user_name;
175 const string& MyUserName() {
176   return g_my_user_name;
177 }
178 static void MyUserNameInitializer() {
179   // TODO(hamaji): Probably this is not portable.
180   const char* user = getenv("USER");
181   if (user != NULL) {
182     g_my_user_name = user;
183   } else {
184     g_my_user_name = "invalid-user";
185   }
186 }
187 REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
188
189 }  // namespace glog_internal_namespace_
190
191 void InitGoogleLogging(const char* argv0) {
192   const char* slash = strrchr(argv0, '/');
193 #ifdef OS_WINDOWS
194   if (!slash)  slash = strrchr(argv0, '\\');
195 #endif
196   g_program_invocation_short_name = slash ? slash + 1 : argv0;
197   g_main_thread_id = pthread_self();
198
199 #ifdef HAVE_STACKTRACE
200   InstallFailureFunction(&DumpStackTraceAndExit);
201 #endif
202 }
203
204 _END_GOOGLE_NAMESPACE_
205
206 // Make an implementation of stacktrace compiled.
207 #ifdef STACKTRACE_H
208 # include STACKTRACE_H
209 #endif