1//===-- ProcessWindows.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 "ProcessWindows.h"
10
11// Windows includes
12#include "lldb/Host/windows/windows.h"
13#include <psapi.h>
14
15#include "lldb/Breakpoint/Watchpoint.h"
16#include "lldb/Core/Module.h"
17#include "lldb/Core/ModuleSpec.h"
18#include "lldb/Core/PluginManager.h"
19#include "lldb/Core/Section.h"
20#include "lldb/Host/FileSystem.h"
21#include "lldb/Host/HostInfo.h"
22#include "lldb/Host/HostNativeProcessBase.h"
23#include "lldb/Host/HostProcess.h"
24#include "lldb/Host/windows/HostThreadWindows.h"
25#include "lldb/Symbol/ObjectFile.h"
26#include "lldb/Target/DynamicLoader.h"
27#include "lldb/Target/MemoryRegionInfo.h"
28#include "lldb/Target/StopInfo.h"
29#include "lldb/Target/Target.h"
30#include "lldb/Utility/State.h"
31
32#include "llvm/Support/ConvertUTF.h"
33#include "llvm/Support/Format.h"
34#include "llvm/Support/Threading.h"
35#include "llvm/Support/raw_ostream.h"
36
37#include "DebuggerThread.h"
38#include "ExceptionRecord.h"
39#include "ForwardDecl.h"
40#include "LocalDebugDelegate.h"
41#include "ProcessWindowsLog.h"
42#include "TargetThreadWindows.h"
43
44using namespace lldb;
45using namespace lldb_private;
46
47LLDB_PLUGIN_DEFINE_ADV(ProcessWindows, ProcessWindowsCommon)
48
49namespace {
50std::string GetProcessExecutableName(HANDLE process_handle) {
51 std::vector<wchar_t> file_name;
52 DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
53 DWORD copied = 0;
54 do {
55 file_name_size *= 2;
56 file_name.resize(file_name_size);
57 copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(),
58 file_name_size);
59 } while (copied >= file_name_size);
60 file_name.resize(copied);
61 std::string result;
62 llvm::convertWideToUTF8(Source: file_name.data(), Result&: result);
63 return result;
64}
65
66std::string GetProcessExecutableName(DWORD pid) {
67 std::string file_name;
68 HANDLE process_handle =
69 ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
70 if (process_handle != NULL) {
71 file_name = GetProcessExecutableName(process_handle);
72 ::CloseHandle(process_handle);
73 }
74 return file_name;
75}
76} // anonymous namespace
77
78namespace lldb_private {
79
80ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
81 lldb::ListenerSP listener_sp,
82 const FileSpec *,
83 bool can_connect) {
84 return ProcessSP(new ProcessWindows(target_sp, listener_sp));
85}
86
87static bool ShouldUseLLDBServer() {
88 llvm::StringRef use_lldb_server = ::getenv(name: "LLDB_USE_LLDB_SERVER");
89 return use_lldb_server.equals_insensitive(RHS: "on") ||
90 use_lldb_server.equals_insensitive(RHS: "yes") ||
91 use_lldb_server.equals_insensitive(RHS: "1") ||
92 use_lldb_server.equals_insensitive(RHS: "true");
93}
94
95void ProcessWindows::Initialize() {
96 if (!ShouldUseLLDBServer()) {
97 static llvm::once_flag g_once_flag;
98
99 llvm::call_once(flag&: g_once_flag, F: []() {
100 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
101 description: GetPluginDescriptionStatic(),
102 create_callback: CreateInstance);
103 });
104 }
105}
106
107void ProcessWindows::Terminate() {}
108
109llvm::StringRef ProcessWindows::GetPluginDescriptionStatic() {
110 return "Process plugin for Windows";
111}
112
113// Constructors and destructors.
114
115ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
116 lldb::ListenerSP listener_sp)
117 : lldb_private::Process(target_sp, listener_sp),
118 m_watchpoint_ids(
119 RegisterContextWindows::GetNumHardwareBreakpointSlots(),
120 LLDB_INVALID_BREAK_ID) {}
121
122ProcessWindows::~ProcessWindows() {}
123
124size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
125 error = Status::FromErrorString(str: "GetSTDOUT unsupported on Windows");
126 return 0;
127}
128
129size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) {
130 error = Status::FromErrorString(str: "GetSTDERR unsupported on Windows");
131 return 0;
132}
133
134size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size,
135 Status &error) {
136 error = Status::FromErrorString(str: "PutSTDIN unsupported on Windows");
137 return 0;
138}
139
140Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) {
141 if (bp_site->HardwareRequired())
142 return Status::FromErrorString(str: "Hardware breakpoints are not supported.");
143
144 Log *log = GetLog(mask: WindowsLog::Breakpoints);
145 LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
146 bp_site->GetID(), bp_site->GetLoadAddress());
147
148 Status error = EnableSoftwareBreakpoint(bp_site);
149 if (!error.Success())
150 LLDB_LOG(log, "error: {0}", error);
151 return error;
152}
153
154Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) {
155 Log *log = GetLog(mask: WindowsLog::Breakpoints);
156 LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
157 bp_site->GetID(), bp_site->GetLoadAddress());
158
159 Status error = DisableSoftwareBreakpoint(bp_site);
160
161 if (!error.Success())
162 LLDB_LOG(log, "error: {0}", error);
163 return error;
164}
165
166Status ProcessWindows::DoDetach(bool keep_stopped) {
167 Status error;
168 Log *log = GetLog(mask: WindowsLog::Process);
169 StateType private_state = GetPrivateState();
170 if (private_state != eStateExited && private_state != eStateDetached) {
171 if (!keep_stopped) {
172 // if the thread is suspended by lldb, we have to resume threads before
173 // detaching process. When we do after DetachProcess(), thread handles
174 // become invalid so we do before detach.
175 if (private_state == eStateStopped || private_state == eStateCrashed) {
176 LLDB_LOG(log, "process {0} is in state {1}. Resuming for detach...",
177 m_session_data->m_debugger->GetProcess().GetProcessId(),
178 GetPrivateState());
179
180 LLDB_LOG(log, "resuming {0} threads for detach.",
181 m_thread_list.GetSize());
182
183 bool failed = false;
184 for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
185 auto thread = std::static_pointer_cast<TargetThreadWindows>(
186 r: m_thread_list.GetThreadAtIndex(idx: i));
187 Status result = thread->DoResume();
188 if (result.Fail()) {
189 failed = true;
190 LLDB_LOG(log,
191 "Trying to resume thread at index {0}, but failed with "
192 "error {1}.",
193 i, result);
194 }
195 }
196
197 if (failed) {
198 error = Status::FromErrorString(str: "Resuming Threads for Detach failed");
199 }
200 }
201 }
202
203 error = DetachProcess();
204 if (error.Success())
205 SetPrivateState(eStateDetached);
206 else
207 LLDB_LOG(log, "Detaching process error: {0}", error);
208 } else {
209 error = Status::FromErrorStringWithFormatv(
210 format: "error: process {0} in state = {1}, but "
211 "cannot detach it in this state.",
212 args: GetID(), args&: private_state);
213 LLDB_LOG(log, "error: {0}", error);
214 }
215 return error;
216}
217
218Status ProcessWindows::DoLaunch(Module *exe_module,
219 ProcessLaunchInfo &launch_info) {
220 Status error;
221 DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
222 error = LaunchProcess(launch_info, delegate);
223 if (error.Success())
224 SetID(launch_info.GetProcessID());
225 return error;
226}
227
228Status
229ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
230 const ProcessAttachInfo &attach_info) {
231 DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
232 Status error = AttachProcess(pid, attach_info, delegate);
233 if (error.Success())
234 SetID(GetDebuggedProcessId());
235 return error;
236}
237
238Status ProcessWindows::DoResume(RunDirection direction) {
239 Log *log = GetLog(mask: WindowsLog::Process);
240 llvm::sys::ScopedLock lock(m_mutex);
241
242 if (direction == RunDirection::eRunReverse) {
243 return Status::FromErrorStringWithFormatv(
244 format: "{0} does not support reverse execution of processes", args: GetPluginName());
245 }
246
247 Status error;
248
249 StateType private_state = GetPrivateState();
250 if (private_state == eStateStopped || private_state == eStateCrashed) {
251 LLDB_LOG(log, "process {0} is in state {1}. Resuming...",
252 m_session_data->m_debugger->GetProcess().GetProcessId(),
253 GetPrivateState());
254
255 LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
256
257 bool failed = false;
258 for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
259 auto thread = std::static_pointer_cast<TargetThreadWindows>(
260 r: m_thread_list.GetThreadAtIndex(idx: i));
261 Status result = thread->DoResume();
262 if (result.Fail()) {
263 failed = true;
264 LLDB_LOG(
265 log,
266 "Trying to resume thread at index {0}, but failed with error {1}.",
267 i, result);
268 }
269 }
270
271 if (failed) {
272 error = Status::FromErrorString(str: "ProcessWindows::DoResume failed");
273 } else {
274 SetPrivateState(eStateRunning);
275 }
276
277 ExceptionRecordSP active_exception =
278 m_session_data->m_debugger->GetActiveException().lock();
279 if (active_exception) {
280 // Resume the process and continue processing debug events. Mask the
281 // exception so that from the process's view, there is no indication that
282 // anything happened.
283 m_session_data->m_debugger->ContinueAsyncException(
284 result: ExceptionResult::MaskException);
285 }
286 } else {
287 LLDB_LOG(log, "error: process {0} is in state {1}. Returning...",
288 m_session_data->m_debugger->GetProcess().GetProcessId(),
289 GetPrivateState());
290 }
291 return error;
292}
293
294Status ProcessWindows::DoDestroy() {
295 StateType private_state = GetPrivateState();
296 return DestroyProcess(process_state: private_state);
297}
298
299Status ProcessWindows::DoHalt(bool &caused_stop) {
300 StateType state = GetPrivateState();
301 if (state != eStateStopped)
302 return HaltProcess(caused_stop);
303 caused_stop = false;
304 return Status();
305}
306
307void ProcessWindows::DidLaunch() {
308 ArchSpec arch_spec;
309 DidAttach(arch_spec);
310}
311
312void ProcessWindows::DidAttach(ArchSpec &arch_spec) {
313 llvm::sys::ScopedLock lock(m_mutex);
314
315 // The initial stop won't broadcast the state change event, so account for
316 // that here.
317 if (m_session_data && GetPrivateState() == eStateStopped &&
318 m_session_data->m_stop_at_entry)
319 RefreshStateAfterStop();
320}
321
322static void
323DumpAdditionalExceptionInformation(llvm::raw_ostream &stream,
324 const ExceptionRecordSP &exception) {
325 // Decode additional exception information for specific exception types based
326 // on
327 // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record
328
329 const int addr_min_width = 2 + 8; // "0x" + 4 address bytes
330
331 const std::vector<ULONG_PTR> &args = exception->GetExceptionArguments();
332 switch (exception->GetExceptionCode()) {
333 case EXCEPTION_ACCESS_VIOLATION: {
334 if (args.size() < 2)
335 break;
336
337 stream << ": ";
338 const int access_violation_code = args[0];
339 const lldb::addr_t access_violation_address = args[1];
340 switch (access_violation_code) {
341 case 0:
342 stream << "Access violation reading";
343 break;
344 case 1:
345 stream << "Access violation writing";
346 break;
347 case 8:
348 stream << "User-mode data execution prevention (DEP) violation at";
349 break;
350 default:
351 stream << "Unknown access violation (code " << access_violation_code
352 << ") at";
353 break;
354 }
355 stream << " location "
356 << llvm::format_hex(N: access_violation_address, Width: addr_min_width);
357 break;
358 }
359 case EXCEPTION_IN_PAGE_ERROR: {
360 if (args.size() < 3)
361 break;
362
363 stream << ": ";
364 const int page_load_error_code = args[0];
365 const lldb::addr_t page_load_error_address = args[1];
366 const DWORD underlying_code = args[2];
367 switch (page_load_error_code) {
368 case 0:
369 stream << "In page error reading";
370 break;
371 case 1:
372 stream << "In page error writing";
373 break;
374 case 8:
375 stream << "User-mode data execution prevention (DEP) violation at";
376 break;
377 default:
378 stream << "Unknown page loading error (code " << page_load_error_code
379 << ") at";
380 break;
381 }
382 stream << " location "
383 << llvm::format_hex(N: page_load_error_address, Width: addr_min_width)
384 << " (status code " << llvm::format_hex(N: underlying_code, Width: 8) << ")";
385 break;
386 }
387 }
388}
389
390void ProcessWindows::RefreshStateAfterStop() {
391 Log *log = GetLog(mask: WindowsLog::Exception);
392 llvm::sys::ScopedLock lock(m_mutex);
393
394 if (!m_session_data) {
395 LLDB_LOG(log, "no active session. Returning...");
396 return;
397 }
398
399 m_thread_list.RefreshStateAfterStop();
400
401 std::weak_ptr<ExceptionRecord> exception_record =
402 m_session_data->m_debugger->GetActiveException();
403 ExceptionRecordSP active_exception = exception_record.lock();
404 if (!active_exception) {
405 LLDB_LOG(log,
406 "there is no active exception in process {0}. Why is the "
407 "process stopped?",
408 m_session_data->m_debugger->GetProcess().GetProcessId());
409 return;
410 }
411
412 StopInfoSP stop_info;
413 m_thread_list.SetSelectedThreadByID(tid: active_exception->GetThreadID());
414 ThreadSP stop_thread = m_thread_list.GetSelectedThread();
415 if (!stop_thread)
416 return;
417
418 RegisterContextSP register_context = stop_thread->GetRegisterContext();
419 uint64_t pc = register_context->GetPC();
420
421 // If we're at a BreakpointSite, mark this as an Unexecuted Breakpoint.
422 // We'll clear that state if we've actually executed the breakpoint.
423 BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(addr: pc));
424 if (site && site->IsEnabled())
425 stop_thread->SetThreadStoppedAtUnexecutedBP(pc);
426
427 switch (active_exception->GetExceptionCode()) {
428 case EXCEPTION_SINGLE_STEP: {
429 auto *reg_ctx = static_cast<RegisterContextWindows *>(
430 stop_thread->GetRegisterContext().get());
431 uint32_t slot_id = reg_ctx->GetTriggeredHardwareBreakpointSlotId();
432 if (slot_id != LLDB_INVALID_INDEX32) {
433 int id = m_watchpoint_ids[slot_id];
434 LLDB_LOG(log,
435 "Single-stepped onto a watchpoint in process {0} at address "
436 "{1:x} with watchpoint {2}",
437 m_session_data->m_debugger->GetProcess().GetProcessId(), pc, id);
438
439 stop_info = StopInfo::CreateStopReasonWithWatchpointID(thread&: *stop_thread, watch_id: id);
440 stop_thread->SetStopInfo(stop_info);
441
442 return;
443 }
444
445 LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
446 stop_info = StopInfo::CreateStopReasonToTrace(thread&: *stop_thread);
447 stop_thread->SetStopInfo(stop_info);
448
449 return;
450 }
451
452 case EXCEPTION_BREAKPOINT: {
453 int breakpoint_size = 1;
454 switch (GetTarget().GetArchitecture().GetMachine()) {
455 case llvm::Triple::aarch64:
456 breakpoint_size = 4;
457 break;
458
459 case llvm::Triple::arm:
460 case llvm::Triple::thumb:
461 breakpoint_size = 2;
462 break;
463
464 case llvm::Triple::x86:
465 case llvm::Triple::x86_64:
466 breakpoint_size = 1;
467 break;
468
469 default:
470 LLDB_LOG(log, "Unknown breakpoint size for architecture");
471 break;
472 }
473
474 // The current PC is AFTER the BP opcode, on all architectures.
475 pc = register_context->GetPC() - breakpoint_size;
476
477 site = GetBreakpointSiteList().FindByAddress(addr: pc);
478 if (site) {
479 LLDB_LOG(log,
480 "detected breakpoint in process {0} at address {1:x} with "
481 "breakpoint site {2}",
482 m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
483 site->GetID());
484
485 stop_thread->SetThreadHitBreakpointSite();
486 if (site->ValidForThisThread(thread&: *stop_thread)) {
487 LLDB_LOG(log,
488 "Breakpoint site {0} is valid for this thread ({1:x}), "
489 "creating stop info.",
490 site->GetID(), stop_thread->GetID());
491
492 stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
493 thread&: *stop_thread, break_id: site->GetID());
494 register_context->SetPC(pc);
495 } else {
496 LLDB_LOG(log,
497 "Breakpoint site {0} is not valid for this thread, "
498 "creating empty stop info.",
499 site->GetID());
500 }
501 stop_thread->SetStopInfo(stop_info);
502 return;
503 } else {
504 // The thread hit a hard-coded breakpoint like an `int 3` or
505 // `__debugbreak()`.
506 LLDB_LOG(log,
507 "No breakpoint site matches for this thread. __debugbreak()? "
508 "Creating stop info with the exception.");
509 // FALLTHROUGH: We'll treat this as a generic exception record in the
510 // default case.
511 [[fallthrough]];
512 }
513 }
514
515 default: {
516 std::string desc;
517 llvm::raw_string_ostream desc_stream(desc);
518 desc_stream << "Exception "
519 << llvm::format_hex(N: active_exception->GetExceptionCode(), Width: 8)
520 << " encountered at address "
521 << llvm::format_hex(N: active_exception->GetExceptionAddress(), Width: 8);
522 DumpAdditionalExceptionInformation(stream&: desc_stream, exception: active_exception);
523
524 stop_info =
525 StopInfo::CreateStopReasonWithException(thread&: *stop_thread, description: desc.c_str());
526 stop_thread->SetStopInfo(stop_info);
527 LLDB_LOG(log, "{0}", desc);
528 return;
529 }
530 }
531}
532
533bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
534 bool plugin_specified_by_name) {
535 if (plugin_specified_by_name)
536 return true;
537
538 // For now we are just making sure the file exists for a given module
539 ModuleSP exe_module_sp(target_sp->GetExecutableModule());
540 if (exe_module_sp.get())
541 return FileSystem::Instance().Exists(file_spec: exe_module_sp->GetFileSpec());
542 // However, if there is no executable module, we return true since we might
543 // be preparing to attach.
544 return true;
545}
546
547bool ProcessWindows::DoUpdateThreadList(ThreadList &old_thread_list,
548 ThreadList &new_thread_list) {
549 Log *log = GetLog(mask: WindowsLog::Thread);
550 // Add all the threads that were previously running and for which we did not
551 // detect a thread exited event.
552 int new_size = 0;
553 int continued_threads = 0;
554 int exited_threads = 0;
555 int new_threads = 0;
556
557 for (ThreadSP old_thread : old_thread_list.Threads()) {
558 lldb::tid_t old_thread_id = old_thread->GetID();
559 auto exited_thread_iter =
560 m_session_data->m_exited_threads.find(x: old_thread_id);
561 if (exited_thread_iter == m_session_data->m_exited_threads.end()) {
562 new_thread_list.AddThread(thread_sp: old_thread);
563 ++new_size;
564 ++continued_threads;
565 LLDB_LOGV(log, "Thread {0} was running and is still running.",
566 old_thread_id);
567 } else {
568 LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id);
569 ++exited_threads;
570 }
571 }
572
573 // Also add all the threads that are new since the last time we broke into
574 // the debugger.
575 for (const auto &thread_info : m_session_data->m_new_threads) {
576 new_thread_list.AddThread(thread_sp: thread_info.second);
577 ++new_size;
578 ++new_threads;
579 LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
580 }
581
582 LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.",
583 new_threads, continued_threads, exited_threads);
584
585 m_session_data->m_new_threads.clear();
586 m_session_data->m_exited_threads.clear();
587
588 return new_size > 0;
589}
590
591bool ProcessWindows::IsAlive() {
592 StateType state = GetPrivateState();
593 switch (state) {
594 case eStateCrashed:
595 case eStateDetached:
596 case eStateUnloaded:
597 case eStateExited:
598 case eStateInvalid:
599 return false;
600 default:
601 return true;
602 }
603}
604
605ArchSpec ProcessWindows::GetSystemArchitecture() {
606 return HostInfo::GetArchitecture();
607}
608
609size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
610 size_t size, Status &error) {
611 size_t bytes_read = 0;
612 error = ProcessDebugger::ReadMemory(addr: vm_addr, buf, size, bytes_read);
613 return bytes_read;
614}
615
616size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
617 size_t size, Status &error) {
618 size_t bytes_written = 0;
619 error = ProcessDebugger::WriteMemory(addr: vm_addr, buf, size, bytes_written);
620 return bytes_written;
621}
622
623lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
624 Status &error) {
625 lldb::addr_t vm_addr = LLDB_INVALID_ADDRESS;
626 error = ProcessDebugger::AllocateMemory(size, permissions, addr&: vm_addr);
627 return vm_addr;
628}
629
630Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) {
631 return ProcessDebugger::DeallocateMemory(addr: ptr);
632}
633
634Status ProcessWindows::DoGetMemoryRegionInfo(lldb::addr_t vm_addr,
635 MemoryRegionInfo &info) {
636 return ProcessDebugger::GetMemoryRegionInfo(load_addr: vm_addr, range_info&: info);
637}
638
639lldb::addr_t ProcessWindows::GetImageInfoAddress() {
640 Target &target = GetTarget();
641 ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
642 Address addr = obj_file->GetImageInfoAddress(target: &target);
643 if (addr.IsValid())
644 return addr.GetLoadAddress(target: &target);
645 else
646 return LLDB_INVALID_ADDRESS;
647}
648
649DynamicLoaderWindowsDYLD *ProcessWindows::GetDynamicLoader() {
650 if (m_dyld_up.get() == NULL)
651 m_dyld_up.reset(p: DynamicLoader::FindPlugin(
652 process: this, plugin_name: DynamicLoaderWindowsDYLD::GetPluginNameStatic()));
653 return static_cast<DynamicLoaderWindowsDYLD *>(m_dyld_up.get());
654}
655
656void ProcessWindows::OnExitProcess(uint32_t exit_code) {
657 // No need to acquire the lock since m_session_data isn't accessed.
658 Log *log = GetLog(mask: WindowsLog::Process);
659 LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
660
661 TargetSP target = CalculateTarget();
662 if (target) {
663 ModuleSP executable_module = target->GetExecutableModule();
664 ModuleList unloaded_modules;
665 unloaded_modules.Append(module_sp: executable_module);
666 target->ModulesDidUnload(module_list&: unloaded_modules, delete_locations: true);
667 }
668
669 SetProcessExitStatus(pid: GetID(), exited: true, signo: 0, status: exit_code);
670 SetPrivateState(eStateExited);
671
672 ProcessDebugger::OnExitProcess(exit_code);
673}
674
675void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
676 DebuggerThreadSP debugger = m_session_data->m_debugger;
677 Log *log = GetLog(mask: WindowsLog::Process);
678 LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",
679 debugger->GetProcess().GetProcessId(), image_base);
680
681 ModuleSP module;
682 // During attach, we won't have the executable module, so find it now.
683 const DWORD pid = debugger->GetProcess().GetProcessId();
684 const std::string file_name = GetProcessExecutableName(pid);
685 if (file_name.empty()) {
686 return;
687 }
688
689 FileSpec executable_file(file_name);
690 FileSystem::Instance().Resolve(file_spec&: executable_file);
691 ModuleSpec module_spec(executable_file);
692 Status error;
693 module =
694 GetTarget().GetOrCreateModule(module_spec, notify: true /* notify */, error_ptr: &error);
695 if (!module) {
696 return;
697 }
698
699 GetTarget().SetExecutableModule(module_sp&: module, load_dependent_files: eLoadDependentsNo);
700
701 if (auto dyld = GetDynamicLoader())
702 dyld->OnLoadModule(module_sp: module, module_spec: ModuleSpec(), module_addr: image_base);
703
704 // Add the main executable module to the list of pending module loads. We
705 // can't call GetTarget().ModulesDidLoad() here because we still haven't
706 // returned from DoLaunch() / DoAttach() yet so the target may not have set
707 // the process instance to `this` yet.
708 llvm::sys::ScopedLock lock(m_mutex);
709
710 const HostThread &host_main_thread = debugger->GetMainThread();
711 ThreadSP main_thread =
712 std::make_shared<TargetThreadWindows>(args&: *this, args: host_main_thread);
713
714 tid_t id = host_main_thread.GetNativeThread().GetThreadId();
715 main_thread->SetID(id);
716
717 m_session_data->m_new_threads[id] = main_thread;
718}
719
720ExceptionResult
721ProcessWindows::OnDebugException(bool first_chance,
722 const ExceptionRecord &record) {
723 Log *log = GetLog(mask: WindowsLog::Exception);
724 llvm::sys::ScopedLock lock(m_mutex);
725
726 // FIXME: Without this check, occasionally when running the test suite there
727 // is
728 // an issue where m_session_data can be null. It's not clear how this could
729 // happen but it only surfaces while running the test suite. In order to
730 // properly diagnose this, we probably need to first figure allow the test
731 // suite to print out full lldb logs, and then add logging to the process
732 // plugin.
733 if (!m_session_data) {
734 LLDB_LOG(log,
735 "Debugger thread reported exception {0:x} at address {1:x}, "
736 "but there is no session.",
737 record.GetExceptionCode(), record.GetExceptionAddress());
738 return ExceptionResult::SendToApplication;
739 }
740
741 if (!first_chance) {
742 // Not any second chance exception is an application crash by definition.
743 // It may be an expression evaluation crash.
744 SetPrivateState(eStateStopped);
745 }
746
747 ExceptionResult result = ExceptionResult::SendToApplication;
748 switch (record.GetExceptionCode()) {
749 case EXCEPTION_BREAKPOINT:
750 // Handle breakpoints at the first chance.
751 result = ExceptionResult::BreakInDebugger;
752
753 if (!m_session_data->m_initial_stop_received) {
754 LLDB_LOG(
755 log,
756 "Hit loader breakpoint at address {0:x}, setting initial stop event.",
757 record.GetExceptionAddress());
758 m_session_data->m_initial_stop_received = true;
759 ::SetEvent(m_session_data->m_initial_stop_event);
760 } else {
761 LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
762 record.GetExceptionAddress());
763 }
764 SetPrivateState(eStateStopped);
765 break;
766 case EXCEPTION_SINGLE_STEP:
767 result = ExceptionResult::BreakInDebugger;
768 SetPrivateState(eStateStopped);
769 break;
770 default:
771 LLDB_LOG(log,
772 "Debugger thread reported exception {0:x} at address {1:x} "
773 "(first_chance={2})",
774 record.GetExceptionCode(), record.GetExceptionAddress(),
775 first_chance);
776 // For non-breakpoints, give the application a chance to handle the
777 // exception first.
778 if (first_chance)
779 result = ExceptionResult::SendToApplication;
780 else
781 result = ExceptionResult::BreakInDebugger;
782 }
783
784 return result;
785}
786
787void ProcessWindows::OnCreateThread(const HostThread &new_thread) {
788 llvm::sys::ScopedLock lock(m_mutex);
789
790 ThreadSP thread = std::make_shared<TargetThreadWindows>(args&: *this, args: new_thread);
791
792 const HostNativeThread &native_new_thread = new_thread.GetNativeThread();
793 tid_t id = native_new_thread.GetThreadId();
794 thread->SetID(id);
795
796 m_session_data->m_new_threads[id] = thread;
797
798 for (const std::map<int, WatchpointInfo>::value_type &p : m_watchpoints) {
799 auto *reg_ctx = static_cast<RegisterContextWindows *>(
800 thread->GetRegisterContext().get());
801 reg_ctx->AddHardwareBreakpoint(slot: p.second.slot_id, address: p.second.address,
802 size: p.second.size, read: p.second.read,
803 write: p.second.write);
804 }
805}
806
807void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
808 llvm::sys::ScopedLock lock(m_mutex);
809
810 // On a forced termination, we may get exit thread events after the session
811 // data has been cleaned up.
812 if (!m_session_data)
813 return;
814
815 // A thread may have started and exited before the debugger stopped allowing a
816 // refresh.
817 // Just remove it from the new threads list in that case.
818 auto iter = m_session_data->m_new_threads.find(x: thread_id);
819 if (iter != m_session_data->m_new_threads.end())
820 m_session_data->m_new_threads.erase(position: iter);
821 else
822 m_session_data->m_exited_threads.insert(x: thread_id);
823}
824
825void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
826 lldb::addr_t module_addr) {
827 if (auto dyld = GetDynamicLoader())
828 dyld->OnLoadModule(module_sp: nullptr, module_spec, module_addr);
829}
830
831void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
832 if (auto dyld = GetDynamicLoader())
833 dyld->OnUnloadModule(module_addr);
834}
835
836void ProcessWindows::OnDebugString(const std::string &string) {}
837
838void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
839 llvm::sys::ScopedLock lock(m_mutex);
840 Log *log = GetLog(mask: WindowsLog::Process);
841
842 if (m_session_data->m_initial_stop_received) {
843 // This happened while debugging. Do we shutdown the debugging session,
844 // try to continue, or do something else?
845 LLDB_LOG(log,
846 "Error {0} occurred during debugging. Unexpected behavior "
847 "may result. {1}",
848 error.GetError(), error);
849 } else {
850 // If we haven't actually launched the process yet, this was an error
851 // launching the process. Set the internal error and signal the initial
852 // stop event so that the DoLaunch method wakes up and returns a failure.
853 m_session_data->m_launch_error = error.Clone();
854 ::SetEvent(m_session_data->m_initial_stop_event);
855 LLDB_LOG(
856 log,
857 "Error {0} occurred launching the process before the initial stop. {1}",
858 error.GetError(), error);
859 return;
860 }
861}
862
863std::optional<uint32_t> ProcessWindows::GetWatchpointSlotCount() {
864 return RegisterContextWindows::GetNumHardwareBreakpointSlots();
865}
866
867Status ProcessWindows::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
868 Status error;
869
870 if (wp_sp->IsEnabled()) {
871 wp_sp->SetEnabled(enabled: true, notify);
872 return error;
873 }
874
875 WatchpointInfo info;
876 for (info.slot_id = 0;
877 info.slot_id < RegisterContextWindows::GetNumHardwareBreakpointSlots();
878 info.slot_id++)
879 if (m_watchpoint_ids[info.slot_id] == LLDB_INVALID_BREAK_ID)
880 break;
881 if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) {
882 error = Status::FromErrorStringWithFormat(
883 format: "Can't find free slot for watchpoint %i", wp_sp->GetID());
884 return error;
885 }
886 info.address = wp_sp->GetLoadAddress();
887 info.size = wp_sp->GetByteSize();
888 info.read = wp_sp->WatchpointRead();
889 info.write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
890
891 for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
892 Thread *thread = m_thread_list.GetThreadAtIndex(idx: i).get();
893 auto *reg_ctx = static_cast<RegisterContextWindows *>(
894 thread->GetRegisterContext().get());
895 if (!reg_ctx->AddHardwareBreakpoint(slot: info.slot_id, address: info.address, size: info.size,
896 read: info.read, write: info.write)) {
897 error = Status::FromErrorStringWithFormat(
898 format: "Can't enable watchpoint %i on thread 0x%llx", wp_sp->GetID(),
899 thread->GetID());
900 break;
901 }
902 }
903 if (error.Fail()) {
904 for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
905 Thread *thread = m_thread_list.GetThreadAtIndex(idx: i).get();
906 auto *reg_ctx = static_cast<RegisterContextWindows *>(
907 thread->GetRegisterContext().get());
908 reg_ctx->RemoveHardwareBreakpoint(slot: info.slot_id);
909 }
910 return error;
911 }
912
913 m_watchpoints[wp_sp->GetID()] = info;
914 m_watchpoint_ids[info.slot_id] = wp_sp->GetID();
915
916 wp_sp->SetEnabled(enabled: true, notify);
917
918 return error;
919}
920
921Status ProcessWindows::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
922 Status error;
923
924 if (!wp_sp->IsEnabled()) {
925 wp_sp->SetEnabled(enabled: false, notify);
926 return error;
927 }
928
929 auto it = m_watchpoints.find(x: wp_sp->GetID());
930 if (it == m_watchpoints.end()) {
931 error = Status::FromErrorStringWithFormat(
932 format: "Info about watchpoint %i is not found", wp_sp->GetID());
933 return error;
934 }
935
936 for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
937 Thread *thread = m_thread_list.GetThreadAtIndex(idx: i).get();
938 auto *reg_ctx = static_cast<RegisterContextWindows *>(
939 thread->GetRegisterContext().get());
940 if (!reg_ctx->RemoveHardwareBreakpoint(slot: it->second.slot_id)) {
941 error = Status::FromErrorStringWithFormat(
942 format: "Can't disable watchpoint %i on thread 0x%llx", wp_sp->GetID(),
943 thread->GetID());
944 break;
945 }
946 }
947 if (error.Fail())
948 return error;
949
950 m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID;
951 m_watchpoints.erase(position: it);
952
953 wp_sp->SetEnabled(enabled: false, notify);
954
955 return error;
956}
957} // namespace lldb_private
958

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