From 6c8a1a39e12fe8b71964c89f3f2acf3659be247e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 11 Aug 2018 18:46:41 -0700 Subject: [PATCH] creport: fix various issues, improve support (closes #187) -Fixes a NULL deref in thread info parsing -Heuristically uses [] instead of rodata contents if NSO has no name segment -Adds full thread/code region dump for all firmwares, instead of just 5.x. --- .../creport/source/creport_code_info.cpp | 40 +++++++++++++++++-- .../creport/source/creport_code_info.hpp | 2 +- .../creport/source/creport_crash_report.cpp | 15 ++++--- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/stratosphere/creport/source/creport_code_info.cpp b/stratosphere/creport/source/creport_code_info.cpp index c57a44df1..d7342ff62 100644 --- a/stratosphere/creport/source/creport_code_info.cpp +++ b/stratosphere/creport/source/creport_code_info.cpp @@ -36,8 +36,14 @@ void CodeList::ReadCodeRegionsFromProcess(Handle debug_handle, u64 pc, u64 lr) { /* Parse CodeInfo. */ this->code_infos[this->code_count].start_address = mi.addr; this->code_infos[this->code_count].end_address = mi.addr + mi.size; - GetCodeInfoName(debug_handle, mi.addr + mi.size, this->code_infos[this->code_count].name); + GetCodeInfoName(debug_handle, mi.addr, mi.addr + mi.size, this->code_infos[this->code_count].name); GetCodeInfoBuildId(debug_handle, mi.addr + mi.size, this->code_infos[this->code_count].build_id); + if (this->code_infos[this->code_count].name[0] == '\x00') { + snprintf(this->code_infos[this->code_count].name, 0x1F, "[%02x%02x%02x%02x]", this->code_infos[this->code_count].build_id[0], + this->code_infos[this->code_count].build_id[1], + this->code_infos[this->code_count].build_id[2], + this->code_infos[this->code_count].build_id[3]); + } this->code_count++; } @@ -79,23 +85,49 @@ bool CodeList::TryFindCodeRegion(Handle debug_handle, u64 guess, u64 *address) { return false; } -void CodeList::GetCodeInfoName(u64 debug_handle, u64 rodata_addr, char *name) { +void CodeList::GetCodeInfoName(u64 debug_handle, u64 rx_address, u64 rodata_addr, char *name) { char name_in_proc[0x200]; /* Clear name. */ memset(name, 0, 0x20); + + /* Check whether this NSO *has* a name... */ + { + u64 rodata_start[0x20/sizeof(u64)]; + MemoryInfo mi; + u32 pi; + u64 rw_address; + + /* Verify .rodata is read-only. */ + if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, debug_handle, rodata_addr)) || mi.perm != Perm_R) { + return; + } + + /* rwdata is after rodata. */ + rw_address = mi.addr + mi.size; + + /* Read start of .rodata. */ + if (R_FAILED(svcReadDebugProcessMemory(rodata_start, debug_handle, rodata_addr, sizeof(rodata_start)))) { + return; + } + + /* Check if name section is present. */ + if (rodata_start[0] == (rw_address - rx_address)) { + return; + } + } /* Read name out of .rodata. */ if (R_FAILED(svcReadDebugProcessMemory(name_in_proc, debug_handle, rodata_addr + 8, sizeof(name_in_proc)))) { return; } - + /* Start after last slash in path. */ int ofs = strnlen(name_in_proc, sizeof(name_in_proc)); while (ofs >= 0 && name_in_proc[ofs] != '/' && name_in_proc[ofs] != '\\') { ofs--; } - + strncpy(name, name_in_proc + ofs + 1, 0x20); name[0x1F] = '\x00'; } diff --git a/stratosphere/creport/source/creport_code_info.hpp b/stratosphere/creport/source/creport_code_info.hpp index 18aa17b23..45b1cd10f 100644 --- a/stratosphere/creport/source/creport_code_info.hpp +++ b/stratosphere/creport/source/creport_code_info.hpp @@ -25,6 +25,6 @@ class CodeList { void SaveToFile(FILE *f_report); private: bool TryFindCodeRegion(Handle debug_handle, u64 guess, u64 *address); - void GetCodeInfoName(u64 debug_handle, u64 ro_address, char *name); + void GetCodeInfoName(u64 debug_handle, u64 rx_address, u64 ro_address, char *name); void GetCodeInfoBuildId(u64 debug_handle, u64 ro_address, u8 *build_id); }; diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index f687b00b3..4ad39ecd4 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -11,10 +11,9 @@ void CrashReport::BuildReport(u64 pid, bool has_extra_info) { this->has_extra_info = has_extra_info; if (OpenProcess(pid)) { ProcessExceptions(); - if (kernelAbove500()) { - this->code_list.ReadCodeRegionsFromProcess(this->debug_handle, this->crashed_thread_info.GetPC(), this->crashed_thread_info.GetLR()); - this->thread_list.ReadThreadsFromProcess(this->debug_handle, Is64Bit()); - } + this->code_list.ReadCodeRegionsFromProcess(this->debug_handle, this->crashed_thread_info.GetPC(), this->crashed_thread_info.GetLR()); + this->thread_list.ReadThreadsFromProcess(this->debug_handle, Is64Bit()); + this->crashed_thread_info.SetCodeList(&this->code_list); this->thread_list.SetCodeList(&this->code_list); if (IsApplication()) { @@ -287,11 +286,11 @@ void CrashReport::SaveToFile(FILE *f_report) { fprintf(f_report, " Size: 0x%016lx\n", this->dying_message_size); CrashReport::Memdump(f_report, " Dying Message: ", this->dying_message, this->dying_message_size); } - fprintf(f_report, "Code Region Info:\n"); - this->code_list.SaveToFile(f_report); - fprintf(f_report, "\nThread Report:\n"); - this->thread_list.SaveToFile(f_report); } + fprintf(f_report, "Code Region Info:\n"); + this->code_list.SaveToFile(f_report); + fprintf(f_report, "\nThread Report:\n"); + this->thread_list.SaveToFile(f_report); } /* Lifted from hactool. */