crash_dump: defer pausing threads until we're ready.
Don't pause the threads we're going to dump until after we're about to
fetch their backtraces.
Bug: http://b/62112103
Test: debuggerd_test
Change-Id: Id7ab0464842b35f98f3b3ebc42fb76161d8afbd2
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 5565cfd..42c3023 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -7,6 +7,7 @@
"-Wno-nullability-completeness",
"-Os",
],
+ cpp_std: "experimental",
local_include_dirs: ["include"],
}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index df7201d..3ca9c92 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -95,11 +95,6 @@
return false;
}
- // Put the task into ptrace-stop state.
- if (ptrace(PTRACE_INTERRUPT, tid, 0, 0) != 0) {
- PLOG(FATAL) << "failed to interrupt thread " << tid;
- }
-
return true;
}
@@ -284,36 +279,38 @@
// Die if we take too long.
alarm(2);
+ std::string process_name = get_process_name(main_tid);
std::string attach_error;
std::map<pid_t, std::string> threads;
{
- ATRACE_NAME("ptrace");
+ ATRACE_NAME("ptrace_interrupt");
+
// Seize the main thread.
if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
LOG(FATAL) << attach_error;
}
- // Seize the siblings.
- {
- std::set<pid_t> siblings;
- if (!android::procinfo::GetProcessTids(target, &siblings)) {
- PLOG(FATAL) << "failed to get process siblings";
- }
+ threads.emplace(main_tid, get_thread_name(main_tid));
- // but not the already attached main thread.
- siblings.erase(main_tid);
- // or the handler pseudothread.
- siblings.erase(pseudothread_tid);
+ // Seize its siblings.
+ std::set<pid_t> siblings;
+ if (!android::procinfo::GetProcessTids(target, &siblings)) {
+ PLOG(FATAL) << "failed to get process siblings";
+ }
- for (pid_t sibling_tid : siblings) {
- if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
- LOG(WARNING) << attach_error;
- } else {
- threads.emplace(sibling_tid, get_thread_name(sibling_tid));
- }
+ // but not the already attached main thread.
+ siblings.erase(main_tid);
+ // or the handler pseudothread.
+ siblings.erase(pseudothread_tid);
+
+ for (pid_t sibling_tid : siblings) {
+ if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
+ LOG(WARNING) << attach_error;
+ continue;
}
+ threads.emplace(sibling_tid, get_thread_name(sibling_tid));
}
}
@@ -334,9 +331,6 @@
populate_open_files_list(target, &open_files);
}
- std::string process_name = get_process_name(main_tid);
- threads.emplace(main_tid, get_thread_name(main_tid));
-
// Drop our capabilities now that we've attached to the threads we care about.
drop_capabilities();
@@ -347,6 +341,16 @@
tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd, dump_type_enum);
}
+ // Pause the threads.
+ {
+ ATRACE_NAME("ptrace_interrupt");
+ for (const auto& [sibling_tid, _] : threads) {
+ if (ptrace(PTRACE_INTERRUPT, sibling_tid, 0, 0) != 0) {
+ PLOG(FATAL) << "failed to interrupt thread " << sibling_tid;
+ }
+ }
+ }
+
// Write a '\1' to stdout to tell the crashing process to resume.
// It also restores the value of PR_SET_DUMPABLE at this point.
if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) {