LLDB mainline
DebuggerThread.cpp
Go to the documentation of this file.
1//===-- DebuggerThread.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DebuggerThread.h"
10#include "ExceptionRecord.h"
11#include "IDebugDelegate.h"
12
20#include "lldb/Target/Process.h"
22#include "lldb/Utility/Log.h"
24#include "lldb/Utility/Status.h"
25
27
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/Support/ConvertUTF.h"
30#include "llvm/Support/Threading.h"
31#include "llvm/Support/raw_ostream.h"
32
33#include <optional>
34#include <psapi.h>
35
36#ifndef STATUS_WX86_BREAKPOINT
37#define STATUS_WX86_BREAKPOINT 0x4000001FL // For WOW64
38#endif
39
40using namespace lldb;
41using namespace lldb_private;
42
44 : m_debug_delegate(debug_delegate), m_pid_to_detach(0),
45 m_is_shutting_down(false) {
46 m_debugging_ended_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
47}
48
50
53 LLDB_LOG(log, "launching '{0}'", launch_info.GetExecutableFile().GetPath());
54
55 Status result;
56 llvm::Expected<HostThread> secondary_thread = ThreadLauncher::LaunchThread(
57 "lldb.plugin.process-windows.secondary[?]",
58 [this, launch_info] { return DebuggerThreadLaunchRoutine(launch_info); });
59 if (!secondary_thread) {
60 result = Status::FromError(secondary_thread.takeError());
61 LLDB_LOG(log, "couldn't launch debugger thread. {0}", result);
62 }
63
64 return result;
65}
66
68 const ProcessAttachInfo &attach_info) {
70 LLDB_LOG(log, "attaching to '{0}'", pid);
71
72 Status result;
73 llvm::Expected<HostThread> secondary_thread = ThreadLauncher::LaunchThread(
74 "lldb.plugin.process-windows.secondary[?]", [this, pid, attach_info] {
75 return DebuggerThreadAttachRoutine(pid, attach_info);
76 });
77 if (!secondary_thread) {
78 result = Status::FromError(secondary_thread.takeError());
79 LLDB_LOG(log, "couldn't attach to process '{0}'. {1}", pid, result);
80 }
81
82 return result;
83}
84
86 const ProcessLaunchInfo &launch_info) {
87 // Grab a shared_ptr reference to this so that we know it won't get deleted
88 // until after the thread routine has exited.
89 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
90
92 LLDB_LOG(log, "preparing to launch '{0}' on background thread.",
93 launch_info.GetExecutableFile().GetPath());
94
97 HostProcess process(launcher.LaunchProcess(launch_info, error));
98 // If we couldn't create the process, notify waiters immediately. Otherwise
99 // enter the debug loop and wait until we get the create process debug
100 // notification. Note that if the process was created successfully, we can
101 // throw away the process handle we got from CreateProcess because Windows
102 // will give us another (potentially more useful?) handle when it sends us
103 // the CREATE_PROCESS_DEBUG_EVENT.
104 if (error.Success())
105 DebugLoop();
106 else
107 m_debug_delegate->OnDebuggerError(error, 0);
108
109 return {};
110}
111
113 lldb::pid_t pid, const ProcessAttachInfo &attach_info) {
114 // Grab a shared_ptr reference to this so that we know it won't get deleted
115 // until after the thread routine has exited.
116 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
117
119 LLDB_LOG(log, "preparing to attach to process '{0}' on background thread.",
120 pid);
121
122 if (!DebugActiveProcess((DWORD)pid)) {
123 Status error(::GetLastError(), eErrorTypeWin32);
124 m_debug_delegate->OnDebuggerError(error, 0);
125 return {};
126 }
127
128 // The attach was successful, enter the debug loop. From here on out, this
129 // is no different than a create process operation, so all the same comments
130 // in DebugLaunch should apply from this point out.
131 DebugLoop();
132
133 return {};
134}
135
138
140
142 LLDB_LOG(log, "terminate = {0}, inferior={1}.", terminate, pid);
143
144 // Set m_is_shutting_down to true if it was false. Return if it was already
145 // true.
146 bool expected = false;
147 if (!m_is_shutting_down.compare_exchange_strong(expected, true))
148 return error;
149
150 // Make a copy of the process, since the termination sequence will reset
151 // DebuggerThread's internal copy and it needs to remain open for the Wait
152 // operation.
153 HostProcess process_copy = m_process;
155
156 if (terminate) {
157 if (handle != nullptr && handle != LLDB_INVALID_PROCESS) {
158 // Initiate the termination before continuing the exception, so that the
159 // next debug event we get is the exit process event, and not some other
160 // event.
161 BOOL terminate_suceeded = TerminateProcess(handle, 0);
162 LLDB_LOG(log,
163 "calling TerminateProcess({0}, 0) (inferior={1}), success={2}",
164 handle, pid, terminate_suceeded);
165 } else {
166 LLDB_LOG(log,
167 "NOT calling TerminateProcess because the inferior is not valid "
168 "({0}, 0) (inferior={1})",
169 handle, pid);
170 }
171 }
172
173 // If we're stuck waiting for an exception to continue (e.g. the user is at a
174 // breakpoint messing around in the debugger), continue it now. But only
175 // AFTER calling TerminateProcess to make sure that the very next call to
176 // WaitForDebugEvent is an exit process event.
177 if (m_active_exception.get()) {
178 LLDB_LOG(log, "masking active exception");
179 ContinueAsyncException(ExceptionResult::MaskException);
180 }
181
182 if (!terminate) {
183 // Indicate that we want to detach.
185
186 // Force a fresh break so that the detach can happen from the debugger
187 // thread.
188 if (!::DebugBreakProcess(
189 GetProcess().GetNativeProcess().GetSystemHandle())) {
190 error = Status(::GetLastError(), eErrorTypeWin32);
191 }
192 }
193
194 LLDB_LOG(log, "waiting for detach from process {0} to complete.", pid);
195
196 DWORD wait_result = WaitForSingleObject(m_debugging_ended_event, 5000);
197 if (wait_result != WAIT_OBJECT_0) {
198 error = Status(GetLastError(), eErrorTypeWin32);
199 LLDB_LOG(log, "error: WaitForSingleObject({0}, 5000) returned {1}",
200 m_debugging_ended_event, wait_result);
201 } else
202 LLDB_LOG(log, "detach from process {0} completed successfully.", pid);
203
204 if (!error.Success()) {
205 LLDB_LOG(log, "encountered an error while trying to stop process {0}. {1}",
206 pid, error);
207 }
208 return error;
209}
210
212 if (!m_active_exception.get())
213 return;
214
216 LLDB_LOG(log, "broadcasting for inferior process {0}.",
218
219 m_active_exception.reset();
221}
222
226 if (m_image_file) {
227 ::CloseHandle(m_image_file);
228 m_image_file = nullptr;
229 }
230}
231
234 DEBUG_EVENT dbe = {};
235 bool should_debug = true;
236 LLDB_LOGV(log, "Entering WaitForDebugEvent loop");
237 while (should_debug) {
238 LLDB_LOGV(log, "Calling WaitForDebugEvent");
239 BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE);
240 if (wait_result) {
241 DWORD continue_status = DBG_CONTINUE;
242 bool shutting_down = m_is_shutting_down;
243 switch (dbe.dwDebugEventCode) {
244 default:
245 llvm_unreachable("Unhandle debug event code!");
246 case EXCEPTION_DEBUG_EVENT: {
248 dbe.u.Exception, dbe.dwThreadId, shutting_down);
249
250 if (status == ExceptionResult::MaskException)
251 continue_status = DBG_CONTINUE;
252 else if (status == ExceptionResult::SendToApplication)
253 continue_status = DBG_EXCEPTION_NOT_HANDLED;
254
255 break;
256 }
257 case CREATE_THREAD_DEBUG_EVENT:
258 continue_status =
259 HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId);
260 break;
261 case CREATE_PROCESS_DEBUG_EVENT:
262 continue_status =
263 HandleCreateProcessEvent(dbe.u.CreateProcessInfo, dbe.dwThreadId);
264 break;
265 case EXIT_THREAD_DEBUG_EVENT:
266 continue_status =
267 HandleExitThreadEvent(dbe.u.ExitThread, dbe.dwThreadId);
268 break;
269 case EXIT_PROCESS_DEBUG_EVENT:
270 continue_status =
271 HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId);
272 should_debug = false;
273 break;
274 case LOAD_DLL_DEBUG_EVENT:
275 continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId);
276 break;
277 case UNLOAD_DLL_DEBUG_EVENT:
278 continue_status = HandleUnloadDllEvent(dbe.u.UnloadDll, dbe.dwThreadId);
279 break;
280 case OUTPUT_DEBUG_STRING_EVENT:
281 continue_status = HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
282 break;
283 case RIP_EVENT:
284 continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId);
285 if (dbe.u.RipInfo.dwType == SLE_ERROR)
286 should_debug = false;
287 break;
288 }
289
290 LLDB_LOGV(log, "calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.",
291 dbe.dwProcessId, dbe.dwThreadId, continue_status,
292 ::GetCurrentThreadId());
293
294 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
295
296 // We have to DebugActiveProcessStop after ContinueDebugEvent, otherwise
297 // the target process will crash
298 if (shutting_down) {
299 // A breakpoint that occurs while `m_pid_to_detach` is non-zero is a
300 // magic exception that we use simply to wake up the DebuggerThread so
301 // that we can close out the debug loop.
302 if (m_pid_to_detach != 0 &&
303 (dbe.u.Exception.ExceptionRecord.ExceptionCode ==
304 EXCEPTION_BREAKPOINT ||
305 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
307 LLDB_LOG(log,
308 "Breakpoint exception is cue to detach from process {0:x}",
309 m_pid_to_detach.load());
310
311 // detaching with leaving breakpoint exception event on the queue may
312 // cause target process to crash so process events as possible since
313 // target threads are running at this time, there is possibility to
314 // have some breakpoint exception between last WaitForDebugEvent and
315 // DebugActiveProcessStop but ignore for now.
316 while (WaitForDebugEvent(&dbe, 0)) {
317 continue_status = DBG_CONTINUE;
318 if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
319 !(dbe.u.Exception.ExceptionRecord.ExceptionCode ==
320 EXCEPTION_BREAKPOINT ||
321 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
323 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
324 EXCEPTION_SINGLE_STEP))
325 continue_status = DBG_EXCEPTION_NOT_HANDLED;
326 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId,
327 continue_status);
328 }
329
330 ::DebugActiveProcessStop(m_pid_to_detach);
331 m_detached = true;
332 }
333 }
334
335 if (m_detached) {
336 should_debug = false;
337 }
338 } else {
339 LLDB_LOG(log, "returned FALSE from WaitForDebugEvent. Error = {0}",
340 ::GetLastError());
341
342 should_debug = false;
343 }
344 }
346
347 LLDB_LOG(log, "WaitForDebugEvent loop completed, exiting.");
348 ::SetEvent(m_debugging_ended_event);
349}
350
352DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info,
353 DWORD thread_id, bool shutting_down) {
355 if (shutting_down) {
356 bool is_breakpoint =
357 (info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ||
358 info.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT);
359
360 // Don't perform any blocking operations while we're shutting down. That
361 // will cause TerminateProcess -> WaitForSingleObject to time out.
362 // We should not send breakpoint exceptions to the application.
363 return is_breakpoint ? ExceptionResult::MaskException
364 : ExceptionResult::SendToApplication;
365 }
366
367 bool first_chance = (info.dwFirstChance != 0);
368
369 m_active_exception.reset(
370 new ExceptionRecord(info.ExceptionRecord, thread_id));
371 LLDB_LOG(log, "encountered {0} chance exception {1:x} on thread {2:x}",
372 first_chance ? "first" : "second",
373 info.ExceptionRecord.ExceptionCode, thread_id);
374
375 ExceptionResult result =
376 m_debug_delegate->OnDebugException(first_chance, *m_active_exception);
378
379 LLDB_LOG(log, "waiting for ExceptionPred != BreakInDebugger");
381 ExceptionResult::BreakInDebugger);
382
383 LLDB_LOG(log, "got ExceptionPred = {0}", (int)m_exception_pred.GetValue());
384 return result;
385}
386
387DWORD
388DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info,
389 DWORD thread_id) {
391 LLDB_LOG(log, "Thread {0} spawned in process {1}", thread_id,
393 HostThread thread(info.hThread);
394 thread.GetNativeThread().SetOwnsHandle(false);
395 m_debug_delegate->OnCreateThread(thread);
396 return DBG_CONTINUE;
397}
398
399DWORD
400DebuggerThread::HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info,
401 DWORD thread_id) {
403 uint32_t process_id = ::GetProcessId(info.hProcess);
404
405 LLDB_LOG(log, "process {0} spawned", process_id);
406
407 std::string thread_name;
408 llvm::raw_string_ostream name_stream(thread_name);
409 name_stream << "lldb.plugin.process-windows.secondary[" << process_id << "]";
410 llvm::set_thread_name(thread_name);
411
412 // info.hProcess and info.hThread are closed automatically by Windows when
413 // EXIT_PROCESS_DEBUG_EVENT is received.
414 m_process = HostProcess(info.hProcess);
415 ((HostProcessWindows &)m_process.GetNativeProcess()).SetOwnsHandle(false);
416 m_main_thread = HostThread(info.hThread);
417 m_main_thread.GetNativeThread().SetOwnsHandle(false);
418 m_image_file = info.hFile;
419
420 lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfImage);
421 m_debug_delegate->OnDebuggerConnected(load_addr);
422
423 return DBG_CONTINUE;
424}
425
426DWORD
427DebuggerThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info,
428 DWORD thread_id) {
430 LLDB_LOG(log, "Thread {0} exited with code {1} in process {2}", thread_id,
431 info.dwExitCode, m_process.GetProcessId());
432 m_debug_delegate->OnExitThread(thread_id, info.dwExitCode);
433 return DBG_CONTINUE;
434}
435
436DWORD
437DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info,
438 DWORD thread_id) {
440 LLDB_LOG(log, "process {0} exited with code {1}", m_process.GetProcessId(),
441 info.dwExitCode);
442
443 m_debug_delegate->OnExitProcess(info.dwExitCode);
444
445 return DBG_CONTINUE;
446}
447
448static std::optional<std::string> GetFileNameFromHandleFallback(HANDLE hFile) {
449 // Check that file is not empty as we cannot map a file with zero length.
450 DWORD dwFileSizeHi = 0;
451 DWORD dwFileSizeLo = ::GetFileSize(hFile, &dwFileSizeHi);
452 if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
453 return std::nullopt;
454
455 AutoHandle filemap(
456 ::CreateFileMappingW(hFile, nullptr, PAGE_READONLY, 0, 1, NULL), nullptr);
457 if (!filemap.IsValid())
458 return std::nullopt;
459
460 auto view_deleter = [](void *pMem) { ::UnmapViewOfFile(pMem); };
461 std::unique_ptr<void, decltype(view_deleter)> pMem(
462 ::MapViewOfFile(filemap.get(), FILE_MAP_READ, 0, 0, 1), view_deleter);
463 if (!pMem)
464 return std::nullopt;
465
466 std::array<wchar_t, MAX_PATH + 1> mapped_filename;
467 if (!::GetMappedFileNameW(::GetCurrentProcess(), pMem.get(),
468 mapped_filename.data(), mapped_filename.size()))
469 return std::nullopt;
470
471 // A series of null-terminated strings, plus an additional null character
472 std::array<wchar_t, 512> drive_strings;
473 drive_strings[0] = L'\0';
474 if (!::GetLogicalDriveStringsW(drive_strings.size(), drive_strings.data()))
475 return std::nullopt;
476
477 std::array<wchar_t, 3> drive = {L"_:"};
478 for (const wchar_t *it = drive_strings.data(); *it != L'\0';
479 it += wcslen(it) + 1) {
480 // Copy the drive letter to the template string
481 drive[0] = it[0];
482 std::array<wchar_t, MAX_PATH> device_name;
483 if (::QueryDosDeviceW(drive.data(), device_name.data(),
484 device_name.size())) {
485 size_t device_name_len = wcslen(device_name.data());
486 if (device_name_len < mapped_filename.size()) {
487 bool match = _wcsnicmp(mapped_filename.data(), device_name.data(),
488 device_name_len) == 0;
489 if (match && mapped_filename[device_name_len] == L'\\') {
490 // Replace device path with its drive letter
491 std::wstring rebuilt_path(drive.data());
492 rebuilt_path.append(&mapped_filename[device_name_len]);
493 std::string path_utf8;
494 llvm::convertWideToUTF8(rebuilt_path, path_utf8);
495 return path_utf8;
496 }
497 }
498 }
499 }
500 return std::nullopt;
501}
502
503DWORD
504DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info,
505 DWORD thread_id) {
507 if (info.hFile == nullptr) {
508 // Not sure what this is, so just ignore it.
509 LLDB_LOG(log, "Warning: Inferior {0} has a NULL file handle, returning...",
511 return DBG_CONTINUE;
512 }
513
514 auto on_load_dll = [&](llvm::StringRef path) {
515 FileSpec file_spec(path);
516 ModuleSpec module_spec(file_spec);
517 lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll);
518
519 LLDB_LOG(log, "Inferior {0} - DLL '{1}' loaded at address {2:x}...",
520 m_process.GetProcessId(), path, info.lpBaseOfDll);
521
522 m_debug_delegate->OnLoadDll(module_spec, load_addr);
523 };
524
525 std::vector<wchar_t> buffer(1);
526 DWORD required_size =
527 GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
528 if (required_size > 0) {
529 buffer.resize(required_size + 1);
530 required_size = GetFinalPathNameByHandleW(info.hFile, &buffer[0],
531 required_size, VOLUME_NAME_DOS);
532 std::string path_str_utf8;
533 llvm::convertWideToUTF8(buffer.data(), path_str_utf8);
534 llvm::StringRef path_str = path_str_utf8;
535 const char *path = path_str.data();
536 if (path_str.starts_with("\\\\?\\"))
537 path += 4;
538
539 on_load_dll(path);
540 } else if (std::optional<std::string> path =
541 GetFileNameFromHandleFallback(info.hFile)) {
542 on_load_dll(*path);
543 } else {
544 LLDB_LOG(
545 log,
546 "Inferior {0} - Error {1} occurred calling GetFinalPathNameByHandle",
547 m_process.GetProcessId(), ::GetLastError());
548 }
549 // Windows does not automatically close info.hFile, so we need to do it.
550 ::CloseHandle(info.hFile);
551 return DBG_CONTINUE;
552}
553
554DWORD
555DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info,
556 DWORD thread_id) {
558 LLDB_LOG(log, "process {0} unloading DLL at addr {1:x}.",
559 m_process.GetProcessId(), info.lpBaseOfDll);
560
561 m_debug_delegate->OnUnloadDll(
562 reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll));
563 return DBG_CONTINUE;
564}
565
566DWORD
567DebuggerThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info,
568 DWORD thread_id) {
569 return DBG_CONTINUE;
570}
571
572DWORD
573DebuggerThread::HandleRipEvent(const RIP_INFO &info, DWORD thread_id) {
575 LLDB_LOG(log, "encountered error {0} (type={1}) in process {2} thread {3}",
576 info.dwError, info.dwType, m_process.GetProcessId(), thread_id);
577
578 Status error(info.dwError, eErrorTypeWin32);
579 m_debug_delegate->OnDebuggerError(error, info.dwType);
580
581 return DBG_CONTINUE;
582}
static llvm::raw_ostream & error(Stream &strm)
static std::optional< std::string > GetFileNameFromHandleFallback(HANDLE hFile)
#define STATUS_WX86_BREAKPOINT
ExceptionResult
Definition: ForwardDecl.h:16
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:369
#define LLDB_LOGV(log,...)
Definition: Log.h:383
bool IsValid() const
Definition: AutoHandle.h:26
HANDLE get() const
Definition: AutoHandle.h:28
std::atomic< bool > m_is_shutting_down
std::atomic< DWORD > m_pid_to_detach
DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id)
DWORD HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id)
DWORD HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
DWORD HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id)
Status StopDebugging(bool terminate)
DWORD HandleRipEvent(const RIP_INFO &info, DWORD thread_id)
void ContinueAsyncException(ExceptionResult result)
HostProcess GetProcess() const
lldb::thread_result_t DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &launch_info)
DebuggerThread(DebugDelegateSP debug_delegate)
DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id)
ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id, bool shutting_down)
Status DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info)
lldb::thread_result_t DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info)
ExceptionRecordSP m_active_exception
Predicate< ExceptionResult > m_exception_pred
Status DebugLaunch(const ProcessLaunchInfo &launch_info)
DWORD HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
DebugDelegateSP m_debug_delegate
DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id)
A file utility class.
Definition: FileSpec.h:56
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
HostNativeProcessBase & GetNativeProcess()
Definition: HostProcess.cpp:36
lldb::pid_t GetProcessId() const
Definition: HostProcess.cpp:25
HostNativeThread & GetNativeThread()
Definition: HostThread.cpp:32
void SetValue(T value, PredicateBroadcastType broadcast_type)
Value set accessor.
Definition: Predicate.h:90
T GetValue() const
Value get accessor.
Definition: Predicate.h:71
std::optional< T > WaitForValueNotEqualTo(T value, const Timeout< std::micro > &timeout=std::nullopt)
Wait for m_value to not be equal to value.
Definition: Predicate.h:185
FileSpec & GetExecutableFile()
Definition: ProcessInfo.h:43
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) override
An error handling class.
Definition: Status.h:115
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition: Status.cpp:137
static llvm::Expected< HostThread > LaunchThread(llvm::StringRef name, std::function< lldb::thread_result_t()> thread_function, size_t min_stack_byte_size=0)
#define LLDB_INVALID_PROCESS
Definition: lldb-types.h:68
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:332
@ eBroadcastNever
No broadcast will be sent when the value is modified.
Definition: Predicate.h:28
@ eBroadcastAlways
Always send a broadcast when the value is modified.
Definition: Predicate.h:29
std::shared_ptr< IDebugDelegate > DebugDelegateSP
Definition: ForwardDecl.h:35
Definition: SBAddress.h:15
void * thread_result_t
Definition: lldb-types.h:62
@ eErrorTypeWin32
Standard Win32 error codes.
uint64_t pid_t
Definition: lldb-types.h:83
uint64_t addr_t
Definition: lldb-types.h:80
uint64_t process_t
Definition: lldb-types.h:57