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 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. 50053eb356SAaron Smith static bool IsPageReadable(uint32_t protect) { 51053eb356SAaron Smith return (protect & PAGE_NOACCESS) == 0; 52053eb356SAaron Smith } 53053eb356SAaron Smith 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 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 66403cd574SMartin Storsjö ProcessDebugger::~ProcessDebugger() {} 67403cd574SMartin Storsjö 68053eb356SAaron 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 74053eb356SAaron Smith Status ProcessDebugger::DetachProcess() { 75053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 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 111053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 171053eb356SAaron Smith Status ProcessDebugger::AttachProcess(lldb::pid_t pid, 172053eb356SAaron Smith const ProcessAttachInfo &attach_info, 173053eb356SAaron Smith DebugDelegateSP delegate) { 174053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 211053eb356SAaron Smith Status ProcessDebugger::DestroyProcess(const lldb::StateType state) { 212053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 247053eb356SAaron Smith Status ProcessDebugger::HaltProcess(bool &caused_stop) { 248053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 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; 266053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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 // Reading from the process can fail for a number of reasons - set the 285053eb356SAaron Smith // error code and make sure that the number of bytes read is set back to 0 286053eb356SAaron Smith // because in some scenarios the value of bytes_read returned from the API 287053eb356SAaron Smith // is garbage. 288053eb356SAaron Smith error.SetError(GetLastError(), eErrorTypeWin32); 289053eb356SAaron Smith LLDB_LOG(log, "reading failed with error: {0}", error); 290053eb356SAaron Smith } else { 291053eb356SAaron Smith bytes_read = num_of_bytes_read; 292053eb356SAaron Smith } 293053eb356SAaron Smith return error; 294053eb356SAaron Smith } 295053eb356SAaron Smith 296053eb356SAaron Smith Status ProcessDebugger::WriteMemory(lldb::addr_t vm_addr, const void *buf, 297053eb356SAaron Smith size_t size, size_t &bytes_written) { 298053eb356SAaron Smith Status error; 299053eb356SAaron Smith bytes_written = 0; 300053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); 301053eb356SAaron Smith llvm::sys::ScopedLock lock(m_mutex); 302053eb356SAaron Smith LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size, 303053eb356SAaron Smith vm_addr); 304053eb356SAaron Smith 305053eb356SAaron Smith if (!m_session_data) { 306053eb356SAaron Smith error.SetErrorString( 307053eb356SAaron Smith "cannot write, there is no active debugger connection."); 308053eb356SAaron Smith LLDB_LOG(log, "error: {0}", error); 309053eb356SAaron Smith return error; 310053eb356SAaron Smith } 311053eb356SAaron Smith 312053eb356SAaron Smith HostProcess process = m_session_data->m_debugger->GetProcess(); 313053eb356SAaron Smith void *addr = reinterpret_cast<void *>(vm_addr); 314053eb356SAaron Smith SIZE_T num_of_bytes_written = 0; 315053eb356SAaron Smith lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); 316053eb356SAaron Smith if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) { 317053eb356SAaron Smith FlushInstructionCache(handle, addr, num_of_bytes_written); 318053eb356SAaron Smith bytes_written = num_of_bytes_written; 319053eb356SAaron Smith } else { 320053eb356SAaron Smith error.SetError(GetLastError(), eErrorTypeWin32); 321053eb356SAaron Smith LLDB_LOG(log, "writing failed with error: {0}", error); 322053eb356SAaron Smith } 323053eb356SAaron Smith return error; 324053eb356SAaron Smith } 325053eb356SAaron Smith 326053eb356SAaron Smith Status ProcessDebugger::AllocateMemory(size_t size, uint32_t permissions, 327053eb356SAaron Smith lldb::addr_t &addr) { 328053eb356SAaron Smith Status error; 329053eb356SAaron Smith addr = LLDB_INVALID_ADDRESS; 330053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); 331053eb356SAaron Smith llvm::sys::ScopedLock lock(m_mutex); 332053eb356SAaron Smith LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size, 333053eb356SAaron Smith permissions); 334053eb356SAaron Smith 335053eb356SAaron Smith if (!m_session_data) { 336053eb356SAaron Smith error.SetErrorString( 337053eb356SAaron Smith "cannot allocate, there is no active debugger connection"); 338053eb356SAaron Smith LLDB_LOG(log, "error: {0}", error); 339053eb356SAaron Smith return error; 340053eb356SAaron Smith } 341053eb356SAaron Smith 342053eb356SAaron Smith HostProcess process = m_session_data->m_debugger->GetProcess(); 343053eb356SAaron Smith lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); 344053eb356SAaron Smith auto protect = ConvertLldbToWinApiProtect(permissions); 345053eb356SAaron Smith auto result = ::VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect); 346053eb356SAaron Smith if (!result) { 347053eb356SAaron Smith error.SetError(GetLastError(), eErrorTypeWin32); 348053eb356SAaron Smith LLDB_LOG(log, "allocating failed with error: {0}", error); 349053eb356SAaron Smith } else { 350053eb356SAaron Smith addr = reinterpret_cast<addr_t>(result); 351053eb356SAaron Smith } 352053eb356SAaron Smith return error; 353053eb356SAaron Smith } 354053eb356SAaron Smith 355053eb356SAaron Smith Status ProcessDebugger::DeallocateMemory(lldb::addr_t vm_addr) { 356053eb356SAaron Smith Status result; 357053eb356SAaron Smith 358053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); 359053eb356SAaron Smith llvm::sys::ScopedLock lock(m_mutex); 360053eb356SAaron Smith LLDB_LOG(log, "attempting to deallocate bytes at address {0}", vm_addr); 361053eb356SAaron Smith 362053eb356SAaron Smith if (!m_session_data) { 363053eb356SAaron Smith result.SetErrorString( 364053eb356SAaron Smith "cannot deallocate, there is no active debugger connection"); 365053eb356SAaron Smith LLDB_LOG(log, "error: {0}", result); 366053eb356SAaron Smith return result; 367053eb356SAaron Smith } 368053eb356SAaron Smith 369053eb356SAaron Smith HostProcess process = m_session_data->m_debugger->GetProcess(); 370053eb356SAaron Smith lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); 371053eb356SAaron Smith if (!::VirtualFreeEx(handle, reinterpret_cast<LPVOID>(vm_addr), 0, 372053eb356SAaron Smith MEM_RELEASE)) { 373053eb356SAaron Smith result.SetError(GetLastError(), eErrorTypeWin32); 374053eb356SAaron Smith LLDB_LOG(log, "deallocating failed with error: {0}", result); 375053eb356SAaron Smith } 376053eb356SAaron Smith 377053eb356SAaron Smith return result; 378053eb356SAaron Smith } 379053eb356SAaron Smith 380*5fbcf677SDavid Spickett Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr, 381053eb356SAaron Smith MemoryRegionInfo &info) { 382053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); 383053eb356SAaron Smith Status error; 384053eb356SAaron Smith llvm::sys::ScopedLock lock(m_mutex); 385053eb356SAaron Smith info.Clear(); 386053eb356SAaron Smith 387053eb356SAaron Smith if (!m_session_data) { 388053eb356SAaron Smith error.SetErrorString( 389*5fbcf677SDavid Spickett "GetMemoryRegionInfo called with no debugging session."); 390053eb356SAaron Smith LLDB_LOG(log, "error: {0}", error); 391053eb356SAaron Smith return error; 392053eb356SAaron Smith } 393053eb356SAaron Smith HostProcess process = m_session_data->m_debugger->GetProcess(); 394053eb356SAaron Smith lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); 395053eb356SAaron Smith if (handle == nullptr || handle == LLDB_INVALID_PROCESS) { 396053eb356SAaron Smith error.SetErrorString( 397*5fbcf677SDavid Spickett "GetMemoryRegionInfo called with an invalid target process."); 398053eb356SAaron Smith LLDB_LOG(log, "error: {0}", error); 399053eb356SAaron Smith return error; 400053eb356SAaron Smith } 401053eb356SAaron Smith 402053eb356SAaron Smith LLDB_LOG(log, "getting info for address {0:x}", vm_addr); 403053eb356SAaron Smith 404053eb356SAaron Smith void *addr = reinterpret_cast<void *>(vm_addr); 405053eb356SAaron Smith MEMORY_BASIC_INFORMATION mem_info = {}; 406053eb356SAaron Smith SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); 407053eb356SAaron Smith if (result == 0) { 40871cf97e9SDavid Spickett DWORD last_error = ::GetLastError(); 40971cf97e9SDavid Spickett if (last_error == ERROR_INVALID_PARAMETER) { 410053eb356SAaron Smith // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with 411053eb356SAaron Smith // an address past the highest accessible address. We should return a 412053eb356SAaron Smith // range from the vm_addr to LLDB_INVALID_ADDRESS 413053eb356SAaron Smith info.GetRange().SetRangeBase(vm_addr); 414053eb356SAaron Smith info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); 415053eb356SAaron Smith info.SetReadable(MemoryRegionInfo::eNo); 416053eb356SAaron Smith info.SetExecutable(MemoryRegionInfo::eNo); 417053eb356SAaron Smith info.SetWritable(MemoryRegionInfo::eNo); 418053eb356SAaron Smith info.SetMapped(MemoryRegionInfo::eNo); 419053eb356SAaron Smith return error; 420053eb356SAaron Smith } else { 42171cf97e9SDavid Spickett error.SetError(last_error, eErrorTypeWin32); 422053eb356SAaron Smith LLDB_LOG(log, 423053eb356SAaron Smith "VirtualQueryEx returned error {0} while getting memory " 424053eb356SAaron Smith "region info for address {1:x}", 425053eb356SAaron Smith error, vm_addr); 426053eb356SAaron Smith return error; 427053eb356SAaron Smith } 428053eb356SAaron Smith } 429053eb356SAaron Smith 430053eb356SAaron Smith // Protect bits are only valid for MEM_COMMIT regions. 431053eb356SAaron Smith if (mem_info.State == MEM_COMMIT) { 432053eb356SAaron Smith const bool readable = IsPageReadable(mem_info.Protect); 433053eb356SAaron Smith const bool executable = IsPageExecutable(mem_info.Protect); 434053eb356SAaron Smith const bool writable = IsPageWritable(mem_info.Protect); 435053eb356SAaron Smith info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); 436053eb356SAaron Smith info.SetExecutable(executable ? MemoryRegionInfo::eYes 437053eb356SAaron Smith : MemoryRegionInfo::eNo); 438053eb356SAaron Smith info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); 439053eb356SAaron Smith } else { 440053eb356SAaron Smith info.SetReadable(MemoryRegionInfo::eNo); 441053eb356SAaron Smith info.SetExecutable(MemoryRegionInfo::eNo); 442053eb356SAaron Smith info.SetWritable(MemoryRegionInfo::eNo); 443053eb356SAaron Smith } 444053eb356SAaron Smith 445053eb356SAaron Smith // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE. 446053eb356SAaron Smith if (mem_info.State != MEM_FREE) { 447053eb356SAaron Smith info.GetRange().SetRangeBase( 448053eb356SAaron Smith reinterpret_cast<addr_t>(mem_info.AllocationBase)); 449053eb356SAaron Smith info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) + 450053eb356SAaron Smith mem_info.RegionSize); 451053eb356SAaron Smith info.SetMapped(MemoryRegionInfo::eYes); 452053eb356SAaron Smith } else { 453053eb356SAaron Smith // In the unmapped case we need to return the distance to the next block of 454053eb356SAaron Smith // memory. VirtualQueryEx nearly does that except that it gives the 455053eb356SAaron Smith // distance from the start of the page containing vm_addr. 456053eb356SAaron Smith SYSTEM_INFO data; 457053eb356SAaron Smith ::GetSystemInfo(&data); 458053eb356SAaron Smith DWORD page_offset = vm_addr % data.dwPageSize; 459053eb356SAaron Smith info.GetRange().SetRangeBase(vm_addr); 460053eb356SAaron Smith info.GetRange().SetByteSize(mem_info.RegionSize - page_offset); 461053eb356SAaron Smith info.SetMapped(MemoryRegionInfo::eNo); 462053eb356SAaron Smith } 463053eb356SAaron Smith 464053eb356SAaron Smith LLDB_LOGV(log, 465053eb356SAaron Smith "Memory region info for address {0}: readable={1}, " 466053eb356SAaron Smith "executable={2}, writable={3}", 467053eb356SAaron Smith vm_addr, info.GetReadable(), info.GetExecutable(), 468053eb356SAaron Smith info.GetWritable()); 469053eb356SAaron Smith return error; 470053eb356SAaron Smith } 471053eb356SAaron Smith 472053eb356SAaron Smith void ProcessDebugger::OnExitProcess(uint32_t exit_code) { 473053eb356SAaron Smith // If the process exits before any initial stop then notify the debugger 474053eb356SAaron Smith // of the error otherwise WaitForDebuggerConnection() will be blocked. 475053eb356SAaron Smith // An example of this issue is when a process fails to load a dependent DLL. 476053eb356SAaron Smith if (m_session_data && !m_session_data->m_initial_stop_received) { 477053eb356SAaron Smith Status error(exit_code, eErrorTypeWin32); 478053eb356SAaron Smith OnDebuggerError(error, 0); 479053eb356SAaron Smith } 480053eb356SAaron Smith } 481053eb356SAaron Smith 482053eb356SAaron Smith void ProcessDebugger::OnDebuggerConnected(lldb::addr_t image_base) {} 483053eb356SAaron Smith 484053eb356SAaron Smith ExceptionResult 485053eb356SAaron Smith ProcessDebugger::OnDebugException(bool first_chance, 486053eb356SAaron Smith const ExceptionRecord &record) { 487053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION); 488053eb356SAaron Smith llvm::sys::ScopedLock lock(m_mutex); 489053eb356SAaron Smith // FIXME: Without this check, occasionally when running the test suite 490053eb356SAaron Smith // there is an issue where m_session_data can be null. It's not clear how 491053eb356SAaron Smith // this could happen but it only surfaces while running the test suite. In 492053eb356SAaron Smith // order to properly diagnose this, we probably need to first figure allow the 493053eb356SAaron Smith // test suite to print out full lldb logs, and then add logging to the process 494053eb356SAaron Smith // plugin. 495053eb356SAaron Smith if (!m_session_data) { 496053eb356SAaron Smith LLDB_LOG(log, 497053eb356SAaron Smith "Debugger thread reported exception {0:x} at address {1:x}, but " 498053eb356SAaron Smith "there is no session.", 499053eb356SAaron Smith record.GetExceptionCode(), record.GetExceptionAddress()); 500053eb356SAaron Smith return ExceptionResult::SendToApplication; 501053eb356SAaron Smith } 502053eb356SAaron Smith 503053eb356SAaron Smith ExceptionResult result = ExceptionResult::SendToApplication; 504053eb356SAaron Smith if ((record.GetExceptionCode() == EXCEPTION_BREAKPOINT || 505053eb356SAaron Smith record.GetExceptionCode() == 506053eb356SAaron Smith 0x4000001FL /*WOW64 STATUS_WX86_BREAKPOINT*/) && 507053eb356SAaron Smith !m_session_data->m_initial_stop_received) { 508053eb356SAaron Smith // Handle breakpoints at the first chance. 509053eb356SAaron Smith result = ExceptionResult::BreakInDebugger; 510053eb356SAaron Smith LLDB_LOG( 511053eb356SAaron Smith log, 512053eb356SAaron Smith "Hit loader breakpoint at address {0:x}, setting initial stop event.", 513053eb356SAaron Smith record.GetExceptionAddress()); 514053eb356SAaron Smith m_session_data->m_initial_stop_received = true; 515053eb356SAaron Smith ::SetEvent(m_session_data->m_initial_stop_event); 516053eb356SAaron Smith } 517053eb356SAaron Smith return result; 518053eb356SAaron Smith } 519053eb356SAaron Smith 520053eb356SAaron Smith void ProcessDebugger::OnCreateThread(const HostThread &thread) { 521053eb356SAaron Smith // Do nothing by default 522053eb356SAaron Smith } 523053eb356SAaron Smith 524053eb356SAaron Smith void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { 525053eb356SAaron Smith // Do nothing by default 526053eb356SAaron Smith } 527053eb356SAaron Smith 528053eb356SAaron Smith void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec, 529053eb356SAaron Smith lldb::addr_t module_addr) { 530053eb356SAaron Smith // Do nothing by default 531053eb356SAaron Smith } 532053eb356SAaron Smith 533053eb356SAaron Smith void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr) { 534053eb356SAaron Smith // Do nothing by default 535053eb356SAaron Smith } 536053eb356SAaron Smith 537053eb356SAaron Smith void ProcessDebugger::OnDebugString(const std::string &string) {} 538053eb356SAaron Smith 539053eb356SAaron Smith void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) { 540053eb356SAaron Smith llvm::sys::ScopedLock lock(m_mutex); 541053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); 542053eb356SAaron Smith 543053eb356SAaron Smith if (m_session_data->m_initial_stop_received) { 544053eb356SAaron Smith // This happened while debugging. Do we shutdown the debugging session, 545053eb356SAaron Smith // try to continue, or do something else? 546053eb356SAaron Smith LLDB_LOG(log, 547053eb356SAaron Smith "Error {0} occurred during debugging. Unexpected behavior " 548053eb356SAaron Smith "may result. {1}", 549053eb356SAaron Smith error.GetError(), error); 550053eb356SAaron Smith } else { 551053eb356SAaron Smith // If we haven't actually launched the process yet, this was an error 552053eb356SAaron Smith // launching the process. Set the internal error and signal the initial 553053eb356SAaron Smith // stop event so that the DoLaunch method wakes up and returns a failure. 554053eb356SAaron Smith m_session_data->m_launch_error = error; 555053eb356SAaron Smith ::SetEvent(m_session_data->m_initial_stop_event); 556053eb356SAaron Smith LLDB_LOG(log, 557053eb356SAaron Smith "Error {0} occurred launching the process before the initial " 558053eb356SAaron Smith "stop. {1}", 559053eb356SAaron Smith error.GetError(), error); 560053eb356SAaron Smith return; 561053eb356SAaron Smith } 562053eb356SAaron Smith } 563053eb356SAaron Smith 564053eb356SAaron Smith Status ProcessDebugger::WaitForDebuggerConnection(DebuggerThreadSP debugger, 565053eb356SAaron Smith HostProcess &process) { 566053eb356SAaron Smith Status result; 567053eb356SAaron Smith Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS | 568053eb356SAaron Smith WINDOWS_LOG_BREAKPOINTS); 569053eb356SAaron Smith LLDB_LOG(log, "Waiting for loader breakpoint."); 570053eb356SAaron Smith 571053eb356SAaron Smith // Block this function until we receive the initial stop from the process. 572053eb356SAaron Smith if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == 573053eb356SAaron Smith WAIT_OBJECT_0) { 574053eb356SAaron Smith LLDB_LOG(log, "hit loader breakpoint, returning."); 575053eb356SAaron Smith 576053eb356SAaron Smith process = debugger->GetProcess(); 577053eb356SAaron Smith return m_session_data->m_launch_error; 578053eb356SAaron Smith } else 579053eb356SAaron Smith return Status(::GetLastError(), eErrorTypeWin32); 580053eb356SAaron Smith } 581053eb356SAaron Smith 582053eb356SAaron Smith } // namespace lldb_private 583