Merge "crash_dump: fetch process/thread names before dropping privileges." am: 7390d96ff2 am: d8e854fdf1

am: e8a5c313b7

Change-Id: I1d65338aa9f121b1326cdb5fc64c49b55a72a59f
This commit is contained in:
Josh Gao 2017-03-16 17:55:14 +00:00 committed by android-build-merger
commit e345ce6060
7 changed files with 109 additions and 100 deletions

View file

@ -27,6 +27,7 @@
#include <unistd.h>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <vector>
@ -36,6 +37,7 @@
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include <log/log.h>
@ -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 = "<unknown>";
ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &result);
return result;
}
static std::string get_thread_name(pid_t tid) {
std::string result = "<unknown>";
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<pid_t> attached_siblings;
std::map<pid_t, std::string> threads;
{
std::set<pid_t> 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<BacktraceMap> 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

View file

@ -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 : "<unknown>", 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(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<pid_t>& 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<pid_t, std::string>& 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), "<unknown>");
log_thread_name(&log, tid, thread_name);
std::unique_ptr<Backtrace> 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), "<unknown>");
dump_process_header(&log, getpid(), process_name);
}
void dump_backtrace_footer(int output_fd) {

View file

@ -20,7 +20,7 @@
#include <sys/types.h>
#include <sys/ucontext.h>
#include <set>
#include <map>
#include <string>
#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<pid_t>& 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<pid_t, std::string>& 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);

View file

@ -20,7 +20,8 @@
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
#include <set>
#include <map>
#include <string>
#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<pid_t>* 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<pid_t, std::string>& 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,

View file

@ -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

View file

@ -32,8 +32,10 @@
#include <memory>
#include <string>
#include <android/log.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <android/log.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <cutils/properties.h>
@ -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(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<pid_t>* 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<pid_t, std::string>& 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<pid_t>* 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<pid_t, std::string>& 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), "<unknown>");
read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
dump_thread_info(&log, pid, tid, thread_name, process_name);
dump_signal_info(&log, siginfo);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));

View file

@ -28,6 +28,7 @@
#include <string>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
@ -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);
}