diff options
author | Christopher Ferris <cferris@google.com> | 2016-05-03 16:32:13 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2016-05-04 17:42:30 -0700 |
commit | 9818bd2bbee00c387247210eeae2a0a0d3912c8b (patch) | |
tree | a8aac80e865924f6d55359c314ce3f0b4452962b /debuggerd/debuggerd.cpp | |
parent | f2049163a4ce602dffaa41a747ee5675a0d82752 (diff) |
Fix problem with wait_for_gdb.
When someone enables wait_for_gdb, activity manager will kill the
stopped process before a developer can attach to the process. To
allow debugging in this case, change the code to only contact the
activity manager right before continuing the process that is
crashing.
Also, modify the conditions under which to do a gdb attach. The previous
code did a partial attach if perform_dump failed. The new version simply
allows an attach regardless of whether perform_dump passes or fails.
Bug: 28409358
Change-Id: I4fe8d390c212d47e007cbe6543c2d114c3c7aeff
Diffstat (limited to 'debuggerd/debuggerd.cpp')
-rw-r--r-- | debuggerd/debuggerd.cpp | 65 |
1 files changed, 58 insertions, 7 deletions
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 7f0e5bb19..b90a5e00c 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <arpa/inet.h> #include <dirent.h> #include <elf.h> #include <errno.h> @@ -32,12 +33,15 @@ #include <sys/un.h> #include <time.h> +#include <memory> #include <set> +#include <string> #include <selinux/android.h> #include <log/logger.h> +#include <android-base/file.h> #include <android-base/unique_fd.h> #include <cutils/debugger.h> #include <cutils/properties.h> @@ -288,6 +292,41 @@ static int activity_manager_connect() { return amfd.release(); } +static void activity_manager_write(int pid, int signal, int amfd, const std::string& amfd_data) { + if (amfd == -1) { + return; + } + + // Activity Manager protocol: binary 32-bit network-byte-order ints for the + // pid and signal number, followed by the raw text of the dump, culminating + // in a zero byte that marks end-of-data. + uint32_t datum = htonl(pid); + if (!android::base::WriteFully(amfd, &datum, 4)) { + ALOGE("AM pid write failed: %s\n", strerror(errno)); + return; + } + datum = htonl(signal); + if (!android::base::WriteFully(amfd, &datum, 4)) { + ALOGE("AM signal write failed: %s\n", strerror(errno)); + return; + } + + if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size())) { + ALOGE("AM data write failed: %s\n", strerror(errno)); + return; + } + + // Send EOD to the Activity Manager, then wait for its ack to avoid racing + // ahead and killing the target out from under it. + uint8_t eodMarker = 0; + if (!android::base::WriteFully(amfd, &eodMarker, 1)) { + ALOGE("AM eod write failed: %s\n", strerror(errno)); + return; + } + // 3 sec timeout reading the ack; we're fine if the read fails. + android::base::ReadFully(amfd, &eodMarker, 1); +} + static bool should_attach_gdb(const debugger_request_t& request) { if (request.action == DEBUGGER_ACTION_CRASH) { return property_get_bool("debug.debuggerd.wait_for_gdb", false); @@ -415,7 +454,7 @@ static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) { static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd, BacktraceMap* backtrace_map, const std::set<pid_t>& siblings, - int* crash_signal, int amfd) { + int* crash_signal, std::string* amfd_data) { if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) { ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno)); return false; @@ -433,10 +472,10 @@ static bool perform_dump(const debugger_request_t& request, int fd, int tombston if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) { ALOGV("debuggerd: stopped -- dumping to tombstone"); engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal, - request.original_si_code, request.abort_msg_address, amfd); + request.original_si_code, request.abort_msg_address, amfd_data); } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) { ALOGV("debuggerd: stopped -- dumping to fd"); - dump_backtrace(fd, -1, backtrace_map, request.pid, request.tid, siblings); + dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr); } else { ALOGV("debuggerd: stopped -- continuing"); if (ptrace(PTRACE_CONT, request.tid, 0, 0) != 0) { @@ -460,7 +499,7 @@ static bool perform_dump(const debugger_request_t& request, int fd, int tombston ALOGV("stopped -- fatal signal\n"); *crash_signal = signal; engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal, - request.original_si_code, request.abort_msg_address, amfd); + request.original_si_code, request.abort_msg_address, amfd_data); break; default: @@ -547,9 +586,11 @@ static void worker_process(int fd, debugger_request_t& request) { std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid)); int amfd = -1; + std::unique_ptr<std::string> amfd_data; if (request.action == DEBUGGER_ACTION_CRASH) { // Connect to the activity manager before dropping privileges. amfd = activity_manager_connect(); + amfd_data.reset(new std::string); } bool succeeded = false; @@ -562,11 +603,11 @@ static void worker_process(int fd, debugger_request_t& request) { int crash_signal = SIGKILL; succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings, - &crash_signal, amfd); + &crash_signal, amfd_data.get()); if (succeeded) { if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) { if (!tombstone_path.empty()) { - write(fd, tombstone_path.c_str(), tombstone_path.length()); + android::base::WriteFully(fd, tombstone_path.c_str(), tombstone_path.length()); } } } @@ -579,6 +620,13 @@ static void worker_process(int fd, debugger_request_t& request) { } } + if (!attach_gdb) { + // Tell the Activity Manager about the crashing process. If we are + // waiting for gdb to attach, do not send this or Activity Manager + // might kill the process before anyone can attach. + activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get()); + } + if (ptrace(PTRACE_DETACH, request.tid, 0, 0) != 0) { ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno)); } @@ -595,9 +643,12 @@ static void worker_process(int fd, debugger_request_t& request) { } // Wait for gdb, if requested. - if (attach_gdb && succeeded) { + if (attach_gdb) { wait_for_user_action(request); + // Now tell the activity manager about this process. + activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get()); + // Tell the signal process to send SIGCONT to the target. if (!send_signal(request.pid, 0, SIGCONT)) { ALOGE("debuggerd: failed to resume process %d: %s", request.pid, strerror(errno)); |