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
This commit is contained in:
Josh Gao 2017-08-18 15:37:26 -07:00
parent de6b44aa0e
commit fd13bf0dcd
2 changed files with 54 additions and 1 deletions

View File

@ -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;
}

View File

@ -16,10 +16,11 @@
#include <err.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
#include <regex>
@ -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();