debuggerd: use One True timestamp function.

An OEM asks for sub-second granularity, and that's most easily done if
we only have one timestamp generator. I'm not convinced sub-second
granularity is particularly useful myself, and I definitely don't think
that nanosecond resolution is meaningful but I do like this cleanup, and
if I'm going to use sub-second precision I may as well use the maximum
precision available to me.

Also reduce some duplication of code reading cmdline/comm.

Bug: https://issuetracker.google.com/161860597
Test: head /data/tombstones/*
Change-Id: I035ecfd4a3338ccd84dae0ef973a998a7c7c5056
This commit is contained in:
Elliott Hughes 2020-07-23 15:26:10 -07:00
parent 4aa073337d
commit a660cb3f13
8 changed files with 38 additions and 92 deletions

View File

@ -70,36 +70,6 @@ static void populate_timeval(struct timeval* tv, const Duration& duration) {
tv->tv_usec = static_cast<long>(microseconds.count());
}
static void get_wchan_header(pid_t pid, std::stringstream& buffer) {
struct tm now;
time_t t = time(nullptr);
localtime_r(&t, &now);
char timestamp[32];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &now);
std::string time_now(timestamp);
std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
char proc_name_buf[1024];
const char* proc_name = nullptr;
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path.c_str(), "r"), &fclose);
if (fp) {
proc_name = fgets(proc_name_buf, sizeof(proc_name_buf), fp.get());
}
if (!proc_name) {
proc_name = "<unknown>";
}
buffer << "\n----- Waiting Channels: pid " << pid << " at " << time_now << " -----\n"
<< "Cmd line: " << proc_name << "\n";
}
static void get_wchan_footer(pid_t pid, std::stringstream& buffer) {
buffer << "----- end " << std::to_string(pid) << " -----\n";
}
/**
* Returns the wchan data for each thread in the process,
* or empty string if unable to obtain any data.
@ -125,9 +95,10 @@ static std::string get_wchan_data(pid_t pid) {
}
if (std::string str = data.str(); !str.empty()) {
get_wchan_header(pid, buffer);
buffer << "\n----- Waiting Channels: pid " << pid << " at " << get_timestamp() << " -----\n"
<< "Cmd line: " << get_process_name(pid) << "\n";
buffer << "\n" << str << "\n";
get_wchan_footer(pid, buffer);
buffer << "----- end " << std::to_string(pid) << " -----\n";
buffer << "\n";
}

View File

@ -27,7 +27,6 @@
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <map>
@ -40,14 +39,10 @@
#include "libdebuggerd/types.h"
#include "libdebuggerd/utility.h"
#include "util.h"
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);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, get_timestamp().c_str());
if (process_name) {
_LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name);
@ -106,9 +101,8 @@ void dump_backtrace_header(int output_fd) {
log.tfd = output_fd;
log.amfd_data = nullptr;
char process_name[128];
read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
dump_process_header(&log, getpid(), process_name);
pid_t pid = getpid();
dump_process_header(&log, pid, get_process_name(pid).c_str());
}
void dump_backtrace_footer(int output_fd) {

View File

@ -83,8 +83,6 @@ void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* pref
void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
void drop_capabilities();
bool signal_has_sender(const siginfo_t*, pid_t caller_pid);

View File

@ -359,13 +359,6 @@ TEST_F(TombstoneTest, dump_thread_info_uid) {
ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}
TEST_F(TombstoneTest, dump_timestamp) {
setenv("TZ", "UTC", 1);
tzset();
dump_timestamp(&log_, 0);
ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
}
class GwpAsanCrashDataTest : public GwpAsanCrashData {
public:
GwpAsanCrashDataTest(

View File

@ -58,6 +58,7 @@
#include "libdebuggerd/open_files_list.h"
#include "libdebuggerd/scudo.h"
#include "libdebuggerd/utility.h"
#include "util.h"
#include "gwp_asan/common.h"
#include "gwp_asan/crash_handler.h"
@ -80,15 +81,6 @@ static void dump_header_info(log_t* log) {
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
static void dump_timestamp(log_t* log, time_t time) {
struct tm tm;
localtime_r(&time, &tm);
char buf[strlen("1970-01-01 00:00:00+0830") + 1];
strftime(buf, sizeof(buf), "%F %T%z", &tm);
_LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
}
static std::string get_stack_overflow_cause(uint64_t fault_addr, uint64_t sp,
unwindstack::Maps* maps) {
static constexpr uint64_t kMaxDifferenceBytes = 256;
@ -507,10 +499,9 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned
// (although in this case the pid is redundant).
char timeBuf[32];
time_t sec = static_cast<time_t>(log_entry.entry.sec);
struct tm tmBuf;
struct tm* ptm;
ptm = localtime_r(&sec, &tmBuf);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
tm tm;
localtime_r(&sec, &tm);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", &tm);
char* msg = log_entry.msg();
if (msg == nullptr) {
@ -571,23 +562,20 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si
log.tfd = tombstone_fd;
log.amfd_data = nullptr;
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>");
std::string thread_name = get_thread_name(tid);
std::string process_name = get_process_name(pid);
std::unique_ptr<unwindstack::Regs> regs(
unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
std::map<pid_t, ThreadInfo> threads;
threads[gettid()] = ThreadInfo{
threads[tid] = ThreadInfo{
.registers = std::move(regs),
.uid = uid,
.tid = tid,
.thread_name = thread_name,
.thread_name = thread_name.c_str(),
.pid = pid,
.process_name = process_name,
.process_name = process_name.c_str(),
.siginfo = siginfo,
};
@ -606,8 +594,8 @@ void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
const ProcessInfo& process_info, OpenFilesList* open_files,
std::string* amfd_data) {
// don't copy log messages to tombstone unless this is a dev device
bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
// Don't copy log messages to tombstone unless this is a development device.
bool want_logs = GetBoolProperty("ro.debuggable", false);
log_t log;
log.current_tid = target_thread;
@ -617,7 +605,7 @@ void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
_LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_header_info(&log);
dump_timestamp(&log, time(nullptr));
_LOG(&log, logtype::HEADER, "Timestamp: %s\n", get_timestamp().c_str());
auto it = threads.find(target_thread);
if (it == threads.end()) {

View File

@ -226,23 +226,6 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s
}
}
void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
unique_fd fd(open(path, O_RDONLY | O_CLOEXEC));
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);
}
void drop_capabilities() {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));

View File

@ -17,6 +17,7 @@
#include "util.h"
#include <sys/socket.h>
#include <time.h>
#include <string>
#include <utility>
@ -38,3 +39,19 @@ std::string get_thread_name(pid_t tid) {
android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/comm", tid), &result);
return android::base::Trim(result);
}
std::string get_timestamp() {
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
tm tm;
localtime_r(&ts.tv_sec, &tm);
char buf[strlen("1970-01-01 00:00:00.123456789+0830") + 1];
char* s = buf;
size_t sz = sizeof(buf), n;
n = strftime(s, sz, "%F %H:%M", &tm), s += n, sz -= n;
n = snprintf(s, sz, ":%02d.%09ld", tm.tm_sec, ts.tv_nsec), s += n, sz -= n;
n = strftime(s, sz, "%z", &tm), s += n, sz -= n;
return buf;
}

View File

@ -23,3 +23,5 @@
std::string get_process_name(pid_t pid);
std::string get_thread_name(pid_t tid);
std::string get_timestamp();