|
8 | 8 |
|
9 | 9 | #include "EventHelper.h" |
10 | 10 | #include "DAP.h" |
11 | | -#include "DAPLog.h" |
| 11 | +#include "DAPError.h" |
12 | 12 | #include "JSONUtils.h" |
13 | 13 | #include "LLDBUtils.h" |
14 | 14 | #include "lldb/API/SBFileSpec.h" |
| 15 | +#include "llvm/Support/Error.h" |
15 | 16 |
|
16 | 17 | #if defined(_WIN32) |
17 | 18 | #define NOMINMAX |
|
22 | 23 | #endif |
23 | 24 | #endif |
24 | 25 |
|
| 26 | +using namespace llvm; |
| 27 | + |
25 | 28 | namespace lldb_dap { |
26 | 29 |
|
27 | 30 | static void SendThreadExitedEvent(DAP &dap, lldb::tid_t tid) { |
@@ -116,78 +119,78 @@ void SendProcessEvent(DAP &dap, LaunchMethod launch_method) { |
116 | 119 |
|
117 | 120 | // Send a thread stopped event for all threads as long as the process |
118 | 121 | // is stopped. |
119 | | -void SendThreadStoppedEvent(DAP &dap) { |
| 122 | +llvm::Error SendThreadStoppedEvent(DAP &dap, bool on_entry) { |
| 123 | + lldb::SBMutex lock = dap.GetAPIMutex(); |
| 124 | + std::lock_guard<lldb::SBMutex> guard(lock); |
| 125 | + |
120 | 126 | lldb::SBProcess process = dap.target.GetProcess(); |
121 | | - if (process.IsValid()) { |
122 | | - auto state = process.GetState(); |
123 | | - if (state == lldb::eStateStopped) { |
124 | | - llvm::DenseSet<lldb::tid_t> old_thread_ids; |
125 | | - old_thread_ids.swap(dap.thread_ids); |
126 | | - uint32_t stop_id = process.GetStopID(); |
127 | | - const uint32_t num_threads = process.GetNumThreads(); |
128 | | - |
129 | | - // First make a pass through the threads to see if the focused thread |
130 | | - // has a stop reason. In case the focus thread doesn't have a stop |
131 | | - // reason, remember the first thread that has a stop reason so we can |
132 | | - // set it as the focus thread if below if needed. |
133 | | - lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID; |
134 | | - uint32_t num_threads_with_reason = 0; |
135 | | - bool focus_thread_exists = false; |
136 | | - for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { |
137 | | - lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); |
138 | | - const lldb::tid_t tid = thread.GetThreadID(); |
139 | | - const bool has_reason = ThreadHasStopReason(thread); |
140 | | - // If the focus thread doesn't have a stop reason, clear the thread ID |
141 | | - if (tid == dap.focus_tid) { |
142 | | - focus_thread_exists = true; |
143 | | - if (!has_reason) |
144 | | - dap.focus_tid = LLDB_INVALID_THREAD_ID; |
145 | | - } |
146 | | - if (has_reason) { |
147 | | - ++num_threads_with_reason; |
148 | | - if (first_tid_with_reason == LLDB_INVALID_THREAD_ID) |
149 | | - first_tid_with_reason = tid; |
150 | | - } |
151 | | - } |
| 127 | + if (!process.IsValid()) |
| 128 | + return make_error<DAPError>("invalid process"); |
| 129 | + |
| 130 | + lldb::StateType state = process.GetState(); |
| 131 | + if (!lldb::SBDebugger::StateIsStoppedState(state)) |
| 132 | + return make_error<NotStoppedError>(); |
| 133 | + |
| 134 | + llvm::DenseSet<lldb::tid_t> old_thread_ids; |
| 135 | + old_thread_ids.swap(dap.thread_ids); |
| 136 | + uint32_t stop_id = process.GetStopID(); |
| 137 | + const uint32_t num_threads = process.GetNumThreads(); |
| 138 | + |
| 139 | + // First make a pass through the threads to see if the focused thread |
| 140 | + // has a stop reason. In case the focus thread doesn't have a stop |
| 141 | + // reason, remember the first thread that has a stop reason so we can |
| 142 | + // set it as the focus thread if below if needed. |
| 143 | + lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID; |
| 144 | + uint32_t num_threads_with_reason = 0; |
| 145 | + bool focus_thread_exists = false; |
| 146 | + for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { |
| 147 | + lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); |
| 148 | + const lldb::tid_t tid = thread.GetThreadID(); |
| 149 | + const bool has_reason = ThreadHasStopReason(thread); |
| 150 | + // If the focus thread doesn't have a stop reason, clear the thread ID |
| 151 | + if (tid == dap.focus_tid) { |
| 152 | + focus_thread_exists = true; |
| 153 | + if (!has_reason) |
| 154 | + dap.focus_tid = LLDB_INVALID_THREAD_ID; |
| 155 | + } |
| 156 | + if (has_reason) { |
| 157 | + ++num_threads_with_reason; |
| 158 | + if (first_tid_with_reason == LLDB_INVALID_THREAD_ID) |
| 159 | + first_tid_with_reason = tid; |
| 160 | + } |
| 161 | + } |
152 | 162 |
|
153 | | - // We will have cleared dap.focus_tid if the focus thread doesn't have |
154 | | - // a stop reason, so if it was cleared, or wasn't set, or doesn't exist, |
155 | | - // then set the focus thread to the first thread with a stop reason. |
156 | | - if (!focus_thread_exists || dap.focus_tid == LLDB_INVALID_THREAD_ID) |
157 | | - dap.focus_tid = first_tid_with_reason; |
158 | | - |
159 | | - // If no threads stopped with a reason, then report the first one so |
160 | | - // we at least let the UI know we stopped. |
161 | | - if (num_threads_with_reason == 0) { |
162 | | - lldb::SBThread thread = process.GetThreadAtIndex(0); |
163 | | - dap.focus_tid = thread.GetThreadID(); |
| 163 | + // We will have cleared dap.focus_tid if the focus thread doesn't have |
| 164 | + // a stop reason, so if it was cleared, or wasn't set, or doesn't exist, |
| 165 | + // then set the focus thread to the first thread with a stop reason. |
| 166 | + if (!focus_thread_exists || dap.focus_tid == LLDB_INVALID_THREAD_ID) |
| 167 | + dap.focus_tid = first_tid_with_reason; |
| 168 | + |
| 169 | + // If no threads stopped with a reason, then report the first one so |
| 170 | + // we at least let the UI know we stopped. |
| 171 | + if (num_threads_with_reason == 0) { |
| 172 | + lldb::SBThread thread = process.GetThreadAtIndex(0); |
| 173 | + dap.focus_tid = thread.GetThreadID(); |
| 174 | + dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); |
| 175 | + } else { |
| 176 | + for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { |
| 177 | + lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); |
| 178 | + dap.thread_ids.insert(thread.GetThreadID()); |
| 179 | + if (ThreadHasStopReason(thread)) { |
164 | 180 | dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); |
165 | | - } else { |
166 | | - for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { |
167 | | - lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); |
168 | | - dap.thread_ids.insert(thread.GetThreadID()); |
169 | | - if (ThreadHasStopReason(thread)) { |
170 | | - dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); |
171 | | - } |
172 | | - } |
173 | 181 | } |
174 | | - |
175 | | - for (auto tid : old_thread_ids) { |
176 | | - auto end = dap.thread_ids.end(); |
177 | | - auto pos = dap.thread_ids.find(tid); |
178 | | - if (pos == end) |
179 | | - SendThreadExitedEvent(dap, tid); |
180 | | - } |
181 | | - } else { |
182 | | - DAP_LOG( |
183 | | - dap.log, |
184 | | - "error: SendThreadStoppedEvent() when process isn't stopped ({0})", |
185 | | - lldb::SBDebugger::StateAsCString(state)); |
186 | 182 | } |
187 | | - } else { |
188 | | - DAP_LOG(dap.log, "error: SendThreadStoppedEvent() invalid process"); |
189 | 183 | } |
| 184 | + |
| 185 | + for (const auto &tid : old_thread_ids) { |
| 186 | + auto end = dap.thread_ids.end(); |
| 187 | + auto pos = dap.thread_ids.find(tid); |
| 188 | + if (pos == end) |
| 189 | + SendThreadExitedEvent(dap, tid); |
| 190 | + } |
| 191 | + |
190 | 192 | dap.RunStopCommands(); |
| 193 | + return Error::success(); |
191 | 194 | } |
192 | 195 |
|
193 | 196 | // Send a "terminated" event to indicate the process is done being |
|
0 commit comments