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))) {
174 LLDB_LOG(log,
"terminate = {0}, inferior={1}.", terminate, pid);
178 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(
223 GetProcess().GetNativeProcess().GetSystemHandle())) {
228 LLDB_LOG(log,
"waiting for detach from process {0} to complete.", pid);
231 if (wait_result != WAIT_OBJECT_0) {
233 LLDB_LOG(log,
"error: WaitForSingleObject({0}, 5000) returned {1}",
236 LLDB_LOG(log,
"detach from process {0} completed successfully.", pid);
238 if (!
error.Success()) {
239 LLDB_LOG(log,
"encountered an error while trying to stop process {0}. {1}",
259 LLDB_LOG(log,
"broadcasting for inferior process {0}.",
287 DEBUG_EVENT dbe = {};
288 bool should_debug =
true;
289 constexpr unsigned max_drained_events = 64;
290 unsigned drained_events = 0;
292 while (should_debug) {
295 if (draining && drained_events >= max_drained_events) {
296 LLDB_LOG(log,
"reporting the stop after taking {0} queued debug events",
317 DWORD continue_status = DBG_CONTINUE;
319 HANDLE exited_process =
nullptr;
320 switch (dbe.dwDebugEventCode) {
322 llvm_unreachable(
"Unhandled debug event code!");
323 case EXCEPTION_DEBUG_EVENT: {
325 dbe.u.Exception, dbe.dwThreadId, shutting_down);
328 continue_status = DBG_CONTINUE;
330 continue_status = DBG_EXCEPTION_NOT_HANDLED;
334 case CREATE_THREAD_DEBUG_EVENT:
338 case CREATE_PROCESS_DEBUG_EVENT:
342 case EXIT_THREAD_DEBUG_EVENT:
346 case EXIT_PROCESS_DEBUG_EVENT:
347 if (!::DuplicateHandle(::GetCurrentProcess(),
348 m_process.GetNativeProcess().GetSystemHandle(),
349 ::GetCurrentProcess(), &exited_process,
350 SYNCHRONIZE, FALSE, 0))
351 exited_process =
nullptr;
352 should_debug =
false;
354 case LOAD_DLL_DEBUG_EVENT:
357 case UNLOAD_DLL_DEBUG_EVENT:
360 case OUTPUT_DEBUG_STRING_EVENT:
361 continue_status =
HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
365 if (dbe.u.RipInfo.dwType == SLE_ERROR)
366 should_debug =
false;
371 log,
"calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.",
372 dbe.dwProcessId, dbe.dwThreadId, continue_status,
373 ::GetCurrentThreadId());
375 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
377 if (dbe.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) {
378 if (exited_process) {
379 ::WaitForSingleObject(exited_process, INFINITE);
380 ::CloseHandle(exited_process);
392 (dbe.u.Exception.ExceptionRecord.ExceptionCode ==
393 EXCEPTION_BREAKPOINT ||
394 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
397 "Breakpoint exception is cue to detach from process {0:x}",
406 continue_status = DBG_CONTINUE;
407 if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
408 !(dbe.u.Exception.ExceptionRecord.ExceptionCode ==
409 EXCEPTION_BREAKPOINT ||
410 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
412 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
413 EXCEPTION_SINGLE_STEP))
414 continue_status = DBG_EXCEPTION_NOT_HANDLED;
415 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId,
425 should_debug =
false;
427 LLDB_LOG(log,
"returned FALSE from WaitForDebugEventEx. Error = {0}",
430 should_debug =
false;
435 LLDB_LOG(log,
"WaitForDebugEventEx loop completed, exiting.");
441 DWORD thread_id,
bool shutting_down) {
445 (info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ||
455 bool first_chance = (info.dwFirstChance != 0);
458 std::make_shared<ExceptionRecord>(info.ExceptionRecord, thread_id);
468 LLDB_LOG(log,
"encountered {0} chance exception {1:x} on thread {2:x}",
469 first_chance ?
"first" :
"second",
470 info.ExceptionRecord.ExceptionCode, thread_id);
483 LLDB_LOG(log,
"waiting for ExceptionPred != BreakInDebugger");
495 LLDB_LOG(log,
"Thread {0} spawned in process {1}", thread_id,
498 thread.GetNativeThread().SetOwnsHandle(
false);
511 static LazyImport<
decltype(&::NtQueryInformationProcess)>
512 s_query_information_process{L
"ntdll.dll",
"NtQueryInformationProcess"};
513 if (!s_query_information_process)
516 PROCESS_BASIC_INFORMATION pbi = {};
517 if ((*s_query_information_process)(process, ProcessBasicInformation, &pbi,
518 sizeof(pbi),
nullptr) < 0 ||
525 !peb.ProcessParameters)
528 RTL_USER_PROCESS_PARAMETERS params = {};
530 sizeof(params),
nullptr) ||
531 !params.ImagePathName.Buffer || params.ImagePathName.Length == 0)
534 std::wstring wpath(params.ImagePathName.Length /
sizeof(
wchar_t), L
'\0');
536 params.ImagePathName.Length,
nullptr))
540 if (!llvm::convertWideToUTF8(wpath, path))
550 uint32_t process_id = ::GetProcessId(info.hProcess);
552 LLDB_LOG(log,
"process {0} spawned", process_id);
554 std::string thread_name;
555 llvm::raw_string_ostream name_stream(thread_name);
556 name_stream <<
"lldb.plugin.process-windows.secondary[" << process_id <<
"]";
557 llvm::set_thread_name(thread_name);
579 LLDB_LOG(log,
"Thread {0} exited with code {1} in process {2}", thread_id,
580 info.dwExitCode,
m_process.GetProcessId());
597static std::optional<std::string>
601 llvm::SmallVector<wchar_t, MAX_PATH> vol_name(
MAX_PATH);
602 HANDLE vol_iter = ::FindFirstVolumeW(vol_name.data(), vol_name.size());
603 if (vol_iter == INVALID_HANDLE_VALUE) {
605 "ConvertNtDevicePathToDosPath: FindFirstVolumeW failed, "
610 llvm::scope_exit close_iter([&] { ::FindVolumeClose(vol_iter); });
615 size_t vol_len = ::wcsnlen(vol_name.data(), vol_name.size());
616 if (vol_len < 5 || vol_name[vol_len - 1] != L
'\\')
619 vol_name[vol_len - 1] = L
'\0';
620 llvm::SmallVector<wchar_t, MAX_PATH> dev_name(
MAX_PATH);
621 bool ok = ::QueryDosDeviceW(vol_name.data() + 4,
622 dev_name.data(), dev_name.size());
623 vol_name[vol_len - 1] = L
'\\';
628 size_t dev_len = ::wcsnlen(dev_name.data(), dev_name.size());
629 if (dev_len == 0 || dev_len >= nt_path.size())
631 if (_wcsnicmp(nt_path.data(), dev_name.data(), dev_len) != 0)
633 if (nt_path[dev_len] != L
'\\')
637 llvm::ArrayRef<wchar_t> mount(vol_name.data(), vol_len);
638 llvm::SmallVector<wchar_t> mount_names;
639 DWORD names_size = 0;
640 ::GetVolumePathNamesForVolumeNameW(vol_name.data(),
nullptr, 0,
642 if (names_size > 1) {
643 mount_names.resize(names_size);
645 if (::GetVolumePathNamesForVolumeNameW(
646 vol_name.data(), mount_names.data(), names_size, &written) &&
647 mount_names[0] != L
'\0') {
648 mount = llvm::ArrayRef<wchar_t>(
650 ::wcsnlen(mount_names.data(), mount_names.size()));
655 llvm::SmallVector<wchar_t> dos_wide(mount.begin(), mount.end());
656 if (!dos_wide.empty() && dos_wide.back() == L
'\\')
658 dos_wide.append(nt_path.begin() + dev_len, nt_path.end());
661 llvm::convertWideToUTF8(std::wstring_view(dos_wide.data(), dos_wide.size()),
664 }
while (::FindNextVolumeW(vol_iter, vol_name.data(), vol_name.size()));
666 LLDB_LOG(log,
"ConvertNtDevicePathToDosPath: no matching volume found");
674 std::vector<wchar_t> mapped_filename(
MAX_PATH + 1);
675 DWORD mapped_len = 0;
677 mapped_len = ::GetMappedFileNameW(process, addr, mapped_filename.data(),
678 mapped_filename.size());
681 if (mapped_len < mapped_filename.size())
683 mapped_filename.resize(mapped_filename.size() * 2);
686 llvm::ArrayRef<wchar_t>(mapped_filename.data(), mapped_len + 1));
691 DWORD dwFileSizeHi = 0;
692 DWORD dwFileSizeLo = ::GetFileSize(hFile, &dwFileSizeHi);
693 if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
697 ::CreateFileMappingW(hFile,
nullptr, PAGE_READONLY, 0, 1,
nullptr),
702 auto view_deleter = [](
void *pMem) { ::UnmapViewOfFile(pMem); };
703 std::unique_ptr<void,
decltype(view_deleter)> pMem(
704 ::MapViewOfFile(filemap.
get(), FILE_MAP_READ, 0, 0, 1), view_deleter);
715 std::vector<wchar_t> module_filename(
MAX_PATH + 1);
718 ::GetModuleFileNameExW(process,
reinterpret_cast<HMODULE
>(base_addr),
719 module_filename.data(), module_filename.size());
722 if (len < module_filename.size()) {
723 std::string path_utf8;
724 llvm::convertWideToUTF8(std::wstring_view(module_filename.data(), len),
728 module_filename.resize(module_filename.size() * 2);
737 MEMORY_BASIC_INFORMATION mbi{};
738 if (!::VirtualQueryEx(process, addr, &mbi,
sizeof(mbi)))
740 if (mbi.State != MEM_COMMIT)
742 uintptr_t region_end =
743 reinterpret_cast<uintptr_t
>(mbi.BaseAddress) + mbi.RegionSize;
744 uintptr_t a =
reinterpret_cast<uintptr_t
>(addr);
745 assert(a < region_end);
746 return region_end - a;
753 std::vector<wchar_t> buf;
754 for (SIZE_T capacity =
MAX_PATH *
sizeof(
wchar_t);; capacity *= 2) {
755 SIZE_T to_read = std::min<SIZE_T>(capacity, limit);
756 to_read &= ~SIZE_T(1);
757 if (to_read <
sizeof(
wchar_t))
760 buf.resize(to_read /
sizeof(
wchar_t));
761 SIZE_T bytes_read = 0;
765 size_t max_chars = bytes_read /
sizeof(wchar_t);
766 size_t len = ::wcsnlen(buf.data(), max_chars);
767 if (len < max_chars) {
771 llvm::convertWideToUTF8(std::wstring_view(buf.data(), len), result);
774 if (to_read >= limit)
783 std::vector<char> buf;
784 for (SIZE_T capacity =
MAX_PATH;; capacity *= 2) {
785 SIZE_T to_read = std::min<SIZE_T>(capacity, limit);
790 SIZE_T bytes_read = 0;
794 size_t len = ::strnlen(buf.data(), bytes_read);
795 if (len < bytes_read) {
798 return std::string(buf.data(), len);
800 if (to_read >= limit)
806static std::optional<std::string>
808 if (info.lpImageName ==
nullptr)
811 LPVOID string_addr =
nullptr;
812 SIZE_T bytes_read = 0;
814 sizeof(string_addr), &bytes_read) ||
815 bytes_read !=
sizeof(string_addr))
829 auto on_load_dll = [&](llvm::StringRef path) {
834 LLDB_LOG(log,
"Inferior {0} - DLL '{1}' loaded at address {2:x}...",
835 m_process.GetProcessId(), path, info.lpBaseOfDll);
845 std::optional<std::string> loader_path =
847 if (loader_path && !llvm::sys::path::is_absolute(
848 *loader_path, llvm::sys::path::Style::windows))
856 std::optional<std::string> file_path;
857 if (info.hFile !=
nullptr) {
858 std::vector<wchar_t> buffer(1);
859 DWORD required_size =
860 GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
861 if (required_size > 0) {
862 buffer.resize(required_size + 1);
863 GetFinalPathNameByHandleW(info.hFile, &buffer[0], required_size,
865 std::string path_str_utf8;
866 llvm::convertWideToUTF8(buffer.data(), path_str_utf8);
876 std::optional<std::string> resolved_path = loader_path;
877 if (!resolved_path ||
879 llvm::StringRef(*file_path).equals_insensitive(*resolved_path)))
880 resolved_path = file_path;
887 on_load_dll(*resolved_path);
890 "Inferior {0} - could not resolve path for LOAD_DLL_DEBUG_EVENT "
891 "(hFile={1}, base={2:x}, last error={3})",
892 m_process.GetProcessId(), info.hFile, info.lpBaseOfDll,
896 if (info.hFile !=
nullptr)
897 ::CloseHandle(info.hFile);
910 LLDB_LOG(log,
"process {0} unloading DLL at addr {1:x}.",
911 m_process.GetProcessId(), info.lpBaseOfDll);
915 reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll), thread_id);
928 reinterpret_cast<uintptr_t
>(info.lpDebugStringData)),
929 info.fUnicode == TRUE, info.nDebugStringLength);
936 LLDB_LOG(log,
"encountered error {0} (type={1}) in process {2} thread {3}",
937 info.dwError, info.dwType,
m_process.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)
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.
void SetOwnsHandle(bool owns)
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.