summaryrefslogtreecommitdiffstats
path: root/debuggerd/debuggerd.cpp
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2016-05-05 17:55:41 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-05-05 17:55:41 +0000
commite423c24f74aaf0cb5d73a228d92ec4e4a56b0f4f (patch)
tree17621c9241f8a557aefee89e27a76b10d90d50b8 /debuggerd/debuggerd.cpp
parent6993211d38547d7007a87cbcd006f0f19c598ff9 (diff)
parenta7431cfa570c6385ecd2041d56ead2603d7b7b80 (diff)
downloadsystem_core-e423c24f74aaf0cb5d73a228d92ec4e4a56b0f4f.tar.gz
system_core-e423c24f74aaf0cb5d73a228d92ec4e4a56b0f4f.tar.bz2
system_core-e423c24f74aaf0cb5d73a228d92ec4e4a56b0f4f.zip
Merge "Fix problem with wait_for_gdb." into nyc-dev
am: a7431cfa57 * commit 'a7431cfa570c6385ecd2041d56ead2603d7b7b80': Fix problem with wait_for_gdb. Change-Id: I6d995c423f4ad9134965a215b1eea4cc7fd338b9
Diffstat (limited to 'debuggerd/debuggerd.cpp')
-rw-r--r--debuggerd/debuggerd.cpp65
1 files changed, 58 insertions, 7 deletions
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 0a43622c5..d2e6c2971 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>
@@ -287,6 +291,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);
@@ -414,7 +453,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;
@@ -432,10 +471,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) {
@@ -459,7 +498,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:
@@ -546,9 +585,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;
@@ -561,11 +602,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());
}
}
}
@@ -578,6 +619,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));
}
@@ -594,9 +642,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));