180814287SRaphael Isemann //===-- ProcessDebugger.cpp -----------------------------------------------===//
2053eb356SAaron Smith //
3053eb356SAaron Smith // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4053eb356SAaron Smith // See https://llvm.org/LICENSE.txt for license information.
5053eb356SAaron Smith // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6053eb356SAaron Smith //
7053eb356SAaron Smith //===----------------------------------------------------------------------===//
8053eb356SAaron Smith 
9053eb356SAaron Smith #include "ProcessDebugger.h"
10053eb356SAaron Smith 
11053eb356SAaron Smith // Windows includes
12053eb356SAaron Smith #include "lldb/Host/windows/windows.h"
13053eb356SAaron Smith #include <psapi.h>
14053eb356SAaron Smith 
15053eb356SAaron Smith #include "lldb/Host/FileSystem.h"
16053eb356SAaron Smith #include "lldb/Host/HostNativeProcessBase.h"
17053eb356SAaron Smith #include "lldb/Host/HostProcess.h"
18053eb356SAaron Smith #include "lldb/Host/HostThread.h"
19053eb356SAaron Smith #include "lldb/Host/ProcessLaunchInfo.h"
20053eb356SAaron Smith #include "lldb/Target/MemoryRegionInfo.h"
21053eb356SAaron Smith #include "lldb/Target/Process.h"
22053eb356SAaron Smith #include "llvm/Support/ConvertUTF.h"
23053eb356SAaron Smith #include "llvm/Support/Error.h"
24053eb356SAaron Smith 
25053eb356SAaron Smith #include "DebuggerThread.h"
26053eb356SAaron Smith #include "ExceptionRecord.h"
27053eb356SAaron Smith #include "ProcessWindowsLog.h"
28053eb356SAaron Smith 
29053eb356SAaron Smith using namespace lldb;
30053eb356SAaron Smith using namespace lldb_private;
31053eb356SAaron Smith 
ConvertLldbToWinApiProtect(uint32_t protect)32053eb356SAaron Smith static DWORD ConvertLldbToWinApiProtect(uint32_t protect) {
33053eb356SAaron Smith   // We also can process a read / write permissions here, but if the debugger
34053eb356SAaron Smith   // will make later a write into the allocated memory, it will fail. To get
35053eb356SAaron Smith   // around it is possible inside DoWriteMemory to remember memory permissions,
36053eb356SAaron Smith   // allow write, write and restore permissions, but for now we process only
37053eb356SAaron Smith   // the executable permission.
38053eb356SAaron Smith   //
39053eb356SAaron Smith   // TODO: Process permissions other than executable
40053eb356SAaron Smith   if (protect & ePermissionsExecutable)
41053eb356SAaron Smith     return PAGE_EXECUTE_READWRITE;
42053eb356SAaron Smith 
43053eb356SAaron Smith   return PAGE_READWRITE;
44053eb356SAaron Smith }
45053eb356SAaron Smith 
46053eb356SAaron Smith // The Windows page protection bits are NOT independent masks that can be
47053eb356SAaron Smith // bitwise-ORed together.  For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE
48053eb356SAaron Smith // | PAGE_READ).  To test for an access type, it's necessary to test for any of
49053eb356SAaron Smith // the bits that provide that access type.
IsPageReadable(uint32_t protect)50053eb356SAaron Smith static bool IsPageReadable(uint32_t protect) {
51053eb356SAaron Smith   return (protect & PAGE_NOACCESS) == 0;
52053eb356SAaron Smith }
53053eb356SAaron Smith 
IsPageWritable(uint32_t protect)54053eb356SAaron Smith static bool IsPageWritable(uint32_t protect) {
55053eb356SAaron Smith   return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
56053eb356SAaron Smith                      PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
57053eb356SAaron Smith }
58053eb356SAaron Smith 
IsPageExecutable(uint32_t protect)59053eb356SAaron Smith static bool IsPageExecutable(uint32_t protect) {
60053eb356SAaron Smith   return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
61053eb356SAaron Smith                      PAGE_EXECUTE_WRITECOPY)) != 0;
62053eb356SAaron Smith }
63053eb356SAaron Smith 
64053eb356SAaron Smith namespace lldb_private {
65053eb356SAaron Smith 
~ProcessDebugger()66403cd574SMartin Storsjö ProcessDebugger::~ProcessDebugger() {}
67403cd574SMartin Storsjö 
GetDebuggedProcessId() const68053eb356SAaron Smith lldb::pid_t ProcessDebugger::GetDebuggedProcessId() const {
69053eb356SAaron Smith   if (m_session_data)
70053eb356SAaron Smith     return m_session_data->m_debugger->GetProcess().GetProcessId();
71053eb356SAaron Smith   return LLDB_INVALID_PROCESS_ID;
72053eb356SAaron Smith }
73053eb356SAaron Smith 
DetachProcess()74053eb356SAaron Smith Status ProcessDebugger::DetachProcess() {
756730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
76053eb356SAaron Smith   DebuggerThreadSP debugger_thread;
77053eb356SAaron Smith   {
78053eb356SAaron Smith     // Acquire the lock only long enough to get the DebuggerThread.
79053eb356SAaron Smith     // StopDebugging() will trigger a call back into ProcessDebugger which will
80053eb356SAaron Smith     // also acquire the lock.  Thus we have to release the lock before calling
81053eb356SAaron Smith     // StopDebugging().
82053eb356SAaron Smith     llvm::sys::ScopedLock lock(m_mutex);
83053eb356SAaron Smith 
84053eb356SAaron Smith     if (!m_session_data) {
85053eb356SAaron Smith       LLDB_LOG(log, "there is no active session.");
86053eb356SAaron Smith       return Status();
87053eb356SAaron Smith     }
88053eb356SAaron Smith 
89053eb356SAaron Smith     debugger_thread = m_session_data->m_debugger;
90053eb356SAaron Smith   }
91053eb356SAaron Smith 
92053eb356SAaron Smith   Status error;
93053eb356SAaron Smith 
94053eb356SAaron Smith   LLDB_LOG(log, "detaching from process {0}.",
95053eb356SAaron Smith            debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
96053eb356SAaron Smith   error = debugger_thread->StopDebugging(false);
97053eb356SAaron Smith 
98053eb356SAaron Smith   // By the time StopDebugging returns, there is no more debugger thread, so
99053eb356SAaron Smith   // we can be assured that no other thread will race for the session data.
100053eb356SAaron Smith   m_session_data.reset();
101053eb356SAaron Smith 
102053eb356SAaron Smith   return error;
103053eb356SAaron Smith }
104053eb356SAaron Smith 
LaunchProcess(ProcessLaunchInfo & launch_info,DebugDelegateSP delegate)105053eb356SAaron Smith Status ProcessDebugger::LaunchProcess(ProcessLaunchInfo &launch_info,
106053eb356SAaron Smith                                       DebugDelegateSP delegate) {
107053eb356SAaron Smith   // Even though m_session_data is accessed here, it is before a debugger
108053eb356SAaron Smith   // thread has been kicked off.  So there's no race conditions, and it
109053eb356SAaron Smith   // shouldn't be necessary to acquire the mutex.
110053eb356SAaron Smith 
1116730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
112053eb356SAaron Smith   Status result;
113053eb356SAaron Smith 
114053eb356SAaron Smith   FileSpec working_dir = launch_info.GetWorkingDirectory();
115053eb356SAaron Smith   namespace fs = llvm::sys::fs;
116053eb356SAaron Smith   if (working_dir) {
117053eb356SAaron Smith     FileSystem::Instance().Resolve(working_dir);
118053eb356SAaron Smith     if (!FileSystem::Instance().IsDirectory(working_dir)) {
119053eb356SAaron Smith       result.SetErrorStringWithFormat("No such file or directory: %s",
120053eb356SAaron Smith                                       working_dir.GetCString());
121053eb356SAaron Smith       return result;
122053eb356SAaron Smith     }
123053eb356SAaron Smith   }
124053eb356SAaron Smith 
125053eb356SAaron Smith   if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) {
126053eb356SAaron Smith     StreamString stream;
127053eb356SAaron Smith     stream.Printf("ProcessDebugger unable to launch '%s'.  ProcessDebugger can "
128053eb356SAaron Smith                   "only be used for debug launches.",
129053eb356SAaron Smith                   launch_info.GetExecutableFile().GetPath().c_str());
130a111ffbbSStella Stamenova     std::string message = stream.GetString().str();
131053eb356SAaron Smith     result.SetErrorString(message.c_str());
132053eb356SAaron Smith 
133053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", message);
134053eb356SAaron Smith     return result;
135053eb356SAaron Smith   }
136053eb356SAaron Smith 
137053eb356SAaron Smith   bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
138053eb356SAaron Smith   m_session_data.reset(new ProcessWindowsData(stop_at_entry));
139053eb356SAaron Smith   m_session_data->m_debugger.reset(new DebuggerThread(delegate));
140053eb356SAaron Smith   DebuggerThreadSP debugger = m_session_data->m_debugger;
141053eb356SAaron Smith 
142053eb356SAaron Smith   // Kick off the DebugLaunch asynchronously and wait for it to complete.
143053eb356SAaron Smith   result = debugger->DebugLaunch(launch_info);
144053eb356SAaron Smith   if (result.Fail()) {
145053eb356SAaron Smith     LLDB_LOG(log, "failed launching '{0}'. {1}",
146053eb356SAaron Smith              launch_info.GetExecutableFile().GetPath(), result);
147053eb356SAaron Smith     return result;
148053eb356SAaron Smith   }
149053eb356SAaron Smith 
150053eb356SAaron Smith   HostProcess process;
151053eb356SAaron Smith   Status error = WaitForDebuggerConnection(debugger, process);
152053eb356SAaron Smith   if (error.Fail()) {
153053eb356SAaron Smith     LLDB_LOG(log, "failed launching '{0}'. {1}",
154053eb356SAaron Smith              launch_info.GetExecutableFile().GetPath(), error);
155053eb356SAaron Smith     return error;
156053eb356SAaron Smith   }
157053eb356SAaron Smith 
158053eb356SAaron Smith   LLDB_LOG(log, "successfully launched '{0}'",
159053eb356SAaron Smith            launch_info.GetExecutableFile().GetPath());
160053eb356SAaron Smith 
161053eb356SAaron Smith   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
162053eb356SAaron Smith   // private state should already be set to eStateStopped as a result of
163053eb356SAaron Smith   // hitting the initial breakpoint.  If it was not set, the breakpoint should
164053eb356SAaron Smith   // have already been resumed from and the private state should already be
165053eb356SAaron Smith   // eStateRunning.
166053eb356SAaron Smith   launch_info.SetProcessID(process.GetProcessId());
167053eb356SAaron Smith 
168053eb356SAaron Smith   return result;
169053eb356SAaron Smith }
170053eb356SAaron Smith 
AttachProcess(lldb::pid_t pid,const ProcessAttachInfo & attach_info,DebugDelegateSP delegate)171053eb356SAaron Smith Status ProcessDebugger::AttachProcess(lldb::pid_t pid,
172053eb356SAaron Smith                                       const ProcessAttachInfo &attach_info,
173053eb356SAaron Smith                                       DebugDelegateSP delegate) {
1746730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
175053eb356SAaron Smith   m_session_data.reset(
176053eb356SAaron Smith       new ProcessWindowsData(!attach_info.GetContinueOnceAttached()));
177053eb356SAaron Smith   DebuggerThreadSP debugger(new DebuggerThread(delegate));
178053eb356SAaron Smith 
179053eb356SAaron Smith   m_session_data->m_debugger = debugger;
180053eb356SAaron Smith 
181053eb356SAaron Smith   DWORD process_id = static_cast<DWORD>(pid);
182053eb356SAaron Smith   Status error = debugger->DebugAttach(process_id, attach_info);
183053eb356SAaron Smith   if (error.Fail()) {
184053eb356SAaron Smith     LLDB_LOG(
185053eb356SAaron Smith         log,
186053eb356SAaron Smith         "encountered an error occurred initiating the asynchronous attach. {0}",
187053eb356SAaron Smith         error);
188053eb356SAaron Smith     return error;
189053eb356SAaron Smith   }
190053eb356SAaron Smith 
191053eb356SAaron Smith   HostProcess process;
192053eb356SAaron Smith   error = WaitForDebuggerConnection(debugger, process);
193053eb356SAaron Smith   if (error.Fail()) {
194053eb356SAaron Smith     LLDB_LOG(log,
195053eb356SAaron Smith              "encountered an error waiting for the debugger to connect. {0}",
196053eb356SAaron Smith              error);
197053eb356SAaron Smith     return error;
198053eb356SAaron Smith   }
199053eb356SAaron Smith 
200053eb356SAaron Smith   LLDB_LOG(log, "successfully attached to process with pid={0}", process_id);
201053eb356SAaron Smith 
202053eb356SAaron Smith   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
203053eb356SAaron Smith   // private state should already be set to eStateStopped as a result of
204053eb356SAaron Smith   // hitting the initial breakpoint.  If it was not set, the breakpoint should
205053eb356SAaron Smith   // have already been resumed from and the private state should already be
206053eb356SAaron Smith   // eStateRunning.
207053eb356SAaron Smith 
208053eb356SAaron Smith   return error;
209053eb356SAaron Smith }
210053eb356SAaron Smith 
DestroyProcess(const lldb::StateType state)211053eb356SAaron Smith Status ProcessDebugger::DestroyProcess(const lldb::StateType state) {
2126730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
213053eb356SAaron Smith   DebuggerThreadSP debugger_thread;
214053eb356SAaron Smith   {
215053eb356SAaron Smith     // Acquire this lock inside an inner scope, only long enough to get the
216053eb356SAaron Smith     // DebuggerThread. StopDebugging() will trigger a call back into
217053eb356SAaron Smith     // ProcessDebugger which will acquire the lock again, so we need to not
218053eb356SAaron Smith     // deadlock.
219053eb356SAaron Smith     llvm::sys::ScopedLock lock(m_mutex);
220053eb356SAaron Smith 
221053eb356SAaron Smith     if (!m_session_data) {
222053eb356SAaron Smith       LLDB_LOG(log, "warning: state = {0}, but there is no active session.",
223053eb356SAaron Smith                state);
224053eb356SAaron Smith       return Status();
225053eb356SAaron Smith     }
226053eb356SAaron Smith 
227053eb356SAaron Smith     debugger_thread = m_session_data->m_debugger;
228053eb356SAaron Smith   }
229053eb356SAaron Smith 
230e97c693bSTatyana Krasnukha   if (state == eStateExited || state == eStateDetached) {
231e97c693bSTatyana Krasnukha     LLDB_LOG(log, "warning: cannot destroy process {0} while state = {1}.",
232e97c693bSTatyana Krasnukha              GetDebuggedProcessId(), state);
233e97c693bSTatyana Krasnukha     return Status();
234e97c693bSTatyana Krasnukha   }
235e97c693bSTatyana Krasnukha 
236e97c693bSTatyana Krasnukha   LLDB_LOG(log, "Shutting down process {0}.",
237053eb356SAaron Smith            debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
238e97c693bSTatyana Krasnukha   auto error = debugger_thread->StopDebugging(true);
239053eb356SAaron Smith 
240053eb356SAaron Smith   // By the time StopDebugging returns, there is no more debugger thread, so
241053eb356SAaron Smith   // we can be assured that no other thread will race for the session data.
242053eb356SAaron Smith   m_session_data.reset();
243e97c693bSTatyana Krasnukha 
244053eb356SAaron Smith   return error;
245053eb356SAaron Smith }
246053eb356SAaron Smith 
HaltProcess(bool & caused_stop)247053eb356SAaron Smith Status ProcessDebugger::HaltProcess(bool &caused_stop) {
2486730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
249053eb356SAaron Smith   Status error;
250053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
251053eb356SAaron Smith   caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess()
252053eb356SAaron Smith                                         .GetNativeProcess()
253053eb356SAaron Smith                                         .GetSystemHandle());
254053eb356SAaron Smith   if (!caused_stop) {
255053eb356SAaron Smith     error.SetError(::GetLastError(), eErrorTypeWin32);
256053eb356SAaron Smith     LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error);
257053eb356SAaron Smith   }
258053eb356SAaron Smith 
259053eb356SAaron Smith   return error;
260053eb356SAaron Smith }
261053eb356SAaron Smith 
ReadMemory(lldb::addr_t vm_addr,void * buf,size_t size,size_t & bytes_read)262053eb356SAaron Smith Status ProcessDebugger::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
263053eb356SAaron Smith                                    size_t &bytes_read) {
264053eb356SAaron Smith   Status error;
265053eb356SAaron Smith   bytes_read = 0;
2666730df47SPavel Labath   Log *log = GetLog(WindowsLog::Memory);
267053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
268053eb356SAaron Smith 
269053eb356SAaron Smith   if (!m_session_data) {
270053eb356SAaron Smith     error.SetErrorString(
271053eb356SAaron Smith         "cannot read, there is no active debugger connection.");
272053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
273053eb356SAaron Smith     return error;
274053eb356SAaron Smith   }
275053eb356SAaron Smith 
276053eb356SAaron Smith   LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size,
277053eb356SAaron Smith            vm_addr);
278053eb356SAaron Smith 
279053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
280053eb356SAaron Smith   void *addr = reinterpret_cast<void *>(vm_addr);
281053eb356SAaron Smith   SIZE_T num_of_bytes_read = 0;
282053eb356SAaron Smith   if (!::ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr,
283053eb356SAaron Smith                            buf, size, &num_of_bytes_read)) {
284053eb356SAaron Smith     error.SetError(GetLastError(), eErrorTypeWin32);
285053eb356SAaron Smith     LLDB_LOG(log, "reading failed with error: {0}", error);
286053eb356SAaron Smith   } else {
287053eb356SAaron Smith     bytes_read = num_of_bytes_read;
288053eb356SAaron Smith   }
289053eb356SAaron Smith   return error;
290053eb356SAaron Smith }
291053eb356SAaron Smith 
WriteMemory(lldb::addr_t vm_addr,const void * buf,size_t size,size_t & bytes_written)292053eb356SAaron Smith Status ProcessDebugger::WriteMemory(lldb::addr_t vm_addr, const void *buf,
293053eb356SAaron Smith                                     size_t size, size_t &bytes_written) {
294053eb356SAaron Smith   Status error;
295053eb356SAaron Smith   bytes_written = 0;
2966730df47SPavel Labath   Log *log = GetLog(WindowsLog::Memory);
297053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
298053eb356SAaron Smith   LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size,
299053eb356SAaron Smith            vm_addr);
300053eb356SAaron Smith 
301053eb356SAaron Smith   if (!m_session_data) {
302053eb356SAaron Smith     error.SetErrorString(
303053eb356SAaron Smith         "cannot write, there is no active debugger connection.");
304053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
305053eb356SAaron Smith     return error;
306053eb356SAaron Smith   }
307053eb356SAaron Smith 
308053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
309053eb356SAaron Smith   void *addr = reinterpret_cast<void *>(vm_addr);
310053eb356SAaron Smith   SIZE_T num_of_bytes_written = 0;
311053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
312053eb356SAaron Smith   if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) {
313053eb356SAaron Smith     FlushInstructionCache(handle, addr, num_of_bytes_written);
314053eb356SAaron Smith     bytes_written = num_of_bytes_written;
315053eb356SAaron Smith   } else {
316053eb356SAaron Smith     error.SetError(GetLastError(), eErrorTypeWin32);
317053eb356SAaron Smith     LLDB_LOG(log, "writing failed with error: {0}", error);
318053eb356SAaron Smith   }
319053eb356SAaron Smith   return error;
320053eb356SAaron Smith }
321053eb356SAaron Smith 
AllocateMemory(size_t size,uint32_t permissions,lldb::addr_t & addr)322053eb356SAaron Smith Status ProcessDebugger::AllocateMemory(size_t size, uint32_t permissions,
323053eb356SAaron Smith                                        lldb::addr_t &addr) {
324053eb356SAaron Smith   Status error;
325053eb356SAaron Smith   addr = LLDB_INVALID_ADDRESS;
3266730df47SPavel Labath   Log *log = GetLog(WindowsLog::Memory);
327053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
328053eb356SAaron Smith   LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size,
329053eb356SAaron Smith            permissions);
330053eb356SAaron Smith 
331053eb356SAaron Smith   if (!m_session_data) {
332053eb356SAaron Smith     error.SetErrorString(
333053eb356SAaron Smith         "cannot allocate, there is no active debugger connection");
334053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
335053eb356SAaron Smith     return error;
336053eb356SAaron Smith   }
337053eb356SAaron Smith 
338053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
339053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
340053eb356SAaron Smith   auto protect = ConvertLldbToWinApiProtect(permissions);
341053eb356SAaron Smith   auto result = ::VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect);
342053eb356SAaron Smith   if (!result) {
343053eb356SAaron Smith     error.SetError(GetLastError(), eErrorTypeWin32);
344053eb356SAaron Smith     LLDB_LOG(log, "allocating failed with error: {0}", error);
345053eb356SAaron Smith   } else {
346053eb356SAaron Smith     addr = reinterpret_cast<addr_t>(result);
347053eb356SAaron Smith   }
348053eb356SAaron Smith   return error;
349053eb356SAaron Smith }
350053eb356SAaron Smith 
DeallocateMemory(lldb::addr_t vm_addr)351053eb356SAaron Smith Status ProcessDebugger::DeallocateMemory(lldb::addr_t vm_addr) {
352053eb356SAaron Smith   Status result;
353053eb356SAaron Smith 
3546730df47SPavel Labath   Log *log = GetLog(WindowsLog::Memory);
355053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
356053eb356SAaron Smith   LLDB_LOG(log, "attempting to deallocate bytes at address {0}", vm_addr);
357053eb356SAaron Smith 
358053eb356SAaron Smith   if (!m_session_data) {
359053eb356SAaron Smith     result.SetErrorString(
360053eb356SAaron Smith         "cannot deallocate, there is no active debugger connection");
361053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", result);
362053eb356SAaron Smith     return result;
363053eb356SAaron Smith   }
364053eb356SAaron Smith 
365053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
366053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
367053eb356SAaron Smith   if (!::VirtualFreeEx(handle, reinterpret_cast<LPVOID>(vm_addr), 0,
368053eb356SAaron Smith                        MEM_RELEASE)) {
369053eb356SAaron Smith     result.SetError(GetLastError(), eErrorTypeWin32);
370053eb356SAaron Smith     LLDB_LOG(log, "deallocating failed with error: {0}", result);
371053eb356SAaron Smith   }
372053eb356SAaron Smith 
373053eb356SAaron Smith   return result;
374053eb356SAaron Smith }
375053eb356SAaron Smith 
GetMemoryRegionInfo(lldb::addr_t vm_addr,MemoryRegionInfo & info)3765fbcf677SDavid Spickett Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr,
377053eb356SAaron Smith                                             MemoryRegionInfo &info) {
3786730df47SPavel Labath   Log *log = GetLog(WindowsLog::Memory);
379053eb356SAaron Smith   Status error;
380053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
381053eb356SAaron Smith   info.Clear();
382053eb356SAaron Smith 
383053eb356SAaron Smith   if (!m_session_data) {
384053eb356SAaron Smith     error.SetErrorString(
3855fbcf677SDavid Spickett         "GetMemoryRegionInfo called with no debugging session.");
386053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
387053eb356SAaron Smith     return error;
388053eb356SAaron Smith   }
389053eb356SAaron Smith   HostProcess process = m_session_data->m_debugger->GetProcess();
390053eb356SAaron Smith   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
391053eb356SAaron Smith   if (handle == nullptr || handle == LLDB_INVALID_PROCESS) {
392053eb356SAaron Smith     error.SetErrorString(
3935fbcf677SDavid Spickett         "GetMemoryRegionInfo called with an invalid target process.");
394053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
395053eb356SAaron Smith     return error;
396053eb356SAaron Smith   }
397053eb356SAaron Smith 
398053eb356SAaron Smith   LLDB_LOG(log, "getting info for address {0:x}", vm_addr);
399053eb356SAaron Smith 
400053eb356SAaron Smith   void *addr = reinterpret_cast<void *>(vm_addr);
401053eb356SAaron Smith   MEMORY_BASIC_INFORMATION mem_info = {};
402053eb356SAaron Smith   SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
403053eb356SAaron Smith   if (result == 0) {
40471cf97e9SDavid Spickett     DWORD last_error = ::GetLastError();
40571cf97e9SDavid Spickett     if (last_error == ERROR_INVALID_PARAMETER) {
406053eb356SAaron Smith       // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with
407053eb356SAaron Smith       // an address past the highest accessible address. We should return a
408053eb356SAaron Smith       // range from the vm_addr to LLDB_INVALID_ADDRESS
409053eb356SAaron Smith       info.GetRange().SetRangeBase(vm_addr);
410053eb356SAaron Smith       info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
411053eb356SAaron Smith       info.SetReadable(MemoryRegionInfo::eNo);
412053eb356SAaron Smith       info.SetExecutable(MemoryRegionInfo::eNo);
413053eb356SAaron Smith       info.SetWritable(MemoryRegionInfo::eNo);
414053eb356SAaron Smith       info.SetMapped(MemoryRegionInfo::eNo);
415053eb356SAaron Smith       return error;
416053eb356SAaron Smith     } else {
41771cf97e9SDavid Spickett       error.SetError(last_error, eErrorTypeWin32);
418053eb356SAaron Smith       LLDB_LOG(log,
419053eb356SAaron Smith                "VirtualQueryEx returned error {0} while getting memory "
420053eb356SAaron Smith                "region info for address {1:x}",
421053eb356SAaron Smith                error, vm_addr);
422053eb356SAaron Smith       return error;
423053eb356SAaron Smith     }
424053eb356SAaron Smith   }
425053eb356SAaron Smith 
426053eb356SAaron Smith   // Protect bits are only valid for MEM_COMMIT regions.
427053eb356SAaron Smith   if (mem_info.State == MEM_COMMIT) {
428053eb356SAaron Smith     const bool readable = IsPageReadable(mem_info.Protect);
429053eb356SAaron Smith     const bool executable = IsPageExecutable(mem_info.Protect);
430053eb356SAaron Smith     const bool writable = IsPageWritable(mem_info.Protect);
431053eb356SAaron Smith     info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
432053eb356SAaron Smith     info.SetExecutable(executable ? MemoryRegionInfo::eYes
433053eb356SAaron Smith                                   : MemoryRegionInfo::eNo);
434053eb356SAaron Smith     info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
435053eb356SAaron Smith   } else {
436053eb356SAaron Smith     info.SetReadable(MemoryRegionInfo::eNo);
437053eb356SAaron Smith     info.SetExecutable(MemoryRegionInfo::eNo);
438053eb356SAaron Smith     info.SetWritable(MemoryRegionInfo::eNo);
439053eb356SAaron Smith   }
440053eb356SAaron Smith 
441053eb356SAaron Smith   // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE.
442053eb356SAaron Smith   if (mem_info.State != MEM_FREE) {
443053eb356SAaron Smith     info.GetRange().SetRangeBase(
444*1ca8a978SDavid Spickett         reinterpret_cast<addr_t>(mem_info.BaseAddress));
445053eb356SAaron Smith     info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) +
446053eb356SAaron Smith                                 mem_info.RegionSize);
447053eb356SAaron Smith     info.SetMapped(MemoryRegionInfo::eYes);
448053eb356SAaron Smith   } else {
449053eb356SAaron Smith     // In the unmapped case we need to return the distance to the next block of
450053eb356SAaron Smith     // memory. VirtualQueryEx nearly does that except that it gives the
451053eb356SAaron Smith     // distance from the start of the page containing vm_addr.
452053eb356SAaron Smith     SYSTEM_INFO data;
453053eb356SAaron Smith     ::GetSystemInfo(&data);
454053eb356SAaron Smith     DWORD page_offset = vm_addr % data.dwPageSize;
455053eb356SAaron Smith     info.GetRange().SetRangeBase(vm_addr);
456053eb356SAaron Smith     info.GetRange().SetByteSize(mem_info.RegionSize - page_offset);
457053eb356SAaron Smith     info.SetMapped(MemoryRegionInfo::eNo);
458053eb356SAaron Smith   }
459053eb356SAaron Smith 
460053eb356SAaron Smith   LLDB_LOGV(log,
461053eb356SAaron Smith             "Memory region info for address {0}: readable={1}, "
462053eb356SAaron Smith             "executable={2}, writable={3}",
463053eb356SAaron Smith             vm_addr, info.GetReadable(), info.GetExecutable(),
464053eb356SAaron Smith             info.GetWritable());
465053eb356SAaron Smith   return error;
466053eb356SAaron Smith }
467053eb356SAaron Smith 
OnExitProcess(uint32_t exit_code)468053eb356SAaron Smith void ProcessDebugger::OnExitProcess(uint32_t exit_code) {
469053eb356SAaron Smith   // If the process exits before any initial stop then notify the debugger
470053eb356SAaron Smith   // of the error otherwise WaitForDebuggerConnection() will be blocked.
471053eb356SAaron Smith   // An example of this issue is when a process fails to load a dependent DLL.
472053eb356SAaron Smith   if (m_session_data && !m_session_data->m_initial_stop_received) {
473053eb356SAaron Smith     Status error(exit_code, eErrorTypeWin32);
474053eb356SAaron Smith     OnDebuggerError(error, 0);
475053eb356SAaron Smith   }
476053eb356SAaron Smith }
477053eb356SAaron Smith 
OnDebuggerConnected(lldb::addr_t image_base)478053eb356SAaron Smith void ProcessDebugger::OnDebuggerConnected(lldb::addr_t image_base) {}
479053eb356SAaron Smith 
480053eb356SAaron Smith ExceptionResult
OnDebugException(bool first_chance,const ExceptionRecord & record)481053eb356SAaron Smith ProcessDebugger::OnDebugException(bool first_chance,
482053eb356SAaron Smith                                   const ExceptionRecord &record) {
4836730df47SPavel Labath   Log *log = GetLog(WindowsLog::Exception);
484053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
485053eb356SAaron Smith   // FIXME: Without this check, occasionally when running the test suite
486053eb356SAaron Smith   // there is an issue where m_session_data can be null.  It's not clear how
487053eb356SAaron Smith   // this could happen but it only surfaces while running the test suite.  In
488053eb356SAaron Smith   // order to properly diagnose this, we probably need to first figure allow the
489053eb356SAaron Smith   // test suite to print out full lldb logs, and then add logging to the process
490053eb356SAaron Smith   // plugin.
491053eb356SAaron Smith   if (!m_session_data) {
492053eb356SAaron Smith     LLDB_LOG(log,
493053eb356SAaron Smith              "Debugger thread reported exception {0:x} at address {1:x}, but "
494053eb356SAaron Smith              "there is no session.",
495053eb356SAaron Smith              record.GetExceptionCode(), record.GetExceptionAddress());
496053eb356SAaron Smith     return ExceptionResult::SendToApplication;
497053eb356SAaron Smith   }
498053eb356SAaron Smith 
499053eb356SAaron Smith   ExceptionResult result = ExceptionResult::SendToApplication;
500053eb356SAaron Smith   if ((record.GetExceptionCode() == EXCEPTION_BREAKPOINT ||
501053eb356SAaron Smith        record.GetExceptionCode() ==
502053eb356SAaron Smith            0x4000001FL /*WOW64 STATUS_WX86_BREAKPOINT*/) &&
503053eb356SAaron Smith       !m_session_data->m_initial_stop_received) {
504053eb356SAaron Smith     // Handle breakpoints at the first chance.
505053eb356SAaron Smith     result = ExceptionResult::BreakInDebugger;
506053eb356SAaron Smith     LLDB_LOG(
507053eb356SAaron Smith         log,
508053eb356SAaron Smith         "Hit loader breakpoint at address {0:x}, setting initial stop event.",
509053eb356SAaron Smith         record.GetExceptionAddress());
510053eb356SAaron Smith     m_session_data->m_initial_stop_received = true;
511053eb356SAaron Smith     ::SetEvent(m_session_data->m_initial_stop_event);
512053eb356SAaron Smith   }
513053eb356SAaron Smith   return result;
514053eb356SAaron Smith }
515053eb356SAaron Smith 
OnCreateThread(const HostThread & thread)516053eb356SAaron Smith void ProcessDebugger::OnCreateThread(const HostThread &thread) {
517053eb356SAaron Smith   // Do nothing by default
518053eb356SAaron Smith }
519053eb356SAaron Smith 
OnExitThread(lldb::tid_t thread_id,uint32_t exit_code)520053eb356SAaron Smith void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
521053eb356SAaron Smith   // Do nothing by default
522053eb356SAaron Smith }
523053eb356SAaron Smith 
OnLoadDll(const ModuleSpec & module_spec,lldb::addr_t module_addr)524053eb356SAaron Smith void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec,
525053eb356SAaron Smith                                 lldb::addr_t module_addr) {
526053eb356SAaron Smith   // Do nothing by default
527053eb356SAaron Smith }
528053eb356SAaron Smith 
OnUnloadDll(lldb::addr_t module_addr)529053eb356SAaron Smith void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr) {
530053eb356SAaron Smith   // Do nothing by default
531053eb356SAaron Smith }
532053eb356SAaron Smith 
OnDebugString(const std::string & string)533053eb356SAaron Smith void ProcessDebugger::OnDebugString(const std::string &string) {}
534053eb356SAaron Smith 
OnDebuggerError(const Status & error,uint32_t type)535053eb356SAaron Smith void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) {
536053eb356SAaron Smith   llvm::sys::ScopedLock lock(m_mutex);
5376730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process);
538053eb356SAaron Smith 
539053eb356SAaron Smith   if (m_session_data->m_initial_stop_received) {
540053eb356SAaron Smith     // This happened while debugging.  Do we shutdown the debugging session,
541053eb356SAaron Smith     // try to continue, or do something else?
542053eb356SAaron Smith     LLDB_LOG(log,
543053eb356SAaron Smith              "Error {0} occurred during debugging.  Unexpected behavior "
544053eb356SAaron Smith              "may result.  {1}",
545053eb356SAaron Smith              error.GetError(), error);
546053eb356SAaron Smith   } else {
547053eb356SAaron Smith     // If we haven't actually launched the process yet, this was an error
548053eb356SAaron Smith     // launching the process.  Set the internal error and signal the initial
549053eb356SAaron Smith     // stop event so that the DoLaunch method wakes up and returns a failure.
550053eb356SAaron Smith     m_session_data->m_launch_error = error;
551053eb356SAaron Smith     ::SetEvent(m_session_data->m_initial_stop_event);
552053eb356SAaron Smith     LLDB_LOG(log,
553053eb356SAaron Smith              "Error {0} occurred launching the process before the initial "
554053eb356SAaron Smith              "stop. {1}",
555053eb356SAaron Smith              error.GetError(), error);
556053eb356SAaron Smith     return;
557053eb356SAaron Smith   }
558053eb356SAaron Smith }
559053eb356SAaron Smith 
WaitForDebuggerConnection(DebuggerThreadSP debugger,HostProcess & process)560053eb356SAaron Smith Status ProcessDebugger::WaitForDebuggerConnection(DebuggerThreadSP debugger,
561053eb356SAaron Smith                                                   HostProcess &process) {
562053eb356SAaron Smith   Status result;
5636730df47SPavel Labath   Log *log = GetLog(WindowsLog::Process | WindowsLog::Breakpoints);
564053eb356SAaron Smith   LLDB_LOG(log, "Waiting for loader breakpoint.");
565053eb356SAaron Smith 
566053eb356SAaron Smith   // Block this function until we receive the initial stop from the process.
567053eb356SAaron Smith   if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) ==
568053eb356SAaron Smith       WAIT_OBJECT_0) {
569053eb356SAaron Smith     LLDB_LOG(log, "hit loader breakpoint, returning.");
570053eb356SAaron Smith 
571053eb356SAaron Smith     process = debugger->GetProcess();
572053eb356SAaron Smith     return m_session_data->m_launch_error;
573053eb356SAaron Smith   } else
574053eb356SAaron Smith     return Status(::GetLastError(), eErrorTypeWin32);
575053eb356SAaron Smith }
576053eb356SAaron Smith 
577053eb356SAaron Smith } // namespace lldb_private
578