Serenity Operating System
at master 140 lines 4.8 kB view raw
1/* 2 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include "BreakpointCallback.h" 10#include <AK/Function.h> 11#include <AK/LexicalPath.h> 12#include <AK/Vector.h> 13#include <LibDebug/DebugSession.h> 14#include <LibThreading/Mutex.h> 15#include <LibThreading/Thread.h> 16 17namespace HackStudio { 18 19class Debugger { 20public: 21 static Debugger& the(); 22 23 enum class HasControlPassedToUser { 24 No, 25 Yes, 26 }; 27 28 static void initialize( 29 DeprecatedString source_root, 30 Function<HasControlPassedToUser(PtraceRegisters const&)> on_stop_callback, 31 Function<void()> on_continue_callback, 32 Function<void()> on_exit_callback, 33 Function<void(float)> on_initialization_progress); 34 35 static bool is_initialized(); 36 37 void on_breakpoint_change(DeprecatedString const& file, size_t line, BreakpointChange change_type); 38 bool set_execution_position(DeprecatedString const& file, size_t line); 39 40 void set_executable_path(DeprecatedString const& path) { m_executable_path = path; } 41 void set_source_root(DeprecatedString const& source_root) { m_source_root = source_root; } 42 void set_pid_to_attach(pid_t pid) { m_pid_to_attach = pid; } 43 44 Debug::DebugSession* session() { return m_debug_session.ptr(); } 45 46 void stop(); 47 48 // Thread entry point 49 static intptr_t start_static(); 50 51 pthread_mutex_t* continue_mutex() { return &m_ui_action_mutex; } 52 pthread_cond_t* continue_cond() { return &m_ui_action_cond; } 53 54 enum class DebuggerAction { 55 Continue, 56 SourceSingleStep, 57 SourceStepOut, 58 SourceStepOver, 59 Exit, 60 }; 61 62 void set_requested_debugger_action(DebuggerAction); 63 void reset_breakpoints() { m_breakpoints.clear(); } 64 65 void set_child_setup_callback(Function<ErrorOr<void>()> callback) { m_child_setup_callback = move(callback); } 66 67 void stop_debuggee(); 68 69private: 70 class DebuggingState { 71 public: 72 enum State { 73 Normal, // Continue normally until we hit a breakpoint / program terminates 74 SingleStepping, 75 SteppingOut, 76 SteppingOver, 77 }; 78 State get() const { return m_state; } 79 80 void set_normal(); 81 void set_single_stepping(Debug::DebugInfo::SourcePosition original_source_position); 82 void set_stepping_out() { m_state = State::SteppingOut; } 83 void set_stepping_over() { m_state = State::SteppingOver; } 84 85 bool should_stop_single_stepping(Debug::DebugInfo::SourcePosition const& current_source_position) const; 86 void clear_temporary_breakpoints(); 87 void add_temporary_breakpoint(FlatPtr address); 88 Vector<FlatPtr> const& temporary_breakpoints() const { return m_addresses_of_temporary_breakpoints; } 89 90 private: 91 State m_state { Normal }; 92 Optional<Debug::DebugInfo::SourcePosition> m_original_source_position; // The source position at which we started the current single step 93 Vector<FlatPtr> m_addresses_of_temporary_breakpoints; 94 }; 95 96 explicit Debugger( 97 DeprecatedString source_root, 98 Function<HasControlPassedToUser(PtraceRegisters const&)> on_stop_callback, 99 Function<void()> on_continue_callback, 100 Function<void()> on_exit_callback, 101 Function<void(float)> on_initialization_progress); 102 103 Debug::DebugInfo::SourcePosition create_source_position(DeprecatedString const& file, size_t line); 104 105 void start(); 106 int debugger_loop(Debug::DebugSession::DesiredInitialDebugeeState); 107 108 void remove_temporary_breakpoints(); 109 void do_step_out(PtraceRegisters const&); 110 void do_step_over(PtraceRegisters const&); 111 void insert_temporary_breakpoint(FlatPtr address); 112 void insert_temporary_breakpoint_at_return_address(PtraceRegisters const&); 113 114 struct CreateDebugSessionResult { 115 NonnullOwnPtr<Debug::DebugSession> session; 116 Debug::DebugSession::DesiredInitialDebugeeState initial_state { Debug::DebugSession::Stopped }; 117 }; 118 CreateDebugSessionResult create_debug_session(); 119 120 OwnPtr<Debug::DebugSession> m_debug_session; 121 DeprecatedString m_source_root; 122 DebuggingState m_state; 123 124 pthread_mutex_t m_ui_action_mutex {}; 125 pthread_cond_t m_ui_action_cond {}; 126 DebuggerAction m_requested_debugger_action { DebuggerAction::Continue }; 127 128 Vector<Debug::DebugInfo::SourcePosition> m_breakpoints; 129 130 DeprecatedString m_executable_path; 131 Optional<pid_t> m_pid_to_attach; 132 133 Function<HasControlPassedToUser(PtraceRegisters const&)> m_on_stopped_callback; 134 Function<void()> m_on_continue_callback; 135 Function<void()> m_on_exit_callback; 136 Function<ErrorOr<void>()> m_child_setup_callback; 137 Function<void(float)> m_on_initialization_progress; 138}; 139 140}