Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions core/libs/prx/libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -569,5 +569,11 @@ if(MINGW)
set_target_properties(windows_exception_tests PROPERTIES EXCLUDE_FROM_ALL FALSE)
add_test(NAME windows_exceptions COMMAND windows_exception_tests)
set_tests_properties(windows_exceptions PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
add_test_executable(windows_backtrace_report_tests ${LIBS_INCLUDE_DIR}/tests/WindowsBacktraceReport.cpp)
target_link_libraries(windows_backtrace_report_tests PRIVATE libc)
add_test(NAME windows_backtrace_report COMMAND windows_backtrace_report_tests)
set_tests_properties(windows_backtrace_report PROPERTIES TIMEOUT 20
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>"
PASS_REGULAR_EXPRESSION "aborting[^~]*SIGABRT. on thread[^~]*stack return address candidates:[^~]*rsp[+]0x")
endif()
endif()
27 changes: 17 additions & 10 deletions core/libs/prx/libc/src/specifics/windows/CrashReport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void Report(const char* format, ...) {
}

void ReportAllThreads();
void ReportStackCandidates(std::uint64_t rsp, int limit, std::uint64_t span);

void DescribeAddress(std::uint64_t address, char* buffer, std::size_t size) {
HMODULE module = nullptr;
Expand Down Expand Up @@ -296,16 +297,7 @@ LONG WINAPI ReportCrash(EXCEPTION_POINTERS* info) {
if (next <= frame) break;
frame = next;
}
Report(" stack return address candidates:\n");
int printed = 0;
for (std::uint64_t slot = context->Rsp; printed < 16 && slot < context->Rsp + 0x2000; slot += 8) {
if (!IsReadable(slot)) break;
const auto value = *reinterpret_cast<const std::uint64_t*>(slot);
if (!IsExecutable(value)) continue;
DescribeAddress(value, line, sizeof(line));
Report(" [rsp+0x%llx] %s\n", static_cast<unsigned long long>(slot - context->Rsp), line);
++printed;
}
ReportStackCandidates(context->Rsp, 16, 0x2000);
if (context->Rip == 0 || !IsExecutable(context->Rip)) {
// A jump into nothing usually follows a return through a clobbered frame; the frames that just
// returned are still below rsp.
Expand Down Expand Up @@ -433,6 +425,20 @@ DWORD WINAPI HangWatchdog(LPVOID param) {
return 0;
}

void ReportStackCandidates(std::uint64_t rsp, int limit, std::uint64_t span) {
char line[256];
Report(" stack return address candidates:\n");
int printed = 0;
for (std::uint64_t slot = rsp; printed < limit && slot < rsp + span; slot += 8) {
if (!IsReadable(slot)) break;
const auto value = *reinterpret_cast<const std::uint64_t*>(slot);
if (!IsExecutable(value)) continue;
DescribeAddress(value, line, sizeof(line));
Report(" [rsp+0x%llx] %s\n", static_cast<unsigned long long>(slot - rsp), line);
++printed;
}
}

// abort() and the UCRT's invalid-parameter path end the process with a silent fast fail
// (0xc0000409); both are reported with the calling thread's stack first.
void ReportBacktrace(const char* what, bool reportThreads) {
Expand All @@ -444,6 +450,7 @@ void ReportBacktrace(const char* what, bool reportThreads) {
DescribeAddress(reinterpret_cast<std::uint64_t>(frames[i]), line, sizeof(line));
Report(" #%u %s\n", static_cast<unsigned>(i), line);
}
ReportStackCandidates(reinterpret_cast<std::uint64_t>(__builtin_frame_address(0)), 32, 0x4000);
if (reportThreads) ReportAllThreads();
std::fflush(stderr);
}
Expand Down
12 changes: 12 additions & 0 deletions core/libs/tests/WindowsBacktraceReport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <cstdio>
#include <cstdlib>
#include "../prx/libc/include/general/VabiMacros.hpp"

extern "C" int* APS5_VABI __error_nid_postfix();

int main() {
if (__error_nid_postfix() == nullptr) return 1;
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
std::fputs("aborting\n", stderr);
std::abort();
}
Loading