1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 09:17:36 +00:00

CrashReporter: Port to LibMain and use TRY() while building the UI :^)

This commit is contained in:
Andreas Kling 2021-12-03 00:17:42 +01:00
parent 2511da1f57
commit 01228bf4ef
2 changed files with 75 additions and 101 deletions

View file

@ -13,4 +13,4 @@ set(SOURCES
) )
serenity_app(CrashReporter ICON app-crash-reporter) serenity_app(CrashReporter ICON app-crash-reporter)
target_link_libraries(CrashReporter LibCore LibCoredump LibDesktop LibGUI) target_link_libraries(CrashReporter LibCore LibCoredump LibDesktop LibGUI LibMain)

View file

@ -14,6 +14,7 @@
#include <LibC/spawn.h> #include <LibC/spawn.h>
#include <LibCore/ArgsParser.h> #include <LibCore/ArgsParser.h>
#include <LibCore/File.h> #include <LibCore/File.h>
#include <LibCore/System.h>
#include <LibCoredump/Backtrace.h> #include <LibCoredump/Backtrace.h>
#include <LibCoredump/Reader.h> #include <LibCoredump/Reader.h>
#include <LibDesktop/AppFile.h> #include <LibDesktop/AppFile.h>
@ -32,6 +33,7 @@
#include <LibGUI/TextEditor.h> #include <LibGUI/TextEditor.h>
#include <LibGUI/Widget.h> #include <LibGUI/Widget.h>
#include <LibGUI/Window.h> #include <LibGUI/Window.h>
#include <LibMain/Main.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -164,14 +166,11 @@ static void unlink_coredump(StringView const& coredump_path)
dbgln("Failed deleting coredump file"); dbgln("Failed deleting coredump file");
} }
int main(int argc, char** argv) ErrorOr<int> serenity_main(Main::Arguments arguments)
{ {
if (pledge("stdio recvfd sendfd cpath rpath unix proc exec", nullptr) < 0) { TRY(Core::System::pledge("stdio recvfd sendfd cpath rpath unix proc exec"));
perror("pledge");
return 1;
}
auto app = GUI::Application::construct(argc, argv); auto app = TRY(GUI::Application::try_create(arguments));
const char* coredump_path = nullptr; const char* coredump_path = nullptr;
bool unlink_on_exit = false; bool unlink_on_exit = false;
@ -180,13 +179,13 @@ int main(int argc, char** argv)
args_parser.set_general_help("Show information from an application crash coredump."); args_parser.set_general_help("Show information from an application crash coredump.");
args_parser.add_positional_argument(coredump_path, "Coredump path", "coredump-path"); args_parser.add_positional_argument(coredump_path, "Coredump path", "coredump-path");
args_parser.add_option(unlink_on_exit, "Delete the coredump after its parsed", "unlink", 0); args_parser.add_option(unlink_on_exit, "Delete the coredump after its parsed", "unlink", 0);
args_parser.parse(argc, argv); args_parser.parse(arguments);
Vector<TitleAndText> thread_backtraces; Vector<TitleAndText> thread_backtraces;
Vector<TitleAndText> thread_cpu_registers; Vector<TitleAndText> thread_cpu_registers;
String executable_path; String executable_path;
Vector<String> arguments; Vector<String> crashed_process_arguments;
Vector<String> environment; Vector<String> environment;
Vector<String> memory_regions; Vector<String> memory_regions;
int pid { 0 }; int pid { 0 };
@ -213,52 +212,27 @@ int main(int argc, char** argv)
}); });
executable_path = coredump->process_executable_path(); executable_path = coredump->process_executable_path();
arguments = coredump->process_arguments(); crashed_process_arguments = coredump->process_arguments();
environment = coredump->process_environment(); environment = coredump->process_environment();
pid = coredump->process_pid(); pid = coredump->process_pid();
termination_signal = coredump->process_termination_signal(); termination_signal = coredump->process_termination_signal();
} }
if (pledge("stdio recvfd sendfd rpath unix cpath proc exec", nullptr) < 0) { TRY(Core::System::pledge("stdio recvfd sendfd rpath unix cpath proc exec"));
perror("pledge");
return 1;
}
if (unveil(executable_path.characters(), "r") < 0) { TRY(Core::System::unveil(executable_path.characters(), "r"));
perror("unveil"); TRY(Core::System::unveil("/res", "r"));
return 1; TRY(Core::System::unveil("/tmp/portal/launch", "rw"));
}
if (unveil("/res", "r") < 0) { if (unlink_on_exit)
perror("unveil"); TRY(Core::System::unveil(coredump_path, "c"));
return 1;
}
if (unveil("/tmp/portal/launch", "rw") < 0) { TRY(Core::System::unveil("/bin/HackStudio", "rx"));
perror("unveil"); TRY(Core::System::unveil(nullptr, nullptr));
return 1;
}
if (unlink_on_exit) {
if (unveil(coredump_path, "c") < 0) {
perror("unveil");
return 1;
}
}
if (unveil("/bin/HackStudio", "rx") < 0) {
perror("unveil");
return 1;
}
if (unveil(nullptr, nullptr) < 0) {
perror("unveil");
return 1;
}
auto app_icon = GUI::Icon::default_icon("app-crash-reporter"); auto app_icon = GUI::Icon::default_icon("app-crash-reporter");
auto window = GUI::Window::construct(); auto window = TRY(GUI::Window::try_create());
window->set_title("Crash Reporter"); window->set_title("Crash Reporter");
window->set_icon(app_icon.bitmap_for_size(16)); window->set_icon(app_icon.bitmap_for_size(16));
window->resize(460, 340); window->resize(460, 340);
@ -268,10 +242,10 @@ int main(int argc, char** argv)
unlink_coredump(coredump_path); unlink_coredump(coredump_path);
}; };
auto& widget = window->set_main_widget<GUI::Widget>(); auto widget = TRY(window->try_set_main_widget<GUI::Widget>());
widget.load_from_gml(crash_reporter_window_gml); widget->load_from_gml(crash_reporter_window_gml);
auto& icon_image_widget = *widget.find_descendant_of_type_named<GUI::ImageWidget>("icon"); auto& icon_image_widget = *widget->find_descendant_of_type_named<GUI::ImageWidget>("icon");
icon_image_widget.set_bitmap(GUI::FileIconProvider::icon_for_executable(executable_path).bitmap_for_size(32)); icon_image_widget.set_bitmap(GUI::FileIconProvider::icon_for_executable(executable_path).bitmap_for_size(32));
auto app_name = LexicalPath::basename(executable_path); auto app_name = LexicalPath::basename(executable_path);
@ -279,96 +253,96 @@ int main(int argc, char** argv)
if (af->is_valid()) if (af->is_valid())
app_name = af->name(); app_name = af->name();
auto& description_label = *widget.find_descendant_of_type_named<GUI::Label>("description"); auto& description_label = *widget->find_descendant_of_type_named<GUI::Label>("description");
description_label.set_text(String::formatted("\"{}\" (PID {}) has crashed - {} (signal {})", app_name, pid, strsignal(termination_signal), termination_signal)); description_label.set_text(String::formatted("\"{}\" (PID {}) has crashed - {} (signal {})", app_name, pid, strsignal(termination_signal), termination_signal));
auto& executable_link_label = *widget.find_descendant_of_type_named<GUI::LinkLabel>("executable_link"); auto& executable_link_label = *widget->find_descendant_of_type_named<GUI::LinkLabel>("executable_link");
executable_link_label.set_text(LexicalPath::canonicalized_path(executable_path)); executable_link_label.set_text(LexicalPath::canonicalized_path(executable_path));
executable_link_label.on_click = [&] { executable_link_label.on_click = [&] {
LexicalPath path { executable_path }; LexicalPath path { executable_path };
Desktop::Launcher::open(URL::create_with_file_protocol(path.dirname(), path.basename())); Desktop::Launcher::open(URL::create_with_file_protocol(path.dirname(), path.basename()));
}; };
auto& coredump_link_label = *widget.find_descendant_of_type_named<GUI::LinkLabel>("coredump_link"); auto& coredump_link_label = *widget->find_descendant_of_type_named<GUI::LinkLabel>("coredump_link");
coredump_link_label.set_text(LexicalPath::canonicalized_path(coredump_path)); coredump_link_label.set_text(LexicalPath::canonicalized_path(coredump_path));
coredump_link_label.on_click = [&] { coredump_link_label.on_click = [&] {
LexicalPath path { coredump_path }; LexicalPath path { coredump_path };
Desktop::Launcher::open(URL::create_with_file_protocol(path.dirname(), path.basename())); Desktop::Launcher::open(URL::create_with_file_protocol(path.dirname(), path.basename()));
}; };
auto& arguments_label = *widget.find_descendant_of_type_named<GUI::Label>("arguments_label"); auto& arguments_label = *widget->find_descendant_of_type_named<GUI::Label>("arguments_label");
arguments_label.set_text(String::join(" ", arguments)); arguments_label.set_text(String::join(" ", crashed_process_arguments));
auto& tab_widget = *widget.find_descendant_of_type_named<GUI::TabWidget>("tab_widget"); auto& tab_widget = *widget->find_descendant_of_type_named<GUI::TabWidget>("tab_widget");
auto& backtrace_tab = tab_widget.add_tab<GUI::Widget>("Backtrace"); auto backtrace_tab = TRY(tab_widget.try_add_tab<GUI::Widget>("Backtrace"));
backtrace_tab.set_layout<GUI::VerticalBoxLayout>(); TRY(backtrace_tab->try_set_layout<GUI::VerticalBoxLayout>());
backtrace_tab.layout()->set_margins(4); backtrace_tab->layout()->set_margins(4);
auto& backtrace_label = backtrace_tab.add<GUI::Label>("A backtrace for each thread alive during the crash is listed below:"); auto backtrace_label = TRY(backtrace_tab->try_add<GUI::Label>("A backtrace for each thread alive during the crash is listed below:"));
backtrace_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); backtrace_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
backtrace_label.set_fixed_height(16); backtrace_label->set_fixed_height(16);
auto& backtrace_tab_widget = backtrace_tab.add<GUI::TabWidget>(); auto backtrace_tab_widget = TRY(backtrace_tab->try_add<GUI::TabWidget>());
backtrace_tab_widget.set_tab_position(GUI::TabWidget::TabPosition::Bottom); backtrace_tab_widget->set_tab_position(GUI::TabWidget::TabPosition::Bottom);
for (auto& backtrace : thread_backtraces) { for (auto& backtrace : thread_backtraces) {
auto& container = backtrace_tab_widget.add_tab<GUI::Widget>(backtrace.title); auto container = TRY(backtrace_tab_widget->try_add_tab<GUI::Widget>(backtrace.title));
container.set_layout<GUI::VerticalBoxLayout>(); TRY(container->try_set_layout<GUI::VerticalBoxLayout>());
container.layout()->set_margins(4); container->layout()->set_margins(4);
auto& backtrace_text_editor = container.add<GUI::TextEditor>(); auto backtrace_text_editor = TRY(container->try_add<GUI::TextEditor>());
backtrace_text_editor.set_text(backtrace.text); backtrace_text_editor->set_text(backtrace.text);
backtrace_text_editor.set_mode(GUI::TextEditor::Mode::ReadOnly); backtrace_text_editor->set_mode(GUI::TextEditor::Mode::ReadOnly);
backtrace_text_editor.set_should_hide_unnecessary_scrollbars(true); backtrace_text_editor->set_should_hide_unnecessary_scrollbars(true);
} }
auto& cpu_registers_tab = tab_widget.add_tab<GUI::Widget>("CPU Registers"); auto cpu_registers_tab = TRY(tab_widget.try_add_tab<GUI::Widget>("CPU Registers"));
cpu_registers_tab.set_layout<GUI::VerticalBoxLayout>(); cpu_registers_tab->set_layout<GUI::VerticalBoxLayout>();
cpu_registers_tab.layout()->set_margins(4); cpu_registers_tab->layout()->set_margins(4);
auto& cpu_registers_label = cpu_registers_tab.add<GUI::Label>("The CPU register state for each thread alive during the crash is listed below:"); auto cpu_registers_label = TRY(cpu_registers_tab->try_add<GUI::Label>("The CPU register state for each thread alive during the crash is listed below:"));
cpu_registers_label.set_text_alignment(Gfx::TextAlignment::CenterLeft); cpu_registers_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
cpu_registers_label.set_fixed_height(16); cpu_registers_label->set_fixed_height(16);
auto& cpu_registers_tab_widget = cpu_registers_tab.add<GUI::TabWidget>(); auto cpu_registers_tab_widget = TRY(cpu_registers_tab->try_add<GUI::TabWidget>());
cpu_registers_tab_widget.set_tab_position(GUI::TabWidget::TabPosition::Bottom); cpu_registers_tab_widget->set_tab_position(GUI::TabWidget::TabPosition::Bottom);
for (auto& cpu_registers : thread_cpu_registers) { for (auto& cpu_registers : thread_cpu_registers) {
auto& container = cpu_registers_tab_widget.add_tab<GUI::Widget>(cpu_registers.title); auto container = TRY(cpu_registers_tab_widget->try_add_tab<GUI::Widget>(cpu_registers.title));
container.set_layout<GUI::VerticalBoxLayout>(); TRY(container->try_set_layout<GUI::VerticalBoxLayout>());
container.layout()->set_margins(4); container->layout()->set_margins(4);
auto& cpu_registers_text_editor = container.add<GUI::TextEditor>(); auto cpu_registers_text_editor = TRY(container->try_add<GUI::TextEditor>());
cpu_registers_text_editor.set_text(cpu_registers.text); cpu_registers_text_editor->set_text(cpu_registers.text);
cpu_registers_text_editor.set_mode(GUI::TextEditor::Mode::ReadOnly); cpu_registers_text_editor->set_mode(GUI::TextEditor::Mode::ReadOnly);
cpu_registers_text_editor.set_should_hide_unnecessary_scrollbars(true); cpu_registers_text_editor->set_should_hide_unnecessary_scrollbars(true);
} }
auto& environment_tab = tab_widget.add_tab<GUI::Widget>("Environment"); auto environment_tab = TRY(tab_widget.try_add_tab<GUI::Widget>("Environment"));
environment_tab.set_layout<GUI::VerticalBoxLayout>(); TRY(environment_tab->try_set_layout<GUI::VerticalBoxLayout>());
environment_tab.layout()->set_margins(4); environment_tab->layout()->set_margins(4);
auto& environment_text_editor = environment_tab.add<GUI::TextEditor>(); auto environment_text_editor = TRY(environment_tab->try_add<GUI::TextEditor>());
environment_text_editor.set_text(String::join("\n", environment)); environment_text_editor->set_text(String::join("\n", environment));
environment_text_editor.set_mode(GUI::TextEditor::Mode::ReadOnly); environment_text_editor->set_mode(GUI::TextEditor::Mode::ReadOnly);
environment_text_editor.set_should_hide_unnecessary_scrollbars(true); environment_text_editor->set_should_hide_unnecessary_scrollbars(true);
auto& memory_regions_tab = tab_widget.add_tab<GUI::Widget>("Memory Regions"); auto memory_regions_tab = TRY(tab_widget.try_add_tab<GUI::Widget>("Memory Regions"));
memory_regions_tab.set_layout<GUI::VerticalBoxLayout>(); TRY(memory_regions_tab->try_set_layout<GUI::VerticalBoxLayout>());
memory_regions_tab.layout()->set_margins(4); memory_regions_tab->layout()->set_margins(4);
auto& memory_regions_text_editor = memory_regions_tab.add<GUI::TextEditor>(); auto memory_regions_text_editor = TRY(memory_regions_tab->try_add<GUI::TextEditor>());
memory_regions_text_editor.set_text(String::join("\n", memory_regions)); memory_regions_text_editor->set_text(String::join("\n", memory_regions));
memory_regions_text_editor.set_mode(GUI::TextEditor::Mode::ReadOnly); memory_regions_text_editor->set_mode(GUI::TextEditor::Mode::ReadOnly);
memory_regions_text_editor.set_should_hide_unnecessary_scrollbars(true); memory_regions_text_editor->set_should_hide_unnecessary_scrollbars(true);
memory_regions_text_editor.set_visualize_trailing_whitespace(false); memory_regions_text_editor->set_visualize_trailing_whitespace(false);
auto& close_button = *widget.find_descendant_of_type_named<GUI::Button>("close_button"); auto& close_button = *widget->find_descendant_of_type_named<GUI::Button>("close_button");
close_button.on_click = [&](auto) { close_button.on_click = [&](auto) {
if (unlink_on_exit) if (unlink_on_exit)
unlink_coredump(coredump_path); unlink_coredump(coredump_path);
app->quit(); app->quit();
}; };
auto& debug_button = *widget.find_descendant_of_type_named<GUI::Button>("debug_button"); auto& debug_button = *widget->find_descendant_of_type_named<GUI::Button>("debug_button");
debug_button.set_icon(MUST(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-hack-studio.png"))); debug_button.set_icon(TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-hack-studio.png")));
debug_button.on_click = [&](int) { debug_button.on_click = [&](int) {
pid_t child; pid_t child;
const char* argv[4] = { "HackStudio", "-c", coredump_path, nullptr }; const char* argv[4] = { "HackStudio", "-c", coredump_path, nullptr };