1//===-- NativeProcessWindows.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 "lldb/Host/windows/windows.h"
10#include <psapi.h>
11
12#include "NativeProcessWindows.h"
13#include "NativeThreadWindows.h"
14#include "lldb/Host/FileSystem.h"
15#include "lldb/Host/HostNativeProcessBase.h"
16#include "lldb/Host/HostProcess.h"
17#include "lldb/Host/ProcessLaunchInfo.h"
18#include "lldb/Host/windows/AutoHandle.h"
19#include "lldb/Host/windows/HostThreadWindows.h"
20#include "lldb/Host/windows/ProcessLauncherWindows.h"
21#include "lldb/Target/MemoryRegionInfo.h"
22#include "lldb/Target/Process.h"
23#include "lldb/Utility/State.h"
24#include "llvm/Support/ConvertUTF.h"
25#include "llvm/Support/Errc.h"
26#include "llvm/Support/Error.h"
27#include "llvm/Support/Format.h"
28#include "llvm/Support/Threading.h"
29#include "llvm/Support/raw_ostream.h"
30
31#include "DebuggerThread.h"
32#include "ExceptionRecord.h"
33#include "ProcessWindowsLog.h"
34
35#include <tlhelp32.h>
36
37#pragma warning(disable : 4005)
38#include "winternl.h"
39#include <ntstatus.h>
40
41using namespace lldb;
42using namespace lldb_private;
43using namespace llvm;
44
45namespace lldb_private {
46
47NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
48 NativeDelegate &delegate,
49 llvm::Error &E)
50 : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID,
51 launch_info.GetPTY().ReleasePrimaryFileDescriptor(),
52 delegate),
53 ProcessDebugger(), m_arch(launch_info.GetArchitecture()) {
54 ErrorAsOutParameter EOut(&E);
55 DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
56 E = LaunchProcess(launch_info, delegate: delegate_sp).ToError();
57 if (E)
58 return;
59
60 SetID(GetDebuggedProcessId());
61}
62
63NativeProcessWindows::NativeProcessWindows(lldb::pid_t pid, int terminal_fd,
64 NativeDelegate &delegate,
65 llvm::Error &E)
66 : NativeProcessProtocol(pid, terminal_fd, delegate), ProcessDebugger() {
67 ErrorAsOutParameter EOut(&E);
68 DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
69 ProcessAttachInfo attach_info;
70 attach_info.SetProcessID(pid);
71 E = AttachProcess(pid, attach_info, delegate: delegate_sp).ToError();
72 if (E)
73 return;
74
75 SetID(GetDebuggedProcessId());
76
77 ProcessInstanceInfo info;
78 if (!Host::GetProcessInfo(pid, proc_info&: info)) {
79 E = createStringError(EC: inconvertibleErrorCode(),
80 S: "Cannot get process information");
81 return;
82 }
83 m_arch = info.GetArchitecture();
84}
85
86Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {
87 Log *log = GetLog(mask: WindowsLog::Process);
88 Status error;
89 llvm::sys::ScopedLock lock(m_mutex);
90
91 StateType state = GetState();
92 if (state == eStateStopped || state == eStateCrashed) {
93 LLDB_LOG(log, "process {0} is in state {1}. Resuming...",
94 GetDebuggedProcessId(), state);
95 LLDB_LOG(log, "resuming {0} threads.", m_threads.size());
96
97 bool failed = false;
98 for (uint32_t i = 0; i < m_threads.size(); ++i) {
99 auto thread = static_cast<NativeThreadWindows *>(m_threads[i].get());
100 const ResumeAction *const action =
101 resume_actions.GetActionForThread(tid: thread->GetID(), default_ok: true);
102 if (action == nullptr)
103 continue;
104
105 switch (action->state) {
106 case eStateRunning:
107 case eStateStepping: {
108 Status result = thread->DoResume(resume_state: action->state);
109 if (result.Fail()) {
110 failed = true;
111 LLDB_LOG(log,
112 "Trying to resume thread at index {0}, but failed with "
113 "error {1}.",
114 i, result);
115 }
116 break;
117 }
118 case eStateSuspended:
119 case eStateStopped:
120 break;
121
122 default:
123 return Status::FromErrorStringWithFormat(
124 format: "NativeProcessWindows::%s (): unexpected state %s specified "
125 "for pid %" PRIu64 ", tid %" PRIu64,
126 __FUNCTION__, StateAsCString(state: action->state), GetID(),
127 thread->GetID());
128 }
129 }
130
131 if (failed) {
132 error = Status::FromErrorString(str: "NativeProcessWindows::DoResume failed");
133 } else {
134 SetState(state: eStateRunning);
135 }
136
137 // Resume the debug loop.
138 ExceptionRecordSP active_exception =
139 m_session_data->m_debugger->GetActiveException().lock();
140 if (active_exception) {
141 // Resume the process and continue processing debug events. Mask the
142 // exception so that from the process's view, there is no indication that
143 // anything happened.
144 m_session_data->m_debugger->ContinueAsyncException(
145 result: ExceptionResult::MaskException);
146 }
147 } else {
148 LLDB_LOG(log, "error: process {0} is in state {1}. Returning...",
149 GetDebuggedProcessId(), GetState());
150 }
151
152 return error;
153}
154
155NativeThreadWindows *
156NativeProcessWindows::GetThreadByID(lldb::tid_t thread_id) {
157 return static_cast<NativeThreadWindows *>(
158 NativeProcessProtocol::GetThreadByID(tid: thread_id));
159}
160
161Status NativeProcessWindows::Halt() {
162 bool caused_stop = false;
163 StateType state = GetState();
164 if (state != eStateStopped)
165 return HaltProcess(caused_stop);
166 return Status();
167}
168
169Status NativeProcessWindows::Detach() {
170 Status error;
171 Log *log = GetLog(mask: WindowsLog::Process);
172 StateType state = GetState();
173 if (state != eStateExited && state != eStateDetached) {
174 error = DetachProcess();
175 if (error.Success())
176 SetState(state: eStateDetached);
177 else
178 LLDB_LOG(log, "Detaching process error: {0}", error);
179 } else {
180 error = Status::FromErrorStringWithFormatv(
181 format: "error: process {0} in state = {1}, but "
182 "cannot detach it in this state.",
183 args: GetID(), args&: state);
184 LLDB_LOG(log, "error: {0}", error);
185 }
186 return error;
187}
188
189Status NativeProcessWindows::Signal(int signo) {
190 Status error;
191 error = Status::FromErrorString(
192 str: "Windows does not support sending signals to processes");
193 return error;
194}
195
196Status NativeProcessWindows::Interrupt() { return Halt(); }
197
198Status NativeProcessWindows::Kill() {
199 StateType state = GetState();
200 return DestroyProcess(process_state: state);
201}
202
203Status NativeProcessWindows::IgnoreSignals(llvm::ArrayRef<int> signals) {
204 return Status();
205}
206
207Status NativeProcessWindows::GetMemoryRegionInfo(lldb::addr_t load_addr,
208 MemoryRegionInfo &range_info) {
209 return ProcessDebugger::GetMemoryRegionInfo(load_addr, range_info);
210}
211
212Status NativeProcessWindows::ReadMemory(lldb::addr_t addr, void *buf,
213 size_t size, size_t &bytes_read) {
214 return ProcessDebugger::ReadMemory(addr, buf, size, bytes_read);
215}
216
217Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf,
218 size_t size, size_t &bytes_written) {
219 return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written);
220}
221
222llvm::Expected<lldb::addr_t>
223NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions) {
224 lldb::addr_t addr;
225 Status ST = ProcessDebugger::AllocateMemory(size, permissions, addr);
226 if (ST.Success())
227 return addr;
228 return ST.ToError();
229}
230
231llvm::Error NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {
232 return ProcessDebugger::DeallocateMemory(addr).ToError();
233}
234
235lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; }
236
237bool NativeProcessWindows::IsAlive() const {
238 StateType state = GetState();
239 switch (state) {
240 case eStateCrashed:
241 case eStateDetached:
242 case eStateExited:
243 case eStateInvalid:
244 case eStateUnloaded:
245 return false;
246 default:
247 return true;
248 }
249}
250
251void NativeProcessWindows::SetStopReasonForThread(NativeThreadWindows &thread,
252 lldb::StopReason reason,
253 std::string description) {
254 SetCurrentThreadID(thread.GetID());
255
256 ThreadStopInfo stop_info;
257 stop_info.reason = reason;
258 // No signal support on Windows but required to provide a 'valid' signum.
259 stop_info.signo = SIGTRAP;
260
261 if (reason == StopReason::eStopReasonException) {
262 stop_info.details.exception.type = 0;
263 stop_info.details.exception.data_count = 0;
264 }
265
266 thread.SetStopReason(stop_info, description);
267}
268
269void NativeProcessWindows::StopThread(lldb::tid_t thread_id,
270 lldb::StopReason reason,
271 std::string description) {
272 NativeThreadWindows *thread = GetThreadByID(thread_id);
273 if (!thread)
274 return;
275
276 for (uint32_t i = 0; i < m_threads.size(); ++i) {
277 auto t = static_cast<NativeThreadWindows *>(m_threads[i].get());
278 Status error = t->DoStop();
279 if (error.Fail())
280 exit(status: 1);
281 }
282 SetStopReasonForThread(thread&: *thread, reason, description);
283}
284
285size_t NativeProcessWindows::UpdateThreads() { return m_threads.size(); }
286
287llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
288NativeProcessWindows::GetAuxvData() const {
289 // Not available on this target.
290 return llvm::errc::not_supported;
291}
292
293llvm::Expected<llvm::ArrayRef<uint8_t>>
294NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
295 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e,
296 0xd4}; // brk #0xf000
297 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
298
299 switch (GetArchitecture().GetMachine()) {
300 case llvm::Triple::aarch64:
301 return llvm::ArrayRef(g_aarch64_opcode);
302
303 case llvm::Triple::arm:
304 case llvm::Triple::thumb:
305 return llvm::ArrayRef(g_thumb_opcode);
306
307 default:
308 return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
309 }
310}
311
312size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() {
313 // Windows always reports an incremented PC after a breakpoint is hit,
314 // even on ARM.
315 return cantFail(ValOrErr: GetSoftwareBreakpointTrapOpcode(size_hint: 0)).size();
316}
317
318bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
319 auto it = m_software_breakpoints.find(x: addr);
320 if (it == m_software_breakpoints.end())
321 return false;
322 return true;
323}
324
325Status NativeProcessWindows::SetBreakpoint(lldb::addr_t addr, uint32_t size,
326 bool hardware) {
327 if (hardware)
328 return SetHardwareBreakpoint(addr, size);
329 return SetSoftwareBreakpoint(addr, size_hint: size);
330}
331
332Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,
333 bool hardware) {
334 if (hardware)
335 return RemoveHardwareBreakpoint(addr);
336 return RemoveSoftwareBreakpoint(addr);
337}
338
339Status NativeProcessWindows::CacheLoadedModules() {
340 Status error;
341 if (!m_loaded_modules.empty())
342 return Status();
343
344 // Retrieve loaded modules by a Target/Module free implemenation.
345 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
346 if (snapshot.IsValid()) {
347 MODULEENTRY32W me;
348 me.dwSize = sizeof(MODULEENTRY32W);
349 if (Module32FirstW(snapshot.get(), &me)) {
350 do {
351 std::string path;
352 if (!llvm::convertWideToUTF8(Source: me.szExePath, Result&: path))
353 continue;
354
355 FileSpec file_spec(path);
356 FileSystem::Instance().Resolve(file_spec);
357 m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr;
358 } while (Module32Next(snapshot.get(), &me));
359 }
360
361 if (!m_loaded_modules.empty())
362 return Status();
363 }
364
365 error = Status(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);
366 return error;
367}
368
369Status NativeProcessWindows::GetLoadedModuleFileSpec(const char *module_path,
370 FileSpec &file_spec) {
371 Status error = CacheLoadedModules();
372 if (error.Fail())
373 return error;
374
375 FileSpec module_file_spec(module_path);
376 FileSystem::Instance().Resolve(file_spec&: module_file_spec);
377 for (auto &it : m_loaded_modules) {
378 if (it.first == module_file_spec) {
379 file_spec = it.first;
380 return Status();
381 }
382 }
383 return Status::FromErrorStringWithFormat(
384 format: "Module (%s) not found in process %" PRIu64 "!",
385 module_file_spec.GetPath().c_str(), GetID());
386}
387
388Status
389NativeProcessWindows::GetFileLoadAddress(const llvm::StringRef &file_name,
390 lldb::addr_t &load_addr) {
391 Status error = CacheLoadedModules();
392 if (error.Fail())
393 return error;
394
395 load_addr = LLDB_INVALID_ADDRESS;
396 FileSpec file_spec(file_name);
397 FileSystem::Instance().Resolve(file_spec);
398 for (auto &it : m_loaded_modules) {
399 if (it.first == file_spec) {
400 load_addr = it.second;
401 return Status();
402 }
403 }
404 return Status::FromErrorStringWithFormat(
405 format: "Can't get loaded address of file (%s) in process %" PRIu64 "!",
406 file_spec.GetPath().c_str(), GetID());
407}
408
409void NativeProcessWindows::OnExitProcess(uint32_t exit_code) {
410 Log *log = GetLog(mask: WindowsLog::Process);
411 LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
412
413 ProcessDebugger::OnExitProcess(exit_code);
414
415 // No signal involved. It is just an exit event.
416 WaitStatus wait_status(WaitStatus::Exit, exit_code);
417 SetExitStatus(status: wait_status, bNotifyStateChange: true);
418
419 // Notify the native delegate.
420 SetState(state: eStateExited, notify_delegates: true);
421}
422
423void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
424 Log *log = GetLog(mask: WindowsLog::Process);
425 LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",
426 GetDebuggedProcessId(), image_base);
427
428 // This is the earliest chance we can resolve the process ID and
429 // architecture if we don't know them yet.
430 if (GetID() == LLDB_INVALID_PROCESS_ID)
431 SetID(GetDebuggedProcessId());
432
433 if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) {
434 ProcessInstanceInfo process_info;
435 if (!Host::GetProcessInfo(pid: GetDebuggedProcessId(), proc_info&: process_info)) {
436 LLDB_LOG(log, "Cannot get process information during debugger connecting "
437 "to process");
438 return;
439 }
440 SetArchitecture(process_info.GetArchitecture());
441 }
442
443 // The very first one shall always be the main thread.
444 assert(m_threads.empty());
445 m_threads.push_back(x: std::make_unique<NativeThreadWindows>(
446 args&: *this, args: m_session_data->m_debugger->GetMainThread()));
447}
448
449ExceptionResult
450NativeProcessWindows::OnDebugException(bool first_chance,
451 const ExceptionRecord &record) {
452 Log *log = GetLog(mask: WindowsLog::Exception);
453 llvm::sys::ScopedLock lock(m_mutex);
454
455 // Let the debugger establish the internal status.
456 ProcessDebugger::OnDebugException(first_chance, record);
457
458 static bool initial_stop = false;
459 if (!first_chance) {
460 SetState(state: eStateStopped, notify_delegates: false);
461 }
462
463 ExceptionResult result = ExceptionResult::SendToApplication;
464 switch (record.GetExceptionCode()) {
465 case DWORD(STATUS_SINGLE_STEP):
466 case STATUS_WX86_SINGLE_STEP: {
467#ifndef __aarch64__
468 uint32_t wp_id = LLDB_INVALID_INDEX32;
469 if (NativeThreadWindows *thread = GetThreadByID(thread_id: record.GetThreadID())) {
470 NativeRegisterContextWindows &reg_ctx = thread->GetRegisterContext();
471 Status error =
472 reg_ctx.GetWatchpointHitIndex(wp_index&: wp_id, trap_addr: record.GetExceptionAddress());
473 if (error.Fail())
474 LLDB_LOG(log,
475 "received error while checking for watchpoint hits, pid = "
476 "{0}, error = {1}",
477 thread->GetID(), error);
478 if (wp_id != LLDB_INVALID_INDEX32) {
479 addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_index: wp_id);
480 addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_index: wp_id);
481 std::string desc =
482 formatv(Fmt: "{0} {1} {2}", Vals&: wp_addr, Vals&: wp_id, Vals&: wp_hit_addr).str();
483 StopThread(thread_id: record.GetThreadID(), reason: StopReason::eStopReasonWatchpoint,
484 description: desc);
485 }
486 }
487 if (wp_id == LLDB_INVALID_INDEX32)
488#endif
489 StopThread(thread_id: record.GetThreadID(), reason: StopReason::eStopReasonTrace);
490
491 SetState(state: eStateStopped, notify_delegates: true);
492
493 // Continue the debugger.
494 return ExceptionResult::MaskException;
495 }
496 case DWORD(STATUS_BREAKPOINT):
497 case STATUS_WX86_BREAKPOINT:
498
499 if (NativeThreadWindows *stop_thread =
500 GetThreadByID(thread_id: record.GetThreadID())) {
501 auto &reg_ctx = stop_thread->GetRegisterContext();
502 const auto exception_addr = record.GetExceptionAddress();
503 const auto thread_id = record.GetThreadID();
504
505 if (FindSoftwareBreakpoint(addr: exception_addr)) {
506 LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
507 exception_addr);
508 // The current PC is AFTER the BP opcode, on all architectures.
509 reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset());
510 StopThread(thread_id, reason: StopReason::eStopReasonBreakpoint);
511 SetState(state: eStateStopped, notify_delegates: true);
512 return ExceptionResult::MaskException;
513 } else {
514 // This block of code will only be entered in case of a hardware
515 // watchpoint or breakpoint hit on AArch64. However, we only handle
516 // hardware watchpoints below as breakpoints are not yet supported.
517 const std::vector<ULONG_PTR> &args = record.GetExceptionArguments();
518 // Check that the ExceptionInformation array of EXCEPTION_RECORD
519 // contains at least two elements: the first is a read-write flag
520 // indicating the type of data access operation (read or write) while
521 // the second contains the virtual address of the accessed data.
522 if (args.size() >= 2) {
523 uint32_t hw_id = LLDB_INVALID_INDEX32;
524 Status error = reg_ctx.GetWatchpointHitIndex(wp_index&: hw_id, trap_addr: args[1]);
525 if (error.Fail())
526 LLDB_LOG(log,
527 "received error while checking for watchpoint hits, pid = "
528 "{0}, error = {1}",
529 thread_id, error);
530
531 if (hw_id != LLDB_INVALID_INDEX32) {
532 std::string desc =
533 formatv(Fmt: "{0} {1} {2}", Vals: reg_ctx.GetWatchpointAddress(wp_index: hw_id),
534 Vals&: hw_id, Vals: exception_addr)
535 .str();
536 StopThread(thread_id, reason: StopReason::eStopReasonWatchpoint, description: desc);
537 SetState(state: eStateStopped, notify_delegates: true);
538 return ExceptionResult::MaskException;
539 }
540 }
541 }
542 }
543
544 if (!initial_stop) {
545 initial_stop = true;
546 LLDB_LOG(log,
547 "Hit loader breakpoint at address {0:x}, setting initial stop "
548 "event.",
549 record.GetExceptionAddress());
550
551 // We are required to report the reason for the first stop after
552 // launching or being attached.
553 if (NativeThreadWindows *thread = GetThreadByID(thread_id: record.GetThreadID()))
554 SetStopReasonForThread(thread&: *thread, reason: StopReason::eStopReasonBreakpoint);
555
556 // Do not notify the native delegate (e.g. llgs) since at this moment
557 // the program hasn't returned from Manager::Launch() and the delegate
558 // might not have an valid native process to operate on.
559 SetState(state: eStateStopped, notify_delegates: false);
560
561 // Hit the initial stop. Continue the application.
562 return ExceptionResult::BreakInDebugger;
563 }
564
565 [[fallthrough]];
566 default:
567 LLDB_LOG(log,
568 "Debugger thread reported exception {0:x} at address {1:x} "
569 "(first_chance={2})",
570 record.GetExceptionCode(), record.GetExceptionAddress(),
571 first_chance);
572
573 {
574 std::string desc;
575 llvm::raw_string_ostream desc_stream(desc);
576 desc_stream << "Exception "
577 << llvm::format_hex(N: record.GetExceptionCode(), Width: 8)
578 << " encountered at address "
579 << llvm::format_hex(N: record.GetExceptionAddress(), Width: 8);
580 StopThread(thread_id: record.GetThreadID(), reason: StopReason::eStopReasonException,
581 description: desc.c_str());
582
583 SetState(state: eStateStopped, notify_delegates: true);
584 }
585
586 // For non-breakpoints, give the application a chance to handle the
587 // exception first.
588 if (first_chance)
589 result = ExceptionResult::SendToApplication;
590 else
591 result = ExceptionResult::BreakInDebugger;
592 }
593
594 return result;
595}
596
597void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
598 llvm::sys::ScopedLock lock(m_mutex);
599
600 auto thread = std::make_unique<NativeThreadWindows>(args&: *this, args: new_thread);
601 thread->GetRegisterContext().ClearAllHardwareWatchpoints();
602 for (const auto &pair : GetWatchpointMap()) {
603 const NativeWatchpoint &wp = pair.second;
604 thread->SetWatchpoint(addr: wp.m_addr, size: wp.m_size, watch_flags: wp.m_watch_flags,
605 hardware: wp.m_hardware);
606 }
607
608 m_threads.push_back(x: std::move(thread));
609}
610
611void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id,
612 uint32_t exit_code) {
613 llvm::sys::ScopedLock lock(m_mutex);
614 NativeThreadWindows *thread = GetThreadByID(thread_id);
615 if (!thread)
616 return;
617
618 for (auto t = m_threads.begin(); t != m_threads.end();) {
619 if ((*t)->GetID() == thread_id) {
620 t = m_threads.erase(position: t);
621 } else {
622 ++t;
623 }
624 }
625}
626
627void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
628 lldb::addr_t module_addr) {
629 // Simply invalidate the cached loaded modules.
630 if (!m_loaded_modules.empty())
631 m_loaded_modules.clear();
632}
633
634void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
635 if (!m_loaded_modules.empty())
636 m_loaded_modules.clear();
637}
638
639llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
640NativeProcessWindows::Manager::Launch(
641 ProcessLaunchInfo &launch_info,
642 NativeProcessProtocol::NativeDelegate &native_delegate) {
643 Error E = Error::success();
644 auto process_up = std::unique_ptr<NativeProcessWindows>(
645 new NativeProcessWindows(launch_info, native_delegate, E));
646 if (E)
647 return std::move(E);
648 return std::move(process_up);
649}
650
651llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
652NativeProcessWindows::Manager::Attach(
653 lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
654 Error E = Error::success();
655 // Set pty primary fd invalid since it is not available.
656 auto process_up = std::unique_ptr<NativeProcessWindows>(
657 new NativeProcessWindows(pid, -1, native_delegate, E));
658 if (E)
659 return std::move(E);
660 return std::move(process_up);
661}
662} // namespace lldb_private
663

source code of lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp