31#include "llvm/ADT/STLExtras.h"
32#include "llvm/Support/ConvertUTF.h"
33#include "llvm/Support/Path.h"
34#include "llvm/Support/Threading.h"
35#include "llvm/Support/raw_ostream.h"
42#ifndef STATUS_WX86_BREAKPOINT
43#define STATUS_WX86_BREAKPOINT 0x4000001FL
58 L
"kernel32.dll",
"WaitForDebugEventEx"};
63 if (!s_wait_for_debug_event_ex) {
66 "WaitForDebugEventEx unavailable, using WaitForDebugEvent instead. "
67 "Unicode strings from OutputDebugStringW might show incorrectly.");
89 "lldb.plugin.process-windows.secondary[?]",
91 if (!secondary_thread) {
93 LLDB_LOG(log,
"couldn't launch debugger thread. {0}", result);
102 LLDB_LOG(log,
"attaching to '{0}'", pid);
106 "lldb.plugin.process-windows.secondary[?]", [
this, pid, attach_info] {
109 if (!secondary_thread) {
111 LLDB_LOG(log,
"couldn't attach to process '{0}'. {1}", pid, result);
121 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
124 LLDB_LOG(log,
"preparing to launch '{0}' on background thread.",
148 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
151 LLDB_LOG(log,
"preparing to attach to process '{0}' on background thread.",
154 if (!DebugActiveProcess(
static_cast<DWORD
>(pid))) {
178 LLDB_LOG(log,
"terminate = {0}, inferior={1}.", terminate, pid);
182 bool expected =
false;
193 BOOL terminate_succeeded = TerminateProcess(handle, 0);
195 "calling TerminateProcess({0}, 0) (inferior={1}), success={2}",
196 handle, pid, terminate_succeeded);
199 "NOT calling TerminateProcess because the inferior is not valid "
200 "({0}, 0) (inferior={1})",
210 LLDB_LOG(log,
"masking active exception");
222 if (!::DebugBreakProcess(handle)) {
227 LLDB_LOG(log,
"waiting for detach from process {0} to complete.", pid);
230 if (wait_result != WAIT_OBJECT_0) {
232 LLDB_LOG(log,
"error: WaitForSingleObject({0}, 5000) returned {1}",
235 LLDB_LOG(log,
"detach from process {0} completed successfully.", pid);
237 if (!
error.Success()) {
238 LLDB_LOG(log,
"encountered an error while trying to stop process {0}. {1}",
258 LLDB_LOG(log,
"broadcasting for inferior process {0}.",
286 DEBUG_EVENT dbe = {};
287 bool should_debug =
true;
288 constexpr unsigned max_drained_events = 64;
289 unsigned drained_events = 0;
291 while (should_debug) {
294 if (draining && drained_events >= max_drained_events) {
295 LLDB_LOG(log,
"reporting the stop after taking {0} queued debug events",
316 DWORD continue_status = DBG_CONTINUE;
318 HANDLE exited_process =
nullptr;
319 switch (dbe.dwDebugEventCode) {
321 llvm_unreachable(
"Unhandled debug event code!");
322 case EXCEPTION_DEBUG_EVENT: {
324 dbe.u.Exception, dbe.dwThreadId, shutting_down);
327 continue_status = DBG_CONTINUE;
329 continue_status = DBG_EXCEPTION_NOT_HANDLED;
333 case CREATE_THREAD_DEBUG_EVENT:
337 case CREATE_PROCESS_DEBUG_EVENT:
341 case EXIT_THREAD_DEBUG_EVENT:
345 case EXIT_PROCESS_DEBUG_EVENT:
346 if (!::DuplicateHandle(
347 ::GetCurrentProcess(),
348 GetProcess().GetNativeProcess().GetSystemHandle(),
349 ::GetCurrentProcess(), &exited_process, SYNCHRONIZE, FALSE, 0))
350 exited_process =
nullptr;
351 should_debug =
false;
353 case LOAD_DLL_DEBUG_EVENT:
356 case UNLOAD_DLL_DEBUG_EVENT:
359 case OUTPUT_DEBUG_STRING_EVENT:
360 continue_status =
HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
364 if (dbe.u.RipInfo.dwType == SLE_ERROR)
365 should_debug =
false;
370 log,
"calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.",
371 dbe.dwProcessId, dbe.dwThreadId, continue_status,
372 ::GetCurrentThreadId());
374 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
376 if (dbe.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) {
377 if (exited_process) {
378 ::WaitForSingleObject(exited_process, INFINITE);
379 ::CloseHandle(exited_process);
391 (dbe.u.Exception.ExceptionRecord.ExceptionCode ==
392 EXCEPTION_BREAKPOINT ||
393 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
396 "Breakpoint exception is cue to detach from process {0:x}",
405 continue_status = DBG_CONTINUE;
406 if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
407 !(dbe.u.Exception.ExceptionRecord.ExceptionCode ==
408 EXCEPTION_BREAKPOINT ||
409 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
411 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
412 EXCEPTION_SINGLE_STEP))
413 continue_status = DBG_EXCEPTION_NOT_HANDLED;
414 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId,
424 should_debug =
false;
426 LLDB_LOG(log,
"returned FALSE from WaitForDebugEventEx. Error = {0}",
429 should_debug =
false;
434 LLDB_LOG(log,
"WaitForDebugEventEx loop completed, exiting.");
440 DWORD thread_id,
bool shutting_down) {
444 (info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ||
454 bool first_chance = (info.dwFirstChance != 0);
457 std::make_shared<ExceptionRecord>(info.ExceptionRecord, thread_id);
467 LLDB_LOG(log,
"encountered {0} chance exception {1:x} on thread {2:x}",
468 first_chance ?
"first" :
"second",
469 info.ExceptionRecord.ExceptionCode, thread_id);
482 LLDB_LOG(log,
"waiting for ExceptionPred != BreakInDebugger");
494 LLDB_LOG(log,
"Thread {0} spawned in process {1}", thread_id,
497 thread.GetNativeThread().SetOwnsHandle(
false);
510 static LazyImport<
decltype(&::NtQueryInformationProcess)>
511 s_query_information_process{L
"ntdll.dll",
"NtQueryInformationProcess"};
512 if (!s_query_information_process)
515 PROCESS_BASIC_INFORMATION pbi = {};
516 if ((*s_query_information_process)(process, ProcessBasicInformation, &pbi,
517 sizeof(pbi),
nullptr) < 0 ||
524 !peb.ProcessParameters)
527 RTL_USER_PROCESS_PARAMETERS params = {};
529 sizeof(params),
nullptr) ||
530 !params.ImagePathName.Buffer || params.ImagePathName.Length == 0)
533 std::wstring wpath(params.ImagePathName.Length /
sizeof(
wchar_t), L
'\0');
535 params.ImagePathName.Length,
nullptr))
539 if (!llvm::convertWideToUTF8(wpath, path))
549 uint32_t process_id = ::GetProcessId(info.hProcess);
551 LLDB_LOG(log,
"process {0} spawned", process_id);
553 std::string thread_name;
554 llvm::raw_string_ostream name_stream(thread_name);
555 name_stream <<
"lldb.plugin.process-windows.secondary[" << process_id <<
"]";
556 llvm::set_thread_name(thread_name);
581 LLDB_LOG(log,
"Thread {0} exited with code {1} in process {2}", thread_id,
582 info.dwExitCode,
GetProcess().GetProcessId());
599static std::optional<std::string>
603 llvm::SmallVector<wchar_t, MAX_PATH> vol_name(
MAX_PATH);
604 HANDLE vol_iter = ::FindFirstVolumeW(vol_name.data(), vol_name.size());
605 if (vol_iter == INVALID_HANDLE_VALUE) {
607 "ConvertNtDevicePathToDosPath: FindFirstVolumeW failed, "
612 llvm::scope_exit close_iter([&] { ::FindVolumeClose(vol_iter); });
617 size_t vol_len = ::wcsnlen(vol_name.data(), vol_name.size());
618 if (vol_len < 5 || vol_name[vol_len - 1] != L
'\\')
621 vol_name[vol_len - 1] = L
'\0';
622 llvm::SmallVector<wchar_t, MAX_PATH> dev_name(
MAX_PATH);
623 bool ok = ::QueryDosDeviceW(vol_name.data() + 4,
624 dev_name.data(), dev_name.size());
625 vol_name[vol_len - 1] = L
'\\';
630 size_t dev_len = ::wcsnlen(dev_name.data(), dev_name.size());
631 if (dev_len == 0 || dev_len >= nt_path.size())
633 if (_wcsnicmp(nt_path.data(), dev_name.data(), dev_len) != 0)
635 if (nt_path[dev_len] != L
'\\')
639 llvm::ArrayRef<wchar_t> mount(vol_name.data(), vol_len);
640 llvm::SmallVector<wchar_t> mount_names;
641 DWORD names_size = 0;
642 ::GetVolumePathNamesForVolumeNameW(vol_name.data(),
nullptr, 0,
644 if (names_size > 1) {
645 mount_names.resize(names_size);
647 if (::GetVolumePathNamesForVolumeNameW(
648 vol_name.data(), mount_names.data(), names_size, &written) &&
649 mount_names[0] != L
'\0') {
650 mount = llvm::ArrayRef<wchar_t>(
652 ::wcsnlen(mount_names.data(), mount_names.size()));
657 llvm::SmallVector<wchar_t> dos_wide(mount.begin(), mount.end());
658 if (!dos_wide.empty() && dos_wide.back() == L
'\\')
660 dos_wide.append(nt_path.begin() + dev_len, nt_path.end());
663 llvm::convertWideToUTF8(std::wstring_view(dos_wide.data(), dos_wide.size()),
666 }
while (::FindNextVolumeW(vol_iter, vol_name.data(), vol_name.size()));
668 LLDB_LOG(log,
"ConvertNtDevicePathToDosPath: no matching volume found");
676 std::vector<wchar_t> mapped_filename(
MAX_PATH + 1);
677 DWORD mapped_len = 0;
679 mapped_len = ::GetMappedFileNameW(process, addr, mapped_filename.data(),
680 mapped_filename.size());
683 if (mapped_len < mapped_filename.size())
685 mapped_filename.resize(mapped_filename.size() * 2);
688 llvm::ArrayRef<wchar_t>(mapped_filename.data(), mapped_len + 1));
693 DWORD dwFileSizeHi = 0;
694 DWORD dwFileSizeLo = ::GetFileSize(hFile, &dwFileSizeHi);
695 if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
699 ::CreateFileMappingW(hFile,
nullptr, PAGE_READONLY, 0, 1,
nullptr),
704 auto view_deleter = [](
void *pMem) { ::UnmapViewOfFile(pMem); };
705 std::unique_ptr<void,
decltype(view_deleter)> pMem(
706 ::MapViewOfFile(filemap.
get(), FILE_MAP_READ, 0, 0, 1), view_deleter);
717 std::vector<wchar_t> module_filename(
MAX_PATH + 1);
720 ::GetModuleFileNameExW(process,
reinterpret_cast<HMODULE
>(base_addr),
721 module_filename.data(), module_filename.size());
724 if (len < module_filename.size()) {
725 std::string path_utf8;
726 llvm::convertWideToUTF8(std::wstring_view(module_filename.data(), len),
730 module_filename.resize(module_filename.size() * 2);
739 MEMORY_BASIC_INFORMATION mbi{};
740 if (!::VirtualQueryEx(process, addr, &mbi,
sizeof(mbi)))
742 if (mbi.State != MEM_COMMIT)
744 uintptr_t region_end =
745 reinterpret_cast<uintptr_t
>(mbi.BaseAddress) + mbi.RegionSize;
746 uintptr_t a =
reinterpret_cast<uintptr_t
>(addr);
747 assert(a < region_end);
748 return region_end - a;
755 std::vector<wchar_t> buf;
756 for (SIZE_T capacity =
MAX_PATH *
sizeof(
wchar_t);; capacity *= 2) {
757 SIZE_T to_read = std::min<SIZE_T>(capacity, limit);
758 to_read &= ~SIZE_T(1);
759 if (to_read <
sizeof(
wchar_t))
762 buf.resize(to_read /
sizeof(
wchar_t));
763 SIZE_T bytes_read = 0;
767 size_t max_chars = bytes_read /
sizeof(wchar_t);
768 size_t len = ::wcsnlen(buf.data(), max_chars);
769 if (len < max_chars) {
773 llvm::convertWideToUTF8(std::wstring_view(buf.data(), len), result);
776 if (to_read >= limit)
785 std::vector<char> buf;
786 for (SIZE_T capacity =
MAX_PATH;; capacity *= 2) {
787 SIZE_T to_read = std::min<SIZE_T>(capacity, limit);
792 SIZE_T bytes_read = 0;
796 size_t len = ::strnlen(buf.data(), bytes_read);
797 if (len < bytes_read) {
800 return std::string(buf.data(), len);
802 if (to_read >= limit)
808static std::optional<std::string>
810 if (info.lpImageName ==
nullptr)
813 LPVOID string_addr =
nullptr;
814 SIZE_T bytes_read = 0;
816 sizeof(string_addr), &bytes_read) ||
817 bytes_read !=
sizeof(string_addr))
831 auto on_load_dll = [&](llvm::StringRef path) {
836 LLDB_LOG(log,
"Inferior {0} - DLL '{1}' loaded at address {2:x}...",
837 GetProcess().GetProcessId(), path, info.lpBaseOfDll);
847 std::optional<std::string> loader_path =
849 if (loader_path && !llvm::sys::path::is_absolute(
850 *loader_path, llvm::sys::path::Style::windows))
858 std::optional<std::string> file_path;
859 if (info.hFile !=
nullptr) {
860 std::vector<wchar_t> buffer(1);
861 DWORD required_size =
862 GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
863 if (required_size > 0) {
864 buffer.resize(required_size + 1);
865 GetFinalPathNameByHandleW(info.hFile, &buffer[0], required_size,
867 std::string path_str_utf8;
868 llvm::convertWideToUTF8(buffer.data(), path_str_utf8);
878 std::optional<std::string> resolved_path = loader_path;
879 if (!resolved_path ||
881 llvm::StringRef(*file_path).equals_insensitive(*resolved_path)))
882 resolved_path = file_path;
889 on_load_dll(*resolved_path);
892 "Inferior {0} - could not resolve path for LOAD_DLL_DEBUG_EVENT "
893 "(hFile={1}, base={2:x}, last error={3})",
894 GetProcess().GetProcessId(), info.hFile, info.lpBaseOfDll,
898 if (info.hFile !=
nullptr)
899 ::CloseHandle(info.hFile);
912 LLDB_LOG(log,
"process {0} unloading DLL at addr {1:x}.",
913 GetProcess().GetProcessId(), info.lpBaseOfDll);
917 reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll), thread_id);
930 reinterpret_cast<uintptr_t
>(info.lpDebugStringData)),
931 info.fUnicode == TRUE, info.nDebugStringLength);
938 LLDB_LOG(log,
"encountered error {0} (type={1}) in process {2} thread {3}",
939 info.dwError, info.dwType,
GetProcess().GetProcessId(), thread_id);
static llvm::raw_ostream & error(Stream &strm)
static std::optional< std::string > GetLoaderModuleName(HANDLE process, LPVOID base_addr)
The path the loader recorded for the module at base_addr, or nullopt if the loader's module list has ...
static std::optional< std::string > GetMappedFileDosPath(HANDLE process, LPVOID addr)
static SIZE_T BytesReadableAt(HANDLE process, LPCVOID addr)
static std::optional< std::string > GetImagePathFromPEB(HANDLE process)
Read the path the process was created with from its process parameters (PEB::ProcessParameters->Image...
static WaitForDebugEventFn * g_wait_for_debug_event
static std::optional< std::string > GetFileNameFromImageNameField(HANDLE process, const LOAD_DLL_DEBUG_INFO &info)
static std::optional< std::string > GetFileNameFromHandleFallback(HANDLE hFile)
static std::optional< std::string > ConvertNtDevicePathToDosPath(llvm::ArrayRef< wchar_t > nt_path)
#define STATUS_WX86_BREAKPOINT
BOOL WINAPI WaitForDebugEventFn(LPDEBUG_EVENT, DWORD)
static std::optional< std::string > ReadRemotePathStringW(HANDLE process, LPCVOID addr)
static void InitializeWaitForDebugEvent()
WaitForDebugEventEx is only available on Windows 10+.
static std::optional< std::string > ReadRemotePathStringA(HANDLE process, LPCVOID addr)
static int ReadProcessMemory(uint8_t *buffer, size_t size, const pt_asid *, uint64_t pc, void *context)
Callback used by libipt for reading the process memory.
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOG_VERBOSE(log,...)
std::atomic< bool > m_is_shutting_down
std::atomic< DWORD > m_pid_to_detach
void ContinueAsyncDllEvent()
Release a HandleLoadDllEvent / HandleUnloadDllEvent that is parked on m_dll_event_pred.
Predicate< bool > m_dll_event_pred
DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id)
DWORD HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id)
DWORD HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
DWORD HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id)
Status StopDebugging(bool terminate)
DWORD HandleRipEvent(const RIP_INFO &info, DWORD thread_id)
void ContinueAsyncException(ExceptionResult result)
HostProcess GetProcess() const
lldb::thread_result_t DebuggerThreadAttachRoutine(lldb::pid_t pid, const ProcessAttachInfo &launch_info)
DebuggerThread(DebugDelegateSP debug_delegate)
void FreeProcessHandles()
ExceptionRecordSP GetActiveException()
Returns the exception the debug loop is currently reporting, or null if there is none.
void ReportDeferredStopAndWaitForResume()
Have the delegate report the stop it collected, then wait until the client resumes before taking the ...
virtual ~DebuggerThread()
DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id)
ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id, bool shutting_down)
Status DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info)
Guarded< HostProcess > m_process
lldb::thread_result_t DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info)
ExceptionRecordSP m_active_exception
Predicate< ExceptionResult > m_exception_pred
HANDLE m_debugging_ended_event
Status DebugLaunch(const ProcessLaunchInfo &launch_info)
DWORD HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
std::mutex m_active_exception_mutex
DebugDelegateSP m_debug_delegate
DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id)
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
lldb::process_t GetSystemHandle() const
void SetOwnsHandle(bool owns)
HostNativeProcessBase & GetNativeProcess()
lldb::pid_t GetProcessId() const
FileSpec & GetExecutableFile()
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) override
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
static llvm::Expected< HostThread > LaunchThread(llvm::StringRef name, std::function< lldb::thread_result_t()> thread_function, size_t min_stack_byte_size=0)
#define LLDB_INVALID_PROCESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::string StripExtendedLengthPrefix(llvm::StringRef path)
Convert an extended-length path to a regular DOS path: "\\?\C:\a" becomes "C:\a" and "\\?...
std::shared_ptr< IDebugDelegate > DebugDelegateSP
std::shared_ptr< ExceptionRecord > ExceptionRecordSP
@ eBroadcastNever
No broadcast will be sent when the value is modified.
@ eBroadcastAlways
Always send a broadcast when the value is modified.
@ eErrorTypeWin32
Standard Win32 error codes.