From fd13bf0dcd374e98a3acd8e3d3672221aef94c7c Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 18 Aug 2017 15:37:26 -0700 Subject: [PATCH] crash_dump: print the identity of tracers. Instead of printing a useless "ptrace attach failed: strerror(EPERM)" message, print the name and pid of a competing tracer when we fail to attach because a process is already being ptraced. Bug: http://b/31531918 Test: debuggerd_test32, debuggerd_test64 on aosp_angler Test: strace -p `pidof surfaceflinger`; debuggerd -b surfaceflinger Change-Id: Ifd3f80fe03de30ff38c0e0068560a7b12875f29d --- debuggerd/crash_dump.cpp | 18 ++++++++++++++++++ debuggerd/debuggerd_test.cpp | 37 +++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 4b1e51dde..cd1da50f5 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -79,9 +79,27 @@ static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0; } +static pid_t get_tracer(pid_t tracee) { + // Check to see if the thread is being ptraced by another process. + android::procinfo::ProcessInfo process_info; + if (android::procinfo::GetProcessInfo(tracee, &process_info)) { + return process_info.tracer; + } + return -1; +} + // Attach to a thread, and verify that it's still a member of the given process static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) { if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) { + if (errno == EPERM) { + pid_t tracer = get_tracer(tid); + if (tracer != -1) { + *error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid, + tracer, get_process_name(tracer).c_str()); + return false; + } + } + *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno)); return false; } diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index b51fc665e..dbf81a4ee 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -16,10 +16,11 @@ #include #include -#include #include #include +#include #include +#include #include #include @@ -569,6 +570,40 @@ TEST_F(CrasherTest, fake_pid) { ASSERT_BACKTRACE_FRAME(result, "tgkill"); } +TEST_F(CrasherTest, competing_tracer) { + int intercept_result; + unique_fd output_fd; + StartProcess([]() { + while (true) { + } + }); + + StartIntercept(&output_fd); + FinishCrasher(); + + ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0)); + ASSERT_EQ(0, kill(crasher_pid, SIGABRT)); + + int status; + ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0)); + ASSERT_TRUE(WIFSTOPPED(status)); + ASSERT_EQ(SIGABRT, WSTOPSIG(status)); + + ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT)); + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + std::string regex = R"(failed to attach to thread \d+, already traced by )"; + regex += std::to_string(gettid()); + regex += R"( \(.+debuggerd_test)"; + ASSERT_MATCH(result, regex.c_str()); + + ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT)); + AssertDeath(SIGABRT); +} + TEST(crash_dump, zombie) { pid_t forkpid = fork();