diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 38b711ff4..88f390b0e 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +54,21 @@ #include "debuggerd/util.h" using android::base::unique_fd; +using android::base::ReadFileToString; using android::base::StringPrintf; +using android::base::Trim; + +static std::string get_process_name(pid_t pid) { + std::string result = ""; + ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &result); + return result; +} + +static std::string get_thread_name(pid_t tid) { + std::string result = ""; + ReadFileToString(StringPrintf("/proc/%d/comm", tid), &result); + return Trim(result); +} static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { struct stat st; @@ -253,7 +269,7 @@ int main(int argc, char** argv) { } // Seize the siblings. - std::set attached_siblings; + std::map threads; { std::set siblings; if (!android::procinfo::GetProcessTids(target, &siblings)) { @@ -269,12 +285,12 @@ int main(int argc, char** argv) { if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) { LOG(WARNING) << attach_error; } else { - attached_siblings.insert(sibling_tid); + threads.emplace(sibling_tid, get_thread_name(sibling_tid)); } } } - // Collect the backtrace map and open files, while the process still has PR_GET_DUMPABLE=1 + // Collect the backtrace map, open files, and process/thread names, while we still have caps. std::unique_ptr backtrace_map(BacktraceMap::Create(main_tid)); if (!backtrace_map) { LOG(FATAL) << "failed to create backtrace map"; @@ -284,6 +300,9 @@ int main(int argc, char** argv) { OpenFilesList open_files; populate_open_files_list(target, &open_files); + std::string process_name = get_process_name(main_tid); + threads.emplace(main_tid, get_thread_name(main_tid)); + // Drop our capabilities now that we've attached to the threads we care about. drop_capabilities(); @@ -341,10 +360,10 @@ int main(int argc, char** argv) { std::string amfd_data; if (backtrace) { - dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0); + dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, process_name, threads, 0); } else { engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid, - &attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr); + process_name, threads, abort_address, fatal_signal ? &amfd_data : nullptr); } // We don't actually need to PTRACE_DETACH, as long as our tracees aren't in diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp index df49aef37..334d97f33 100644 --- a/debuggerd/libdebuggerd/backtrace.cpp +++ b/debuggerd/libdebuggerd/backtrace.cpp @@ -38,18 +38,7 @@ #include "utility.h" -static void dump_process_header(log_t* log, pid_t pid) { - char path[PATH_MAX]; - char procnamebuf[1024]; - char* procname = NULL; - FILE* fp; - - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - if ((fp = fopen(path, "r"))) { - procname = fgets(procnamebuf, sizeof(procnamebuf), fp); - fclose(fp); - } - +static void dump_process_header(log_t* log, pid_t pid, const char* process_name) { time_t t = time(NULL); struct tm tm; localtime_r(&t, &tm); @@ -57,8 +46,8 @@ static void dump_process_header(log_t* log, pid_t pid) { strftime(timestr, sizeof(timestr), "%F %T", &tm); _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr); - if (procname) { - _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname); + if (process_name) { + _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name); } _LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING); } @@ -67,28 +56,13 @@ static void dump_process_footer(log_t* log, pid_t pid) { _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid); } -static void log_thread_name(log_t* log, pid_t tid) { - FILE* fp; - char buf[1024]; - char path[PATH_MAX]; - char* threadname = NULL; - - snprintf(path, sizeof(path), "/proc/%d/comm", tid); - if ((fp = fopen(path, "r"))) { - threadname = fgets(buf, sizeof(buf), fp); - fclose(fp); - if (threadname) { - size_t len = strlen(threadname); - if (len && threadname[len - 1] == '\n') { - threadname[len - 1] = '\0'; - } - } - } - _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "", tid); +static void log_thread_name(log_t* log, pid_t tid, const char* thread_name) { + _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread_name, tid); } -static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) { - log_thread_name(log, tid); +static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid, + const std::string& thread_name) { + log_thread_name(log, tid, thread_name.c_str()); std::unique_ptr backtrace(Backtrace::Create(pid, tid, map)); if (backtrace->Unwind(0)) { @@ -99,17 +73,21 @@ static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) { } } -void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, - const std::set& siblings, std::string* amfd_data) { +void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name, + const std::map& threads, std::string* amfd_data) { log_t log; log.tfd = fd; log.amfd_data = amfd_data; - dump_process_header(&log, pid); - dump_thread(&log, map, pid, tid); + dump_process_header(&log, pid, process_name.c_str()); + dump_thread(&log, map, pid, tid, threads.find(tid)->second.c_str()); - for (pid_t sibling : siblings) { - dump_thread(&log, map, pid, sibling); + for (const auto& it : threads) { + pid_t thread_tid = it.first; + const std::string& thread_name = it.second; + if (thread_tid != tid) { + dump_thread(&log, map, pid, thread_tid, thread_name.c_str()); + } } dump_process_footer(&log, pid); @@ -123,7 +101,9 @@ void dump_backtrace_ucontext(int output_fd, ucontext_t* ucontext) { log.tfd = output_fd; log.amfd_data = nullptr; - log_thread_name(&log, tid); + char thread_name[16]; + read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), ""); + log_thread_name(&log, tid, thread_name); std::unique_ptr backtrace(Backtrace::Create(pid, tid)); if (backtrace->Unwind(0, ucontext)) { @@ -139,7 +119,9 @@ void dump_backtrace_header(int output_fd) { log.tfd = output_fd; log.amfd_data = nullptr; - dump_process_header(&log, getpid()); + char process_name[128]; + read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), ""); + dump_process_header(&log, getpid(), process_name); } void dump_backtrace_footer(int output_fd) { diff --git a/debuggerd/libdebuggerd/include/backtrace.h b/debuggerd/libdebuggerd/include/backtrace.h index 5bfdac8fc..fe738f1c7 100644 --- a/debuggerd/libdebuggerd/include/backtrace.h +++ b/debuggerd/libdebuggerd/include/backtrace.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include "utility.h" @@ -30,8 +30,8 @@ class BacktraceMap; // Dumps a backtrace using a format similar to what Dalvik uses so that the result // can be intermixed in a bug report. -void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, - const std::set& siblings, std::string* amfd_data); +void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid, const std::string& process_name, + const std::map& threads, std::string* amfd_data); /* Dumps the backtrace in the backtrace data structure to the log. */ void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix); diff --git a/debuggerd/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/tombstone.h index d2a4a4bb7..79743b61c 100644 --- a/debuggerd/libdebuggerd/include/tombstone.h +++ b/debuggerd/libdebuggerd/include/tombstone.h @@ -20,7 +20,8 @@ #include #include #include -#include + +#include #include #include "open_files_list.h" @@ -34,9 +35,9 @@ class BacktraceMap; int open_tombstone(std::string* path); /* Creates a tombstone file and writes the crash dump to it. */ -void engrave_tombstone(int tombstone_fd, BacktraceMap* map, - const OpenFilesList* open_files, pid_t pid, pid_t tid, - const std::set* siblings, uintptr_t abort_msg_address, +void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files, + pid_t pid, pid_t tid, const std::string& process_name, + const std::map& threads, uintptr_t abort_msg_address, std::string* amfd_data); void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo, diff --git a/debuggerd/libdebuggerd/include/utility.h b/debuggerd/libdebuggerd/include/utility.h index bbc45468b..e5e510634 100644 --- a/debuggerd/libdebuggerd/include/utility.h +++ b/debuggerd/libdebuggerd/include/utility.h @@ -83,4 +83,6 @@ bool wait_for_signal(pid_t tid, siginfo_t* siginfo); void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...); +void read_with_default(const char* path, char* buf, size_t len, const char* default_value); + #endif // _DEBUGGERD_UTILITY_H diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index c05ccc358..c23da4415 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -32,8 +32,10 @@ #include #include -#include +#include #include +#include +#include #include #include #include @@ -247,41 +249,16 @@ static void dump_signal_info(log_t* log, pid_t tid) { dump_signal_info(log, &si); } -static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) { - char path[64]; - char threadnamebuf[1024]; - char* threadname = nullptr; - FILE *fp; - - snprintf(path, sizeof(path), "/proc/%d/comm", tid); - if ((fp = fopen(path, "r"))) { - threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp); - fclose(fp); - if (threadname) { - size_t len = strlen(threadname); - if (len && threadname[len - 1] == '\n') { - threadname[len - 1] = '\0'; - } - } - } +static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, const char* process_name, + const char* thread_name) { // Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ... - static const char logd[] = "logd"; - if (threadname != nullptr && !strncmp(threadname, logd, sizeof(logd) - 1) - && (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) { + // TODO: Why is this controlled by thread name? + if (strcmp(thread_name, "logd") == 0 || strncmp(thread_name, "logd.", 4) == 0) { log->should_retrieve_logcat = false; } - char procnamebuf[1024]; - char* procname = nullptr; - - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - if ((fp = fopen(path, "r"))) { - procname = fgets(procnamebuf, sizeof(procnamebuf), fp); - fclose(fp); - } - - _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, - threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN"); + _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, thread_name, + process_name); } static void dump_stack_segment( @@ -493,13 +470,14 @@ static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) { } } -static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map, +static void dump_thread(log_t* log, pid_t pid, pid_t tid, const std::string& process_name, + const std::string& thread_name, BacktraceMap* map, uintptr_t abort_msg_address, bool primary_thread) { log->current_tid = tid; if (!primary_thread) { _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); } - dump_thread_info(log, pid, tid); + dump_thread_info(log, pid, tid, process_name.c_str(), thread_name.c_str()); dump_signal_info(log, tid); std::unique_ptr backtrace(Backtrace::Create(pid, tid, map)); @@ -654,9 +632,9 @@ static void dump_logs(log_t* log, pid_t pid, unsigned int tail) { } // Dumps all information about the specified pid to the tombstone. -static void dump_crash(log_t* log, BacktraceMap* map, - const OpenFilesList* open_files, pid_t pid, pid_t tid, - const std::set* siblings, uintptr_t abort_msg_address) { +static void dump_crash(log_t* log, BacktraceMap* map, const OpenFilesList* open_files, pid_t pid, + pid_t tid, const std::string& process_name, + const std::map& threads, uintptr_t abort_msg_address) { // don't copy log messages to tombstone unless this is a dev device char value[PROPERTY_VALUE_MAX]; property_get("ro.debuggable", value, "0"); @@ -665,14 +643,17 @@ static void dump_crash(log_t* log, BacktraceMap* map, _LOG(log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); dump_header_info(log); - dump_thread(log, pid, tid, map, abort_msg_address, true); + dump_thread(log, pid, tid, process_name, threads.find(tid)->second, map, abort_msg_address, true); if (want_logs) { dump_logs(log, pid, 5); } - if (siblings && !siblings->empty()) { - for (pid_t sibling : *siblings) { - dump_thread(log, pid, sibling, map, 0, false); + for (const auto& it : threads) { + pid_t thread_tid = it.first; + const std::string& thread_name = it.second; + + if (thread_tid != tid) { + dump_thread(log, pid, thread_tid, process_name, thread_name, map, 0, false); } } @@ -739,16 +720,16 @@ int open_tombstone(std::string* out_path) { return fd; } -void engrave_tombstone(int tombstone_fd, BacktraceMap* map, - const OpenFilesList* open_files, pid_t pid, pid_t tid, - const std::set* siblings, uintptr_t abort_msg_address, +void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files, + pid_t pid, pid_t tid, const std::string& process_name, + const std::map& threads, uintptr_t abort_msg_address, std::string* amfd_data) { log_t log; log.current_tid = tid; log.crashed_tid = tid; log.tfd = tombstone_fd; log.amfd_data = amfd_data; - dump_crash(&log, map, open_files, pid, tid, siblings, abort_msg_address); + dump_crash(&log, map, open_files, pid, tid, process_name, threads, abort_msg_address); } void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo, @@ -762,7 +743,13 @@ void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, s log.tfd = tombstone_fd; log.amfd_data = nullptr; - dump_thread_info(&log, pid, tid); + char thread_name[16]; + char process_name[128]; + + read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), ""); + read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), ""); + + dump_thread_info(&log, pid, tid, thread_name, process_name); dump_signal_info(&log, siginfo); std::unique_ptr backtrace(Backtrace::Create(pid, tid)); diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 744cd72af..22fde5ea4 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -202,3 +203,20 @@ void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* f _LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str()); } } + +void read_with_default(const char* path, char* buf, size_t len, const char* default_value) { + android::base::unique_fd fd(open(path, O_RDONLY)); + if (fd != -1) { + int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1)); + if (rc != -1) { + buf[rc] = '\0'; + + // Trim trailing newlines. + if (rc > 0 && buf[rc - 1] == '\n') { + buf[rc - 1] = '\0'; + } + return; + } + } + strcpy(buf, default_value); +}