HackStudio: Add a registers view for the current function in debug mode

This commit is contained in:
Luke 2020-08-25 04:39:29 +01:00 committed by Andreas Kling
parent 3ddc42fdf1
commit 916e5e8cb3
Notes: sideshowbarker 2024-07-19 03:11:42 +09:00
5 changed files with 200 additions and 6 deletions

View File

@ -5,6 +5,7 @@ set(SOURCES
Debugger/DebugInfoWidget.cpp Debugger/DebugInfoWidget.cpp
Debugger/DisassemblyModel.cpp Debugger/DisassemblyModel.cpp
Debugger/DisassemblyWidget.cpp Debugger/DisassemblyWidget.cpp
Debugger/RegistersModel.cpp
Debugger/VariablesModel.cpp Debugger/VariablesModel.cpp
Editor.cpp Editor.cpp
EditorWrapper.cpp EditorWrapper.cpp

View File

@ -27,6 +27,7 @@
#include "DebugInfoWidget.h" #include "DebugInfoWidget.h"
#include "BacktraceModel.h" #include "BacktraceModel.h"
#include "Debugger.h" #include "Debugger.h"
#include "RegistersModel.h"
#include "VariablesModel.h" #include "VariablesModel.h"
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
@ -37,6 +38,7 @@
#include <LibGUI/Menu.h> #include <LibGUI/Menu.h>
#include <LibGUI/Model.h> #include <LibGUI/Model.h>
#include <LibGUI/Splitter.h> #include <LibGUI/Splitter.h>
#include <LibGUI/TabWidget.h>
#include <LibGUI/TreeView.h> #include <LibGUI/TreeView.h>
namespace HackStudio { namespace HackStudio {
@ -90,7 +92,10 @@ DebugInfoWidget::DebugInfoWidget()
auto& splitter = bottom_box.add<GUI::HorizontalSplitter>(); auto& splitter = bottom_box.add<GUI::HorizontalSplitter>();
m_backtrace_view = splitter.add<GUI::ListView>(); m_backtrace_view = splitter.add<GUI::ListView>();
m_variables_view = splitter.add<GUI::TreeView>(); auto& variables_tab_widget = splitter.add<GUI::TabWidget>();
variables_tab_widget.set_tab_position(GUI::TabWidget::TabPosition::Bottom);
variables_tab_widget.add_widget("Variables", build_variables_tab());
variables_tab_widget.add_widget("Registers", build_registers_tab());
m_backtrace_view->on_selection = [this](auto& index) { m_backtrace_view->on_selection = [this](auto& index) {
auto& model = static_cast<BacktraceModel&>(*m_backtrace_view->model()); auto& model = static_cast<BacktraceModel&>(*m_backtrace_view->model());
@ -104,13 +109,14 @@ DebugInfoWidget::DebugInfoWidget()
m_variables_view->set_model(VariablesModel::create(frame_regs)); m_variables_view->set_model(VariablesModel::create(frame_regs));
}; };
}
auto edit_variable_action = GUI::Action::create("Change value", [&](auto&) { NonnullRefPtr<GUI::Widget> DebugInfoWidget::build_variables_tab()
m_variables_view->on_activation(m_variables_view->selection().first()); {
}); auto variables_widget = GUI::Widget::construct();
variables_widget->set_layout<GUI::HorizontalBoxLayout>();
m_variable_context_menu = GUI::Menu::construct(); m_variables_view = variables_widget->add<GUI::TreeView>();
m_variable_context_menu->add_action(edit_variable_action);
auto is_valid_index = [](auto& index) { auto is_valid_index = [](auto& index) {
if (!index.is_valid()) if (!index.is_valid())
@ -137,12 +143,32 @@ DebugInfoWidget::DebugInfoWidget()
model.set_variable_value(index, value, window()); model.set_variable_value(index, value, window());
} }
}; };
auto edit_variable_action = GUI::Action::create("Change value", [&](auto&) {
m_variables_view->on_activation(m_variables_view->selection().first());
});
m_variable_context_menu = GUI::Menu::construct();
m_variable_context_menu->add_action(edit_variable_action);
return variables_widget;
}
NonnullRefPtr<GUI::Widget> DebugInfoWidget::build_registers_tab()
{
auto registers_widget = GUI::Widget::construct();
registers_widget->set_layout<GUI::HorizontalBoxLayout>();
m_registers_view = registers_widget->add<GUI::TableView>();
return registers_widget;
} }
void DebugInfoWidget::update_state(const Debug::DebugSession& debug_session, const PtraceRegisters& regs) void DebugInfoWidget::update_state(const Debug::DebugSession& debug_session, const PtraceRegisters& regs)
{ {
m_variables_view->set_model(VariablesModel::create(regs)); m_variables_view->set_model(VariablesModel::create(regs));
m_backtrace_view->set_model(BacktraceModel::create(debug_session, regs)); m_backtrace_view->set_model(BacktraceModel::create(debug_session, regs));
m_registers_view->set_model(RegistersModel::create(regs));
auto selected_index = m_backtrace_view->model()->index(0); auto selected_index = m_backtrace_view->model()->index(0);
if (!selected_index.is_valid()) { if (!selected_index.is_valid()) {
dbg() << "Warning: DebugInfoWidget: backtrace selected index is invalid"; dbg() << "Warning: DebugInfoWidget: backtrace selected index is invalid";
@ -154,6 +180,8 @@ void DebugInfoWidget::update_state(const Debug::DebugSession& debug_session, con
void DebugInfoWidget::program_stopped() void DebugInfoWidget::program_stopped()
{ {
m_variables_view->set_model({}); m_variables_view->set_model({});
m_backtrace_view->set_model({});
m_registers_view->set_model({});
} }
void DebugInfoWidget::set_debug_actions_enabled(bool enabled) void DebugInfoWidget::set_debug_actions_enabled(bool enabled)
@ -163,4 +191,5 @@ void DebugInfoWidget::set_debug_actions_enabled(bool enabled)
m_step_in_action->set_enabled(enabled); m_step_in_action->set_enabled(enabled);
m_step_out_action->set_enabled(enabled); m_step_out_action->set_enabled(enabled);
} }
} }

View File

@ -31,6 +31,7 @@
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/ListView.h> #include <LibGUI/ListView.h>
#include <LibGUI/Model.h> #include <LibGUI/Model.h>
#include <LibGUI/TableView.h>
#include <LibGUI/ToolBar.h> #include <LibGUI/ToolBar.h>
#include <LibGUI/ToolBarContainer.h> #include <LibGUI/ToolBarContainer.h>
#include <LibGUI/Widget.h> #include <LibGUI/Widget.h>
@ -51,7 +52,11 @@ private:
explicit DebugInfoWidget(); explicit DebugInfoWidget();
void init_toolbar(); void init_toolbar();
NonnullRefPtr<GUI::Widget> build_variables_tab();
NonnullRefPtr<GUI::Widget> build_registers_tab();
RefPtr<GUI::TreeView> m_variables_view; RefPtr<GUI::TreeView> m_variables_view;
RefPtr<GUI::TableView> m_registers_view;
RefPtr<GUI::ListView> m_backtrace_view; RefPtr<GUI::ListView> m_backtrace_view;
RefPtr<GUI::Menu> m_variable_context_menu; RefPtr<GUI::Menu> m_variable_context_menu;
RefPtr<GUI::ToolBar> m_toolbar; RefPtr<GUI::ToolBar> m_toolbar;

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "RegistersModel.h"
namespace HackStudio {
RegistersModel::RegistersModel(const PtraceRegisters& regs)
{
m_registers.append({ "eax", regs.eax });
m_registers.append({ "ebx", regs.ebx });
m_registers.append({ "ecx", regs.ecx });
m_registers.append({ "edx", regs.edx });
m_registers.append({ "esp", regs.esp });
m_registers.append({ "ebp", regs.ebp });
m_registers.append({ "esi", regs.esi });
m_registers.append({ "edi", regs.edi });
m_registers.append({ "eip", regs.eip });
m_registers.append({ "eflags", regs.eflags });
m_registers.append({ "cs", regs.cs });
m_registers.append({ "ss", regs.ss });
m_registers.append({ "ds", regs.ds });
m_registers.append({ "es", regs.es });
m_registers.append({ "fs", regs.fs });
m_registers.append({ "gs", regs.gs });
}
RegistersModel::~RegistersModel()
{
}
int RegistersModel::row_count(const GUI::ModelIndex&) const
{
return m_registers.size();
}
String RegistersModel::column_name(int column) const
{
switch (column) {
case Column::Register:
return "Register";
case Column::Value:
return "Value";
default:
ASSERT_NOT_REACHED();
return {};
}
}
GUI::Variant RegistersModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
{
auto& reg = m_registers[index.row()];
if (role == GUI::ModelRole::Display) {
if (index.column() == Column::Register)
return reg.name;
if (index.column() == Column::Value)
return String::format("%#08x", reg.value);
return {};
}
return {};
}
void RegistersModel::update()
{
did_update();
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <AK/Vector.h>
#include <LibGUI/Model.h>
#include <sys/arch/i386/regs.h>
namespace HackStudio {
struct RegisterData {
String name;
u32 value;
};
class RegistersModel final : public GUI::Model {
public:
static RefPtr<RegistersModel> create(const PtraceRegisters& regs)
{
return adopt(*new RegistersModel(regs));
}
enum Column {
Register,
Value,
__Count
};
virtual ~RegistersModel() override;
virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return Column::__Count; }
virtual String column_name(int) const override;
virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
virtual void update() override;
private:
explicit RegistersModel(const PtraceRegisters& regs);
Vector<RegisterData> m_registers;
};
}