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