blob: 079a574d3ac3e364156218ac226229d846b26086 [file] [log] [blame]
Josh Gaoe73c9322017-02-08 16:06:26 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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 copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080029#include <dirent.h>
30#include <fcntl.h>
31#include <poll.h>
32#include <pthread.h>
Josh Gaoe73c9322017-02-08 16:06:26 -080033#include <stddef.h>
34#include <sys/ucontext.h>
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080035#include <syscall.h>
Josh Gaoe73c9322017-02-08 16:06:26 -080036#include <unistd.h>
37
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080038#include <atomic>
Josh Gao2b2ae0c2017-08-21 14:31:17 -070039#include <memory>
Josh Gao70adac62018-02-22 11:38:33 -080040#include <mutex>
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080041
42#include <android-base/file.h>
43#include <android-base/unique_fd.h>
Christopher Ferrisac225782017-04-25 11:23:10 -070044#include <async_safe/log.h>
Josh Gao2b2ae0c2017-08-21 14:31:17 -070045#include <backtrace/BacktraceMap.h>
46#include <unwindstack/Memory.h>
47#include <unwindstack/Regs.h>
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080048
49#include "debuggerd/handler.h"
Narayan Kamath2d377cd2017-05-10 10:58:59 +010050#include "tombstoned/tombstoned.h"
51#include "util.h"
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080052
Josh Gaoc3706662017-08-29 13:08:32 -070053#include "libdebuggerd/backtrace.h"
54#include "libdebuggerd/tombstone.h"
Josh Gaoe73c9322017-02-08 16:06:26 -080055
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080056using android::base::unique_fd;
Josh Gao2b2ae0c2017-08-21 14:31:17 -070057using unwindstack::Regs;
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080058
Josh Gaoc531ed62018-01-24 14:23:42 -080059extern "C" bool __linker_enable_fallback_allocator();
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080060extern "C" void __linker_disable_fallback_allocator();
61
62// This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
63// uses the C++ standard library throughout, but this code runs in the linker, so we'll be using
64// the linker's malloc instead of the libc one. Switch it out for a replacement, just in case.
65//
66// This isn't the default method of dumping because it can fail in cases such as address space
67// exhaustion.
68static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
Josh Gaoc531ed62018-01-24 14:23:42 -080069 if (!__linker_enable_fallback_allocator()) {
70 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
71 return;
72 }
73
Josh Gao2b2ae0c2017-08-21 14:31:17 -070074 {
75 std::unique_ptr<Regs> regs;
76
77 ThreadInfo thread;
78 thread.pid = getpid();
79 thread.tid = gettid();
80 thread.thread_name = get_thread_name(gettid());
81 thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
82
83 // TODO: Create this once and store it in a global?
84 std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
85 dump_backtrace_thread(output_fd, map.get(), thread);
86 }
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080087 __linker_disable_fallback_allocator();
88}
89
90static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
91 void* abort_message) {
Josh Gaoc531ed62018-01-24 14:23:42 -080092 if (!__linker_enable_fallback_allocator()) {
93 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
94 return;
95 }
96
Josh Gaoe1aa0ca2017-03-01 17:23:22 -080097 engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
98 ucontext);
99 __linker_disable_fallback_allocator();
100}
101
102static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) {
103 pid_t current_tid = gettid();
104 char buf[BUFSIZ];
105 snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid);
106 DIR* dir = opendir(buf);
107
108 if (!dir) {
Christopher Ferrisac225782017-04-25 11:23:10 -0700109 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno));
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800110 return;
111 }
112
113 struct dirent* ent;
114 while ((ent = readdir(dir))) {
115 char* end;
116 long tid = strtol(ent->d_name, &end, 10);
117 if (end == ent->d_name || *end != '\0') {
118 continue;
119 }
120
121 if (tid != current_tid) {
122 callback(tid, output_fd);
123 }
124 }
125 closedir(dir);
126}
127
Josh Gaoc531ed62018-01-24 14:23:42 -0800128static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800129 // Make sure the thread actually got the signal.
130 struct pollfd pfd = {
131 .fd = src_fd, .events = POLLIN,
132 };
133
134 // Wait for up to a second for output to start flowing.
135 if (poll(&pfd, 1, 1000) != 1) {
136 return false;
137 }
138
Josh Gaoc531ed62018-01-24 14:23:42 -0800139 pid_t tid;
140 if (TEMP_FAILURE_RETRY(read(src_fd, &tid, sizeof(tid))) != sizeof(tid)) {
141 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to read tid");
142 return false;
143 }
144
145 if (tid != expected_tid) {
146 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "received tid %d, expected %d", tid,
147 expected_tid);
148 return false;
149 }
150
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800151 while (true) {
152 char buf[512];
153 ssize_t rc = TEMP_FAILURE_RETRY(read(src_fd, buf, sizeof(buf)));
154 if (rc == 0) {
155 return true;
156 } else if (rc < 0) {
157 return false;
158 }
159
160 if (!android::base::WriteFully(dst_fd, buf, rc)) {
161 // We failed to write to tombstoned, but there's not much we can do.
162 // Keep reading from src_fd to keep things going.
163 continue;
164 }
165 }
166}
167
Josh Gaoc531ed62018-01-24 14:23:42 -0800168struct __attribute__((__packed__)) packed_thread_output {
169 int32_t tid;
170 int32_t fd;
171};
172
173static uint64_t pack_thread_fd(pid_t tid, int fd) {
174 packed_thread_output packed = {.tid = tid, .fd = fd};
175 uint64_t result;
176 static_assert(sizeof(packed) == sizeof(result));
177 memcpy(&result, &packed, sizeof(packed));
178 return result;
179}
180
181static std::pair<pid_t, int> unpack_thread_fd(uint64_t value) {
182 packed_thread_output result;
183 memcpy(&result, &value, sizeof(value));
184 return std::make_pair(result.tid, result.fd);
185}
186
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800187static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
Josh Gaoc531ed62018-01-24 14:23:42 -0800188 static std::atomic<uint64_t> trace_output(pack_thread_fd(-1, -1));
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800189
190 if (info->si_value.sival_int == ~0) {
191 // Asked to dump by the original signal recipient.
Josh Gaoc531ed62018-01-24 14:23:42 -0800192 uint64_t val = trace_output.load();
193 auto [tid, fd] = unpack_thread_fd(val);
194 if (tid != gettid()) {
195 // We received some other thread's info request?
196 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
197 "thread %d received output fd for thread %d?", gettid(), tid);
198 return;
199 }
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800200
Josh Gaoc531ed62018-01-24 14:23:42 -0800201 if (!trace_output.compare_exchange_strong(val, pack_thread_fd(-1, -1))) {
202 // Presumably, the timeout in forward_output expired, and the main thread moved on.
203 // If this happened, the main thread closed our fd for us, so just return.
204 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "cmpxchg for thread %d failed", gettid());
205 return;
206 }
207
208 // Write our tid to the output fd to let the main thread know that we're working.
209 if (TEMP_FAILURE_RETRY(write(fd, &tid, sizeof(tid))) == sizeof(tid)) {
210 debuggerd_fallback_trace(fd, ucontext);
211 } else {
212 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write to output fd");
213 }
214
215 close(fd);
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800216 return;
217 }
218
219 // Only allow one thread to perform a trace at a time.
220 static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER;
221 int ret = pthread_mutex_trylock(&trace_mutex);
222 if (ret != 0) {
Christopher Ferrisac225782017-04-25 11:23:10 -0700223 async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s",
224 strerror(ret));
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800225 return;
226 }
227
228 // Fetch output fd from tombstoned.
229 unique_fd tombstone_socket, output_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100230 if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdNativeBacktrace)) {
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800231 goto exit;
232 }
233
234 dump_backtrace_header(output_fd.get());
235
236 // Dump our own stack.
237 debuggerd_fallback_trace(output_fd.get(), ucontext);
238
239 // Send a signal to all of our siblings, asking them to dump their stack.
240 iterate_siblings(
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700241 [](pid_t tid, int output_fd) {
242 // Use a pipe, to be able to detect situations where the thread gracefully exits before
243 // receiving our signal.
244 unique_fd pipe_read, pipe_write;
245 if (!Pipe(&pipe_read, &pipe_write)) {
246 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s",
247 strerror(errno));
248 return false;
249 }
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800250
Josh Gaoc531ed62018-01-24 14:23:42 -0800251 uint64_t expected = pack_thread_fd(-1, -1);
252 if (!trace_output.compare_exchange_strong(expected,
253 pack_thread_fd(tid, pipe_write.release()))) {
254 auto [tid, fd] = unpack_thread_fd(expected);
255 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
256 "thread %d is already outputting to fd %d?", tid, fd);
257 return false;
258 }
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800259
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700260 siginfo_t siginfo = {};
261 siginfo.si_code = SI_QUEUE;
262 siginfo.si_value.sival_int = ~0;
263 siginfo.si_pid = getpid();
264 siginfo.si_uid = getuid();
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800265
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700266 if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
267 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
268 tid, strerror(errno));
269 return false;
270 }
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800271
Josh Gaoc531ed62018-01-24 14:23:42 -0800272 bool success = forward_output(pipe_read.get(), output_fd, tid);
273 if (!success) {
274 async_safe_format_log(ANDROID_LOG_ERROR, "libc",
275 "timeout expired while waiting for thread %d to dump", tid);
276 }
277
278 // Regardless of whether the poll succeeds, check to see if the thread took fd ownership.
279 uint64_t post_wait = trace_output.exchange(pack_thread_fd(-1, -1));
280 if (post_wait != pack_thread_fd(-1, -1)) {
281 auto [tid, fd] = unpack_thread_fd(post_wait);
282 if (fd != -1) {
283 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "closing fd %d for thread %d", fd, tid);
284 close(fd);
285 }
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700286 }
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800287
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700288 return true;
289 },
290 output_fd.get());
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800291
292 dump_backtrace_footer(output_fd.get());
293 tombstoned_notify_completion(tombstone_socket.get());
294
295exit:
296 pthread_mutex_unlock(&trace_mutex);
297}
298
299static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700300 // Only allow one thread to handle a crash at a time (this can happen multiple times without
301 // exit, since tombstones can be requested without a real crash happening.)
Josh Gao70adac62018-02-22 11:38:33 -0800302 static std::recursive_mutex crash_mutex;
303 static int lock_count;
304
305 crash_mutex.lock();
306 if (lock_count++ > 0) {
Josh Gaod2b15dd2018-05-15 17:49:59 -0700307 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "recursed signal handler call, aborting");
308 signal(SIGABRT, SIG_DFL);
309 raise(SIGABRT);
310 sigset_t sigset;
311 sigemptyset(&sigset);
312 sigaddset(&sigset, SIGABRT);
313 sigprocmask(SIG_UNBLOCK, &sigset, nullptr);
314
315 // Just in case...
316 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "abort didn't exit, exiting");
Josh Gao70adac62018-02-22 11:38:33 -0800317 _exit(1);
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800318 }
319
320 unique_fd tombstone_socket, output_fd;
Narayan Kamatha73df602017-05-24 15:07:25 +0100321 bool tombstoned_connected =
322 tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdTombstone);
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800323 debuggerd_fallback_tombstone(output_fd.get(), ucontext, info, abort_message);
324 if (tombstoned_connected) {
325 tombstoned_notify_completion(tombstone_socket.get());
326 }
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700327
Josh Gao70adac62018-02-22 11:38:33 -0800328 --lock_count;
329 crash_mutex.unlock();
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800330}
331
332extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
333 void* abort_message) {
Josh Gao2b2ae0c2017-08-21 14:31:17 -0700334 if (info->si_signo == DEBUGGER_SIGNAL && info->si_value.sival_int != 0) {
Josh Gaoe1aa0ca2017-03-01 17:23:22 -0800335 return trace_handler(info, ucontext);
336 } else {
337 return crash_handler(info, ucontext, abort_message);
338 }
Josh Gaoe73c9322017-02-08 16:06:26 -0800339}