xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ProcessWindows.cpp ------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "ProcessWindows.h"
10061da546Spatrick 
11061da546Spatrick // Windows includes
12061da546Spatrick #include "lldb/Host/windows/windows.h"
13061da546Spatrick #include <psapi.h>
14061da546Spatrick 
15061da546Spatrick #include "lldb/Breakpoint/Watchpoint.h"
16061da546Spatrick #include "lldb/Core/Module.h"
17061da546Spatrick #include "lldb/Core/ModuleSpec.h"
18061da546Spatrick #include "lldb/Core/PluginManager.h"
19061da546Spatrick #include "lldb/Core/Section.h"
20061da546Spatrick #include "lldb/Host/FileSystem.h"
21*f6aab3d8Srobert #include "lldb/Host/HostInfo.h"
22061da546Spatrick #include "lldb/Host/HostNativeProcessBase.h"
23061da546Spatrick #include "lldb/Host/HostProcess.h"
24061da546Spatrick #include "lldb/Host/windows/HostThreadWindows.h"
25061da546Spatrick #include "lldb/Host/windows/windows.h"
26061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
27061da546Spatrick #include "lldb/Target/DynamicLoader.h"
28061da546Spatrick #include "lldb/Target/MemoryRegionInfo.h"
29061da546Spatrick #include "lldb/Target/StopInfo.h"
30061da546Spatrick #include "lldb/Target/Target.h"
31061da546Spatrick #include "lldb/Utility/State.h"
32061da546Spatrick 
33061da546Spatrick #include "llvm/Support/ConvertUTF.h"
34061da546Spatrick #include "llvm/Support/Format.h"
35061da546Spatrick #include "llvm/Support/Threading.h"
36061da546Spatrick #include "llvm/Support/raw_ostream.h"
37061da546Spatrick 
38061da546Spatrick #include "DebuggerThread.h"
39061da546Spatrick #include "ExceptionRecord.h"
40061da546Spatrick #include "ForwardDecl.h"
41061da546Spatrick #include "LocalDebugDelegate.h"
42061da546Spatrick #include "ProcessWindowsLog.h"
43061da546Spatrick #include "TargetThreadWindows.h"
44061da546Spatrick 
45061da546Spatrick using namespace lldb;
46061da546Spatrick using namespace lldb_private;
47061da546Spatrick 
48dda28197Spatrick LLDB_PLUGIN_DEFINE_ADV(ProcessWindows, ProcessWindowsCommon)
49dda28197Spatrick 
50061da546Spatrick namespace {
GetProcessExecutableName(HANDLE process_handle)51061da546Spatrick std::string GetProcessExecutableName(HANDLE process_handle) {
52061da546Spatrick   std::vector<wchar_t> file_name;
53061da546Spatrick   DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
54061da546Spatrick   DWORD copied = 0;
55061da546Spatrick   do {
56061da546Spatrick     file_name_size *= 2;
57061da546Spatrick     file_name.resize(file_name_size);
58061da546Spatrick     copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(),
59061da546Spatrick                                     file_name_size);
60061da546Spatrick   } while (copied >= file_name_size);
61061da546Spatrick   file_name.resize(copied);
62061da546Spatrick   std::string result;
63061da546Spatrick   llvm::convertWideToUTF8(file_name.data(), result);
64061da546Spatrick   return result;
65061da546Spatrick }
66061da546Spatrick 
GetProcessExecutableName(DWORD pid)67061da546Spatrick std::string GetProcessExecutableName(DWORD pid) {
68061da546Spatrick   std::string file_name;
69061da546Spatrick   HANDLE process_handle =
70061da546Spatrick       ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
71061da546Spatrick   if (process_handle != NULL) {
72061da546Spatrick     file_name = GetProcessExecutableName(process_handle);
73061da546Spatrick     ::CloseHandle(process_handle);
74061da546Spatrick   }
75061da546Spatrick   return file_name;
76061da546Spatrick }
77061da546Spatrick } // anonymous namespace
78061da546Spatrick 
79061da546Spatrick namespace lldb_private {
80061da546Spatrick 
CreateInstance(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp,const FileSpec *,bool can_connect)81061da546Spatrick ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
82061da546Spatrick                                          lldb::ListenerSP listener_sp,
83be691f3bSpatrick                                          const FileSpec *,
84be691f3bSpatrick                                          bool can_connect) {
85061da546Spatrick   return ProcessSP(new ProcessWindows(target_sp, listener_sp));
86061da546Spatrick }
87061da546Spatrick 
ShouldUseLLDBServer()88061da546Spatrick static bool ShouldUseLLDBServer() {
89061da546Spatrick   llvm::StringRef use_lldb_server = ::getenv("LLDB_USE_LLDB_SERVER");
90be691f3bSpatrick   return use_lldb_server.equals_insensitive("on") ||
91be691f3bSpatrick          use_lldb_server.equals_insensitive("yes") ||
92be691f3bSpatrick          use_lldb_server.equals_insensitive("1") ||
93be691f3bSpatrick          use_lldb_server.equals_insensitive("true");
94061da546Spatrick }
95061da546Spatrick 
Initialize()96061da546Spatrick void ProcessWindows::Initialize() {
97061da546Spatrick   if (!ShouldUseLLDBServer()) {
98061da546Spatrick     static llvm::once_flag g_once_flag;
99061da546Spatrick 
100061da546Spatrick     llvm::call_once(g_once_flag, []() {
101061da546Spatrick       PluginManager::RegisterPlugin(GetPluginNameStatic(),
102061da546Spatrick                                     GetPluginDescriptionStatic(),
103061da546Spatrick                                     CreateInstance);
104061da546Spatrick     });
105061da546Spatrick   }
106061da546Spatrick }
107061da546Spatrick 
Terminate()108061da546Spatrick void ProcessWindows::Terminate() {}
109061da546Spatrick 
GetPluginDescriptionStatic()110*f6aab3d8Srobert llvm::StringRef ProcessWindows::GetPluginDescriptionStatic() {
111061da546Spatrick   return "Process plugin for Windows";
112061da546Spatrick }
113061da546Spatrick 
114061da546Spatrick // Constructors and destructors.
115061da546Spatrick 
ProcessWindows(lldb::TargetSP target_sp,lldb::ListenerSP listener_sp)116061da546Spatrick ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
117061da546Spatrick                                lldb::ListenerSP listener_sp)
118061da546Spatrick     : lldb_private::Process(target_sp, listener_sp),
119061da546Spatrick       m_watchpoint_ids(
120061da546Spatrick           RegisterContextWindows::GetNumHardwareBreakpointSlots(),
121061da546Spatrick           LLDB_INVALID_BREAK_ID) {}
122061da546Spatrick 
~ProcessWindows()123061da546Spatrick ProcessWindows::~ProcessWindows() {}
124061da546Spatrick 
GetSTDOUT(char * buf,size_t buf_size,Status & error)125061da546Spatrick size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
126061da546Spatrick   error.SetErrorString("GetSTDOUT unsupported on Windows");
127061da546Spatrick   return 0;
128061da546Spatrick }
129061da546Spatrick 
GetSTDERR(char * buf,size_t buf_size,Status & error)130061da546Spatrick size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) {
131061da546Spatrick   error.SetErrorString("GetSTDERR unsupported on Windows");
132061da546Spatrick   return 0;
133061da546Spatrick }
134061da546Spatrick 
PutSTDIN(const char * buf,size_t buf_size,Status & error)135061da546Spatrick size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size,
136061da546Spatrick                                 Status &error) {
137061da546Spatrick   error.SetErrorString("PutSTDIN unsupported on Windows");
138061da546Spatrick   return 0;
139061da546Spatrick }
140061da546Spatrick 
EnableBreakpointSite(BreakpointSite * bp_site)141061da546Spatrick Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) {
142be691f3bSpatrick   if (bp_site->HardwareRequired())
143be691f3bSpatrick     return Status("Hardware breakpoints are not supported.");
144be691f3bSpatrick 
145*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Breakpoints);
146061da546Spatrick   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
147061da546Spatrick            bp_site->GetID(), bp_site->GetLoadAddress());
148061da546Spatrick 
149061da546Spatrick   Status error = EnableSoftwareBreakpoint(bp_site);
150061da546Spatrick   if (!error.Success())
151061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
152061da546Spatrick   return error;
153061da546Spatrick }
154061da546Spatrick 
DisableBreakpointSite(BreakpointSite * bp_site)155061da546Spatrick Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) {
156*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Breakpoints);
157061da546Spatrick   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
158061da546Spatrick            bp_site->GetID(), bp_site->GetLoadAddress());
159061da546Spatrick 
160061da546Spatrick   Status error = DisableSoftwareBreakpoint(bp_site);
161061da546Spatrick 
162061da546Spatrick   if (!error.Success())
163061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
164061da546Spatrick   return error;
165061da546Spatrick }
166061da546Spatrick 
DoDetach(bool keep_stopped)167061da546Spatrick Status ProcessWindows::DoDetach(bool keep_stopped) {
168061da546Spatrick   Status error;
169*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
170061da546Spatrick   StateType private_state = GetPrivateState();
171061da546Spatrick   if (private_state != eStateExited && private_state != eStateDetached) {
172061da546Spatrick     error = DetachProcess();
173061da546Spatrick     if (error.Success())
174061da546Spatrick       SetPrivateState(eStateDetached);
175061da546Spatrick     else
176061da546Spatrick       LLDB_LOG(log, "Detaching process error: {0}", error);
177061da546Spatrick   } else {
178061da546Spatrick     error.SetErrorStringWithFormatv("error: process {0} in state = {1}, but "
179061da546Spatrick                                     "cannot detach it in this state.",
180061da546Spatrick                                     GetID(), private_state);
181061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
182061da546Spatrick   }
183061da546Spatrick   return error;
184061da546Spatrick }
185061da546Spatrick 
DoLaunch(Module * exe_module,ProcessLaunchInfo & launch_info)186061da546Spatrick Status ProcessWindows::DoLaunch(Module *exe_module,
187061da546Spatrick                                 ProcessLaunchInfo &launch_info) {
188061da546Spatrick   Status error;
189061da546Spatrick   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
190061da546Spatrick   error = LaunchProcess(launch_info, delegate);
191061da546Spatrick   if (error.Success())
192061da546Spatrick     SetID(launch_info.GetProcessID());
193061da546Spatrick   return error;
194061da546Spatrick }
195061da546Spatrick 
196061da546Spatrick Status
DoAttachToProcessWithID(lldb::pid_t pid,const ProcessAttachInfo & attach_info)197061da546Spatrick ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
198061da546Spatrick                                         const ProcessAttachInfo &attach_info) {
199061da546Spatrick   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
200061da546Spatrick   Status error = AttachProcess(pid, attach_info, delegate);
201061da546Spatrick   if (error.Success())
202061da546Spatrick     SetID(GetDebuggedProcessId());
203061da546Spatrick   return error;
204061da546Spatrick }
205061da546Spatrick 
DoResume()206061da546Spatrick Status ProcessWindows::DoResume() {
207*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
208061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
209061da546Spatrick   Status error;
210061da546Spatrick 
211061da546Spatrick   StateType private_state = GetPrivateState();
212061da546Spatrick   if (private_state == eStateStopped || private_state == eStateCrashed) {
213061da546Spatrick     LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
214061da546Spatrick              m_session_data->m_debugger->GetProcess().GetProcessId(),
215061da546Spatrick              GetPrivateState());
216061da546Spatrick 
217061da546Spatrick     LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
218061da546Spatrick 
219061da546Spatrick     bool failed = false;
220061da546Spatrick     for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
221061da546Spatrick       auto thread = std::static_pointer_cast<TargetThreadWindows>(
222061da546Spatrick           m_thread_list.GetThreadAtIndex(i));
223061da546Spatrick       Status result = thread->DoResume();
224061da546Spatrick       if (result.Fail()) {
225061da546Spatrick         failed = true;
226061da546Spatrick         LLDB_LOG(
227061da546Spatrick             log,
228061da546Spatrick             "Trying to resume thread at index {0}, but failed with error {1}.",
229061da546Spatrick             i, result);
230061da546Spatrick       }
231061da546Spatrick     }
232061da546Spatrick 
233061da546Spatrick     if (failed) {
234061da546Spatrick       error.SetErrorString("ProcessWindows::DoResume failed");
235061da546Spatrick     } else {
236061da546Spatrick       SetPrivateState(eStateRunning);
237061da546Spatrick     }
238061da546Spatrick 
239061da546Spatrick     ExceptionRecordSP active_exception =
240061da546Spatrick         m_session_data->m_debugger->GetActiveException().lock();
241061da546Spatrick     if (active_exception) {
242061da546Spatrick       // Resume the process and continue processing debug events.  Mask the
243061da546Spatrick       // exception so that from the process's view, there is no indication that
244061da546Spatrick       // anything happened.
245061da546Spatrick       m_session_data->m_debugger->ContinueAsyncException(
246061da546Spatrick           ExceptionResult::MaskException);
247061da546Spatrick     }
248061da546Spatrick   } else {
249061da546Spatrick     LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
250061da546Spatrick              m_session_data->m_debugger->GetProcess().GetProcessId(),
251061da546Spatrick              GetPrivateState());
252061da546Spatrick   }
253061da546Spatrick   return error;
254061da546Spatrick }
255061da546Spatrick 
DoDestroy()256061da546Spatrick Status ProcessWindows::DoDestroy() {
257061da546Spatrick   StateType private_state = GetPrivateState();
258061da546Spatrick   return DestroyProcess(private_state);
259061da546Spatrick }
260061da546Spatrick 
DoHalt(bool & caused_stop)261061da546Spatrick Status ProcessWindows::DoHalt(bool &caused_stop) {
262061da546Spatrick   StateType state = GetPrivateState();
263061da546Spatrick   if (state != eStateStopped)
264061da546Spatrick     return HaltProcess(caused_stop);
265061da546Spatrick   caused_stop = false;
266061da546Spatrick   return Status();
267061da546Spatrick }
268061da546Spatrick 
DidLaunch()269061da546Spatrick void ProcessWindows::DidLaunch() {
270061da546Spatrick   ArchSpec arch_spec;
271061da546Spatrick   DidAttach(arch_spec);
272061da546Spatrick }
273061da546Spatrick 
DidAttach(ArchSpec & arch_spec)274061da546Spatrick void ProcessWindows::DidAttach(ArchSpec &arch_spec) {
275061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
276061da546Spatrick 
277061da546Spatrick   // The initial stop won't broadcast the state change event, so account for
278061da546Spatrick   // that here.
279061da546Spatrick   if (m_session_data && GetPrivateState() == eStateStopped &&
280061da546Spatrick       m_session_data->m_stop_at_entry)
281061da546Spatrick     RefreshStateAfterStop();
282061da546Spatrick }
283061da546Spatrick 
284061da546Spatrick static void
DumpAdditionalExceptionInformation(llvm::raw_ostream & stream,const ExceptionRecordSP & exception)285061da546Spatrick DumpAdditionalExceptionInformation(llvm::raw_ostream &stream,
286061da546Spatrick                                    const ExceptionRecordSP &exception) {
287061da546Spatrick   // Decode additional exception information for specific exception types based
288061da546Spatrick   // on
289061da546Spatrick   // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record
290061da546Spatrick 
291061da546Spatrick   const int addr_min_width = 2 + 8; // "0x" + 4 address bytes
292061da546Spatrick 
293061da546Spatrick   const std::vector<ULONG_PTR> &args = exception->GetExceptionArguments();
294061da546Spatrick   switch (exception->GetExceptionCode()) {
295061da546Spatrick   case EXCEPTION_ACCESS_VIOLATION: {
296061da546Spatrick     if (args.size() < 2)
297061da546Spatrick       break;
298061da546Spatrick 
299061da546Spatrick     stream << ": ";
300061da546Spatrick     const int access_violation_code = args[0];
301061da546Spatrick     const lldb::addr_t access_violation_address = args[1];
302061da546Spatrick     switch (access_violation_code) {
303061da546Spatrick     case 0:
304061da546Spatrick       stream << "Access violation reading";
305061da546Spatrick       break;
306061da546Spatrick     case 1:
307061da546Spatrick       stream << "Access violation writing";
308061da546Spatrick       break;
309061da546Spatrick     case 8:
310061da546Spatrick       stream << "User-mode data execution prevention (DEP) violation at";
311061da546Spatrick       break;
312061da546Spatrick     default:
313061da546Spatrick       stream << "Unknown access violation (code " << access_violation_code
314061da546Spatrick              << ") at";
315061da546Spatrick       break;
316061da546Spatrick     }
317061da546Spatrick     stream << " location "
318061da546Spatrick            << llvm::format_hex(access_violation_address, addr_min_width);
319061da546Spatrick     break;
320061da546Spatrick   }
321061da546Spatrick   case EXCEPTION_IN_PAGE_ERROR: {
322061da546Spatrick     if (args.size() < 3)
323061da546Spatrick       break;
324061da546Spatrick 
325061da546Spatrick     stream << ": ";
326061da546Spatrick     const int page_load_error_code = args[0];
327061da546Spatrick     const lldb::addr_t page_load_error_address = args[1];
328061da546Spatrick     const DWORD underlying_code = args[2];
329061da546Spatrick     switch (page_load_error_code) {
330061da546Spatrick     case 0:
331061da546Spatrick       stream << "In page error reading";
332061da546Spatrick       break;
333061da546Spatrick     case 1:
334061da546Spatrick       stream << "In page error writing";
335061da546Spatrick       break;
336061da546Spatrick     case 8:
337061da546Spatrick       stream << "User-mode data execution prevention (DEP) violation at";
338061da546Spatrick       break;
339061da546Spatrick     default:
340061da546Spatrick       stream << "Unknown page loading error (code " << page_load_error_code
341061da546Spatrick              << ") at";
342061da546Spatrick       break;
343061da546Spatrick     }
344061da546Spatrick     stream << " location "
345061da546Spatrick            << llvm::format_hex(page_load_error_address, addr_min_width)
346061da546Spatrick            << " (status code " << llvm::format_hex(underlying_code, 8) << ")";
347061da546Spatrick     break;
348061da546Spatrick   }
349061da546Spatrick   }
350061da546Spatrick }
351061da546Spatrick 
RefreshStateAfterStop()352061da546Spatrick void ProcessWindows::RefreshStateAfterStop() {
353*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Exception);
354061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
355061da546Spatrick 
356061da546Spatrick   if (!m_session_data) {
357061da546Spatrick     LLDB_LOG(log, "no active session.  Returning...");
358061da546Spatrick     return;
359061da546Spatrick   }
360061da546Spatrick 
361061da546Spatrick   m_thread_list.RefreshStateAfterStop();
362061da546Spatrick 
363061da546Spatrick   std::weak_ptr<ExceptionRecord> exception_record =
364061da546Spatrick       m_session_data->m_debugger->GetActiveException();
365061da546Spatrick   ExceptionRecordSP active_exception = exception_record.lock();
366061da546Spatrick   if (!active_exception) {
367061da546Spatrick     LLDB_LOG(log,
368061da546Spatrick              "there is no active exception in process {0}.  Why is the "
369061da546Spatrick              "process stopped?",
370061da546Spatrick              m_session_data->m_debugger->GetProcess().GetProcessId());
371061da546Spatrick     return;
372061da546Spatrick   }
373061da546Spatrick 
374061da546Spatrick   StopInfoSP stop_info;
375061da546Spatrick   m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
376061da546Spatrick   ThreadSP stop_thread = m_thread_list.GetSelectedThread();
377061da546Spatrick   if (!stop_thread)
378061da546Spatrick     return;
379061da546Spatrick 
380061da546Spatrick   switch (active_exception->GetExceptionCode()) {
381061da546Spatrick   case EXCEPTION_SINGLE_STEP: {
382061da546Spatrick     RegisterContextSP register_context = stop_thread->GetRegisterContext();
383061da546Spatrick     const uint64_t pc = register_context->GetPC();
384061da546Spatrick     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
385be691f3bSpatrick     if (site && site->ValidForThisThread(*stop_thread)) {
386061da546Spatrick       LLDB_LOG(log,
387061da546Spatrick                "Single-stepped onto a breakpoint in process {0} at "
388061da546Spatrick                "address {1:x} with breakpoint site {2}",
389061da546Spatrick                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
390061da546Spatrick                site->GetID());
391061da546Spatrick       stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
392061da546Spatrick                                                                  site->GetID());
393061da546Spatrick       stop_thread->SetStopInfo(stop_info);
394061da546Spatrick 
395061da546Spatrick       return;
396061da546Spatrick     }
397061da546Spatrick 
398061da546Spatrick     auto *reg_ctx = static_cast<RegisterContextWindows *>(
399061da546Spatrick         stop_thread->GetRegisterContext().get());
400061da546Spatrick     uint32_t slot_id = reg_ctx->GetTriggeredHardwareBreakpointSlotId();
401061da546Spatrick     if (slot_id != LLDB_INVALID_INDEX32) {
402061da546Spatrick       int id = m_watchpoint_ids[slot_id];
403061da546Spatrick       LLDB_LOG(log,
404061da546Spatrick                "Single-stepped onto a watchpoint in process {0} at address "
405061da546Spatrick                "{1:x} with watchpoint {2}",
406061da546Spatrick                m_session_data->m_debugger->GetProcess().GetProcessId(), pc, id);
407061da546Spatrick 
408061da546Spatrick       if (lldb::WatchpointSP wp_sp =
409061da546Spatrick               GetTarget().GetWatchpointList().FindByID(id))
410061da546Spatrick         wp_sp->SetHardwareIndex(slot_id);
411061da546Spatrick 
412061da546Spatrick       stop_info = StopInfo::CreateStopReasonWithWatchpointID(
413061da546Spatrick           *stop_thread, id, m_watchpoints[id].address);
414061da546Spatrick       stop_thread->SetStopInfo(stop_info);
415061da546Spatrick 
416061da546Spatrick       return;
417061da546Spatrick     }
418061da546Spatrick 
419061da546Spatrick     LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
420061da546Spatrick     stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
421061da546Spatrick     stop_thread->SetStopInfo(stop_info);
422061da546Spatrick 
423061da546Spatrick     return;
424061da546Spatrick   }
425061da546Spatrick 
426061da546Spatrick   case EXCEPTION_BREAKPOINT: {
427061da546Spatrick     RegisterContextSP register_context = stop_thread->GetRegisterContext();
428061da546Spatrick 
429*f6aab3d8Srobert     int breakpoint_size = 1;
430*f6aab3d8Srobert     switch (GetTarget().GetArchitecture().GetMachine()) {
431*f6aab3d8Srobert     case llvm::Triple::aarch64:
432*f6aab3d8Srobert       breakpoint_size = 4;
433*f6aab3d8Srobert       break;
434*f6aab3d8Srobert 
435*f6aab3d8Srobert     case llvm::Triple::arm:
436*f6aab3d8Srobert     case llvm::Triple::thumb:
437*f6aab3d8Srobert       breakpoint_size = 2;
438*f6aab3d8Srobert       break;
439*f6aab3d8Srobert 
440*f6aab3d8Srobert     case llvm::Triple::x86:
441*f6aab3d8Srobert     case llvm::Triple::x86_64:
442*f6aab3d8Srobert       breakpoint_size = 1;
443*f6aab3d8Srobert       break;
444*f6aab3d8Srobert 
445*f6aab3d8Srobert     default:
446*f6aab3d8Srobert       LLDB_LOG(log, "Unknown breakpoint size for architecture");
447*f6aab3d8Srobert       break;
448*f6aab3d8Srobert     }
449*f6aab3d8Srobert 
450*f6aab3d8Srobert     // The current PC is AFTER the BP opcode, on all architectures.
451*f6aab3d8Srobert     uint64_t pc = register_context->GetPC() - breakpoint_size;
452061da546Spatrick 
453061da546Spatrick     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
454061da546Spatrick     if (site) {
455061da546Spatrick       LLDB_LOG(log,
456061da546Spatrick                "detected breakpoint in process {0} at address {1:x} with "
457061da546Spatrick                "breakpoint site {2}",
458061da546Spatrick                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
459061da546Spatrick                site->GetID());
460061da546Spatrick 
461be691f3bSpatrick       if (site->ValidForThisThread(*stop_thread)) {
462061da546Spatrick         LLDB_LOG(log,
463061da546Spatrick                  "Breakpoint site {0} is valid for this thread ({1:x}), "
464061da546Spatrick                  "creating stop info.",
465061da546Spatrick                  site->GetID(), stop_thread->GetID());
466061da546Spatrick 
467061da546Spatrick         stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
468061da546Spatrick             *stop_thread, site->GetID());
469061da546Spatrick         register_context->SetPC(pc);
470061da546Spatrick       } else {
471061da546Spatrick         LLDB_LOG(log,
472061da546Spatrick                  "Breakpoint site {0} is not valid for this thread, "
473061da546Spatrick                  "creating empty stop info.",
474061da546Spatrick                  site->GetID());
475061da546Spatrick       }
476061da546Spatrick       stop_thread->SetStopInfo(stop_info);
477061da546Spatrick       return;
478061da546Spatrick     } else {
479061da546Spatrick       // The thread hit a hard-coded breakpoint like an `int 3` or
480061da546Spatrick       // `__debugbreak()`.
481061da546Spatrick       LLDB_LOG(log,
482061da546Spatrick                "No breakpoint site matches for this thread. __debugbreak()?  "
483061da546Spatrick                "Creating stop info with the exception.");
484061da546Spatrick       // FALLTHROUGH:  We'll treat this as a generic exception record in the
485061da546Spatrick       // default case.
486*f6aab3d8Srobert       [[fallthrough]];
487061da546Spatrick     }
488061da546Spatrick   }
489061da546Spatrick 
490061da546Spatrick   default: {
491061da546Spatrick     std::string desc;
492061da546Spatrick     llvm::raw_string_ostream desc_stream(desc);
493061da546Spatrick     desc_stream << "Exception "
494061da546Spatrick                 << llvm::format_hex(active_exception->GetExceptionCode(), 8)
495061da546Spatrick                 << " encountered at address "
496061da546Spatrick                 << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
497061da546Spatrick     DumpAdditionalExceptionInformation(desc_stream, active_exception);
498061da546Spatrick 
499061da546Spatrick     stop_info = StopInfo::CreateStopReasonWithException(
500061da546Spatrick         *stop_thread, desc_stream.str().c_str());
501061da546Spatrick     stop_thread->SetStopInfo(stop_info);
502061da546Spatrick     LLDB_LOG(log, "{0}", desc_stream.str());
503061da546Spatrick     return;
504061da546Spatrick   }
505061da546Spatrick   }
506061da546Spatrick }
507061da546Spatrick 
CanDebug(lldb::TargetSP target_sp,bool plugin_specified_by_name)508061da546Spatrick bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
509061da546Spatrick                               bool plugin_specified_by_name) {
510061da546Spatrick   if (plugin_specified_by_name)
511061da546Spatrick     return true;
512061da546Spatrick 
513061da546Spatrick   // For now we are just making sure the file exists for a given module
514061da546Spatrick   ModuleSP exe_module_sp(target_sp->GetExecutableModule());
515061da546Spatrick   if (exe_module_sp.get())
516061da546Spatrick     return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec());
517061da546Spatrick   // However, if there is no executable module, we return true since we might
518061da546Spatrick   // be preparing to attach.
519061da546Spatrick   return true;
520061da546Spatrick }
521061da546Spatrick 
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)522be691f3bSpatrick bool ProcessWindows::DoUpdateThreadList(ThreadList &old_thread_list,
523061da546Spatrick                                         ThreadList &new_thread_list) {
524*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Thread);
525061da546Spatrick   // Add all the threads that were previously running and for which we did not
526061da546Spatrick   // detect a thread exited event.
527061da546Spatrick   int new_size = 0;
528061da546Spatrick   int continued_threads = 0;
529061da546Spatrick   int exited_threads = 0;
530061da546Spatrick   int new_threads = 0;
531061da546Spatrick 
532061da546Spatrick   for (ThreadSP old_thread : old_thread_list.Threads()) {
533061da546Spatrick     lldb::tid_t old_thread_id = old_thread->GetID();
534061da546Spatrick     auto exited_thread_iter =
535061da546Spatrick         m_session_data->m_exited_threads.find(old_thread_id);
536061da546Spatrick     if (exited_thread_iter == m_session_data->m_exited_threads.end()) {
537061da546Spatrick       new_thread_list.AddThread(old_thread);
538061da546Spatrick       ++new_size;
539061da546Spatrick       ++continued_threads;
540061da546Spatrick       LLDB_LOGV(log, "Thread {0} was running and is still running.",
541061da546Spatrick                 old_thread_id);
542061da546Spatrick     } else {
543061da546Spatrick       LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id);
544061da546Spatrick       ++exited_threads;
545061da546Spatrick     }
546061da546Spatrick   }
547061da546Spatrick 
548061da546Spatrick   // Also add all the threads that are new since the last time we broke into
549061da546Spatrick   // the debugger.
550061da546Spatrick   for (const auto &thread_info : m_session_data->m_new_threads) {
551061da546Spatrick     new_thread_list.AddThread(thread_info.second);
552061da546Spatrick     ++new_size;
553061da546Spatrick     ++new_threads;
554061da546Spatrick     LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
555061da546Spatrick   }
556061da546Spatrick 
557061da546Spatrick   LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.",
558061da546Spatrick            new_threads, continued_threads, exited_threads);
559061da546Spatrick 
560061da546Spatrick   m_session_data->m_new_threads.clear();
561061da546Spatrick   m_session_data->m_exited_threads.clear();
562061da546Spatrick 
563061da546Spatrick   return new_size > 0;
564061da546Spatrick }
565061da546Spatrick 
IsAlive()566061da546Spatrick bool ProcessWindows::IsAlive() {
567061da546Spatrick   StateType state = GetPrivateState();
568061da546Spatrick   switch (state) {
569061da546Spatrick   case eStateCrashed:
570061da546Spatrick   case eStateDetached:
571061da546Spatrick   case eStateUnloaded:
572061da546Spatrick   case eStateExited:
573061da546Spatrick   case eStateInvalid:
574061da546Spatrick     return false;
575061da546Spatrick   default:
576061da546Spatrick     return true;
577061da546Spatrick   }
578061da546Spatrick }
579061da546Spatrick 
GetSystemArchitecture()580*f6aab3d8Srobert ArchSpec ProcessWindows::GetSystemArchitecture() {
581*f6aab3d8Srobert   return HostInfo::GetArchitecture();
582*f6aab3d8Srobert }
583*f6aab3d8Srobert 
DoReadMemory(lldb::addr_t vm_addr,void * buf,size_t size,Status & error)584061da546Spatrick size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
585061da546Spatrick                                     size_t size, Status &error) {
586061da546Spatrick   size_t bytes_read = 0;
587061da546Spatrick   error = ProcessDebugger::ReadMemory(vm_addr, buf, size, bytes_read);
588061da546Spatrick   return bytes_read;
589061da546Spatrick }
590061da546Spatrick 
DoWriteMemory(lldb::addr_t vm_addr,const void * buf,size_t size,Status & error)591061da546Spatrick size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
592061da546Spatrick                                      size_t size, Status &error) {
593061da546Spatrick   size_t bytes_written = 0;
594061da546Spatrick   error = ProcessDebugger::WriteMemory(vm_addr, buf, size, bytes_written);
595061da546Spatrick   return bytes_written;
596061da546Spatrick }
597061da546Spatrick 
DoAllocateMemory(size_t size,uint32_t permissions,Status & error)598061da546Spatrick lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
599061da546Spatrick                                               Status &error) {
600061da546Spatrick   lldb::addr_t vm_addr = LLDB_INVALID_ADDRESS;
601061da546Spatrick   error = ProcessDebugger::AllocateMemory(size, permissions, vm_addr);
602061da546Spatrick   return vm_addr;
603061da546Spatrick }
604061da546Spatrick 
DoDeallocateMemory(lldb::addr_t ptr)605061da546Spatrick Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) {
606061da546Spatrick   return ProcessDebugger::DeallocateMemory(ptr);
607061da546Spatrick }
608061da546Spatrick 
DoGetMemoryRegionInfo(lldb::addr_t vm_addr,MemoryRegionInfo & info)609*f6aab3d8Srobert Status ProcessWindows::DoGetMemoryRegionInfo(lldb::addr_t vm_addr,
610061da546Spatrick                                              MemoryRegionInfo &info) {
611061da546Spatrick   return ProcessDebugger::GetMemoryRegionInfo(vm_addr, info);
612061da546Spatrick }
613061da546Spatrick 
GetImageInfoAddress()614061da546Spatrick lldb::addr_t ProcessWindows::GetImageInfoAddress() {
615061da546Spatrick   Target &target = GetTarget();
616061da546Spatrick   ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
617061da546Spatrick   Address addr = obj_file->GetImageInfoAddress(&target);
618061da546Spatrick   if (addr.IsValid())
619061da546Spatrick     return addr.GetLoadAddress(&target);
620061da546Spatrick   else
621061da546Spatrick     return LLDB_INVALID_ADDRESS;
622061da546Spatrick }
623061da546Spatrick 
GetDynamicLoader()624061da546Spatrick DynamicLoaderWindowsDYLD *ProcessWindows::GetDynamicLoader() {
625061da546Spatrick   if (m_dyld_up.get() == NULL)
626061da546Spatrick     m_dyld_up.reset(DynamicLoader::FindPlugin(
627*f6aab3d8Srobert         this, DynamicLoaderWindowsDYLD::GetPluginNameStatic()));
628061da546Spatrick   return static_cast<DynamicLoaderWindowsDYLD *>(m_dyld_up.get());
629061da546Spatrick }
630061da546Spatrick 
OnExitProcess(uint32_t exit_code)631061da546Spatrick void ProcessWindows::OnExitProcess(uint32_t exit_code) {
632061da546Spatrick   // No need to acquire the lock since m_session_data isn't accessed.
633*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
634061da546Spatrick   LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
635061da546Spatrick 
636061da546Spatrick   TargetSP target = CalculateTarget();
637061da546Spatrick   if (target) {
638061da546Spatrick     ModuleSP executable_module = target->GetExecutableModule();
639061da546Spatrick     ModuleList unloaded_modules;
640061da546Spatrick     unloaded_modules.Append(executable_module);
641061da546Spatrick     target->ModulesDidUnload(unloaded_modules, true);
642061da546Spatrick   }
643061da546Spatrick 
644061da546Spatrick   SetProcessExitStatus(GetID(), true, 0, exit_code);
645061da546Spatrick   SetPrivateState(eStateExited);
646061da546Spatrick 
647061da546Spatrick   ProcessDebugger::OnExitProcess(exit_code);
648061da546Spatrick }
649061da546Spatrick 
OnDebuggerConnected(lldb::addr_t image_base)650061da546Spatrick void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
651061da546Spatrick   DebuggerThreadSP debugger = m_session_data->m_debugger;
652*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
653061da546Spatrick   LLDB_LOG(log, "Debugger connected to process {0}.  Image base = {1:x}",
654061da546Spatrick            debugger->GetProcess().GetProcessId(), image_base);
655061da546Spatrick 
656*f6aab3d8Srobert   ModuleSP module;
657061da546Spatrick   // During attach, we won't have the executable module, so find it now.
658061da546Spatrick   const DWORD pid = debugger->GetProcess().GetProcessId();
659061da546Spatrick   const std::string file_name = GetProcessExecutableName(pid);
660061da546Spatrick   if (file_name.empty()) {
661061da546Spatrick     return;
662061da546Spatrick   }
663061da546Spatrick 
664061da546Spatrick   FileSpec executable_file(file_name);
665061da546Spatrick   FileSystem::Instance().Resolve(executable_file);
666061da546Spatrick   ModuleSpec module_spec(executable_file);
667061da546Spatrick   Status error;
668061da546Spatrick   module =
669061da546Spatrick       GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
670061da546Spatrick   if (!module) {
671061da546Spatrick     return;
672061da546Spatrick   }
673061da546Spatrick 
674061da546Spatrick   GetTarget().SetExecutableModule(module, eLoadDependentsNo);
675061da546Spatrick 
676061da546Spatrick   if (auto dyld = GetDynamicLoader())
677061da546Spatrick     dyld->OnLoadModule(module, ModuleSpec(), image_base);
678061da546Spatrick 
679061da546Spatrick   // Add the main executable module to the list of pending module loads.  We
680061da546Spatrick   // can't call GetTarget().ModulesDidLoad() here because we still haven't
681061da546Spatrick   // returned from DoLaunch() / DoAttach() yet so the target may not have set
682061da546Spatrick   // the process instance to `this` yet.
683061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
684061da546Spatrick 
685061da546Spatrick   const HostThread &host_main_thread = debugger->GetMainThread();
686061da546Spatrick   ThreadSP main_thread =
687061da546Spatrick       std::make_shared<TargetThreadWindows>(*this, host_main_thread);
688061da546Spatrick 
689061da546Spatrick   tid_t id = host_main_thread.GetNativeThread().GetThreadId();
690061da546Spatrick   main_thread->SetID(id);
691061da546Spatrick 
692061da546Spatrick   m_session_data->m_new_threads[id] = main_thread;
693061da546Spatrick }
694061da546Spatrick 
695061da546Spatrick ExceptionResult
OnDebugException(bool first_chance,const ExceptionRecord & record)696061da546Spatrick ProcessWindows::OnDebugException(bool first_chance,
697061da546Spatrick                                  const ExceptionRecord &record) {
698*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Exception);
699061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
700061da546Spatrick 
701061da546Spatrick   // FIXME: Without this check, occasionally when running the test suite there
702061da546Spatrick   // is
703061da546Spatrick   // an issue where m_session_data can be null.  It's not clear how this could
704061da546Spatrick   // happen but it only surfaces while running the test suite.  In order to
705061da546Spatrick   // properly diagnose this, we probably need to first figure allow the test
706061da546Spatrick   // suite to print out full lldb logs, and then add logging to the process
707061da546Spatrick   // plugin.
708061da546Spatrick   if (!m_session_data) {
709061da546Spatrick     LLDB_LOG(log,
710061da546Spatrick              "Debugger thread reported exception {0:x} at address {1:x}, "
711061da546Spatrick              "but there is no session.",
712061da546Spatrick              record.GetExceptionCode(), record.GetExceptionAddress());
713061da546Spatrick     return ExceptionResult::SendToApplication;
714061da546Spatrick   }
715061da546Spatrick 
716061da546Spatrick   if (!first_chance) {
717061da546Spatrick     // Not any second chance exception is an application crash by definition.
718061da546Spatrick     // It may be an expression evaluation crash.
719061da546Spatrick     SetPrivateState(eStateStopped);
720061da546Spatrick   }
721061da546Spatrick 
722061da546Spatrick   ExceptionResult result = ExceptionResult::SendToApplication;
723061da546Spatrick   switch (record.GetExceptionCode()) {
724061da546Spatrick   case EXCEPTION_BREAKPOINT:
725061da546Spatrick     // Handle breakpoints at the first chance.
726061da546Spatrick     result = ExceptionResult::BreakInDebugger;
727061da546Spatrick 
728061da546Spatrick     if (!m_session_data->m_initial_stop_received) {
729061da546Spatrick       LLDB_LOG(
730061da546Spatrick           log,
731061da546Spatrick           "Hit loader breakpoint at address {0:x}, setting initial stop event.",
732061da546Spatrick           record.GetExceptionAddress());
733061da546Spatrick       m_session_data->m_initial_stop_received = true;
734061da546Spatrick       ::SetEvent(m_session_data->m_initial_stop_event);
735061da546Spatrick     } else {
736061da546Spatrick       LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
737061da546Spatrick                record.GetExceptionAddress());
738061da546Spatrick     }
739061da546Spatrick     SetPrivateState(eStateStopped);
740061da546Spatrick     break;
741061da546Spatrick   case EXCEPTION_SINGLE_STEP:
742061da546Spatrick     result = ExceptionResult::BreakInDebugger;
743061da546Spatrick     SetPrivateState(eStateStopped);
744061da546Spatrick     break;
745061da546Spatrick   default:
746061da546Spatrick     LLDB_LOG(log,
747061da546Spatrick              "Debugger thread reported exception {0:x} at address {1:x} "
748061da546Spatrick              "(first_chance={2})",
749061da546Spatrick              record.GetExceptionCode(), record.GetExceptionAddress(),
750061da546Spatrick              first_chance);
751061da546Spatrick     // For non-breakpoints, give the application a chance to handle the
752061da546Spatrick     // exception first.
753061da546Spatrick     if (first_chance)
754061da546Spatrick       result = ExceptionResult::SendToApplication;
755061da546Spatrick     else
756061da546Spatrick       result = ExceptionResult::BreakInDebugger;
757061da546Spatrick   }
758061da546Spatrick 
759061da546Spatrick   return result;
760061da546Spatrick }
761061da546Spatrick 
OnCreateThread(const HostThread & new_thread)762061da546Spatrick void ProcessWindows::OnCreateThread(const HostThread &new_thread) {
763061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
764061da546Spatrick 
765061da546Spatrick   ThreadSP thread = std::make_shared<TargetThreadWindows>(*this, new_thread);
766061da546Spatrick 
767061da546Spatrick   const HostNativeThread &native_new_thread = new_thread.GetNativeThread();
768061da546Spatrick   tid_t id = native_new_thread.GetThreadId();
769061da546Spatrick   thread->SetID(id);
770061da546Spatrick 
771061da546Spatrick   m_session_data->m_new_threads[id] = thread;
772061da546Spatrick 
773061da546Spatrick   for (const std::map<int, WatchpointInfo>::value_type &p : m_watchpoints) {
774061da546Spatrick     auto *reg_ctx = static_cast<RegisterContextWindows *>(
775061da546Spatrick         thread->GetRegisterContext().get());
776061da546Spatrick     reg_ctx->AddHardwareBreakpoint(p.second.slot_id, p.second.address,
777061da546Spatrick                                    p.second.size, p.second.read,
778061da546Spatrick                                    p.second.write);
779061da546Spatrick   }
780061da546Spatrick }
781061da546Spatrick 
OnExitThread(lldb::tid_t thread_id,uint32_t exit_code)782061da546Spatrick void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
783061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
784061da546Spatrick 
785061da546Spatrick   // On a forced termination, we may get exit thread events after the session
786061da546Spatrick   // data has been cleaned up.
787061da546Spatrick   if (!m_session_data)
788061da546Spatrick     return;
789061da546Spatrick 
790061da546Spatrick   // A thread may have started and exited before the debugger stopped allowing a
791061da546Spatrick   // refresh.
792061da546Spatrick   // Just remove it from the new threads list in that case.
793061da546Spatrick   auto iter = m_session_data->m_new_threads.find(thread_id);
794061da546Spatrick   if (iter != m_session_data->m_new_threads.end())
795061da546Spatrick     m_session_data->m_new_threads.erase(iter);
796061da546Spatrick   else
797061da546Spatrick     m_session_data->m_exited_threads.insert(thread_id);
798061da546Spatrick }
799061da546Spatrick 
OnLoadDll(const ModuleSpec & module_spec,lldb::addr_t module_addr)800061da546Spatrick void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
801061da546Spatrick                                lldb::addr_t module_addr) {
802061da546Spatrick   if (auto dyld = GetDynamicLoader())
803061da546Spatrick     dyld->OnLoadModule(nullptr, module_spec, module_addr);
804061da546Spatrick }
805061da546Spatrick 
OnUnloadDll(lldb::addr_t module_addr)806061da546Spatrick void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
807061da546Spatrick   if (auto dyld = GetDynamicLoader())
808061da546Spatrick     dyld->OnUnloadModule(module_addr);
809061da546Spatrick }
810061da546Spatrick 
OnDebugString(const std::string & string)811061da546Spatrick void ProcessWindows::OnDebugString(const std::string &string) {}
812061da546Spatrick 
OnDebuggerError(const Status & error,uint32_t type)813061da546Spatrick void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
814061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
815*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
816061da546Spatrick 
817061da546Spatrick   if (m_session_data->m_initial_stop_received) {
818061da546Spatrick     // This happened while debugging.  Do we shutdown the debugging session,
819061da546Spatrick     // try to continue, or do something else?
820061da546Spatrick     LLDB_LOG(log,
821061da546Spatrick              "Error {0} occurred during debugging.  Unexpected behavior "
822061da546Spatrick              "may result.  {1}",
823061da546Spatrick              error.GetError(), error);
824061da546Spatrick   } else {
825061da546Spatrick     // If we haven't actually launched the process yet, this was an error
826061da546Spatrick     // launching the process.  Set the internal error and signal the initial
827061da546Spatrick     // stop event so that the DoLaunch method wakes up and returns a failure.
828061da546Spatrick     m_session_data->m_launch_error = error;
829061da546Spatrick     ::SetEvent(m_session_data->m_initial_stop_event);
830061da546Spatrick     LLDB_LOG(
831061da546Spatrick         log,
832061da546Spatrick         "Error {0} occurred launching the process before the initial stop. {1}",
833061da546Spatrick         error.GetError(), error);
834061da546Spatrick     return;
835061da546Spatrick   }
836061da546Spatrick }
837061da546Spatrick 
GetWatchpointSupportInfo(uint32_t & num)838061da546Spatrick Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num) {
839061da546Spatrick   num = RegisterContextWindows::GetNumHardwareBreakpointSlots();
840061da546Spatrick   return {};
841061da546Spatrick }
842061da546Spatrick 
GetWatchpointSupportInfo(uint32_t & num,bool & after)843061da546Spatrick Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
844061da546Spatrick   num = RegisterContextWindows::GetNumHardwareBreakpointSlots();
845061da546Spatrick   after = RegisterContextWindows::DoHardwareBreakpointsTriggerAfter();
846061da546Spatrick   return {};
847061da546Spatrick }
848061da546Spatrick 
EnableWatchpoint(Watchpoint * wp,bool notify)849061da546Spatrick Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
850061da546Spatrick   Status error;
851061da546Spatrick 
852061da546Spatrick   if (wp->IsEnabled()) {
853061da546Spatrick     wp->SetEnabled(true, notify);
854061da546Spatrick     return error;
855061da546Spatrick   }
856061da546Spatrick 
857061da546Spatrick   WatchpointInfo info;
858061da546Spatrick   for (info.slot_id = 0;
859061da546Spatrick        info.slot_id < RegisterContextWindows::GetNumHardwareBreakpointSlots();
860061da546Spatrick        info.slot_id++)
861061da546Spatrick     if (m_watchpoint_ids[info.slot_id] == LLDB_INVALID_BREAK_ID)
862061da546Spatrick       break;
863061da546Spatrick   if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) {
864061da546Spatrick     error.SetErrorStringWithFormat("Can't find free slot for watchpoint %i",
865061da546Spatrick                                    wp->GetID());
866061da546Spatrick     return error;
867061da546Spatrick   }
868061da546Spatrick   info.address = wp->GetLoadAddress();
869061da546Spatrick   info.size = wp->GetByteSize();
870061da546Spatrick   info.read = wp->WatchpointRead();
871061da546Spatrick   info.write = wp->WatchpointWrite();
872061da546Spatrick 
873061da546Spatrick   for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
874061da546Spatrick     Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
875061da546Spatrick     auto *reg_ctx = static_cast<RegisterContextWindows *>(
876061da546Spatrick         thread->GetRegisterContext().get());
877061da546Spatrick     if (!reg_ctx->AddHardwareBreakpoint(info.slot_id, info.address, info.size,
878061da546Spatrick                                         info.read, info.write)) {
879061da546Spatrick       error.SetErrorStringWithFormat(
880061da546Spatrick           "Can't enable watchpoint %i on thread 0x%llx", wp->GetID(),
881061da546Spatrick           thread->GetID());
882061da546Spatrick       break;
883061da546Spatrick     }
884061da546Spatrick   }
885061da546Spatrick   if (error.Fail()) {
886061da546Spatrick     for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
887061da546Spatrick       Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
888061da546Spatrick       auto *reg_ctx = static_cast<RegisterContextWindows *>(
889061da546Spatrick           thread->GetRegisterContext().get());
890061da546Spatrick       reg_ctx->RemoveHardwareBreakpoint(info.slot_id);
891061da546Spatrick     }
892061da546Spatrick     return error;
893061da546Spatrick   }
894061da546Spatrick 
895061da546Spatrick   m_watchpoints[wp->GetID()] = info;
896061da546Spatrick   m_watchpoint_ids[info.slot_id] = wp->GetID();
897061da546Spatrick 
898061da546Spatrick   wp->SetEnabled(true, notify);
899061da546Spatrick 
900061da546Spatrick   return error;
901061da546Spatrick }
902061da546Spatrick 
DisableWatchpoint(Watchpoint * wp,bool notify)903061da546Spatrick Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) {
904061da546Spatrick   Status error;
905061da546Spatrick 
906061da546Spatrick   if (!wp->IsEnabled()) {
907061da546Spatrick     wp->SetEnabled(false, notify);
908061da546Spatrick     return error;
909061da546Spatrick   }
910061da546Spatrick 
911061da546Spatrick   auto it = m_watchpoints.find(wp->GetID());
912061da546Spatrick   if (it == m_watchpoints.end()) {
913061da546Spatrick     error.SetErrorStringWithFormat("Info about watchpoint %i is not found",
914061da546Spatrick                                    wp->GetID());
915061da546Spatrick     return error;
916061da546Spatrick   }
917061da546Spatrick 
918061da546Spatrick   for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
919061da546Spatrick     Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
920061da546Spatrick     auto *reg_ctx = static_cast<RegisterContextWindows *>(
921061da546Spatrick         thread->GetRegisterContext().get());
922061da546Spatrick     if (!reg_ctx->RemoveHardwareBreakpoint(it->second.slot_id)) {
923061da546Spatrick       error.SetErrorStringWithFormat(
924061da546Spatrick           "Can't disable watchpoint %i on thread 0x%llx", wp->GetID(),
925061da546Spatrick           thread->GetID());
926061da546Spatrick       break;
927061da546Spatrick     }
928061da546Spatrick   }
929061da546Spatrick   if (error.Fail())
930061da546Spatrick     return error;
931061da546Spatrick 
932061da546Spatrick   m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID;
933061da546Spatrick   m_watchpoints.erase(it);
934061da546Spatrick 
935061da546Spatrick   wp->SetEnabled(false, notify);
936061da546Spatrick 
937061da546Spatrick   return error;
938061da546Spatrick }
939061da546Spatrick } // namespace lldb_private
940