From 916e5e8cb31be0ab61748807d473743bf2130848 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 25 Aug 2020 04:39:29 +0100 Subject: [PATCH] HackStudio: Add a registers view for the current function in debug mode --- DevTools/HackStudio/CMakeLists.txt | 1 + .../HackStudio/Debugger/DebugInfoWidget.cpp | 41 +++++++-- .../HackStudio/Debugger/DebugInfoWidget.h | 5 + .../HackStudio/Debugger/RegistersModel.cpp | 92 +++++++++++++++++++ DevTools/HackStudio/Debugger/RegistersModel.h | 67 ++++++++++++++ 5 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 DevTools/HackStudio/Debugger/RegistersModel.cpp create mode 100644 DevTools/HackStudio/Debugger/RegistersModel.h diff --git a/DevTools/HackStudio/CMakeLists.txt b/DevTools/HackStudio/CMakeLists.txt index b60225946e..8105917661 100644 --- a/DevTools/HackStudio/CMakeLists.txt +++ b/DevTools/HackStudio/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES Debugger/DebugInfoWidget.cpp Debugger/DisassemblyModel.cpp Debugger/DisassemblyWidget.cpp + Debugger/RegistersModel.cpp Debugger/VariablesModel.cpp Editor.cpp EditorWrapper.cpp diff --git a/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp b/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp index 30fb546a74..15b3288512 100644 --- a/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp +++ b/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp @@ -27,6 +27,7 @@ #include "DebugInfoWidget.h" #include "BacktraceModel.h" #include "Debugger.h" +#include "RegistersModel.h" #include "VariablesModel.h" #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include namespace HackStudio { @@ -90,7 +92,10 @@ DebugInfoWidget::DebugInfoWidget() auto& splitter = bottom_box.add(); m_backtrace_view = splitter.add(); - m_variables_view = splitter.add(); + auto& variables_tab_widget = splitter.add(); + 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) { auto& model = static_cast(*m_backtrace_view->model()); @@ -104,13 +109,14 @@ DebugInfoWidget::DebugInfoWidget() m_variables_view->set_model(VariablesModel::create(frame_regs)); }; +} - auto edit_variable_action = GUI::Action::create("Change value", [&](auto&) { - m_variables_view->on_activation(m_variables_view->selection().first()); - }); +NonnullRefPtr DebugInfoWidget::build_variables_tab() +{ + auto variables_widget = GUI::Widget::construct(); + variables_widget->set_layout(); - m_variable_context_menu = GUI::Menu::construct(); - m_variable_context_menu->add_action(edit_variable_action); + m_variables_view = variables_widget->add(); auto is_valid_index = [](auto& index) { if (!index.is_valid()) @@ -137,12 +143,32 @@ DebugInfoWidget::DebugInfoWidget() 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 DebugInfoWidget::build_registers_tab() +{ + auto registers_widget = GUI::Widget::construct(); + registers_widget->set_layout(); + + m_registers_view = registers_widget->add(); + + return registers_widget; } void DebugInfoWidget::update_state(const Debug::DebugSession& debug_session, const PtraceRegisters& regs) { m_variables_view->set_model(VariablesModel::create(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); if (!selected_index.is_valid()) { 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() { m_variables_view->set_model({}); + m_backtrace_view->set_model({}); + m_registers_view->set_model({}); } 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_out_action->set_enabled(enabled); } + } diff --git a/DevTools/HackStudio/Debugger/DebugInfoWidget.h b/DevTools/HackStudio/Debugger/DebugInfoWidget.h index 308ec6c02f..bf8c7825ad 100644 --- a/DevTools/HackStudio/Debugger/DebugInfoWidget.h +++ b/DevTools/HackStudio/Debugger/DebugInfoWidget.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,11 @@ private: explicit DebugInfoWidget(); void init_toolbar(); + NonnullRefPtr build_variables_tab(); + NonnullRefPtr build_registers_tab(); + RefPtr m_variables_view; + RefPtr m_registers_view; RefPtr m_backtrace_view; RefPtr m_variable_context_menu; RefPtr m_toolbar; diff --git a/DevTools/HackStudio/Debugger/RegistersModel.cpp b/DevTools/HackStudio/Debugger/RegistersModel.cpp new file mode 100644 index 0000000000..9eae341317 --- /dev/null +++ b/DevTools/HackStudio/Debugger/RegistersModel.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020, Luke Wilde + * 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(); +} + +} diff --git a/DevTools/HackStudio/Debugger/RegistersModel.h b/DevTools/HackStudio/Debugger/RegistersModel.h new file mode 100644 index 0000000000..8881b28505 --- /dev/null +++ b/DevTools/HackStudio/Debugger/RegistersModel.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020, Luke Wilde + * 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 +#include +#include + +namespace HackStudio { + +struct RegisterData { + String name; + u32 value; +}; + +class RegistersModel final : public GUI::Model { +public: + static RefPtr 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 m_registers; +}; + +}