Merge "crash_dump: fetch process/thread names before dropping privileges." am: 7390d96ff2
am: d8e854fdf1
Change-Id: I5ae84b16287e9c88e73da1c250f574757e5ea635
This commit is contained in:
commit
e8a5c313b7
7 changed files with 109 additions and 100 deletions
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue