• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef VK_DEBUG_THREAD_HPP_
16 #define VK_DEBUG_THREAD_HPP_
17 
18 #include "Context.hpp"
19 #include "ID.hpp"
20 #include "Location.hpp"
21 
22 #include "marl/mutex.h"
23 #include "marl/tsa.h"
24 
25 #include <condition_variable>
26 #include <memory>
27 #include <string>
28 #include <vector>
29 
30 namespace vk {
31 namespace dbg {
32 
33 class File;
34 class VariableContainer;
35 class ServerEventListener;
36 
37 // Scope is a container for variables and is used to provide source data for the
38 // DAP 'Scope' type:
39 // https://microsoft.github.io/debug-adapter-protocol/specification#Types_Scope
40 class Scope
41 {
42 public:
43 	using ID = dbg::ID<Scope>;
44 
45 	inline Scope(ID id,
46 	             const std::shared_ptr<File> &file,
47 	             const std::shared_ptr<VariableContainer> &variables);
48 
49 	// The unique identifier of the scope.
50 	const ID id;
51 
52 	// The file this scope is associated with.
53 	const std::shared_ptr<File> file;
54 
55 	// The scope's variables.
56 	const std::shared_ptr<VariableContainer> variables;
57 };
58 
Scope(ID id,const std::shared_ptr<File> & file,const std::shared_ptr<VariableContainer> & variables)59 Scope::Scope(ID id,
60              const std::shared_ptr<File> &file,
61              const std::shared_ptr<VariableContainer> &variables)
62     : id(id)
63     , file(file)
64     , variables(variables)
65 {}
66 
67 // Frame holds a number of variable scopes for one of a thread's stack frame,
68 // and is used to provide source data for the DAP 'StackFrame' type:
69 // https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame
70 class Frame
71 {
72 public:
73 	using ID = dbg::ID<Frame>;
74 
75 	inline Frame(ID id, std::string function);
76 
77 	// The unique identifier of the stack frame.
78 	const ID id;
79 
80 	// The name of function for this stack frame.
81 	const std::string function;
82 
83 	// The current execution location within the stack frame.
84 	Location location;
85 
86 	// The scope for the frame's arguments.
87 	std::shared_ptr<Scope> arguments;
88 
89 	// The scope for the frame's locals.
90 	std::shared_ptr<Scope> locals;
91 
92 	// The scope for the frame's registers.
93 	std::shared_ptr<Scope> registers;
94 
95 	// The scope for variables that should only appear in hover tooltips.
96 	std::shared_ptr<Scope> hovers;
97 };
98 
Frame(ID id,std::string function)99 Frame::Frame(ID id, std::string function)
100     : id(id)
101     , function(std::move(function))
102 {}
103 
104 // Thread holds the state for a single thread of execution.
105 class Thread
106 {
107 public:
108 	using ID = dbg::ID<Thread>;
109 
110 	using UpdateFrame = std::function<void(Frame &)>;
111 
112 	// The current execution state.
113 	enum class State
114 	{
115 		Running,   // Thread is running.
116 		Stepping,  // Thread is currently single line stepping.
117 		Paused     // Thread is currently paused.
118 	};
119 
120 	Thread(ID id, Context *ctx);
121 
122 	// setName() sets the name of the thread.
123 	void setName(const std::string &);
124 
125 	// name() returns the name of the thread.
126 	std::string name() const;
127 
128 	// enter() pushes the thread's stack with a new frame created with the given
129 	// file and function, then calls f to modify the new frame of the stack.
130 	void enter(const std::shared_ptr<File> &file, const std::string &function, const UpdateFrame &f = nullptr);
131 
132 	// exit() pops the thread's stack frame.
133 	// If isStep is true, then this will be considered a line-steppable event,
134 	// and the debugger may pause at the function call at the new top most stack
135 	// frame.
136 	void exit(bool isStep = false);
137 
138 	// frame() returns a copy of the thread's top most stack frame.
139 	Frame frame() const;
140 
141 	// stack() returns a copy of the thread's current stack frames.
142 	std::vector<Frame> stack() const;
143 
144 	// depth() returns the number of stack frames.
145 	size_t depth() const;
146 
147 	// state() returns the current thread's state.
148 	State state() const;
149 
150 	// update() calls f to modify the top most frame of the stack.
151 	// If the frame's location is changed and isStep is true, update()
152 	// potentially blocks until the thread is resumed with one of the methods
153 	// below.
154 	// isStep is used to distinguish same-statement column position updates
155 	// from full line updates. Note that we cannot simply examine line position
156 	// changes as single-line loops such as `while(true) { foo(); }` would not
157 	// be correctly steppable.
158 	void update(bool isStep, const UpdateFrame &f);
159 
160 	// resume() resumes execution of the thread by unblocking a call to
161 	// update() and setting the thread's state to State::Running.
162 	void resume();
163 
164 	// pause() suspends execution of the thread by blocking the next call to
165 	// update() and setting the thread's state to State::Paused.
166 	void pause();
167 
168 	// stepIn() temporarily resumes execution of the thread by unblocking a
169 	// call to update(), and setting the thread's state to State::Stepping.
170 	// The next call to update() will suspend execution again.
171 	void stepIn();
172 
173 	// stepOver() temporarily resumes execution of the thread by unblocking a
174 	// call to update(), and setting the thread's state to State::Stepping.
175 	// The next call to update() within the same stack frame will suspend
176 	// execution again.
177 	void stepOver();
178 
179 	// stepOut() temporarily resumes execution of the thread by unblocking a
180 	// call to update(), and setting the thread's state to State::Stepping.
181 	// The next call to update() at the stack frame above the current frame will
182 	// suspend execution again.
183 	void stepOut();
184 
185 	// The unique identifier of the thread.
186 	const ID id;
187 
188 private:
189 	Context *const ctx;
190 
191 	void onLocationUpdate(marl::lock &lock) REQUIRES(mutex);
192 
193 	mutable marl::mutex mutex;
194 	std::string name_ GUARDED_BY(mutex);
195 	std::vector<std::shared_ptr<Frame>> frames GUARDED_BY(mutex);
196 	State state_ GUARDED_BY(mutex) = State::Running;
197 	std::weak_ptr<Frame> pauseAtFrame GUARDED_BY(mutex);
198 
199 	std::condition_variable stateCV;
200 };
201 
202 }  // namespace dbg
203 }  // namespace vk
204 
205 #endif  // VK_DEBUG_THREAD_HPP_
206