1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 04:57:45 +00:00

HackStudio: Add option to inspect Coredump

This adds a --coredump <file> option to Hack Studio.

When used, Hack Studio will open the coredump and allow the user to
inspect it in the Debug tab.
This commit is contained in:
Itamar 2021-11-19 16:13:07 +02:00 committed by Linus Groh
parent ce726fe027
commit 8316eb7306
8 changed files with 72 additions and 19 deletions

View file

@ -50,5 +50,5 @@ set(SOURCES
)
serenity_app(HackStudio ICON app-hack-studio)
target_link_libraries(HackStudio LibWeb LibMarkdown LibGUI LibCpp LibGfx LibCore LibVT LibDebug LibX86 LibDiff LibShell LibSymbolication LibRegex LibSQL)
target_link_libraries(HackStudio LibWeb LibMarkdown LibGUI LibCpp LibGfx LibCore LibVT LibDebug LibX86 LibDiff LibShell LibSymbolication LibRegex LibSQL LibCoredump)
add_dependencies(HackStudio CppLanguageServer)

View file

@ -76,10 +76,16 @@ DebugInfoWidget::DebugInfoWidget()
// We currently only reconstruct eip & ebp. Ideally would also reconstruct the other registers somehow.
// (Other registers may be needed to get the values of variables who are not stored on the stack)
PtraceRegisters frame_regs {};
frame_regs.set_ip(model.frames()[index.row()].instruction_address);
frame_regs.set_bp(model.frames()[index.row()].frame_base);
auto backtrace_frame = model.frames()[index.row()];
frame_regs.set_ip(backtrace_frame.instruction_address);
frame_regs.set_bp(backtrace_frame.frame_base);
m_variables_view->set_model(VariablesModel::create(frame_regs));
m_variables_view->set_model(VariablesModel::create(static_cast<VariablesModel&>(*m_variables_view->model()).inspector(), frame_regs));
if (on_backtrace_frame_selection && backtrace_frame.m_source_position.has_value()) {
on_backtrace_frame_selection(*backtrace_frame.m_source_position);
} else {
dbgln("no source position info");
}
};
}
@ -149,9 +155,9 @@ NonnullRefPtr<GUI::Widget> DebugInfoWidget::build_registers_tab()
return registers_widget;
}
void DebugInfoWidget::update_state(const Debug::ProcessInspector& inspector, const PtraceRegisters& regs)
void DebugInfoWidget::update_state(Debug::ProcessInspector& inspector, const PtraceRegisters& regs)
{
m_variables_view->set_model(VariablesModel::create(regs));
m_variables_view->set_model(VariablesModel::create(inspector, regs));
m_backtrace_view->set_model(BacktraceModel::create(inspector, regs));
if (m_registers_view->model()) {
auto& previous_registers = static_cast<RegistersModel*>(m_registers_view->model())->raw_registers();

View file

@ -26,10 +26,12 @@ class DebugInfoWidget final : public GUI::Widget {
public:
virtual ~DebugInfoWidget() override { }
void update_state(Debug::ProcessInspector const&, PtraceRegisters const&);
void update_state(Debug::ProcessInspector&, PtraceRegisters const&);
void program_stopped();
void set_debug_actions_enabled(bool enabled);
Function<void(Debug::DebugInfo::SourcePosition const&)> on_backtrace_frame_selection;
private:
explicit DebugInfoWidget();
void init_toolbar();

View file

@ -78,7 +78,7 @@
namespace HackStudio {
HackStudioWidget::HackStudioWidget(const String& path_to_project)
HackStudioWidget::HackStudioWidget(String path_to_project)
: m_editor_font(read_editor_font_from_config())
{
set_fill_with_background_color(true);
@ -207,7 +207,7 @@ void HackStudioWidget::open_project(const String& root_path)
m_project_tree_view->set_model(m_project->model());
m_project_tree_view->update();
}
if (m_git_widget) {
if (m_git_widget && m_git_widget->initialized()) {
m_git_widget->change_repo(LexicalPath(root_path));
m_git_widget->refresh();
}
@ -855,8 +855,9 @@ void HackStudioWidget::initialize_debugger()
String HackStudioWidget::get_full_path_of_serenity_source(const String& file)
{
auto path_parts = LexicalPath(file).parts();
VERIFY(path_parts[0] == "..");
path_parts.remove(0);
while (!path_parts.is_empty() && path_parts[0] == "..") {
path_parts.remove(0);
}
StringBuilder relative_path_builder;
relative_path_builder.join("/", path_parts);
constexpr char SERENITY_LIBS_PREFIX[] = "/usr/src/serenity";
@ -864,12 +865,20 @@ String HackStudioWidget::get_full_path_of_serenity_source(const String& file)
return String::formatted("{}/{}", serenity_sources_base, relative_path_builder.to_string());
}
String HackStudioWidget::get_absolute_path(const String& path) const
{
// TODO: We can probably do a more specific condition here, something like
// "if (file.starts_with("../Libraries/") || file.starts_with("../AK/"))"
if (path.starts_with("..")) {
return get_full_path_of_serenity_source(path);
}
return m_project->to_absolute_path(path);
}
RefPtr<EditorWrapper> HackStudioWidget::get_editor_of_file(const String& filename)
{
String file_path = filename;
// TODO: We can probably do a more specific condition here, something like
// "if (file.starts_with("../Libraries/") || file.starts_with("../AK/"))"
if (filename.starts_with("../")) {
file_path = get_full_path_of_serenity_source(filename);
}
@ -1060,6 +1069,11 @@ void HackStudioWidget::create_action_tab(GUI::Widget& parent)
m_todo_entries_widget = m_action_tab_widget->add_tab<ToDoEntriesWidget>("TODO");
m_terminal_wrapper = m_action_tab_widget->add_tab<TerminalWrapper>("Build", false);
m_debug_info_widget = m_action_tab_widget->add_tab<DebugInfoWidget>("Debug");
m_debug_info_widget->on_backtrace_frame_selection = [this](Debug::DebugInfo::SourcePosition const& source_position) {
open_file(get_absolute_path(source_position.file_path), source_position.line_number - 1);
};
m_disassembly_widget = m_action_tab_widget->add_tab<DisassemblyWidget>("Disassembly");
m_git_widget = m_action_tab_widget->add_tab<GitWidget>("Git", LexicalPath(m_project->root_path()));
m_git_widget->set_view_diff_callback([this](const auto& original_content, const auto& diff) {
@ -1452,4 +1466,20 @@ void HackStudioWidget::change_editor_font(RefPtr<Gfx::Font> font)
Config::write_i32("HackStudio", "EditorFont", "Size", m_editor_font->presentation_size());
}
void HackStudioWidget::open_coredump(String const& coredump_path)
{
open_project("/usr/src/serenity");
m_mode = Mode::Coredump;
m_coredump_inspector = Coredump::Inspector::create(coredump_path, [this](float progress) {
window()->set_progress(progress * 100);
});
window()->set_progress(0);
if (m_coredump_inspector) {
m_debug_info_widget->update_state(*m_coredump_inspector, m_coredump_inspector->get_registers());
reveal_action_tab(*m_debug_info_widget);
}
}
}

View file

@ -21,6 +21,7 @@
#include "ProjectFile.h"
#include "TerminalWrapper.h"
#include "ToDoEntriesWidget.h"
#include <LibCoredump/Inspector.h>
#include <LibGUI/ActionGroup.h>
#include <LibGUI/Scrollbar.h>
#include <LibGUI/Splitter.h>
@ -62,11 +63,19 @@ public:
};
ContinueDecision warn_unsaved_changes(const String& prompt);
enum class Mode {
Code,
Coredump
};
void open_coredump(String const& coredump_path);
private:
static String get_full_path_of_serenity_source(const String& file);
String get_absolute_path(String const&) const;
Vector<String> selected_file_paths() const;
HackStudioWidget(const String& path_to_project);
HackStudioWidget(String path_to_project);
void open_project(const String& root_path);
enum class EditMode {
@ -215,5 +224,8 @@ private:
RefPtr<GUI::Action> m_no_wrapping_action;
RefPtr<GUI::Action> m_wrap_anywhere_action;
RefPtr<GUI::Action> m_wrap_at_words_action;
Mode m_mode { Mode::Code };
OwnPtr<Coredump::Inspector> m_coredump_inspector;
};
}

View file

@ -51,7 +51,7 @@ NonnullRefPtr<ProjectFile> Project::create_file(const String& path) const
return ProjectFile::construct_with_name(full_path);
}
String Project::to_absolute_path(const String& path) const
String Project::to_absolute_path(String const& path) const
{
if (LexicalPath { path }.is_absolute()) {
return path;

View file

@ -29,12 +29,11 @@ public:
NonnullRefPtr<ProjectFile> create_file(const String& path) const;
void for_each_text_file(Function<void(const ProjectFile&)>) const;
String to_absolute_path(String const&) const;
private:
explicit Project(const String& root_path);
String to_absolute_path(const String&) const;
RefPtr<GUI::FileSystemModel> m_model;
String m_root_path;

View file

@ -52,14 +52,16 @@ int main(int argc, char** argv)
}
const char* path_argument = nullptr;
bool mode_coredump = false;
Core::ArgsParser args_parser;
args_parser.add_positional_argument(path_argument, "Path to a workspace or a file", "path", Core::ArgsParser::Required::No);
args_parser.add_option(mode_coredump, "Inspect a coredump in HackStudio", "coredump", 'c');
args_parser.parse(argc, argv);
auto argument_absolute_path = Core::File::real_path_for(path_argument);
auto project_path = argument_absolute_path;
if (argument_absolute_path.is_null())
if (argument_absolute_path.is_null() || mode_coredump)
project_path = Core::File::real_path_for(".");
s_hack_studio_widget = window->set_main_widget<HackStudioWidget>(project_path);
@ -76,9 +78,11 @@ int main(int argc, char** argv)
};
window->show();
s_hack_studio_widget->update_actions();
if (mode_coredump)
s_hack_studio_widget->open_coredump(argument_absolute_path);
return app->exec();
}