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