1*053eb356SAaron Smith //===-- ProcessDebugger.cpp -------------------------------------*- C++ -*-===//
2*053eb356SAaron Smith //
3*053eb356SAaron Smith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*053eb356SAaron Smith // See https://llvm.org/LICENSE.txt for license information.
5*053eb356SAaron Smith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*053eb356SAaron Smith //
7*053eb356SAaron Smith //===----------------------------------------------------------------------===//
8*053eb356SAaron Smith 
9*053eb356SAaron Smith #include "ProcessDebugger.h"
10*053eb356SAaron Smith 
11*053eb356SAaron Smith // Windows includes
12*053eb356SAaron Smith #include "lldb/Host/windows/windows.h"
13*053eb356SAaron Smith #include <psapi.h>
14*053eb356SAaron Smith 
15*053eb356SAaron Smith #include "lldb/Host/FileSystem.h"
16*053eb356SAaron Smith #include "lldb/Host/HostNativeProcessBase.h"
17*053eb356SAaron Smith #include "lldb/Host/HostProcess.h"
18*053eb356SAaron Smith #include "lldb/Host/HostThread.h"
19*053eb356SAaron Smith #include "lldb/Host/ProcessLaunchInfo.h"
20*053eb356SAaron Smith #include "lldb/Target/MemoryRegionInfo.h"
21*053eb356SAaron Smith #include "lldb/Target/Process.h"
22*053eb356SAaron Smith #include "llvm/Support/ConvertUTF.h"
23*053eb356SAaron Smith #include "llvm/Support/Error.h"
24*053eb356SAaron Smith 
25*053eb356SAaron Smith #include "DebuggerThread.h"
26*053eb356SAaron Smith #include "ExceptionRecord.h"
27*053eb356SAaron Smith #include "ProcessWindowsLog.h"
28*053eb356SAaron Smith 
29*053eb356SAaron Smith using namespace lldb;
30*053eb356SAaron Smith using namespace lldb_private;
31*053eb356SAaron Smith 
32*053eb356SAaron Smith static DWORD ConvertLldbToWinApiProtect(uint32_t protect) {
33*053eb356SAaron Smith   // We also can process a read / write permissions here, but if the debugger
34*053eb356SAaron Smith   // will make later a write into the allocated memory, it will fail. To get
35*053eb356SAaron Smith   // around it is possible inside DoWriteMemory to remember memory permissions,
36*053eb356SAaron Smith   // allow write, write and restore permissions, but for now we process only
37*053eb356SAaron Smith   // the executable permission.
38*053eb356SAaron Smith   //
39*053eb356SAaron Smith   // TODO: Process permissions other than executable
40*053eb356SAaron Smith   if (protect & ePermissionsExecutable)
41*053eb356SAaron Smith     return PAGE_EXECUTE_READWRITE;
42*053eb356SAaron Smith 
43*053eb356SAaron Smith   return PAGE_READWRITE;
44*053eb356SAaron Smith }
45*053eb356SAaron Smith 
46*053eb356SAaron Smith // The Windows page protection bits are NOT independent masks that can be
47*053eb356SAaron Smith // bitwise-ORed together.  For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE
48*053eb356SAaron Smith // | PAGE_READ).  To test for an access type, it's necessary to test for any of
49*053eb356SAaron Smith // the bits that provide that access type.
50*053eb356SAaron Smith static bool IsPageReadable(uint32_t protect) {
51*053eb356SAaron Smith   return (protect & PAGE_NOACCESS) == 0;
52*053eb356SAaron Smith }
53*053eb356SAaron Smith 
54*053eb356SAaron Smith static bool IsPageWritable(uint32_t protect) {
55*053eb356SAaron Smith   return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
56*053eb356SAaron Smith                      PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
57*053eb356SAaron Smith }
58*053eb356SAaron Smith 
59*053eb356SAaron Smith static bool IsPageExecutable(uint32_t protect) {
60*053eb356SAaron Smith   return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
61*053eb356SAaron Smith                      PAGE_EXECUTE_WRITECOPY)) != 0;
62*053eb356SAaron Smith }
63*053eb356SAaron Smith 
64*053eb356SAaron Smith namespace lldb_private {
65*053eb356SAaron Smith 
66*053eb356SAaron Smith lldb::pid_t ProcessDebugger::GetDebuggedProcessId() const {
67*053eb356SAaron Smith   if (m_session_data)
68*053eb356SAaron Smith     return m_session_data->m_debugger->GetProcess().GetProcessId();
69*053eb356SAaron Smith   return LLDB_INVALID_PROCESS_ID;
70*053eb356SAaron Smith }
71*053eb356SAaron Smith 
72*053eb356SAaron Smith Status ProcessDebugger::DetachProcess() {
73*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
74*053eb356SAaron Smith   DebuggerThreadSP debugger_thread;
75*053eb356SAaron Smith   {
76*053eb356SAaron Smith     // Acquire the lock only long enough to get the DebuggerThread.
77*053eb356SAaron Smith     // StopDebugging() will trigger a call back into ProcessDebugger which will
78*053eb356SAaron Smith     // also acquire the lock.  Thus we have to release the lock before calling
79*053eb356SAaron Smith     // StopDebugging().
80*053eb356SAaron Smith     llvm::sys::ScopedLock lock(m_mutex);
81*053eb356SAaron Smith 
82*053eb356SAaron Smith     if (!m_session_data) {
83*053eb356SAaron Smith       LLDB_LOG(log, "there is no active session.");
84*053eb356SAaron Smith       return Status();
85*053eb356SAaron Smith     }
86*053eb356SAaron Smith 
87*053eb356SAaron Smith     debugger_thread = m_session_data->m_debugger;
88*053eb356SAaron Smith   }
89*053eb356SAaron Smith 
90*053eb356SAaron Smith   Status error;
91*053eb356SAaron Smith 
92*053eb356SAaron Smith   LLDB_LOG(log, "detaching from process {0}.",
93*053eb356SAaron Smith            debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
94*053eb356SAaron Smith   error = debugger_thread->StopDebugging(false);
95*053eb356SAaron Smith 
96*053eb356SAaron Smith   // By the time StopDebugging returns, there is no more debugger thread, so
97*053eb356SAaron Smith   // we can be assured that no other thread will race for the session data.
98*053eb356SAaron Smith   m_session_data.reset();
99*053eb356SAaron Smith 
100*053eb356SAaron Smith   return error;
101*053eb356SAaron Smith }
102*053eb356SAaron Smith 
103*053eb356SAaron Smith Status ProcessDebugger::LaunchProcess(ProcessLaunchInfo &launch_info,
104*053eb356SAaron Smith                                       DebugDelegateSP delegate) {
105*053eb356SAaron Smith   // Even though m_session_data is accessed here, it is before a debugger
106*053eb356SAaron Smith   // thread has been kicked off.  So there's no race conditions, and it
107*053eb356SAaron Smith   // shouldn't be necessary to acquire the mutex.
108*053eb356SAaron Smith 
109*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
110*053eb356SAaron Smith   Status result;
111*053eb356SAaron Smith 
112*053eb356SAaron Smith   FileSpec working_dir = launch_info.GetWorkingDirectory();
113*053eb356SAaron Smith   namespace fs = llvm::sys::fs;
114*053eb356SAaron Smith   if (working_dir) {
115*053eb356SAaron Smith     FileSystem::Instance().Resolve(working_dir);
116*053eb356SAaron Smith     if (!FileSystem::Instance().IsDirectory(working_dir)) {
117*053eb356SAaron Smith       result.SetErrorStringWithFormat("No such file or directory: %s",
118*053eb356SAaron Smith                                       working_dir.GetCString());
119*053eb356SAaron Smith       return result;
120*053eb356SAaron Smith     }
121*053eb356SAaron Smith   }
122*053eb356SAaron Smith 
123*053eb356SAaron Smith   if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) {
124*053eb356SAaron Smith     StreamString stream;
125*053eb356SAaron Smith     stream.Printf("ProcessDebugger unable to launch '%s'.  ProcessDebugger can "
126*053eb356SAaron Smith                   "only be used for debug launches.",
127*053eb356SAaron Smith                   launch_info.GetExecutableFile().GetPath().c_str());
128*053eb356SAaron Smith     std::string message = stream.GetString();
129*053eb356SAaron Smith     result.SetErrorString(message.c_str());
130*053eb356SAaron Smith 
131*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", message);
132*053eb356SAaron Smith     return result;
133*053eb356SAaron Smith   }
134*053eb356SAaron Smith 
135*053eb356SAaron Smith   bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
136*053eb356SAaron Smith   m_session_data.reset(new ProcessWindowsData(stop_at_entry));
137*053eb356SAaron Smith   m_session_data->m_debugger.reset(new DebuggerThread(delegate));
138*053eb356SAaron Smith   DebuggerThreadSP debugger = m_session_data->m_debugger;
139*053eb356SAaron Smith 
140*053eb356SAaron Smith   // Kick off the DebugLaunch asynchronously and wait for it to complete.
141*053eb356SAaron Smith   result = debugger->DebugLaunch(launch_info);
142*053eb356SAaron Smith   if (result.Fail()) {
143*053eb356SAaron Smith     LLDB_LOG(log, "failed launching '{0}'. {1}",
144*053eb356SAaron Smith              launch_info.GetExecutableFile().GetPath(), result);
145*053eb356SAaron Smith     return result;
146*053eb356SAaron Smith   }
147*053eb356SAaron Smith 
148*053eb356SAaron Smith   HostProcess process;
149*053eb356SAaron Smith   Status error = WaitForDebuggerConnection(debugger, process);
150*053eb356SAaron Smith   if (error.Fail()) {
151*053eb356SAaron Smith     LLDB_LOG(log, "failed launching '{0}'. {1}",
152*053eb356SAaron Smith              launch_info.GetExecutableFile().GetPath(), error);
153*053eb356SAaron Smith     return error;
154*053eb356SAaron Smith   }
155*053eb356SAaron Smith 
156*053eb356SAaron Smith   LLDB_LOG(log, "successfully launched '{0}'",
157*053eb356SAaron Smith            launch_info.GetExecutableFile().GetPath());
158*053eb356SAaron Smith 
159*053eb356SAaron Smith   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
160*053eb356SAaron Smith   // private state should already be set to eStateStopped as a result of
161*053eb356SAaron Smith   // hitting the initial breakpoint.  If it was not set, the breakpoint should
162*053eb356SAaron Smith   // have already been resumed from and the private state should already be
163*053eb356SAaron Smith   // eStateRunning.
164*053eb356SAaron Smith   launch_info.SetProcessID(process.GetProcessId());
165*053eb356SAaron Smith 
166*053eb356SAaron Smith   return result;
167*053eb356SAaron Smith }
168*053eb356SAaron Smith 
169*053eb356SAaron Smith Status ProcessDebugger::AttachProcess(lldb::pid_t pid,
170*053eb356SAaron Smith                                       const ProcessAttachInfo &attach_info,
171*053eb356SAaron Smith                                       DebugDelegateSP delegate) {
172*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
173*053eb356SAaron Smith   m_session_data.reset(
174*053eb356SAaron Smith       new ProcessWindowsData(!attach_info.GetContinueOnceAttached()));
175*053eb356SAaron Smith   DebuggerThreadSP debugger(new DebuggerThread(delegate));
176*053eb356SAaron Smith 
177*053eb356SAaron Smith   m_session_data->m_debugger = debugger;
178*053eb356SAaron Smith 
179*053eb356SAaron Smith   DWORD process_id = static_cast<DWORD>(pid);
180*053eb356SAaron Smith   Status error = debugger->DebugAttach(process_id, attach_info);
181*053eb356SAaron Smith   if (error.Fail()) {
182*053eb356SAaron Smith     LLDB_LOG(
183*053eb356SAaron Smith         log,
184*053eb356SAaron Smith         "encountered an error occurred initiating the asynchronous attach. {0}",
185*053eb356SAaron Smith         error);
186*053eb356SAaron Smith     return error;
187*053eb356SAaron Smith   }
188*053eb356SAaron Smith 
189*053eb356SAaron Smith   HostProcess process;
190*053eb356SAaron Smith   error = WaitForDebuggerConnection(debugger, process);
191*053eb356SAaron Smith   if (error.Fail()) {
192*053eb356SAaron Smith     LLDB_LOG(log,
193*053eb356SAaron Smith              "encountered an error waiting for the debugger to connect. {0}",
194*053eb356SAaron Smith              error);
195*053eb356SAaron Smith     return error;
196*053eb356SAaron Smith   }
197*053eb356SAaron Smith 
198*053eb356SAaron Smith   LLDB_LOG(log, "successfully attached to process with pid={0}", process_id);
199*053eb356SAaron Smith 
200*053eb356SAaron Smith   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
201*053eb356SAaron Smith   // private state should already be set to eStateStopped as a result of
202*053eb356SAaron Smith   // hitting the initial breakpoint.  If it was not set, the breakpoint should
203*053eb356SAaron Smith   // have already been resumed from and the private state should already be
204*053eb356SAaron Smith   // eStateRunning.
205*053eb356SAaron Smith 
206*053eb356SAaron Smith   return error;
207*053eb356SAaron Smith }
208*053eb356SAaron Smith 
209*053eb356SAaron Smith Status ProcessDebugger::DestroyProcess(const lldb::StateType state) {
210*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
211*053eb356SAaron Smith   DebuggerThreadSP debugger_thread;
212*053eb356SAaron Smith   {
213*053eb356SAaron Smith     // Acquire this lock inside an inner scope, only long enough to get the
214*053eb356SAaron Smith     // DebuggerThread. StopDebugging() will trigger a call back into
215*053eb356SAaron Smith     // ProcessDebugger which will acquire the lock again, so we need to not
216*053eb356SAaron Smith     // deadlock.
217*053eb356SAaron Smith     llvm::sys::ScopedLock lock(m_mutex);
218*053eb356SAaron Smith 
219*053eb356SAaron Smith     if (!m_session_data) {
220*053eb356SAaron Smith       LLDB_LOG(log, "warning: state = {0}, but there is no active session.",
221*053eb356SAaron Smith                state);
222*053eb356SAaron Smith       return Status();
223*053eb356SAaron Smith     }
224*053eb356SAaron Smith 
225*053eb356SAaron Smith     debugger_thread = m_session_data->m_debugger;
226*053eb356SAaron Smith   }
227*053eb356SAaron Smith 
228*053eb356SAaron Smith   Status error;
229*053eb356SAaron Smith   if (state != eStateExited && state != eStateDetached) {
230*053eb356SAaron Smith     LLDB_LOG(
231*053eb356SAaron Smith         log, "Shutting down process {0}.",
232*053eb356SAaron Smith         debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
233*053eb356SAaron Smith     error = debugger_thread->StopDebugging(true);
234*053eb356SAaron Smith 
235*053eb356SAaron Smith     // By the time StopDebugging returns, there is no more debugger thread, so
236*053eb356SAaron Smith     // we can be assured that no other thread will race for the session data.
237*053eb356SAaron Smith     m_session_data.reset();
238*053eb356SAaron Smith   } else {
239*053eb356SAaron Smith     error.SetErrorStringWithFormat("cannot destroy process %" PRIx64
240*053eb356SAaron Smith                                    " while state = %d",
241*053eb356SAaron Smith                                    GetDebuggedProcessId(), state);
242*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
243*053eb356SAaron Smith   }
244*053eb356SAaron Smith   return error;
245*053eb356SAaron Smith }
246*053eb356SAaron Smith 
247*053eb356SAaron Smith Status ProcessDebugger::HaltProcess(bool &caused_stop) {
248*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
249*053eb356SAaron Smith   Status error;
250*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
251*053eb356SAaron Smith   caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess()
252*053eb356SAaron Smith                                         .GetNativeProcess()
253*053eb356SAaron Smith                                         .GetSystemHandle());
254*053eb356SAaron Smith   if (!caused_stop) {
255*053eb356SAaron Smith     error.SetError(::GetLastError(), eErrorTypeWin32);
256*053eb356SAaron Smith     LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error);
257*053eb356SAaron Smith   }
258*053eb356SAaron Smith 
259*053eb356SAaron Smith   return error;
260*053eb356SAaron Smith }
261*053eb356SAaron Smith 
262*053eb356SAaron Smith Status ProcessDebugger::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
263*053eb356SAaron Smith                                    size_t &bytes_read) {
264*053eb356SAaron Smith   Status error;
265*053eb356SAaron Smith   bytes_read = 0;
266*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
267*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
268*053eb356SAaron Smith 
269*053eb356SAaron Smith   if (!m_session_data) {
270*053eb356SAaron Smith     error.SetErrorString(
271*053eb356SAaron Smith         "cannot read, there is no active debugger connection.");
272*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
273*053eb356SAaron Smith     return error;
274*053eb356SAaron Smith   }
275*053eb356SAaron Smith 
276*053eb356SAaron Smith   LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size,
277*053eb356SAaron Smith            vm_addr);
278*053eb356SAaron Smith 
279*053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
280*053eb356SAaron Smith   void *addr = reinterpret_cast<void *>(vm_addr);
281*053eb356SAaron Smith   SIZE_T num_of_bytes_read = 0;
282*053eb356SAaron Smith   if (!::ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr,
283*053eb356SAaron Smith                            buf, size, &num_of_bytes_read)) {
284*053eb356SAaron Smith     // Reading from the process can fail for a number of reasons - set the
285*053eb356SAaron Smith     // error code and make sure that the number of bytes read is set back to 0
286*053eb356SAaron Smith     // because in some scenarios the value of bytes_read returned from the API
287*053eb356SAaron Smith     // is garbage.
288*053eb356SAaron Smith     error.SetError(GetLastError(), eErrorTypeWin32);
289*053eb356SAaron Smith     LLDB_LOG(log, "reading failed with error: {0}", error);
290*053eb356SAaron Smith   } else {
291*053eb356SAaron Smith     bytes_read = num_of_bytes_read;
292*053eb356SAaron Smith   }
293*053eb356SAaron Smith   return error;
294*053eb356SAaron Smith }
295*053eb356SAaron Smith 
296*053eb356SAaron Smith Status ProcessDebugger::WriteMemory(lldb::addr_t vm_addr, const void *buf,
297*053eb356SAaron Smith                                     size_t size, size_t &bytes_written) {
298*053eb356SAaron Smith   Status error;
299*053eb356SAaron Smith   bytes_written = 0;
300*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
301*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
302*053eb356SAaron Smith   LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size,
303*053eb356SAaron Smith            vm_addr);
304*053eb356SAaron Smith 
305*053eb356SAaron Smith   if (!m_session_data) {
306*053eb356SAaron Smith     error.SetErrorString(
307*053eb356SAaron Smith         "cannot write, there is no active debugger connection.");
308*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
309*053eb356SAaron Smith     return error;
310*053eb356SAaron Smith   }
311*053eb356SAaron Smith 
312*053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
313*053eb356SAaron Smith   void *addr = reinterpret_cast<void *>(vm_addr);
314*053eb356SAaron Smith   SIZE_T num_of_bytes_written = 0;
315*053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
316*053eb356SAaron Smith   if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) {
317*053eb356SAaron Smith     FlushInstructionCache(handle, addr, num_of_bytes_written);
318*053eb356SAaron Smith     bytes_written = num_of_bytes_written;
319*053eb356SAaron Smith   } else {
320*053eb356SAaron Smith     error.SetError(GetLastError(), eErrorTypeWin32);
321*053eb356SAaron Smith     LLDB_LOG(log, "writing failed with error: {0}", error);
322*053eb356SAaron Smith   }
323*053eb356SAaron Smith   return error;
324*053eb356SAaron Smith }
325*053eb356SAaron Smith 
326*053eb356SAaron Smith Status ProcessDebugger::AllocateMemory(size_t size, uint32_t permissions,
327*053eb356SAaron Smith                                        lldb::addr_t &addr) {
328*053eb356SAaron Smith   Status error;
329*053eb356SAaron Smith   addr = LLDB_INVALID_ADDRESS;
330*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
331*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
332*053eb356SAaron Smith   LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size,
333*053eb356SAaron Smith            permissions);
334*053eb356SAaron Smith 
335*053eb356SAaron Smith   if (!m_session_data) {
336*053eb356SAaron Smith     error.SetErrorString(
337*053eb356SAaron Smith         "cannot allocate, there is no active debugger connection");
338*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
339*053eb356SAaron Smith     return error;
340*053eb356SAaron Smith   }
341*053eb356SAaron Smith 
342*053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
343*053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
344*053eb356SAaron Smith   auto protect = ConvertLldbToWinApiProtect(permissions);
345*053eb356SAaron Smith   auto result = ::VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect);
346*053eb356SAaron Smith   if (!result) {
347*053eb356SAaron Smith     error.SetError(GetLastError(), eErrorTypeWin32);
348*053eb356SAaron Smith     LLDB_LOG(log, "allocating failed with error: {0}", error);
349*053eb356SAaron Smith   } else {
350*053eb356SAaron Smith     addr = reinterpret_cast<addr_t>(result);
351*053eb356SAaron Smith   }
352*053eb356SAaron Smith   return error;
353*053eb356SAaron Smith }
354*053eb356SAaron Smith 
355*053eb356SAaron Smith Status ProcessDebugger::DeallocateMemory(lldb::addr_t vm_addr) {
356*053eb356SAaron Smith   Status result;
357*053eb356SAaron Smith 
358*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
359*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
360*053eb356SAaron Smith   LLDB_LOG(log, "attempting to deallocate bytes at address {0}", vm_addr);
361*053eb356SAaron Smith 
362*053eb356SAaron Smith   if (!m_session_data) {
363*053eb356SAaron Smith     result.SetErrorString(
364*053eb356SAaron Smith         "cannot deallocate, there is no active debugger connection");
365*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", result);
366*053eb356SAaron Smith     return result;
367*053eb356SAaron Smith   }
368*053eb356SAaron Smith 
369*053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
370*053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
371*053eb356SAaron Smith   if (!::VirtualFreeEx(handle, reinterpret_cast<LPVOID>(vm_addr), 0,
372*053eb356SAaron Smith                        MEM_RELEASE)) {
373*053eb356SAaron Smith     result.SetError(GetLastError(), eErrorTypeWin32);
374*053eb356SAaron Smith     LLDB_LOG(log, "deallocating failed with error: {0}", result);
375*053eb356SAaron Smith   }
376*053eb356SAaron Smith 
377*053eb356SAaron Smith   return result;
378*053eb356SAaron Smith }
379*053eb356SAaron Smith 
380*053eb356SAaron Smith Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr,
381*053eb356SAaron Smith                                             MemoryRegionInfo &info) {
382*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY);
383*053eb356SAaron Smith   Status error;
384*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
385*053eb356SAaron Smith   info.Clear();
386*053eb356SAaron Smith 
387*053eb356SAaron Smith   if (!m_session_data) {
388*053eb356SAaron Smith     error.SetErrorString(
389*053eb356SAaron Smith         "GetMemoryRegionInfo called with no debugging session.");
390*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
391*053eb356SAaron Smith     return error;
392*053eb356SAaron Smith   }
393*053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
394*053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
395*053eb356SAaron Smith   if (handle == nullptr || handle == LLDB_INVALID_PROCESS) {
396*053eb356SAaron Smith     error.SetErrorString(
397*053eb356SAaron Smith         "GetMemoryRegionInfo called with an invalid target process.");
398*053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
399*053eb356SAaron Smith     return error;
400*053eb356SAaron Smith   }
401*053eb356SAaron Smith 
402*053eb356SAaron Smith   LLDB_LOG(log, "getting info for address {0:x}", vm_addr);
403*053eb356SAaron Smith 
404*053eb356SAaron Smith   void *addr = reinterpret_cast<void *>(vm_addr);
405*053eb356SAaron Smith   MEMORY_BASIC_INFORMATION mem_info = {};
406*053eb356SAaron Smith   SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
407*053eb356SAaron Smith   if (result == 0) {
408*053eb356SAaron Smith     if (::GetLastError() == ERROR_INVALID_PARAMETER) {
409*053eb356SAaron Smith       // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with
410*053eb356SAaron Smith       // an address past the highest accessible address. We should return a
411*053eb356SAaron Smith       // range from the vm_addr to LLDB_INVALID_ADDRESS
412*053eb356SAaron Smith       info.GetRange().SetRangeBase(vm_addr);
413*053eb356SAaron Smith       info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
414*053eb356SAaron Smith       info.SetReadable(MemoryRegionInfo::eNo);
415*053eb356SAaron Smith       info.SetExecutable(MemoryRegionInfo::eNo);
416*053eb356SAaron Smith       info.SetWritable(MemoryRegionInfo::eNo);
417*053eb356SAaron Smith       info.SetMapped(MemoryRegionInfo::eNo);
418*053eb356SAaron Smith       return error;
419*053eb356SAaron Smith     } else {
420*053eb356SAaron Smith       error.SetError(::GetLastError(), eErrorTypeWin32);
421*053eb356SAaron Smith       LLDB_LOG(log,
422*053eb356SAaron Smith                "VirtualQueryEx returned error {0} while getting memory "
423*053eb356SAaron Smith                "region info for address {1:x}",
424*053eb356SAaron Smith                error, vm_addr);
425*053eb356SAaron Smith       return error;
426*053eb356SAaron Smith     }
427*053eb356SAaron Smith   }
428*053eb356SAaron Smith 
429*053eb356SAaron Smith   // Protect bits are only valid for MEM_COMMIT regions.
430*053eb356SAaron Smith   if (mem_info.State == MEM_COMMIT) {
431*053eb356SAaron Smith     const bool readable = IsPageReadable(mem_info.Protect);
432*053eb356SAaron Smith     const bool executable = IsPageExecutable(mem_info.Protect);
433*053eb356SAaron Smith     const bool writable = IsPageWritable(mem_info.Protect);
434*053eb356SAaron Smith     info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
435*053eb356SAaron Smith     info.SetExecutable(executable ? MemoryRegionInfo::eYes
436*053eb356SAaron Smith                                   : MemoryRegionInfo::eNo);
437*053eb356SAaron Smith     info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
438*053eb356SAaron Smith   } else {
439*053eb356SAaron Smith     info.SetReadable(MemoryRegionInfo::eNo);
440*053eb356SAaron Smith     info.SetExecutable(MemoryRegionInfo::eNo);
441*053eb356SAaron Smith     info.SetWritable(MemoryRegionInfo::eNo);
442*053eb356SAaron Smith   }
443*053eb356SAaron Smith 
444*053eb356SAaron Smith   // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE.
445*053eb356SAaron Smith   if (mem_info.State != MEM_FREE) {
446*053eb356SAaron Smith     info.GetRange().SetRangeBase(
447*053eb356SAaron Smith         reinterpret_cast<addr_t>(mem_info.AllocationBase));
448*053eb356SAaron Smith     info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) +
449*053eb356SAaron Smith                                 mem_info.RegionSize);
450*053eb356SAaron Smith     info.SetMapped(MemoryRegionInfo::eYes);
451*053eb356SAaron Smith   } else {
452*053eb356SAaron Smith     // In the unmapped case we need to return the distance to the next block of
453*053eb356SAaron Smith     // memory. VirtualQueryEx nearly does that except that it gives the
454*053eb356SAaron Smith     // distance from the start of the page containing vm_addr.
455*053eb356SAaron Smith     SYSTEM_INFO data;
456*053eb356SAaron Smith     ::GetSystemInfo(&data);
457*053eb356SAaron Smith     DWORD page_offset = vm_addr % data.dwPageSize;
458*053eb356SAaron Smith     info.GetRange().SetRangeBase(vm_addr);
459*053eb356SAaron Smith     info.GetRange().SetByteSize(mem_info.RegionSize - page_offset);
460*053eb356SAaron Smith     info.SetMapped(MemoryRegionInfo::eNo);
461*053eb356SAaron Smith   }
462*053eb356SAaron Smith 
463*053eb356SAaron Smith   error.SetError(::GetLastError(), eErrorTypeWin32);
464*053eb356SAaron Smith   LLDB_LOGV(log,
465*053eb356SAaron Smith             "Memory region info for address {0}: readable={1}, "
466*053eb356SAaron Smith             "executable={2}, writable={3}",
467*053eb356SAaron Smith             vm_addr, info.GetReadable(), info.GetExecutable(),
468*053eb356SAaron Smith             info.GetWritable());
469*053eb356SAaron Smith   return error;
470*053eb356SAaron Smith }
471*053eb356SAaron Smith 
472*053eb356SAaron Smith void ProcessDebugger::OnExitProcess(uint32_t exit_code) {
473*053eb356SAaron Smith   // If the process exits before any initial stop then notify the debugger
474*053eb356SAaron Smith   // of the error otherwise WaitForDebuggerConnection() will be blocked.
475*053eb356SAaron Smith   // An example of this issue is when a process fails to load a dependent DLL.
476*053eb356SAaron Smith   if (m_session_data && !m_session_data->m_initial_stop_received) {
477*053eb356SAaron Smith     Status error(exit_code, eErrorTypeWin32);
478*053eb356SAaron Smith     OnDebuggerError(error, 0);
479*053eb356SAaron Smith   }
480*053eb356SAaron Smith }
481*053eb356SAaron Smith 
482*053eb356SAaron Smith void ProcessDebugger::OnDebuggerConnected(lldb::addr_t image_base) {}
483*053eb356SAaron Smith 
484*053eb356SAaron Smith ExceptionResult
485*053eb356SAaron Smith ProcessDebugger::OnDebugException(bool first_chance,
486*053eb356SAaron Smith                                   const ExceptionRecord &record) {
487*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
488*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
489*053eb356SAaron Smith   // FIXME: Without this check, occasionally when running the test suite
490*053eb356SAaron Smith   // there is an issue where m_session_data can be null.  It's not clear how
491*053eb356SAaron Smith   // this could happen but it only surfaces while running the test suite.  In
492*053eb356SAaron Smith   // order to properly diagnose this, we probably need to first figure allow the
493*053eb356SAaron Smith   // test suite to print out full lldb logs, and then add logging to the process
494*053eb356SAaron Smith   // plugin.
495*053eb356SAaron Smith   if (!m_session_data) {
496*053eb356SAaron Smith     LLDB_LOG(log,
497*053eb356SAaron Smith              "Debugger thread reported exception {0:x} at address {1:x}, but "
498*053eb356SAaron Smith              "there is no session.",
499*053eb356SAaron Smith              record.GetExceptionCode(), record.GetExceptionAddress());
500*053eb356SAaron Smith     return ExceptionResult::SendToApplication;
501*053eb356SAaron Smith   }
502*053eb356SAaron Smith 
503*053eb356SAaron Smith   ExceptionResult result = ExceptionResult::SendToApplication;
504*053eb356SAaron Smith   if ((record.GetExceptionCode() == EXCEPTION_BREAKPOINT ||
505*053eb356SAaron Smith        record.GetExceptionCode() ==
506*053eb356SAaron Smith            0x4000001FL /*WOW64 STATUS_WX86_BREAKPOINT*/) &&
507*053eb356SAaron Smith       !m_session_data->m_initial_stop_received) {
508*053eb356SAaron Smith     // Handle breakpoints at the first chance.
509*053eb356SAaron Smith     result = ExceptionResult::BreakInDebugger;
510*053eb356SAaron Smith     LLDB_LOG(
511*053eb356SAaron Smith         log,
512*053eb356SAaron Smith         "Hit loader breakpoint at address {0:x}, setting initial stop event.",
513*053eb356SAaron Smith         record.GetExceptionAddress());
514*053eb356SAaron Smith     m_session_data->m_initial_stop_received = true;
515*053eb356SAaron Smith     ::SetEvent(m_session_data->m_initial_stop_event);
516*053eb356SAaron Smith   }
517*053eb356SAaron Smith   return result;
518*053eb356SAaron Smith }
519*053eb356SAaron Smith 
520*053eb356SAaron Smith void ProcessDebugger::OnCreateThread(const HostThread &thread) {
521*053eb356SAaron Smith   // Do nothing by default
522*053eb356SAaron Smith }
523*053eb356SAaron Smith 
524*053eb356SAaron Smith void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
525*053eb356SAaron Smith   // Do nothing by default
526*053eb356SAaron Smith }
527*053eb356SAaron Smith 
528*053eb356SAaron Smith void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec,
529*053eb356SAaron Smith                                 lldb::addr_t module_addr) {
530*053eb356SAaron Smith   // Do nothing by default
531*053eb356SAaron Smith }
532*053eb356SAaron Smith 
533*053eb356SAaron Smith void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr) {
534*053eb356SAaron Smith   // Do nothing by default
535*053eb356SAaron Smith }
536*053eb356SAaron Smith 
537*053eb356SAaron Smith void ProcessDebugger::OnDebugString(const std::string &string) {}
538*053eb356SAaron Smith 
539*053eb356SAaron Smith void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) {
540*053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
541*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
542*053eb356SAaron Smith 
543*053eb356SAaron Smith   if (m_session_data->m_initial_stop_received) {
544*053eb356SAaron Smith     // This happened while debugging.  Do we shutdown the debugging session,
545*053eb356SAaron Smith     // try to continue, or do something else?
546*053eb356SAaron Smith     LLDB_LOG(log,
547*053eb356SAaron Smith              "Error {0} occurred during debugging.  Unexpected behavior "
548*053eb356SAaron Smith              "may result.  {1}",
549*053eb356SAaron Smith              error.GetError(), error);
550*053eb356SAaron Smith   } else {
551*053eb356SAaron Smith     // If we haven't actually launched the process yet, this was an error
552*053eb356SAaron Smith     // launching the process.  Set the internal error and signal the initial
553*053eb356SAaron Smith     // stop event so that the DoLaunch method wakes up and returns a failure.
554*053eb356SAaron Smith     m_session_data->m_launch_error = error;
555*053eb356SAaron Smith     ::SetEvent(m_session_data->m_initial_stop_event);
556*053eb356SAaron Smith     LLDB_LOG(log,
557*053eb356SAaron Smith              "Error {0} occurred launching the process before the initial "
558*053eb356SAaron Smith              "stop. {1}",
559*053eb356SAaron Smith              error.GetError(), error);
560*053eb356SAaron Smith     return;
561*053eb356SAaron Smith   }
562*053eb356SAaron Smith }
563*053eb356SAaron Smith 
564*053eb356SAaron Smith Status ProcessDebugger::WaitForDebuggerConnection(DebuggerThreadSP debugger,
565*053eb356SAaron Smith                                                   HostProcess &process) {
566*053eb356SAaron Smith   Status result;
567*053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS |
568*053eb356SAaron Smith                                             WINDOWS_LOG_BREAKPOINTS);
569*053eb356SAaron Smith   LLDB_LOG(log, "Waiting for loader breakpoint.");
570*053eb356SAaron Smith 
571*053eb356SAaron Smith   // Block this function until we receive the initial stop from the process.
572*053eb356SAaron Smith   if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) ==
573*053eb356SAaron Smith       WAIT_OBJECT_0) {
574*053eb356SAaron Smith     LLDB_LOG(log, "hit loader breakpoint, returning.");
575*053eb356SAaron Smith 
576*053eb356SAaron Smith     process = debugger->GetProcess();
577*053eb356SAaron Smith     return m_session_data->m_launch_error;
578*053eb356SAaron Smith   } else
579*053eb356SAaron Smith     return Status(::GetLastError(), eErrorTypeWin32);
580*053eb356SAaron Smith }
581*053eb356SAaron Smith 
582*053eb356SAaron Smith } // namespace lldb_private
583