1 // Copyright 2008 Google Inc. All Rights Reserved.
2 // Author: Satoru Takabayashi
4 // Implementation of InstallFailureSignalHandler().
7 #include "stacktrace.h"
9 #include "glog/logging.h"
13 #ifdef HAVE_UCONTEXT_H
14 # include <ucontext.h>
18 _START_GOOGLE_NAMESPACE_
20 // There is a better way, but this is good enough in this file.
21 #define NAIVE_ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
25 // We'll install the failure signal handler for these signals. We could
26 // use strsignal() to get signal names, but we don't use it to avoid
27 // introducing yet another #ifdef complication.
29 // The list should be synced with the comment in signalhandler.h.
33 } kFailureSignals[] = {
34 { SIGSEGV, "SIGSEGV" },
37 { SIGABRT, "SIGABRT" },
39 { SIGTERM, "SIGTERM" },
42 // Returns the program counter from signal context, NULL if unknown.
43 void* GetPC(void* ucontext_in_void) {
44 #if defined(HAVE_UCONTEXT_H) && defined(PC_FROM_UCONTEXT)
45 if (ucontext_in_void != NULL) {
46 ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
47 return (void*)context->PC_FROM_UCONTEXT;
53 // The class is used for formatting error messages. We don't use printf()
54 // as it's not async signal safe.
55 class MinimalFormatter {
57 MinimalFormatter(char *buffer, int size)
63 // Returns the number of bytes written in the buffer.
64 int num_bytes_written() const { return cursor_ - buffer_; }
66 // Appends string from "str" and updates the internal cursor.
67 void AppendString(const char* str) {
69 while (str[i] != '\0' && cursor_ + i < end_) {
76 // Formats "number" in "radix" and updates the internal cursor.
77 // Lowercase letters are used for 'a' - 'z'.
78 void AppendUint64(uint64 number, int radix) {
80 while (cursor_ + i < end_) {
81 const int tmp = number % radix;
83 cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
89 // Reverse the bytes written.
90 std::reverse(cursor_, cursor_ + i);
94 // Formats "number" as hexadecimal number, and updates the internal
95 // cursor. Padding will be added in front if needed.
96 void AppendHexWithPadding(uint64 number, int width) {
97 char* start = cursor_;
99 AppendUint64(number, 16);
100 // Move to right and add padding in front if needed.
101 if (cursor_ < start + width) {
102 const int64 delta = start + width - cursor_;
103 std::copy(start, cursor_, start + delta);
104 std::fill(start, start + delta, ' ');
105 cursor_ = start + width;
112 const char * const end_;
115 // Writes the given data with the size to the standard error.
116 void WriteToStderr(const char* data, int size) {
117 write(STDERR_FILENO, data, size);
120 // The writer function can be changed by InstallFailureWriter().
121 void (*g_failure_writer)(const char* data, int size) = WriteToStderr;
123 // Dumps time information. We don't dump human-readable time information
124 // as localtime() is not guaranteed to be async signal safe.
125 void DumpTimeInfo() {
126 time_t time_in_sec = time(NULL);
127 char buf[256]; // Big enough for time info.
128 MinimalFormatter formatter(buf, sizeof(buf));
129 formatter.AppendString("*** Aborted at ");
130 formatter.AppendUint64(time_in_sec, 10);
131 formatter.AppendString(" (unix time)");
132 formatter.AppendString(" try \"date -d @");
133 formatter.AppendUint64(time_in_sec, 10);
134 formatter.AppendString("\" if you are using GNU date ***\n");
135 g_failure_writer(buf, formatter.num_bytes_written());
138 // Dumps information about the signal to STDERR.
139 void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
140 // Get the signal name.
141 const char* signal_name = NULL;
142 for (int i = 0; i < NAIVE_ARRAYSIZE(kFailureSignals); ++i) {
143 if (signal_number == kFailureSignals[i].number) {
144 signal_name = kFailureSignals[i].name;
148 char buf[256]; // Big enough for signal info.
149 MinimalFormatter formatter(buf, sizeof(buf));
151 formatter.AppendString("*** ");
153 formatter.AppendString(signal_name);
155 // Use the signal number if the name is unknown. The signal name
156 // should be known, but just in case.
157 formatter.AppendString("Signal ");
158 formatter.AppendUint64(signal_number, 10);
160 formatter.AppendString(" (@0x");
161 formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
162 formatter.AppendString(")");
163 formatter.AppendString(" received by PID ");
164 formatter.AppendUint64(getpid(), 10);
165 formatter.AppendString(" (TID 0x");
166 // We assume pthread_t is an integral number or a pointer, rather
167 // than a complex struct. In some environments, pthread_self()
168 // returns an uint64 but in some other environments pthread_self()
169 // returns a pointer. Hence we use C-style cast here, rather than
170 // reinterpret/static_cast, to support both types of environments.
171 formatter.AppendUint64((uintptr_t)pthread_self(), 16);
172 formatter.AppendString(") ");
173 // Only linux has the PID of the signal sender in si_pid.
175 formatter.AppendString("from PID ");
176 formatter.AppendUint64(siginfo->si_pid, 10);
177 formatter.AppendString("; ");
179 formatter.AppendString("stack trace: ***\n");
180 g_failure_writer(buf, formatter.num_bytes_written());
183 // Dumps information about the stack frame to STDERR.
184 void DumpStackFrameInfo(const char* prefix, void* pc) {
185 // Get the symbol name.
186 const char *symbol = "(unknown)";
187 char symbolized[1024]; // Big enough for a sane symbol.
188 // Symbolizes the previous address of pc because pc may be in the
190 if (Symbolize(reinterpret_cast<char *>(pc) - 1,
191 symbolized, sizeof(symbolized))) {
195 char buf[1024]; // Big enough for stack frame info.
196 MinimalFormatter formatter(buf, sizeof(buf));
198 formatter.AppendString(prefix);
199 formatter.AppendString("@ ");
200 const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
201 formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
202 formatter.AppendString(" ");
203 formatter.AppendString(symbol);
204 formatter.AppendString("\n");
205 g_failure_writer(buf, formatter.num_bytes_written());
208 // Invoke the default signal handler.
209 void InvokeDefaultSignalHandler(int signal_number) {
210 struct sigaction sig_action = {}; // Zero-clear.
211 sigemptyset(&sig_action.sa_mask);
212 sig_action.sa_handler = SIG_DFL;
213 sigaction(signal_number, &sig_action, NULL);
214 kill(getpid(), signal_number);
217 // This variable is used for protecting FailureSignalHandler() from
218 // dumping stuff while another thread is doing it. Our policy is to let
219 // the first thread dump stuff and let other threads wait.
220 // See also comments in FailureSignalHandler().
221 static pthread_t* g_entered_thread_id_pointer = NULL;
223 // Dumps signal and stack frame information, and invokes the default
224 // signal handler once our job is done.
225 void FailureSignalHandler(int signal_number,
226 siginfo_t *signal_info,
228 // First check if we've already entered the function. We use an atomic
229 // compare and swap operation for platforms that support it. For other
230 // platforms, we use a naive method that could lead to a subtle race.
232 // We assume pthread_self() is async signal safe, though it's not
233 // officially guaranteed.
234 pthread_t my_thread_id = pthread_self();
235 // NOTE: We could simply use pthread_t rather than pthread_t* for this,
236 // if pthread_self() is guaranteed to return non-zero value for thread
237 // ids, but there is no such guarantee. We need to distinguish if the
238 // old value (value returned from __sync_val_compare_and_swap) is
239 // different from the original value (in this case NULL).
240 pthread_t* old_thread_id_pointer =
241 glog_internal_namespace_::sync_val_compare_and_swap(
242 &g_entered_thread_id_pointer,
243 static_cast<pthread_t*>(NULL),
245 if (old_thread_id_pointer != NULL) {
246 // We've already entered the signal handler. What should we do?
247 if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
248 // It looks the current thread is reentering the signal handler.
249 // Something must be going wrong (maybe we are reentering by another
250 // type of signal?). Kill ourself by the default signal handler.
251 InvokeDefaultSignalHandler(signal_number);
253 // Another thread is dumping stuff. Let's wait until that thread
254 // finishes the job and kills the process.
259 // This is the first time we enter the signal handler. We are going to
260 // do some interesting stuff from here.
261 // TODO(satorux): We might want to set timeout here using alarm(), but
262 // mixing alarm() and sleep() can be a bad idea.
264 // First dump time info.
267 // Get the program counter from ucontext.
268 void *pc = GetPC(ucontext);
269 DumpStackFrameInfo("PC: ", pc);
271 #ifdef HAVE_STACKTRACE
272 // Get the stack traces.
274 // +1 to exclude this function.
275 const int depth = GetStackTrace(stack, NAIVE_ARRAYSIZE(stack), 1);
276 DumpSignalInfo(signal_number, signal_info);
277 // Dump the stack traces.
278 for (int i = 0; i < depth; ++i) {
279 DumpStackFrameInfo(" ", stack[i]);
282 // Kill ourself by the default signal handler.
283 InvokeDefaultSignalHandler(signal_number);
288 void InstallFailureSignalHandler() {
289 // Build the sigaction struct.
290 struct sigaction sig_action = {}; // Zero-clear.
291 sigemptyset(&sig_action.sa_mask);
292 sig_action.sa_flags |= SA_SIGINFO;
293 sig_action.sa_sigaction = &FailureSignalHandler;
295 for (int i = 0; i < NAIVE_ARRAYSIZE(kFailureSignals); ++i) {
296 CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
300 void InstallFailureWriter(void (*writer)(const char* data, int size)) {
301 g_failure_writer = writer;
304 _END_GOOGLE_NAMESPACE_