From 58ed00f63350f174289b88c8fde4a9b50c413753 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Wed, 26 Jan 2022 23:16:36 +0330 Subject: [PATCH] run-tests: Dump a backtrace for crashed tests It only makes sense to see what a crashed test was up to, so generate a backtrace if we can find the coredump and read it. --- Userland/Utilities/CMakeLists.txt | 2 +- Userland/Utilities/run-tests.cpp | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Userland/Utilities/CMakeLists.txt b/Userland/Utilities/CMakeLists.txt index 6d821e833c..a416684fa7 100644 --- a/Userland/Utilities/CMakeLists.txt +++ b/Userland/Utilities/CMakeLists.txt @@ -152,7 +152,7 @@ target_link_libraries(pwd LibMain) target_link_libraries(rev LibMain) target_link_libraries(rm LibMain) target_link_libraries(rmdir LibMain) -target_link_libraries(run-tests LibRegex) +target_link_libraries(run-tests LibRegex LibCoredump) target_link_libraries(shot LibGUI) target_link_libraries(shuf LibMain) target_link_libraries(sql LibLine LibSQL LibIPC) diff --git a/Userland/Utilities/run-tests.cpp b/Userland/Utilities/run-tests.cpp index a263743073..94c1b63d6d 100644 --- a/Userland/Utilities/run-tests.cpp +++ b/Userland/Utilities/run-tests.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ struct FileResult { double time_taken { 0 }; Test::Result result { Test::Result::Pass }; int stdout_err_fd { -1 }; + pid_t child_pid { 0 }; }; String g_currently_running_test; @@ -129,6 +131,32 @@ void TestRunner::do_run_single_test(const String& test_path, size_t current_test print_modifiers({ Test::BG_RED, Test::FG_BLACK, Test::FG_BOLD }); out("{}", test_result.result == Test::Result::Fail ? " FAIL " : "CRASHED"); print_modifiers({ Test::CLEAR }); + if (test_result.result == Test::Result::Crashed) { + auto pid_search_string = String::formatted("_{}_", test_result.child_pid); + Core::DirIterator iterator("/tmp/coredump"sv); + if (!iterator.has_error()) { + while (iterator.has_next()) { + auto path = iterator.next_full_path(); + if (!path.contains(pid_search_string)) + continue; + + auto reader = Coredump::Reader::create(path); + if (!reader) + break; + + dbgln("Last crash backtrace for {} (was pid {}):", test_path, test_result.child_pid); + reader->for_each_thread_info([&](auto thread_info) { + Coredump::Backtrace thread_backtrace(*reader, thread_info); + auto tid = thread_info.tid; // Note: Yoinking this out of the struct because we can't pass a reference to it (as it's a misaligned field in a packed struct) + dbgln("Thread {}", tid); + for (auto const& entry : thread_backtrace.entries()) + dbgln("- {}", entry.to_string(true)); + return IterationDecision::Continue; + }); + break; + } + } + } } else { print_modifiers({ Test::BG_GREEN, Test::FG_BLACK, Test::FG_BOLD }); out(" PASS "); @@ -251,7 +279,7 @@ FileResult TestRunner::run_test_file(const String& test_path) ret = unlink(child_out_err_path); VERIFY(ret == 0); - return FileResult { move(path_for_test), get_time_in_ms() - start_time, test_result, child_out_err_file }; + return FileResult { move(path_for_test), get_time_in_ms() - start_time, test_result, child_out_err_file, child_pid }; } int main(int argc, char** argv)