diff options
Diffstat (limited to 'debuggerd/debuggerd.cpp')
-rw-r--r-- | debuggerd/debuggerd.cpp | 100 |
1 files changed, 98 insertions, 2 deletions
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 2ab716d..7f3fbc3 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -1,5 +1,6 @@ /* * Copyright 2006, The Android Open Source Project + * Copyright (c) 2015, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,6 +15,8 @@ * limitations under the License. */ +#define LOG_TAG "DEBUG" + #include <stdio.h> #include <errno.h> #include <signal.h> @@ -84,11 +87,13 @@ static void wait_for_user_action(const debugger_request_t &request) { "* and start gdbclient:\n" "*\n" "* gdbclient %s :5039 %d\n" + "* or\n" + "* dddclient %s :5039 %d\n" "*\n" "* Wait for gdb to start, then press the VOLUME DOWN key\n" "* to let the process continue crashing.\n" "********************************************************", - request.pid, exe, request.tid); + request.pid, exe, request.tid, exe, request.tid); // Wait for VOLUME DOWN. if (init_getevent() == 0) { @@ -134,6 +139,84 @@ static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* ou return fields == 7 ? 0 : -1; } +static bool copy_file(const char* src, char* dest) +{ + #define BUF_SIZE 64 + ssize_t bytes; + int source_fh, dest_fh; + int total_size = 0; + char buffer[BUF_SIZE]; + + if ((source_fh = open(src, O_RDONLY, O_NOFOLLOW)) == -1) { + ALOGE("Unable to open source file %s\n", src); + } else { + if((dest_fh = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0640)) == -1) { + ALOGE("Unable to write destination file %s\n", dest); + } else { + while ((bytes = read(source_fh, buffer, BUF_SIZE)) > 0) { + if (write(dest_fh, buffer, bytes) < 0) { + ALOGE("Write failed for destination file %s. Copied %d bytes\n", + dest, total_size); + break; + } + total_size += bytes; + } + ALOGI("Copied %s to %s - size: %d\n", src, dest, total_size); + fsync(dest_fh); + close(dest_fh); + } + close(source_fh); + if (total_size > 0) { + return true; + } + } + return false; +} + +static void collect_etb_map(int cr_pid) +{ + struct stat s; + char src_buf[64]; + char dest_buf[64]; + + snprintf(dest_buf, sizeof dest_buf, "/data/core/etb.%d", cr_pid); + if (!copy_file("/dev/coresight-tmc-etf", dest_buf)) { + ALOGE("Unable to copy ETB buffer file /dev/coresight-tmc-etf\n"); + } else { + memset(src_buf, 0, sizeof(src_buf)); + snprintf(src_buf, sizeof(src_buf), "/proc/%d/maps", cr_pid); + if(stat(src_buf, &s)) { + ALOGE("map file /proc/%d/maps does not exist for pid %d\n", + cr_pid, cr_pid); + } else { + snprintf(dest_buf, sizeof dest_buf, "/data/core/maps.%d", cr_pid); + if (!copy_file(src_buf, dest_buf)) { + ALOGE("Unable to copy map file /proc/%d/maps", cr_pid); + } + } + } +} + +static void enable_etb_trace(struct ucred cr) { + char value[PROPERTY_VALUE_MAX]; + property_get("persist.debug.trace", value, ""); + if ((strcmp(value,"1") == 0)) { + /* Allow ETB collection only once; Note: in future this behavior can be changed + * To allow this, use a property to indicate whether the ETB has been collected */ + property_get("debug.etb.collected", value, ""); + if(strcmp(value,"1")) { + ALOGI("Collecting ETB dumps (from pid=%d uid=%d)\n", + cr.pid, cr.uid); + property_set("debug.etb.collected", "1"); + collect_etb_map(cr.pid); + } + else { + ALOGI("ETB already collected once, skipping (from pid=%d uid=%d)\n", + cr.pid, cr.uid); + } + } +} + static int selinux_enabled; /* @@ -231,6 +314,7 @@ static int read_request(int fd, debugger_request_t* out_request) { out_request->tid, out_request->pid); return -1; } + enable_etb_trace(cr); } else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) { // Only root or system can ask us to attach to any process and dump it explicitly. @@ -256,7 +340,19 @@ static bool should_attach_gdb(debugger_request_t* request) { char value[PROPERTY_VALUE_MAX]; property_get("debug.db.uid", value, "-1"); int debug_uid = atoi(value); - return debug_uid >= 0 && request->uid <= (uid_t)debug_uid; + if (debug_uid >= 0 && request->uid <= (uid_t)debug_uid) { + return true; + } else { + /* External docs say to use 10,000 but more is likely needed; be helpful. */ + if (request->uid > (uid_t)debug_uid) { + ALOGI("request->uid:%d > property debug.db.uid:%d; NOT waiting for gdb.", + request->uid, debug_uid); + } else { + ALOGI("property debug.db.uid not set; NOT waiting for gdb."); + ALOGI("HINT: adb shell setprop debug.db.uid 100000"); + ALOGI("HINT: adb forward tcp:5039 tcp:5039"); + } + } } return false; } |