xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ProcessDebugger.cpp -----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "ProcessDebugger.h"
10061da546Spatrick 
11061da546Spatrick // Windows includes
12061da546Spatrick #include "lldb/Host/windows/windows.h"
13061da546Spatrick #include <psapi.h>
14061da546Spatrick 
15061da546Spatrick #include "lldb/Host/FileSystem.h"
16061da546Spatrick #include "lldb/Host/HostNativeProcessBase.h"
17061da546Spatrick #include "lldb/Host/HostProcess.h"
18061da546Spatrick #include "lldb/Host/HostThread.h"
19061da546Spatrick #include "lldb/Host/ProcessLaunchInfo.h"
20061da546Spatrick #include "lldb/Target/MemoryRegionInfo.h"
21061da546Spatrick #include "lldb/Target/Process.h"
22061da546Spatrick #include "llvm/Support/ConvertUTF.h"
23061da546Spatrick #include "llvm/Support/Error.h"
24061da546Spatrick 
25061da546Spatrick #include "DebuggerThread.h"
26061da546Spatrick #include "ExceptionRecord.h"
27061da546Spatrick #include "ProcessWindowsLog.h"
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick 
ConvertLldbToWinApiProtect(uint32_t protect)32061da546Spatrick static DWORD ConvertLldbToWinApiProtect(uint32_t protect) {
33061da546Spatrick   // We also can process a read / write permissions here, but if the debugger
34061da546Spatrick   // will make later a write into the allocated memory, it will fail. To get
35061da546Spatrick   // around it is possible inside DoWriteMemory to remember memory permissions,
36061da546Spatrick   // allow write, write and restore permissions, but for now we process only
37061da546Spatrick   // the executable permission.
38061da546Spatrick   //
39061da546Spatrick   // TODO: Process permissions other than executable
40061da546Spatrick   if (protect & ePermissionsExecutable)
41061da546Spatrick     return PAGE_EXECUTE_READWRITE;
42061da546Spatrick 
43061da546Spatrick   return PAGE_READWRITE;
44061da546Spatrick }
45061da546Spatrick 
46061da546Spatrick // The Windows page protection bits are NOT independent masks that can be
47061da546Spatrick // bitwise-ORed together.  For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE
48061da546Spatrick // | PAGE_READ).  To test for an access type, it's necessary to test for any of
49061da546Spatrick // the bits that provide that access type.
IsPageReadable(uint32_t protect)50061da546Spatrick static bool IsPageReadable(uint32_t protect) {
51061da546Spatrick   return (protect & PAGE_NOACCESS) == 0;
52061da546Spatrick }
53061da546Spatrick 
IsPageWritable(uint32_t protect)54061da546Spatrick static bool IsPageWritable(uint32_t protect) {
55061da546Spatrick   return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
56061da546Spatrick                      PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
57061da546Spatrick }
58061da546Spatrick 
IsPageExecutable(uint32_t protect)59061da546Spatrick static bool IsPageExecutable(uint32_t protect) {
60061da546Spatrick   return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
61061da546Spatrick                      PAGE_EXECUTE_WRITECOPY)) != 0;
62061da546Spatrick }
63061da546Spatrick 
64061da546Spatrick namespace lldb_private {
65061da546Spatrick 
~ProcessDebugger()66061da546Spatrick ProcessDebugger::~ProcessDebugger() {}
67061da546Spatrick 
GetDebuggedProcessId() const68061da546Spatrick lldb::pid_t ProcessDebugger::GetDebuggedProcessId() const {
69061da546Spatrick   if (m_session_data)
70061da546Spatrick     return m_session_data->m_debugger->GetProcess().GetProcessId();
71061da546Spatrick   return LLDB_INVALID_PROCESS_ID;
72061da546Spatrick }
73061da546Spatrick 
DetachProcess()74061da546Spatrick Status ProcessDebugger::DetachProcess() {
75*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
76061da546Spatrick   DebuggerThreadSP debugger_thread;
77061da546Spatrick   {
78061da546Spatrick     // Acquire the lock only long enough to get the DebuggerThread.
79061da546Spatrick     // StopDebugging() will trigger a call back into ProcessDebugger which will
80061da546Spatrick     // also acquire the lock.  Thus we have to release the lock before calling
81061da546Spatrick     // StopDebugging().
82061da546Spatrick     llvm::sys::ScopedLock lock(m_mutex);
83061da546Spatrick 
84061da546Spatrick     if (!m_session_data) {
85061da546Spatrick       LLDB_LOG(log, "there is no active session.");
86061da546Spatrick       return Status();
87061da546Spatrick     }
88061da546Spatrick 
89061da546Spatrick     debugger_thread = m_session_data->m_debugger;
90061da546Spatrick   }
91061da546Spatrick 
92061da546Spatrick   Status error;
93061da546Spatrick 
94061da546Spatrick   LLDB_LOG(log, "detaching from process {0}.",
95061da546Spatrick            debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
96061da546Spatrick   error = debugger_thread->StopDebugging(false);
97061da546Spatrick 
98061da546Spatrick   // By the time StopDebugging returns, there is no more debugger thread, so
99061da546Spatrick   // we can be assured that no other thread will race for the session data.
100061da546Spatrick   m_session_data.reset();
101061da546Spatrick 
102061da546Spatrick   return error;
103061da546Spatrick }
104061da546Spatrick 
LaunchProcess(ProcessLaunchInfo & launch_info,DebugDelegateSP delegate)105061da546Spatrick Status ProcessDebugger::LaunchProcess(ProcessLaunchInfo &launch_info,
106061da546Spatrick                                       DebugDelegateSP delegate) {
107061da546Spatrick   // Even though m_session_data is accessed here, it is before a debugger
108061da546Spatrick   // thread has been kicked off.  So there's no race conditions, and it
109061da546Spatrick   // shouldn't be necessary to acquire the mutex.
110061da546Spatrick 
111*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
112061da546Spatrick   Status result;
113061da546Spatrick 
114061da546Spatrick   FileSpec working_dir = launch_info.GetWorkingDirectory();
115061da546Spatrick   namespace fs = llvm::sys::fs;
116061da546Spatrick   if (working_dir) {
117061da546Spatrick     FileSystem::Instance().Resolve(working_dir);
118061da546Spatrick     if (!FileSystem::Instance().IsDirectory(working_dir)) {
119061da546Spatrick       result.SetErrorStringWithFormat("No such file or directory: %s",
120*f6aab3d8Srobert                                       working_dir.GetPath().c_str());
121061da546Spatrick       return result;
122061da546Spatrick     }
123061da546Spatrick   }
124061da546Spatrick 
125061da546Spatrick   if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) {
126061da546Spatrick     StreamString stream;
127061da546Spatrick     stream.Printf("ProcessDebugger unable to launch '%s'.  ProcessDebugger can "
128061da546Spatrick                   "only be used for debug launches.",
129061da546Spatrick                   launch_info.GetExecutableFile().GetPath().c_str());
130dda28197Spatrick     std::string message = stream.GetString().str();
131061da546Spatrick     result.SetErrorString(message.c_str());
132061da546Spatrick 
133061da546Spatrick     LLDB_LOG(log, "error: {0}", message);
134061da546Spatrick     return result;
135061da546Spatrick   }
136061da546Spatrick 
137061da546Spatrick   bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
138061da546Spatrick   m_session_data.reset(new ProcessWindowsData(stop_at_entry));
139061da546Spatrick   m_session_data->m_debugger.reset(new DebuggerThread(delegate));
140061da546Spatrick   DebuggerThreadSP debugger = m_session_data->m_debugger;
141061da546Spatrick 
142061da546Spatrick   // Kick off the DebugLaunch asynchronously and wait for it to complete.
143061da546Spatrick   result = debugger->DebugLaunch(launch_info);
144061da546Spatrick   if (result.Fail()) {
145061da546Spatrick     LLDB_LOG(log, "failed launching '{0}'. {1}",
146061da546Spatrick              launch_info.GetExecutableFile().GetPath(), result);
147061da546Spatrick     return result;
148061da546Spatrick   }
149061da546Spatrick 
150061da546Spatrick   HostProcess process;
151061da546Spatrick   Status error = WaitForDebuggerConnection(debugger, process);
152061da546Spatrick   if (error.Fail()) {
153061da546Spatrick     LLDB_LOG(log, "failed launching '{0}'. {1}",
154061da546Spatrick              launch_info.GetExecutableFile().GetPath(), error);
155061da546Spatrick     return error;
156061da546Spatrick   }
157061da546Spatrick 
158061da546Spatrick   LLDB_LOG(log, "successfully launched '{0}'",
159061da546Spatrick            launch_info.GetExecutableFile().GetPath());
160061da546Spatrick 
161061da546Spatrick   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
162061da546Spatrick   // private state should already be set to eStateStopped as a result of
163061da546Spatrick   // hitting the initial breakpoint.  If it was not set, the breakpoint should
164061da546Spatrick   // have already been resumed from and the private state should already be
165061da546Spatrick   // eStateRunning.
166061da546Spatrick   launch_info.SetProcessID(process.GetProcessId());
167061da546Spatrick 
168061da546Spatrick   return result;
169061da546Spatrick }
170061da546Spatrick 
AttachProcess(lldb::pid_t pid,const ProcessAttachInfo & attach_info,DebugDelegateSP delegate)171061da546Spatrick Status ProcessDebugger::AttachProcess(lldb::pid_t pid,
172061da546Spatrick                                       const ProcessAttachInfo &attach_info,
173061da546Spatrick                                       DebugDelegateSP delegate) {
174*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
175061da546Spatrick   m_session_data.reset(
176061da546Spatrick       new ProcessWindowsData(!attach_info.GetContinueOnceAttached()));
177061da546Spatrick   DebuggerThreadSP debugger(new DebuggerThread(delegate));
178061da546Spatrick 
179061da546Spatrick   m_session_data->m_debugger = debugger;
180061da546Spatrick 
181061da546Spatrick   DWORD process_id = static_cast<DWORD>(pid);
182061da546Spatrick   Status error = debugger->DebugAttach(process_id, attach_info);
183061da546Spatrick   if (error.Fail()) {
184061da546Spatrick     LLDB_LOG(
185061da546Spatrick         log,
186061da546Spatrick         "encountered an error occurred initiating the asynchronous attach. {0}",
187061da546Spatrick         error);
188061da546Spatrick     return error;
189061da546Spatrick   }
190061da546Spatrick 
191061da546Spatrick   HostProcess process;
192061da546Spatrick   error = WaitForDebuggerConnection(debugger, process);
193061da546Spatrick   if (error.Fail()) {
194061da546Spatrick     LLDB_LOG(log,
195061da546Spatrick              "encountered an error waiting for the debugger to connect. {0}",
196061da546Spatrick              error);
197061da546Spatrick     return error;
198061da546Spatrick   }
199061da546Spatrick 
200061da546Spatrick   LLDB_LOG(log, "successfully attached to process with pid={0}", process_id);
201061da546Spatrick 
202061da546Spatrick   // We've hit the initial stop.  If eLaunchFlagsStopAtEntry was specified, the
203061da546Spatrick   // private state should already be set to eStateStopped as a result of
204061da546Spatrick   // hitting the initial breakpoint.  If it was not set, the breakpoint should
205061da546Spatrick   // have already been resumed from and the private state should already be
206061da546Spatrick   // eStateRunning.
207061da546Spatrick 
208061da546Spatrick   return error;
209061da546Spatrick }
210061da546Spatrick 
DestroyProcess(const lldb::StateType state)211061da546Spatrick Status ProcessDebugger::DestroyProcess(const lldb::StateType state) {
212*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
213061da546Spatrick   DebuggerThreadSP debugger_thread;
214061da546Spatrick   {
215061da546Spatrick     // Acquire this lock inside an inner scope, only long enough to get the
216061da546Spatrick     // DebuggerThread. StopDebugging() will trigger a call back into
217061da546Spatrick     // ProcessDebugger which will acquire the lock again, so we need to not
218061da546Spatrick     // deadlock.
219061da546Spatrick     llvm::sys::ScopedLock lock(m_mutex);
220061da546Spatrick 
221061da546Spatrick     if (!m_session_data) {
222061da546Spatrick       LLDB_LOG(log, "warning: state = {0}, but there is no active session.",
223061da546Spatrick                state);
224061da546Spatrick       return Status();
225061da546Spatrick     }
226061da546Spatrick 
227061da546Spatrick     debugger_thread = m_session_data->m_debugger;
228061da546Spatrick   }
229061da546Spatrick 
230be691f3bSpatrick   if (state == eStateExited || state == eStateDetached) {
231be691f3bSpatrick     LLDB_LOG(log, "warning: cannot destroy process {0} while state = {1}.",
232be691f3bSpatrick              GetDebuggedProcessId(), state);
233be691f3bSpatrick     return Status();
234be691f3bSpatrick   }
235be691f3bSpatrick 
236be691f3bSpatrick   LLDB_LOG(log, "Shutting down process {0}.",
237061da546Spatrick            debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
238be691f3bSpatrick   auto error = debugger_thread->StopDebugging(true);
239061da546Spatrick 
240061da546Spatrick   // By the time StopDebugging returns, there is no more debugger thread, so
241061da546Spatrick   // we can be assured that no other thread will race for the session data.
242061da546Spatrick   m_session_data.reset();
243be691f3bSpatrick 
244061da546Spatrick   return error;
245061da546Spatrick }
246061da546Spatrick 
HaltProcess(bool & caused_stop)247061da546Spatrick Status ProcessDebugger::HaltProcess(bool &caused_stop) {
248*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
249061da546Spatrick   Status error;
250061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
251061da546Spatrick   caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess()
252061da546Spatrick                                         .GetNativeProcess()
253061da546Spatrick                                         .GetSystemHandle());
254061da546Spatrick   if (!caused_stop) {
255061da546Spatrick     error.SetError(::GetLastError(), eErrorTypeWin32);
256061da546Spatrick     LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error);
257061da546Spatrick   }
258061da546Spatrick 
259061da546Spatrick   return error;
260061da546Spatrick }
261061da546Spatrick 
ReadMemory(lldb::addr_t vm_addr,void * buf,size_t size,size_t & bytes_read)262061da546Spatrick Status ProcessDebugger::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
263061da546Spatrick                                    size_t &bytes_read) {
264061da546Spatrick   Status error;
265061da546Spatrick   bytes_read = 0;
266*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Memory);
267061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
268061da546Spatrick 
269061da546Spatrick   if (!m_session_data) {
270061da546Spatrick     error.SetErrorString(
271061da546Spatrick         "cannot read, there is no active debugger connection.");
272061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
273061da546Spatrick     return error;
274061da546Spatrick   }
275061da546Spatrick 
276061da546Spatrick   LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size,
277061da546Spatrick            vm_addr);
278061da546Spatrick 
279061da546Spatrick   HostProcess process = m_session_data->m_debugger->GetProcess();
280061da546Spatrick   void *addr = reinterpret_cast<void *>(vm_addr);
281061da546Spatrick   SIZE_T num_of_bytes_read = 0;
282061da546Spatrick   if (!::ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr,
283061da546Spatrick                            buf, size, &num_of_bytes_read)) {
284061da546Spatrick     error.SetError(GetLastError(), eErrorTypeWin32);
285061da546Spatrick     LLDB_LOG(log, "reading failed with error: {0}", error);
286061da546Spatrick   } else {
287061da546Spatrick     bytes_read = num_of_bytes_read;
288061da546Spatrick   }
289061da546Spatrick   return error;
290061da546Spatrick }
291061da546Spatrick 
WriteMemory(lldb::addr_t vm_addr,const void * buf,size_t size,size_t & bytes_written)292061da546Spatrick Status ProcessDebugger::WriteMemory(lldb::addr_t vm_addr, const void *buf,
293061da546Spatrick                                     size_t size, size_t &bytes_written) {
294061da546Spatrick   Status error;
295061da546Spatrick   bytes_written = 0;
296*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Memory);
297061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
298061da546Spatrick   LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size,
299061da546Spatrick            vm_addr);
300061da546Spatrick 
301061da546Spatrick   if (!m_session_data) {
302061da546Spatrick     error.SetErrorString(
303061da546Spatrick         "cannot write, there is no active debugger connection.");
304061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
305061da546Spatrick     return error;
306061da546Spatrick   }
307061da546Spatrick 
308061da546Spatrick   HostProcess process = m_session_data->m_debugger->GetProcess();
309061da546Spatrick   void *addr = reinterpret_cast<void *>(vm_addr);
310061da546Spatrick   SIZE_T num_of_bytes_written = 0;
311061da546Spatrick   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
312061da546Spatrick   if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) {
313061da546Spatrick     FlushInstructionCache(handle, addr, num_of_bytes_written);
314061da546Spatrick     bytes_written = num_of_bytes_written;
315061da546Spatrick   } else {
316061da546Spatrick     error.SetError(GetLastError(), eErrorTypeWin32);
317061da546Spatrick     LLDB_LOG(log, "writing failed with error: {0}", error);
318061da546Spatrick   }
319061da546Spatrick   return error;
320061da546Spatrick }
321061da546Spatrick 
AllocateMemory(size_t size,uint32_t permissions,lldb::addr_t & addr)322061da546Spatrick Status ProcessDebugger::AllocateMemory(size_t size, uint32_t permissions,
323061da546Spatrick                                        lldb::addr_t &addr) {
324061da546Spatrick   Status error;
325061da546Spatrick   addr = LLDB_INVALID_ADDRESS;
326*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Memory);
327061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
328061da546Spatrick   LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size,
329061da546Spatrick            permissions);
330061da546Spatrick 
331061da546Spatrick   if (!m_session_data) {
332061da546Spatrick     error.SetErrorString(
333061da546Spatrick         "cannot allocate, there is no active debugger connection");
334061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
335061da546Spatrick     return error;
336061da546Spatrick   }
337061da546Spatrick 
338061da546Spatrick   HostProcess process = m_session_data->m_debugger->GetProcess();
339061da546Spatrick   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
340061da546Spatrick   auto protect = ConvertLldbToWinApiProtect(permissions);
341061da546Spatrick   auto result = ::VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect);
342061da546Spatrick   if (!result) {
343061da546Spatrick     error.SetError(GetLastError(), eErrorTypeWin32);
344061da546Spatrick     LLDB_LOG(log, "allocating failed with error: {0}", error);
345061da546Spatrick   } else {
346061da546Spatrick     addr = reinterpret_cast<addr_t>(result);
347061da546Spatrick   }
348061da546Spatrick   return error;
349061da546Spatrick }
350061da546Spatrick 
DeallocateMemory(lldb::addr_t vm_addr)351061da546Spatrick Status ProcessDebugger::DeallocateMemory(lldb::addr_t vm_addr) {
352061da546Spatrick   Status result;
353061da546Spatrick 
354*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Memory);
355061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
356061da546Spatrick   LLDB_LOG(log, "attempting to deallocate bytes at address {0}", vm_addr);
357061da546Spatrick 
358061da546Spatrick   if (!m_session_data) {
359061da546Spatrick     result.SetErrorString(
360061da546Spatrick         "cannot deallocate, there is no active debugger connection");
361061da546Spatrick     LLDB_LOG(log, "error: {0}", result);
362061da546Spatrick     return result;
363061da546Spatrick   }
364061da546Spatrick 
365061da546Spatrick   HostProcess process = m_session_data->m_debugger->GetProcess();
366061da546Spatrick   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
367061da546Spatrick   if (!::VirtualFreeEx(handle, reinterpret_cast<LPVOID>(vm_addr), 0,
368061da546Spatrick                        MEM_RELEASE)) {
369061da546Spatrick     result.SetError(GetLastError(), eErrorTypeWin32);
370061da546Spatrick     LLDB_LOG(log, "deallocating failed with error: {0}", result);
371061da546Spatrick   }
372061da546Spatrick 
373061da546Spatrick   return result;
374061da546Spatrick }
375061da546Spatrick 
GetMemoryRegionInfo(lldb::addr_t vm_addr,MemoryRegionInfo & info)376061da546Spatrick Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr,
377061da546Spatrick                                             MemoryRegionInfo &info) {
378*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Memory);
379061da546Spatrick   Status error;
380061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
381061da546Spatrick   info.Clear();
382061da546Spatrick 
383061da546Spatrick   if (!m_session_data) {
384061da546Spatrick     error.SetErrorString(
385061da546Spatrick         "GetMemoryRegionInfo called with no debugging session.");
386061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
387061da546Spatrick     return error;
388061da546Spatrick   }
389061da546Spatrick   HostProcess process = m_session_data->m_debugger->GetProcess();
390061da546Spatrick   lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
391061da546Spatrick   if (handle == nullptr || handle == LLDB_INVALID_PROCESS) {
392061da546Spatrick     error.SetErrorString(
393061da546Spatrick         "GetMemoryRegionInfo called with an invalid target process.");
394061da546Spatrick     LLDB_LOG(log, "error: {0}", error);
395061da546Spatrick     return error;
396061da546Spatrick   }
397061da546Spatrick 
398061da546Spatrick   LLDB_LOG(log, "getting info for address {0:x}", vm_addr);
399061da546Spatrick 
400061da546Spatrick   void *addr = reinterpret_cast<void *>(vm_addr);
401061da546Spatrick   MEMORY_BASIC_INFORMATION mem_info = {};
402061da546Spatrick   SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
403061da546Spatrick   if (result == 0) {
404be691f3bSpatrick     DWORD last_error = ::GetLastError();
405be691f3bSpatrick     if (last_error == ERROR_INVALID_PARAMETER) {
406061da546Spatrick       // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with
407061da546Spatrick       // an address past the highest accessible address. We should return a
408061da546Spatrick       // range from the vm_addr to LLDB_INVALID_ADDRESS
409061da546Spatrick       info.GetRange().SetRangeBase(vm_addr);
410061da546Spatrick       info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
411061da546Spatrick       info.SetReadable(MemoryRegionInfo::eNo);
412061da546Spatrick       info.SetExecutable(MemoryRegionInfo::eNo);
413061da546Spatrick       info.SetWritable(MemoryRegionInfo::eNo);
414061da546Spatrick       info.SetMapped(MemoryRegionInfo::eNo);
415061da546Spatrick       return error;
416061da546Spatrick     } else {
417be691f3bSpatrick       error.SetError(last_error, eErrorTypeWin32);
418061da546Spatrick       LLDB_LOG(log,
419061da546Spatrick                "VirtualQueryEx returned error {0} while getting memory "
420061da546Spatrick                "region info for address {1:x}",
421061da546Spatrick                error, vm_addr);
422061da546Spatrick       return error;
423061da546Spatrick     }
424061da546Spatrick   }
425061da546Spatrick 
426061da546Spatrick   // Protect bits are only valid for MEM_COMMIT regions.
427061da546Spatrick   if (mem_info.State == MEM_COMMIT) {
428061da546Spatrick     const bool readable = IsPageReadable(mem_info.Protect);
429061da546Spatrick     const bool executable = IsPageExecutable(mem_info.Protect);
430061da546Spatrick     const bool writable = IsPageWritable(mem_info.Protect);
431061da546Spatrick     info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
432061da546Spatrick     info.SetExecutable(executable ? MemoryRegionInfo::eYes
433061da546Spatrick                                   : MemoryRegionInfo::eNo);
434061da546Spatrick     info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
435061da546Spatrick   } else {
436061da546Spatrick     info.SetReadable(MemoryRegionInfo::eNo);
437061da546Spatrick     info.SetExecutable(MemoryRegionInfo::eNo);
438061da546Spatrick     info.SetWritable(MemoryRegionInfo::eNo);
439061da546Spatrick   }
440061da546Spatrick 
441061da546Spatrick   // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE.
442061da546Spatrick   if (mem_info.State != MEM_FREE) {
443061da546Spatrick     info.GetRange().SetRangeBase(
444*f6aab3d8Srobert         reinterpret_cast<addr_t>(mem_info.BaseAddress));
445061da546Spatrick     info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) +
446061da546Spatrick                                 mem_info.RegionSize);
447061da546Spatrick     info.SetMapped(MemoryRegionInfo::eYes);
448061da546Spatrick   } else {
449061da546Spatrick     // In the unmapped case we need to return the distance to the next block of
450061da546Spatrick     // memory. VirtualQueryEx nearly does that except that it gives the
451061da546Spatrick     // distance from the start of the page containing vm_addr.
452061da546Spatrick     SYSTEM_INFO data;
453061da546Spatrick     ::GetSystemInfo(&data);
454061da546Spatrick     DWORD page_offset = vm_addr % data.dwPageSize;
455061da546Spatrick     info.GetRange().SetRangeBase(vm_addr);
456061da546Spatrick     info.GetRange().SetByteSize(mem_info.RegionSize - page_offset);
457061da546Spatrick     info.SetMapped(MemoryRegionInfo::eNo);
458061da546Spatrick   }
459061da546Spatrick 
460061da546Spatrick   LLDB_LOGV(log,
461061da546Spatrick             "Memory region info for address {0}: readable={1}, "
462061da546Spatrick             "executable={2}, writable={3}",
463061da546Spatrick             vm_addr, info.GetReadable(), info.GetExecutable(),
464061da546Spatrick             info.GetWritable());
465061da546Spatrick   return error;
466061da546Spatrick }
467061da546Spatrick 
OnExitProcess(uint32_t exit_code)468061da546Spatrick void ProcessDebugger::OnExitProcess(uint32_t exit_code) {
469061da546Spatrick   // If the process exits before any initial stop then notify the debugger
470061da546Spatrick   // of the error otherwise WaitForDebuggerConnection() will be blocked.
471061da546Spatrick   // An example of this issue is when a process fails to load a dependent DLL.
472061da546Spatrick   if (m_session_data && !m_session_data->m_initial_stop_received) {
473061da546Spatrick     Status error(exit_code, eErrorTypeWin32);
474061da546Spatrick     OnDebuggerError(error, 0);
475061da546Spatrick   }
476061da546Spatrick }
477061da546Spatrick 
OnDebuggerConnected(lldb::addr_t image_base)478061da546Spatrick void ProcessDebugger::OnDebuggerConnected(lldb::addr_t image_base) {}
479061da546Spatrick 
480061da546Spatrick ExceptionResult
OnDebugException(bool first_chance,const ExceptionRecord & record)481061da546Spatrick ProcessDebugger::OnDebugException(bool first_chance,
482061da546Spatrick                                   const ExceptionRecord &record) {
483*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Exception);
484061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
485061da546Spatrick   // FIXME: Without this check, occasionally when running the test suite
486061da546Spatrick   // there is an issue where m_session_data can be null.  It's not clear how
487061da546Spatrick   // this could happen but it only surfaces while running the test suite.  In
488061da546Spatrick   // order to properly diagnose this, we probably need to first figure allow the
489061da546Spatrick   // test suite to print out full lldb logs, and then add logging to the process
490061da546Spatrick   // plugin.
491061da546Spatrick   if (!m_session_data) {
492061da546Spatrick     LLDB_LOG(log,
493061da546Spatrick              "Debugger thread reported exception {0:x} at address {1:x}, but "
494061da546Spatrick              "there is no session.",
495061da546Spatrick              record.GetExceptionCode(), record.GetExceptionAddress());
496061da546Spatrick     return ExceptionResult::SendToApplication;
497061da546Spatrick   }
498061da546Spatrick 
499061da546Spatrick   ExceptionResult result = ExceptionResult::SendToApplication;
500061da546Spatrick   if ((record.GetExceptionCode() == EXCEPTION_BREAKPOINT ||
501061da546Spatrick        record.GetExceptionCode() ==
502061da546Spatrick            0x4000001FL /*WOW64 STATUS_WX86_BREAKPOINT*/) &&
503061da546Spatrick       !m_session_data->m_initial_stop_received) {
504061da546Spatrick     // Handle breakpoints at the first chance.
505061da546Spatrick     result = ExceptionResult::BreakInDebugger;
506061da546Spatrick     LLDB_LOG(
507061da546Spatrick         log,
508061da546Spatrick         "Hit loader breakpoint at address {0:x}, setting initial stop event.",
509061da546Spatrick         record.GetExceptionAddress());
510061da546Spatrick     m_session_data->m_initial_stop_received = true;
511061da546Spatrick     ::SetEvent(m_session_data->m_initial_stop_event);
512061da546Spatrick   }
513061da546Spatrick   return result;
514061da546Spatrick }
515061da546Spatrick 
OnCreateThread(const HostThread & thread)516061da546Spatrick void ProcessDebugger::OnCreateThread(const HostThread &thread) {
517061da546Spatrick   // Do nothing by default
518061da546Spatrick }
519061da546Spatrick 
OnExitThread(lldb::tid_t thread_id,uint32_t exit_code)520061da546Spatrick void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
521061da546Spatrick   // Do nothing by default
522061da546Spatrick }
523061da546Spatrick 
OnLoadDll(const ModuleSpec & module_spec,lldb::addr_t module_addr)524061da546Spatrick void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec,
525061da546Spatrick                                 lldb::addr_t module_addr) {
526061da546Spatrick   // Do nothing by default
527061da546Spatrick }
528061da546Spatrick 
OnUnloadDll(lldb::addr_t module_addr)529061da546Spatrick void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr) {
530061da546Spatrick   // Do nothing by default
531061da546Spatrick }
532061da546Spatrick 
OnDebugString(const std::string & string)533061da546Spatrick void ProcessDebugger::OnDebugString(const std::string &string) {}
534061da546Spatrick 
OnDebuggerError(const Status & error,uint32_t type)535061da546Spatrick void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) {
536061da546Spatrick   llvm::sys::ScopedLock lock(m_mutex);
537*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process);
538061da546Spatrick 
539061da546Spatrick   if (m_session_data->m_initial_stop_received) {
540061da546Spatrick     // This happened while debugging.  Do we shutdown the debugging session,
541061da546Spatrick     // try to continue, or do something else?
542061da546Spatrick     LLDB_LOG(log,
543061da546Spatrick              "Error {0} occurred during debugging.  Unexpected behavior "
544061da546Spatrick              "may result.  {1}",
545061da546Spatrick              error.GetError(), error);
546061da546Spatrick   } else {
547061da546Spatrick     // If we haven't actually launched the process yet, this was an error
548061da546Spatrick     // launching the process.  Set the internal error and signal the initial
549061da546Spatrick     // stop event so that the DoLaunch method wakes up and returns a failure.
550061da546Spatrick     m_session_data->m_launch_error = error;
551061da546Spatrick     ::SetEvent(m_session_data->m_initial_stop_event);
552061da546Spatrick     LLDB_LOG(log,
553061da546Spatrick              "Error {0} occurred launching the process before the initial "
554061da546Spatrick              "stop. {1}",
555061da546Spatrick              error.GetError(), error);
556061da546Spatrick     return;
557061da546Spatrick   }
558061da546Spatrick }
559061da546Spatrick 
WaitForDebuggerConnection(DebuggerThreadSP debugger,HostProcess & process)560061da546Spatrick Status ProcessDebugger::WaitForDebuggerConnection(DebuggerThreadSP debugger,
561061da546Spatrick                                                   HostProcess &process) {
562061da546Spatrick   Status result;
563*f6aab3d8Srobert   Log *log = GetLog(WindowsLog::Process | WindowsLog::Breakpoints);
564061da546Spatrick   LLDB_LOG(log, "Waiting for loader breakpoint.");
565061da546Spatrick 
566061da546Spatrick   // Block this function until we receive the initial stop from the process.
567061da546Spatrick   if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) ==
568061da546Spatrick       WAIT_OBJECT_0) {
569061da546Spatrick     LLDB_LOG(log, "hit loader breakpoint, returning.");
570061da546Spatrick 
571061da546Spatrick     process = debugger->GetProcess();
572061da546Spatrick     return m_session_data->m_launch_error;
573061da546Spatrick   } else
574061da546Spatrick     return Status(::GetLastError(), eErrorTypeWin32);
575061da546Spatrick }
576061da546Spatrick 
577061da546Spatrick } // namespace lldb_private
578