Reland "[Berberis][CrashReporting] Dump guest thread inf..."
Guest thread information will print out follow host thread. Revert submission 3081452-revert-3062926-CJGHTRPCBP Reason for revert: Will make the change base on the original CLs for a reland. Bug: b/321799516 Test: riscv64, checked tombstone file has wanted block. https://paste.googleplex.com/6282302317658112 Added arm64 support and tested arm64 unwinding in internal repo. https://paste.googleplex.com/6545612887818240 Change-Id: Ie54ad6f359d60283442adfcd9ee95f5a116e4b72
This commit is contained in:
parent
cb53fe136b
commit
c8027933b3
|
@ -81,6 +81,10 @@ using android::base::ErrnoRestorer;
|
||||||
using android::base::StringPrintf;
|
using android::base::StringPrintf;
|
||||||
using android::base::unique_fd;
|
using android::base::unique_fd;
|
||||||
|
|
||||||
|
// This stores guest architecture. When the architecture is supported, tombstone file will output
|
||||||
|
// guest state information.
|
||||||
|
static Architecture g_guest_arch;
|
||||||
|
|
||||||
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
|
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
std::string task_path = StringPrintf("task/%d", tid);
|
std::string task_path = StringPrintf("task/%d", tid);
|
||||||
|
@ -495,6 +499,8 @@ static void ReadGuestRegisters([[maybe_unused]] std::unique_ptr<unwindstack::Reg
|
||||||
arm64_user_regs.sp = guest_regs.regs_arm64.sp;
|
arm64_user_regs.sp = guest_regs.regs_arm64.sp;
|
||||||
arm64_user_regs.pc = guest_regs.regs_arm64.ip;
|
arm64_user_regs.pc = guest_regs.regs_arm64.ip;
|
||||||
regs->reset(unwindstack::RegsArm64::Read(&arm64_user_regs));
|
regs->reset(unwindstack::RegsArm64::Read(&arm64_user_regs));
|
||||||
|
|
||||||
|
g_guest_arch = Architecture::ARM64;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NATIVE_BRIDGE_ARCH_RISCV64: {
|
case NATIVE_BRIDGE_ARCH_RISCV64: {
|
||||||
|
@ -505,6 +511,8 @@ static void ReadGuestRegisters([[maybe_unused]] std::unique_ptr<unwindstack::Reg
|
||||||
riscv64_user_regs.regs[i] = guest_regs.regs_riscv64.x[i];
|
riscv64_user_regs.regs[i] = guest_regs.regs_riscv64.x[i];
|
||||||
}
|
}
|
||||||
regs->reset(unwindstack::RegsRiscv64::Read(&riscv64_user_regs, tid));
|
regs->reset(unwindstack::RegsRiscv64::Read(&riscv64_user_regs, tid));
|
||||||
|
|
||||||
|
g_guest_arch = Architecture::RISCV64;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -771,8 +779,32 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
{
|
{
|
||||||
ATRACE_NAME("engrave_tombstone");
|
ATRACE_NAME("engrave_tombstone");
|
||||||
engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
|
unwindstack::ArchEnum regs_arch = unwindstack::ARCH_UNKNOWN;
|
||||||
g_target_thread, process_info, &open_files, &amfd_data);
|
switch (g_guest_arch) {
|
||||||
|
case Architecture::ARM32: {
|
||||||
|
regs_arch = unwindstack::ARCH_ARM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Architecture::ARM64: {
|
||||||
|
regs_arch = unwindstack::ARCH_ARM64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Architecture::RISCV64: {
|
||||||
|
regs_arch = unwindstack::ARCH_RISCV64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (regs_arch == unwindstack::ARCH_UNKNOWN) {
|
||||||
|
engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
|
||||||
|
g_target_thread, process_info, &open_files, &amfd_data);
|
||||||
|
} else {
|
||||||
|
unwindstack::AndroidRemoteUnwinder guest_unwinder(vm_pid, regs_arch);
|
||||||
|
engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
|
||||||
|
g_target_thread, process_info, &open_files, &amfd_data, &g_guest_arch,
|
||||||
|
&guest_unwinder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <android-base/unique_fd.h>
|
#include <android-base/unique_fd.h>
|
||||||
|
|
||||||
#include "open_files_list.h"
|
#include "open_files_list.h"
|
||||||
|
#include "tombstone.pb.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
|
@ -54,14 +55,17 @@ void engrave_tombstone(android::base::unique_fd output_fd, android::base::unique
|
||||||
unwindstack::AndroidUnwinder* unwinder,
|
unwindstack::AndroidUnwinder* unwinder,
|
||||||
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
|
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
|
||||||
const ProcessInfo& process_info, OpenFilesList* open_files,
|
const ProcessInfo& process_info, OpenFilesList* open_files,
|
||||||
std::string* amfd_data);
|
std::string* amfd_data, const Architecture* guest_arch = nullptr,
|
||||||
|
unwindstack::AndroidUnwinder* guest_unwinder = nullptr);
|
||||||
|
|
||||||
void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_msg_address,
|
void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_msg_address,
|
||||||
siginfo_t* siginfo, ucontext_t* ucontext);
|
siginfo_t* siginfo, ucontext_t* ucontext);
|
||||||
|
|
||||||
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
|
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
|
||||||
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
|
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
|
||||||
const ProcessInfo& process_info, const OpenFilesList* open_files);
|
const ProcessInfo& process_info, const OpenFilesList* open_files,
|
||||||
|
const Architecture* guest_arch,
|
||||||
|
unwindstack::AndroidUnwinder* guest_unwinder);
|
||||||
|
|
||||||
bool tombstone_proto_to_text(
|
bool tombstone_proto_to_text(
|
||||||
const Tombstone& tombstone,
|
const Tombstone& tombstone,
|
||||||
|
|
|
@ -125,10 +125,12 @@ void engrave_tombstone(unique_fd output_fd, unique_fd proto_fd,
|
||||||
unwindstack::AndroidUnwinder* unwinder,
|
unwindstack::AndroidUnwinder* unwinder,
|
||||||
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
|
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
|
||||||
const ProcessInfo& process_info, OpenFilesList* open_files,
|
const ProcessInfo& process_info, OpenFilesList* open_files,
|
||||||
std::string* amfd_data) {
|
std::string* amfd_data, const Architecture* guest_arch,
|
||||||
|
unwindstack::AndroidUnwinder* guest_unwinder) {
|
||||||
// Don't copy log messages to tombstone unless this is a development device.
|
// Don't copy log messages to tombstone unless this is a development device.
|
||||||
Tombstone tombstone;
|
Tombstone tombstone;
|
||||||
engrave_tombstone_proto(&tombstone, unwinder, threads, target_thread, process_info, open_files);
|
engrave_tombstone_proto(&tombstone, unwinder, threads, target_thread, process_info, open_files,
|
||||||
|
guest_arch, guest_unwinder);
|
||||||
|
|
||||||
if (proto_fd != -1) {
|
if (proto_fd != -1) {
|
||||||
if (!tombstone.SerializeToFileDescriptor(proto_fd.get())) {
|
if (!tombstone.SerializeToFileDescriptor(proto_fd.get())) {
|
||||||
|
|
|
@ -482,7 +482,8 @@ static void dump_thread_backtrace(std::vector<unwindstack::FrameData>& frames, T
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
|
static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
|
||||||
const ThreadInfo& thread_info, bool memory_dump = false) {
|
const ThreadInfo& thread_info, bool memory_dump = false,
|
||||||
|
unwindstack::AndroidUnwinder* guest_unwinder = nullptr) {
|
||||||
Thread thread;
|
Thread thread;
|
||||||
|
|
||||||
thread.set_id(thread_info.tid);
|
thread.set_id(thread_info.tid);
|
||||||
|
@ -509,6 +510,27 @@ static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwi
|
||||||
|
|
||||||
auto& threads = *tombstone->mutable_threads();
|
auto& threads = *tombstone->mutable_threads();
|
||||||
threads[thread_info.tid] = thread;
|
threads[thread_info.tid] = thread;
|
||||||
|
|
||||||
|
if (guest_unwinder) {
|
||||||
|
if (!thread_info.guest_registers) {
|
||||||
|
async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
|
||||||
|
"No guest state registers information for tid %d", thread_info.tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Thread guest_thread;
|
||||||
|
unwindstack::AndroidUnwinderData guest_data;
|
||||||
|
guest_data.saved_initial_regs = std::make_optional<std::unique_ptr<unwindstack::Regs>>();
|
||||||
|
if (guest_unwinder->Unwind(thread_info.guest_registers.get(), guest_data)) {
|
||||||
|
dump_thread_backtrace(guest_data.frames, guest_thread);
|
||||||
|
} else {
|
||||||
|
async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
|
||||||
|
"Unwind guest state registers failed for tid %d: Error %s",
|
||||||
|
thread_info.tid, guest_data.GetErrorString().c_str());
|
||||||
|
}
|
||||||
|
dump_registers(guest_unwinder, *guest_data.saved_initial_regs, guest_thread, memory_dump);
|
||||||
|
auto& guest_threads = *tombstone->mutable_guest_threads();
|
||||||
|
guest_threads[thread_info.tid] = guest_thread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps,
|
static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps,
|
||||||
|
@ -686,10 +708,17 @@ static void dump_tags_around_fault_addr(Signal* signal, const Tombstone& tombsto
|
||||||
|
|
||||||
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
|
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
|
||||||
const std::map<pid_t, ThreadInfo>& threads, pid_t target_tid,
|
const std::map<pid_t, ThreadInfo>& threads, pid_t target_tid,
|
||||||
const ProcessInfo& process_info, const OpenFilesList* open_files) {
|
const ProcessInfo& process_info, const OpenFilesList* open_files,
|
||||||
|
const Architecture* guest_arch,
|
||||||
|
unwindstack::AndroidUnwinder* guest_unwinder) {
|
||||||
Tombstone result;
|
Tombstone result;
|
||||||
|
|
||||||
result.set_arch(get_arch());
|
result.set_arch(get_arch());
|
||||||
|
if (guest_arch != nullptr) {
|
||||||
|
result.set_guest_arch(*guest_arch);
|
||||||
|
} else {
|
||||||
|
result.set_guest_arch(Architecture::NONE);
|
||||||
|
}
|
||||||
result.set_build_fingerprint(android::base::GetProperty("ro.build.fingerprint", "unknown"));
|
result.set_build_fingerprint(android::base::GetProperty("ro.build.fingerprint", "unknown"));
|
||||||
result.set_revision(android::base::GetProperty("ro.revision", "unknown"));
|
result.set_revision(android::base::GetProperty("ro.revision", "unknown"));
|
||||||
result.set_timestamp(get_timestamp());
|
result.set_timestamp(get_timestamp());
|
||||||
|
@ -750,11 +779,11 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder*
|
||||||
dump_abort_message(&result, unwinder->GetProcessMemory(), process_info);
|
dump_abort_message(&result, unwinder->GetProcessMemory(), process_info);
|
||||||
dump_crash_details(&result, unwinder->GetProcessMemory(), process_info);
|
dump_crash_details(&result, unwinder->GetProcessMemory(), process_info);
|
||||||
// Dump the target thread, but save the memory around the registers.
|
// Dump the target thread, but save the memory around the registers.
|
||||||
dump_thread(&result, unwinder, target_thread, /* memory_dump */ true);
|
dump_thread(&result, unwinder, target_thread, /* memory_dump */ true, guest_unwinder);
|
||||||
|
|
||||||
for (const auto& [tid, thread_info] : threads) {
|
for (const auto& [tid, thread_info] : threads) {
|
||||||
if (tid != target_tid) {
|
if (tid != target_tid) {
|
||||||
dump_thread(&result, unwinder, thread_info);
|
dump_thread(&result, unwinder, thread_info, /* memory_dump */ false, guest_unwinder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ static std::string describe_pac_enabled_keys(long value) {
|
||||||
return describe_end(value, desc);
|
return describe_end(value, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* abi_string(const Tombstone& tombstone) {
|
static const char* abi_string(const Architecture& arch) {
|
||||||
switch (tombstone.arch()) {
|
switch (arch) {
|
||||||
case Architecture::ARM32:
|
case Architecture::ARM32:
|
||||||
return "arm";
|
return "arm";
|
||||||
case Architecture::ARM64:
|
case Architecture::ARM64:
|
||||||
|
@ -578,11 +578,28 @@ void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_guest_thread(CallbackType callback, const Tombstone& tombstone,
|
||||||
|
const Thread& guest_thread, pid_t tid, bool should_log) {
|
||||||
|
CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
|
||||||
|
CBS("Guest thread information for tid: %d", tid);
|
||||||
|
print_thread_registers(callback, tombstone, guest_thread, should_log);
|
||||||
|
|
||||||
|
CBS("");
|
||||||
|
CB(true, "%d total frames", guest_thread.current_backtrace().size());
|
||||||
|
CB(true, "backtrace:");
|
||||||
|
print_backtrace(callback, tombstone, guest_thread.current_backtrace(), should_log);
|
||||||
|
|
||||||
|
print_thread_memory_dump(callback, tombstone, guest_thread);
|
||||||
|
}
|
||||||
|
|
||||||
bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) {
|
bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) {
|
||||||
CBL("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***");
|
CBL("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***");
|
||||||
CBL("Build fingerprint: '%s'", tombstone.build_fingerprint().c_str());
|
CBL("Build fingerprint: '%s'", tombstone.build_fingerprint().c_str());
|
||||||
CBL("Revision: '%s'", tombstone.revision().c_str());
|
CBL("Revision: '%s'", tombstone.revision().c_str());
|
||||||
CBL("ABI: '%s'", abi_string(tombstone));
|
CBL("ABI: '%s'", abi_string(tombstone.arch()));
|
||||||
|
if (tombstone.guest_arch() != Architecture::NONE) {
|
||||||
|
CBL("Guest architecture: '%s'", abi_string(tombstone.guest_arch()));
|
||||||
|
}
|
||||||
CBL("Timestamp: %s", tombstone.timestamp().c_str());
|
CBL("Timestamp: %s", tombstone.timestamp().c_str());
|
||||||
CBL("Process uptime: %ds", tombstone.process_uptime());
|
CBL("Process uptime: %ds", tombstone.process_uptime());
|
||||||
|
|
||||||
|
@ -607,6 +624,12 @@ bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback)
|
||||||
|
|
||||||
print_logs(callback, tombstone, 50);
|
print_logs(callback, tombstone, 50);
|
||||||
|
|
||||||
|
const auto& guest_threads = tombstone.guest_threads();
|
||||||
|
auto main_guest_thread_it = guest_threads.find(tombstone.tid());
|
||||||
|
if (main_guest_thread_it != threads.end()) {
|
||||||
|
print_guest_thread(callback, tombstone, main_guest_thread_it->second, tombstone.tid(), true);
|
||||||
|
}
|
||||||
|
|
||||||
// protobuf's map is unordered, so sort the keys first.
|
// protobuf's map is unordered, so sort the keys first.
|
||||||
std::set<int> thread_ids;
|
std::set<int> thread_ids;
|
||||||
for (const auto& [tid, _] : threads) {
|
for (const auto& [tid, _] : threads) {
|
||||||
|
@ -618,6 +641,10 @@ bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback)
|
||||||
for (const auto& tid : thread_ids) {
|
for (const auto& tid : thread_ids) {
|
||||||
CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
|
CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
|
||||||
print_thread(callback, tombstone, threads.find(tid)->second);
|
print_thread(callback, tombstone, threads.find(tid)->second);
|
||||||
|
auto guest_thread_it = guest_threads.find(tid);
|
||||||
|
if (guest_thread_it != guest_threads.end()) {
|
||||||
|
print_guest_thread(callback, tombstone, guest_thread_it->second, tid, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tombstone.open_fds().size() > 0) {
|
if (tombstone.open_fds().size() > 0) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ message CrashDetail {
|
||||||
|
|
||||||
message Tombstone {
|
message Tombstone {
|
||||||
Architecture arch = 1;
|
Architecture arch = 1;
|
||||||
|
Architecture guest_arch = 24;
|
||||||
string build_fingerprint = 2;
|
string build_fingerprint = 2;
|
||||||
string revision = 3;
|
string revision = 3;
|
||||||
string timestamp = 4;
|
string timestamp = 4;
|
||||||
|
@ -42,6 +43,7 @@ message Tombstone {
|
||||||
repeated Cause causes = 15;
|
repeated Cause causes = 15;
|
||||||
|
|
||||||
map<uint32, Thread> threads = 16;
|
map<uint32, Thread> threads = 16;
|
||||||
|
map<uint32, Thread> guest_threads = 25;
|
||||||
repeated MemoryMapping memory_mappings = 17;
|
repeated MemoryMapping memory_mappings = 17;
|
||||||
repeated LogBuffer log_buffers = 18;
|
repeated LogBuffer log_buffers = 18;
|
||||||
repeated FD open_fds = 19;
|
repeated FD open_fds = 19;
|
||||||
|
@ -49,7 +51,7 @@ message Tombstone {
|
||||||
uint32 page_size = 22;
|
uint32 page_size = 22;
|
||||||
bool has_been_16kb_mode = 23;
|
bool has_been_16kb_mode = 23;
|
||||||
|
|
||||||
reserved 24 to 999;
|
reserved 26 to 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Architecture {
|
enum Architecture {
|
||||||
|
@ -58,8 +60,9 @@ enum Architecture {
|
||||||
X86 = 2;
|
X86 = 2;
|
||||||
X86_64 = 3;
|
X86_64 = 3;
|
||||||
RISCV64 = 4;
|
RISCV64 = 4;
|
||||||
|
NONE = 5;
|
||||||
|
|
||||||
reserved 5 to 999;
|
reserved 6 to 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Signal {
|
message Signal {
|
||||||
|
|
Loading…
Reference in New Issue