diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp index 6bfb5f2c2..530e0e88f 100644 --- a/debuggerd/client/debuggerd_client.cpp +++ b/debuggerd/client/debuggerd_client.cpp @@ -96,7 +96,7 @@ static std::string get_wchan_data(pid_t pid) { if (std::string str = data.str(); !str.empty()) { buffer << "\n----- Waiting Channels: pid " << pid << " at " << get_timestamp() << " -----\n" - << "Cmd line: " << get_process_name(pid) << "\n"; + << "Cmd line: " << android::base::Join(get_command_line(pid), " ") << "\n"; buffer << "\n" << str << "\n"; buffer << "----- end " << std::to_string(pid) << " -----\n"; buffer << "\n"; diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 04e1e4ee3..a15274019 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -450,9 +450,6 @@ int main(int argc, char** argv) { // unwind, do not make this too small. b/62828735 alarm(30 * android::base::HwTimeoutMultiplier()); - // Get the process name (aka cmdline). - std::string process_name = get_process_name(g_target_thread); - // Collect the list of open files. OpenFilesList open_files; { @@ -489,7 +486,6 @@ int main(int argc, char** argv) { info.pid = target_process; info.tid = thread; info.uid = getuid(); - info.process_name = process_name; info.thread_name = get_thread_name(thread); unique_fd attr_fd(openat(target_proc_fd, "attr/current", O_RDONLY | O_CLOEXEC)); @@ -517,6 +513,8 @@ int main(int argc, char** argv) { ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info); info.siginfo = &siginfo; info.signo = info.siginfo->si_signo; + + info.command_line = get_command_line(g_target_thread); } else { info.registers.reset(unwindstack::Regs::RemoteGet(thread)); if (!info.registers) { diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp index c543a8392..fd9103824 100644 --- a/debuggerd/libdebuggerd/backtrace.cpp +++ b/debuggerd/libdebuggerd/backtrace.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -42,11 +43,12 @@ #include "libdebuggerd/utility.h" #include "util.h" -static void dump_process_header(log_t* log, pid_t pid, const char* process_name) { +static void dump_process_header(log_t* log, pid_t pid, + const std::vector& command_line) { _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); + if (!command_line.empty()) { + _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", android::base::Join(command_line, " ").c_str()); } _LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING); } @@ -89,7 +91,7 @@ void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* u return; } - dump_process_header(&log, target->second.pid, target->second.process_name.c_str()); + dump_process_header(&log, target->second.pid, target->second.command_line); dump_backtrace_thread(output_fd.get(), unwinder, target->second); for (const auto& [tid, info] : thread_info) { @@ -107,7 +109,7 @@ void dump_backtrace_header(int output_fd) { log.amfd_data = nullptr; pid_t pid = getpid(); - dump_process_header(&log, pid, get_process_name(pid).c_str()); + dump_process_header(&log, pid, get_command_line(pid)); } void dump_backtrace_footer(int output_fd) { diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h index dcb52f92a..086dc97da 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h @@ -18,6 +18,7 @@ #include #include +#include #include @@ -32,13 +33,14 @@ struct ThreadInfo { pid_t pid; - std::string process_name; + std::vector command_line; std::string selinux_label; int signo = 0; siginfo_t* siginfo = nullptr; }; +// This struct is written into a pipe from inside the crashing process. struct ProcessInfo { uintptr_t abort_msg_address = 0; uintptr_t fdsan_table_address = 0; diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp index 79ac122a7..a14dcb0e7 100644 --- a/debuggerd/libdebuggerd/test/tombstone_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp @@ -350,11 +350,11 @@ TEST_F(TombstoneTest, dump_header_info) { } TEST_F(TombstoneTest, dump_thread_info_uid) { - dump_thread_info(&log_, ThreadInfo{.uid = 1, - .tid = 3, - .thread_name = "some_thread", - .pid = 2, - .process_name = "some_process"}); + std::vector cmdline = {"some_process"}; + dump_thread_info( + &log_, + ThreadInfo{ + .uid = 1, .tid = 3, .thread_name = "some_thread", .pid = 2, .command_line = cmdline}); std::string expected = "pid: 2, tid: 3, name: some_thread >>> some_process <<<\nuid: 1\n"; ASSERT_STREQ(expected.c_str(), amfd_data_.c_str()); } diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index 4f75ff138..e0cc6629e 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -182,8 +182,13 @@ static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) { // Don't try to collect logs from the threads that implement the logging system itself. if (thread_info.uid == AID_LOGD) log->should_retrieve_logcat = false; + const char* process_name = ""; + if (!thread_info.command_line.empty()) { + process_name = thread_info.command_line[0].c_str(); + } + _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", thread_info.pid, - thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str()); + thread_info.tid, thread_info.thread_name.c_str(), process_name); _LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid); if (thread_info.tagged_addr_ctrl != -1) { _LOG(log, logtype::HEADER, "tagged_addr_ctrl: %016lx\n", thread_info.tagged_addr_ctrl); @@ -567,7 +572,7 @@ void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_m log.amfd_data = nullptr; std::string thread_name = get_thread_name(tid); - std::string process_name = get_process_name(pid); + std::vector command_line = get_command_line(pid); std::unique_ptr regs( unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); @@ -582,7 +587,7 @@ void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_m .tid = tid, .thread_name = std::move(thread_name), .pid = pid, - .process_name = std::move(process_name), + .command_line = std::move(command_line), .selinux_label = std::move(selinux_label), .siginfo = siginfo, }; diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index 3444e29e1..765700156 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -562,7 +562,11 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind result.set_uid(main_thread.uid); result.set_selinux_label(main_thread.selinux_label); - result.set_process_name(main_thread.process_name); + auto cmd_line = result.mutable_command_line(); + for (const auto& arg : main_thread.command_line) { + *cmd_line->Add() = arg; + } + if (!main_thread.siginfo) { async_safe_fatal("siginfo missing"); } diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index 00ca7c18f..020b0a576 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -71,8 +72,13 @@ static int pointer_width(const Tombstone& tombstone) { static void print_thread_header(CallbackType callback, const Tombstone& tombstone, const Thread& thread, bool should_log) { + const char* process_name = ""; + if (!tombstone.command_line().empty()) { + process_name = tombstone.command_line()[0].c_str(); + CB(should_log, "Cmdline: %s", android::base::Join(tombstone.command_line(), " ").c_str()); + } CB(should_log, "pid: %d, tid: %d, name: %s >>> %s <<<", tombstone.pid(), thread.id(), - thread.name().c_str(), tombstone.process_name().c_str()); + thread.name().c_str(), process_name); CB(should_log, "uid: %d", tombstone.uid()); if (thread.tagged_addr_ctrl() != -1) { CB(should_log, "tagged_addr_ctrl: %016" PRIx64, thread.tagged_addr_ctrl()); diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto index dd15ff637..294e4e518 100644 --- a/debuggerd/proto/tombstone.proto +++ b/debuggerd/proto/tombstone.proto @@ -17,7 +17,7 @@ message Tombstone { uint32 uid = 7; string selinux_label = 8; - string process_name = 9; + repeated string command_line = 9; // Process uptime in seconds. uint32 process_uptime = 20; diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp index f3bff8c3d..ce0fd30f7 100644 --- a/debuggerd/util.cpp +++ b/debuggerd/util.cpp @@ -26,10 +26,31 @@ #include #include "protocol.h" +std::vector get_command_line(pid_t pid) { + std::vector result; + + std::string cmdline; + android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), &cmdline); + + auto it = cmdline.cbegin(); + while (it != cmdline.cend()) { + // string::iterator is a wrapped type, not a raw char*. + auto terminator = std::find(it, cmdline.cend(), '\0'); + result.emplace_back(it, terminator); + it = std::find_if(terminator, cmdline.cend(), [](char c) { return c != '\0'; }); + } + if (result.empty()) { + result.emplace_back(""); + } + + return result; +} + std::string get_process_name(pid_t pid) { std::string result = ""; android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), &result); - return result; + // We only want the name, not the whole command line, so truncate at the first NUL. + return result.c_str(); } std::string get_thread_name(pid_t tid) { diff --git a/debuggerd/util.h b/debuggerd/util.h index 07e7e992c..ec2862a2a 100644 --- a/debuggerd/util.h +++ b/debuggerd/util.h @@ -17,10 +17,12 @@ #pragma once #include +#include #include #include +std::vector get_command_line(pid_t pid); std::string get_process_name(pid_t pid); std::string get_thread_name(pid_t tid);