diff options
-rw-r--r-- | Base/home/anon/little/main.cpp | 8 | ||||
-rw-r--r-- | DevTools/HackStudio/Debugger/DebugInfoWidget.cpp | 64 | ||||
-rw-r--r-- | DevTools/HackStudio/Debugger/DebugInfoWidget.h | 1 | ||||
-rw-r--r-- | DevTools/HackStudio/Debugger/VariablesModel.cpp | 47 | ||||
-rw-r--r-- | DevTools/HackStudio/Debugger/VariablesModel.h | 2 |
5 files changed, 108 insertions, 14 deletions
diff --git a/Base/home/anon/little/main.cpp b/Base/home/anon/little/main.cpp index 3cd4932ea5..e5f35cda0f 100644 --- a/Base/home/anon/little/main.cpp +++ b/Base/home/anon/little/main.cpp @@ -1,8 +1,16 @@ #include <stdio.h> #include <sys/stat.h> +struct MyStruct { + int x { -1 }; + bool status { false }; +}; + int main(int, char**) { + MyStruct my_struct; + my_struct.status = !my_struct.status; + printf("my_struct.x is %d\n", my_struct.x); for (int i = 0; i < 3; ++i) { // This is a comment :^) printf("Hello friends!\n"); diff --git a/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp b/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp index 3ef42535c0..199f8d85cf 100644 --- a/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp +++ b/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp @@ -29,8 +29,11 @@ #include "Debugger.h" #include "VariablesModel.h" #include <AK/StringBuilder.h> +#include <LibGUI/Action.h> #include <LibGUI/BoxLayout.h> +#include <LibGUI/InputBox.h> #include <LibGUI/ListView.h> +#include <LibGUI/Menu.h> #include <LibGUI/Model.h> #include <LibGUI/Splitter.h> #include <LibGUI/TreeView.h> @@ -41,6 +44,53 @@ DebugInfoWidget::DebugInfoWidget() auto& splitter = add<GUI::HorizontalSplitter>(); m_backtrace_view = splitter.add<GUI::ListView>(); m_variables_view = splitter.add<GUI::TreeView>(); + + m_backtrace_view->on_selection = [this](auto& index) { + auto& model = static_cast<BacktraceModel&>(*m_backtrace_view->model()); + + // Note: The reconstruction of the register set here is obviously incomplete. + // 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.eip = model.frames()[index.row()].instruction_address; + frame_regs.ebp = model.frames()[index.row()].frame_base; + + 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()); + }); + + m_variable_context_menu = GUI::Menu::construct(); + m_variable_context_menu->add_action(edit_variable_action); + + auto is_valid_index = [](auto& index) { + if (!index.is_valid()) + return false; + auto* variable = static_cast<const DebugInfo::VariableInfo*>(index.internal_data()); + if (variable->location_type != DebugInfo::VariableInfo::LocationType::Address) + return false; + return variable->type.is_one_of("int", "bool"); + }; + + m_variables_view->on_context_menu_request = [this, is_valid_index](auto& index, auto& event) { + if (!is_valid_index(index)) + return; + m_variable_context_menu->popup(event.screen_position()); + }; + + m_variables_view->on_activation = [this, is_valid_index](auto& index) { + if (!is_valid_index(index)) + return; + + auto input = GUI::InputBox::construct("Enter new value:", "Set variable value", window()); + + if (input->exec() == GUI::InputBox::ExecOK) { + auto& model = static_cast<VariablesModel&>(*m_variables_view->model()); + model.set_variable_value(index, input->text_value(), window()); + } + }; } void DebugInfoWidget::update_state(const DebugSession& debug_session, const PtraceRegisters& regs) @@ -48,20 +98,6 @@ void DebugInfoWidget::update_state(const DebugSession& debug_session, const Ptra m_variables_view->set_model(VariablesModel::create(regs)); m_backtrace_view->set_model(BacktraceModel::create(debug_session, regs)); m_backtrace_view->selection().set(m_backtrace_view->model()->index(0)); - - m_backtrace_view->on_selection - = [this](auto& index) { - auto& model = static_cast<BacktraceModel&>(*m_backtrace_view->model()); - - // Note: The recontruction of the register set here is obviously incomplete. - // 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.eip = model.frames()[index.row()].instruction_address; - frame_regs.ebp = model.frames()[index.row()].frame_base; - - m_variables_view->set_model(VariablesModel::create(frame_regs)); - }; } void DebugInfoWidget::program_stopped() diff --git a/DevTools/HackStudio/Debugger/DebugInfoWidget.h b/DevTools/HackStudio/Debugger/DebugInfoWidget.h index 21167ff29c..410e1ab889 100644 --- a/DevTools/HackStudio/Debugger/DebugInfoWidget.h +++ b/DevTools/HackStudio/Debugger/DebugInfoWidget.h @@ -46,4 +46,5 @@ private: RefPtr<GUI::TreeView> m_variables_view; RefPtr<GUI::ListView> m_backtrace_view; + RefPtr<GUI::Menu> m_variable_context_menu; }; diff --git a/DevTools/HackStudio/Debugger/VariablesModel.cpp b/DevTools/HackStudio/Debugger/VariablesModel.cpp index 482622554a..35e382e465 100644 --- a/DevTools/HackStudio/Debugger/VariablesModel.cpp +++ b/DevTools/HackStudio/Debugger/VariablesModel.cpp @@ -25,6 +25,8 @@ */ #include "VariablesModel.h" +#include <LibGUI/Application.h> +#include <LibGUI/MessageBox.h> GUI::ModelIndex VariablesModel::index(int row, int column, const GUI::ModelIndex& parent_index) const { @@ -85,9 +87,54 @@ String variable_value_as_string(const DebugInfo::VariableInfo& variable) return String::format("'%c' (%d)", static_cast<char>(value.value()), static_cast<char>(value.value())); } + if (variable.type == "bool") { + auto value = Debugger::the().session()->peek((u32*)variable_address); + ASSERT(value.has_value()); + return (value.value() & 1) ? "true" : "false"; + } + return String::format("type: %s @ %08x, ", variable.type.characters(), variable_address); } +static Optional<u32> string_to_value_of_type(const StringView& string_value, const StringView& type) +{ + if (type == "int") { + bool success = false; + auto value = string_value.to_int(success); + return success ? value : Optional<u32>(); + } + + if (type == "bool") { + if (string_value == "true") + return true; + if (string_value == "false") + return false; + return {}; + } + + return {}; +} + +void VariablesModel::set_variable_value(const GUI::ModelIndex& index, const StringView& string_value, GUI::Window* parent_window) +{ + auto variable = static_cast<const DebugInfo::VariableInfo*>(index.internal_data()); + + auto value = string_to_value_of_type(string_value, variable->type); + + if (value.has_value()) { + auto success = Debugger::the().session()->poke((u32*)variable->location_data.address, value.value()); + ASSERT(success); + return; + } + + GUI::MessageBox::show( + String::format("String value \"%s\" could not be converted to a value of type %s.", string_value.to_string().characters(), variable->type.characters()), + "Set value failed", + GUI::MessageBox::Type::Error, + GUI::MessageBox::InputType::OK, + parent_window); +} + GUI::Variant VariablesModel::data(const GUI::ModelIndex& index, Role role) const { auto* variable = static_cast<const DebugInfo::VariableInfo*>(index.internal_data()); diff --git a/DevTools/HackStudio/Debugger/VariablesModel.h b/DevTools/HackStudio/Debugger/VariablesModel.h index f693b6759d..322b49c50d 100644 --- a/DevTools/HackStudio/Debugger/VariablesModel.h +++ b/DevTools/HackStudio/Debugger/VariablesModel.h @@ -36,6 +36,8 @@ class VariablesModel final : public GUI::Model { public: static RefPtr<VariablesModel> create(const PtraceRegisters& regs); + void set_variable_value(const GUI::ModelIndex&, const StringView&, GUI::Window*); + virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override; virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return 1; } virtual GUI::Variant data(const GUI::ModelIndex& index, Role role = Role::Display) const override; |