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