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