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