diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h index ae6bfc4d0..4bcc8e6b4 100644 --- a/include/cutils/debugger.h +++ b/include/cutils/debugger.h @@ -23,10 +23,13 @@ extern "C" { #endif -#if __LP64__ -#define DEBUGGER_SOCKET_NAME "android:debuggerd64" +#define DEBUGGER32_SOCKET_NAME "android:debuggerd" +#define DEBUGGER64_SOCKET_NAME "android:debuggerd64" + +#if defined(__LP64__) +#define DEBUGGER_SOCKET_NAME DEBUGGER64_SOCKET_NAME #else -#define DEBUGGER_SOCKET_NAME "android:debuggerd" +#define DEBUGGER_SOCKET_NAME DEBUGGER32_SOCKET_NAME #endif typedef enum { @@ -45,6 +48,16 @@ typedef struct { int32_t original_si_code; } debugger_msg_t; +#if defined(__LP64__) +// For a 64 bit process to contact the 32 bit debuggerd. +typedef struct { + debugger_action_t action; + pid_t tid; + uint32_t abort_msg_address; + int32_t original_si_code; +} debugger32_msg_t; +#endif + /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root). * Stores the tombstone path in the provided buffer. * Returns 0 on success, -1 on error. diff --git a/libcutils/debugger.c b/libcutils/debugger.c index 056de5da8..4035ee160 100644 --- a/libcutils/debugger.c +++ b/libcutils/debugger.c @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include +#include #include #include #include @@ -21,70 +24,129 @@ #include #include -int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) { - int s = socket_local_client(DEBUGGER_SOCKET_NAME, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - if (s < 0) { - return -1; - } +#if defined(__LP64__) +#include - debugger_msg_t msg; - memset(&msg, 0, sizeof(msg)); +static bool is32bit(pid_t tid) { + char* exeline; + if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) { + return false; + } + int fd = open(exeline, O_RDONLY | O_CLOEXEC); + free(exeline); + if (fd == -1) { + return false; + } + + char ehdr[EI_NIDENT]; + ssize_t bytes = read(fd, &ehdr, sizeof(ehdr)); + close(fd); + if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) { + return false; + } + if (ehdr[EI_CLASS] == ELFCLASS32) { + return true; + } + return false; +} +#endif + +static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) { + int result = 0; + if (TEMP_FAILURE_RETRY(write(sock_fd, msg_ptr, msg_len)) != (ssize_t) msg_len) { + result = -1; + } else { + char ack; + if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) != 1) { + result = -1; + } + } + return result; +} + +static int make_dump_request(debugger_action_t action, pid_t tid) { + const char* socket_name; + debugger_msg_t msg; + size_t msg_len; + void* msg_ptr; + +#if defined(__LP64__) + debugger32_msg_t msg32; + if (is32bit(tid)) { + msg_len = sizeof(debugger32_msg_t); + memset(&msg32, 0, msg_len); + msg32.tid = tid; + msg32.action = action; + msg_ptr = &msg32; + + socket_name = DEBUGGER32_SOCKET_NAME; + } else +#endif + { + msg_len = sizeof(debugger_msg_t); + memset(&msg, 0, msg_len); msg.tid = tid; - msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE; + msg.action = action; + msg_ptr = &msg; - int result = 0; - if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) { - result = -1; - } else { - char ack; - if (TEMP_FAILURE_RETRY(read(s, &ack, 1)) != 1) { - result = -1; - } else { - if (pathbuf && pathlen) { - ssize_t n = TEMP_FAILURE_RETRY(read(s, pathbuf, pathlen - 1)); - if (n <= 0) { - result = -1; - } else { - pathbuf[n] = '\0'; - } - } - } - } - TEMP_FAILURE_RETRY(close(s)); - return result; + socket_name = DEBUGGER_SOCKET_NAME; + } + + int sock_fd = socket_local_client(socket_name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, + SOCK_STREAM | SOCK_CLOEXEC); + if (sock_fd < 0) { + return -1; + } + + if (send_request(sock_fd, msg_ptr, msg_len) < 0) { + TEMP_FAILURE_RETRY(close(sock_fd)); + return -1; + } + + return sock_fd; } int dump_backtrace_to_file(pid_t tid, int fd) { - int s = socket_local_client(DEBUGGER_SOCKET_NAME, - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - if (s < 0) { - return -1; - } + int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid); + if (sock_fd < 0) { + return -1; + } - debugger_msg_t msg; - memset(&msg, 0, sizeof(msg)); - msg.tid = tid; - msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE; - - int result = 0; - if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) { - result = -1; - } else { - char ack; - if (TEMP_FAILURE_RETRY(read(s, &ack, 1)) != 1) { - result = -1; - } else { - char buffer[4096]; - ssize_t n; - while ((n = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)))) > 0) { - if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) { - result = -1; - break; - } - } - } + /* Write the data read from the socket to the fd. */ + int result = 0; + char buffer[1024]; + ssize_t n; + while ((n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) { + if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) { + result = -1; + break; } - TEMP_FAILURE_RETRY(close(s)); - return result; + } + TEMP_FAILURE_RETRY(close(sock_fd)); + return result; +} + +int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) { + int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid); + if (sock_fd < 0) { + return -1; + } + + /* Read the tombstone file name. */ + char buffer[100]; /* This is larger than the largest tombstone path. */ + int result = 0; + ssize_t n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer) - 1)); + if (n <= 0) { + result = -1; + } else { + if (pathbuf && pathlen) { + if (n >= (ssize_t) pathlen) { + n = pathlen - 1; + } + buffer[n] = '\0'; + memcpy(pathbuf, buffer, n + 1); + } + } + TEMP_FAILURE_RETRY(close(sock_fd)); + return result; }