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