crash_dump: set a watchdog timer.

PTRACE_DETACH is only necessary if the process is in group-stop state,
the tracer exiting is sufficient to detach and resume tracees.

Using this, set a 5 second timer with alarm(2) that just kills us, to
avoid leaving processes stopped.

Bug: http://b/34472671
Test: debuggerd_test
Test: crasher + manually inserting a 10 second sleep into crash_dump
Change-Id: Iacaa796f79037aa1585f3f2159abe45ef0069311
This commit is contained in:
Josh Gao 2017-01-22 17:59:02 -08:00
parent 122479f4a0
commit 7c6e3133f5
2 changed files with 31 additions and 39 deletions

View File

@ -257,6 +257,9 @@ int main(int argc, char** argv) {
exit(0);
}
// Die if we take too long.
alarm(20);
check_process(target_proc_fd, target);
std::string attach_error;
@ -316,10 +319,9 @@ int main(int argc, char** argv) {
// Now that we have the signal that kicked things off, attach all of the
// sibling threads, and then proceed.
bool fatal_signal = signo != DEBUGGER_SIGNAL;
int resume_signal = fatal_signal ? signo : 0;
std::set<pid_t> siblings;
std::set<pid_t> attached_siblings;
if (resume_signal == 0) {
if (fatal_signal) {
if (!android::procinfo::GetProcessTids(target, &siblings)) {
PLOG(FATAL) << "failed to get process siblings";
}
@ -352,40 +354,39 @@ int main(int argc, char** argv) {
attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
}
// We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
// group-stop state, which is true as long as no stopping signals are sent.
bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
if (wait_for_gdb) {
if (!fatal_signal || siginfo.si_code == SI_USER) {
// Don't wait_for_gdb when the process didn't actually crash.
if (!fatal_signal) {
wait_for_gdb = false;
} else {
// Use ALOGI to line up with output from engrave_tombstone.
ALOGI(
"***********************************************************\n"
"* Process %d has been suspended while crashing.\n"
"* To attach gdbserver and start gdb, run this on the host:\n"
"*\n"
"* gdbclient.py -p %d\n"
"*\n"
"***********************************************************",
target, main_tid);
}
wait_for_gdb = false;
}
for (pid_t tid : attached_siblings) {
// Don't send the signal to sibling threads.
if (ptrace(PTRACE_DETACH, tid, 0, wait_for_gdb ? SIGSTOP : 0) != 0) {
PLOG(ERROR) << "ptrace detach from " << tid << " failed";
// If the process crashed or we need to send it SIGSTOP for wait_for_gdb,
// get it in a state where it can receive signals, and then send the relevant
// signal.
if (wait_for_gdb || fatal_signal) {
if (ptrace(PTRACE_INTERRUPT, main_tid, 0, 0) != 0) {
PLOG(ERROR) << "failed to use PTRACE_INTERRUPT on " << main_tid;
}
}
if (ptrace(PTRACE_DETACH, main_tid, 0, wait_for_gdb ? SIGSTOP : resume_signal)) {
PLOG(ERROR) << "ptrace detach from main thread " << main_tid << " failed";
if (tgkill(target, main_tid, wait_for_gdb ? SIGSTOP : signo) != 0) {
PLOG(ERROR) << "failed to resend signal " << signo << " to " << main_tid;
}
}
if (wait_for_gdb) {
if (tgkill(target, main_tid, resume_signal) != 0) {
PLOG(ERROR) << "failed to resend signal to process " << target;
}
// Use ALOGI to line up with output from engrave_tombstone.
ALOGI(
"***********************************************************\n"
"* Process %d has been suspended while crashing.\n"
"* To attach gdbserver and start gdb, run this on the host:\n"
"*\n"
"* gdbclient.py -p %d\n"
"*\n"
"***********************************************************",
target, main_tid);
}
if (fatal_signal) {

View File

@ -340,24 +340,15 @@ TEST_F(CrasherTest, wait_for_gdb) {
AssertDeath(SIGABRT);
}
// wait_for_gdb shouldn't trigger on manually sent signals.
TEST_F(CrasherTest, wait_for_gdb_signal) {
if (!android::base::SetProperty(kWaitForGdbKey, "1")) {
FAIL() << "failed to enable wait_for_gdb";
}
StartCrasher("abort");
ASSERT_EQ(0, kill(crasher_pid, SIGABRT)) << strerror(errno);
std::this_thread::sleep_for(500ms);
int status;
ASSERT_EQ(crasher_pid, (TIMEOUT(1, waitpid(crasher_pid, &status, WUNTRACED))));
ASSERT_TRUE(WIFSTOPPED(status));
ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
ASSERT_EQ(0, kill(crasher_pid, SIGCONT)) << strerror(errno);
AssertDeath(SIGABRT);
ASSERT_EQ(0, kill(crasher_pid, SIGSEGV)) << strerror(errno);
AssertDeath(SIGSEGV);
}
TEST_F(CrasherTest, backtrace) {