diff --git a/DevTools/HackStudio/Debugger/BacktraceModel.cpp b/DevTools/HackStudio/Debugger/BacktraceModel.cpp index 2b4426fa18..1e1c86c6a0 100644 --- a/DevTools/HackStudio/Debugger/BacktraceModel.cpp +++ b/DevTools/HackStudio/Debugger/BacktraceModel.cpp @@ -27,9 +27,9 @@ #include "BacktraceModel.h" #include "Debugger.h" -RefPtr BacktraceModel::create(const PtraceRegisters& regs) +NonnullRefPtr BacktraceModel::create(const DebugSession& debug_session, const PtraceRegisters& regs) { - return adopt(*new BacktraceModel(create_backtrace(regs))); + return adopt(*new BacktraceModel(create_backtrace(debug_session, regs))); } GUI::Variant BacktraceModel::data(const GUI::ModelIndex& index, Role role) const @@ -41,20 +41,19 @@ GUI::Variant BacktraceModel::data(const GUI::ModelIndex& index, Role role) const return {}; } -Vector BacktraceModel::create_backtrace(const PtraceRegisters& regs) +Vector BacktraceModel::create_backtrace(const DebugSession& debug_session, const PtraceRegisters& regs) { u32 current_ebp = regs.ebp; u32 current_instruction = regs.eip; Vector frames; do { - const auto& debug_info = Debugger::the().session()->debug_info(); - String name = debug_info.name_of_containing_function(current_instruction); + String name = debug_session.debug_info().name_of_containing_function(current_instruction); if (name.is_null()) { dbg() << "BacktraceModel: couldn't find containing function for address: " << (void*)current_instruction; break; } - frames.append({ name, current_instruction }); + frames.append({ name, current_instruction, current_ebp }); current_instruction = Debugger::the().session()->peek(reinterpret_cast(current_ebp + 4)).value(); current_ebp = Debugger::the().session()->peek(reinterpret_cast(current_ebp)).value(); } while (current_ebp); diff --git a/DevTools/HackStudio/Debugger/BacktraceModel.h b/DevTools/HackStudio/Debugger/BacktraceModel.h index 2f5ffc6114..bc54c758d3 100644 --- a/DevTools/HackStudio/Debugger/BacktraceModel.h +++ b/DevTools/HackStudio/Debugger/BacktraceModel.h @@ -30,9 +30,11 @@ #include #include +class DebugSession; + class BacktraceModel final : public GUI::Model { public: - static RefPtr create(const PtraceRegisters& regs); + static NonnullRefPtr create(const DebugSession&, const PtraceRegisters& regs); virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_frames.size(); } virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return 1; } @@ -47,18 +49,21 @@ public: virtual void update() override {} virtual GUI::ModelIndex index(int row, int column = 0, const GUI::ModelIndex& = GUI::ModelIndex()) const override { return create_index(row, column, &m_frames.at(row)); } -private: struct FrameInfo { String function_name; - u32 address_in_frame; + u32 instruction_address; + u32 frame_base; }; + const Vector& frames() const { return m_frames; } + +private: explicit BacktraceModel(Vector&& frames) : m_frames(move(frames)) { } - static Vector create_backtrace(const PtraceRegisters&); + static Vector create_backtrace(const DebugSession&, const PtraceRegisters&); Vector m_frames; }; diff --git a/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp b/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp index 78adfa6c91..3ef42535c0 100644 --- a/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp +++ b/DevTools/HackStudio/Debugger/DebugInfoWidget.cpp @@ -43,10 +43,25 @@ DebugInfoWidget::DebugInfoWidget() m_variables_view = splitter.add(); } -void DebugInfoWidget::update_state(const PtraceRegisters& regs) +void DebugInfoWidget::update_state(const DebugSession& debug_session, const PtraceRegisters& regs) { m_variables_view->set_model(VariablesModel::create(regs)); - m_backtrace_view->set_model(BacktraceModel::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(*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 6300467208..21167ff29c 100644 --- a/DevTools/HackStudio/Debugger/DebugInfoWidget.h +++ b/DevTools/HackStudio/Debugger/DebugInfoWidget.h @@ -38,7 +38,7 @@ class DebugInfoWidget final : public GUI::Widget { public: virtual ~DebugInfoWidget() override {} - void update_state(const PtraceRegisters&); + void update_state(const DebugSession&, const PtraceRegisters&); void program_stopped(); private: diff --git a/DevTools/HackStudio/main.cpp b/DevTools/HackStudio/main.cpp index 3c5eceefae..601098f587 100644 --- a/DevTools/HackStudio/main.cpp +++ b/DevTools/HackStudio/main.cpp @@ -608,14 +608,16 @@ int main(int argc, char** argv) [&](const PtraceRegisters& regs) { dbg() << "Program stopped"; - auto source_position = Debugger::the().session()->debug_info().get_source_position(regs.eip); + ASSERT(Debugger::the().session()); + const auto& debug_session = *Debugger::the().session(); + auto source_position = debug_session.debug_info().get_source_position(regs.eip); if (!source_position.has_value()) { dbg() << "Could not find source position for address: " << (void*)regs.eip; return Debugger::HasControlPassedToUser::No; } current_editor_in_execution = get_editor_of_file(source_position.value().file_path); current_editor_in_execution->editor().set_execution_position(source_position.value().line_number - 1); - debug_info_widget.update_state(regs); + debug_info_widget.update_state(debug_session, regs); continue_action->set_enabled(true); single_step_action->set_enabled(true); reveal_action_tab(debug_info_widget);