28#include "llvm/ADT/STLExtras.h"
29#include "llvm/Support/ConvertUTF.h"
30#include "llvm/Support/Threading.h"
31#include "llvm/Support/raw_ostream.h"
36#ifndef STATUS_WX86_BREAKPOINT
37#define STATUS_WX86_BREAKPOINT 0x4000001FL
57 "lldb.plugin.process-windows.secondary[?]",
59 if (!secondary_thread) {
61 LLDB_LOG(log,
"couldn't launch debugger thread. {0}", result);
70 LLDB_LOG(log,
"attaching to '{0}'", pid);
74 "lldb.plugin.process-windows.secondary[?]", [
this, pid, attach_info] {
77 if (!secondary_thread) {
79 LLDB_LOG(log,
"couldn't attach to process '{0}'. {1}", pid, result);
89 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
92 LLDB_LOG(log,
"preparing to launch '{0}' on background thread.",
116 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
119 LLDB_LOG(log,
"preparing to attach to process '{0}' on background thread.",
122 if (!DebugActiveProcess((DWORD)pid)) {
142 LLDB_LOG(log,
"terminate = {0}, inferior={1}.", terminate, pid);
146 bool expected =
false;
161 BOOL terminate_suceeded = TerminateProcess(handle, 0);
163 "calling TerminateProcess({0}, 0) (inferior={1}), success={2}",
164 handle, pid, terminate_suceeded);
167 "NOT calling TerminateProcess because the inferior is not valid "
168 "({0}, 0) (inferior={1})",
178 LLDB_LOG(log,
"masking active exception");
188 if (!::DebugBreakProcess(
189 GetProcess().GetNativeProcess().GetSystemHandle())) {
194 LLDB_LOG(log,
"waiting for detach from process {0} to complete.", pid);
197 if (wait_result != WAIT_OBJECT_0) {
199 LLDB_LOG(log,
"error: WaitForSingleObject({0}, 5000) returned {1}",
202 LLDB_LOG(log,
"detach from process {0} completed successfully.", pid);
204 if (!
error.Success()) {
205 LLDB_LOG(log,
"encountered an error while trying to stop process {0}. {1}",
216 LLDB_LOG(log,
"broadcasting for inferior process {0}.",
234 DEBUG_EVENT dbe = {};
235 bool should_debug =
true;
237 while (should_debug) {
239 BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE);
241 DWORD continue_status = DBG_CONTINUE;
243 switch (dbe.dwDebugEventCode) {
245 llvm_unreachable(
"Unhandle debug event code!");
246 case EXCEPTION_DEBUG_EVENT: {
248 dbe.u.Exception, dbe.dwThreadId, shutting_down);
251 continue_status = DBG_CONTINUE;
253 continue_status = DBG_EXCEPTION_NOT_HANDLED;
257 case CREATE_THREAD_DEBUG_EVENT:
261 case CREATE_PROCESS_DEBUG_EVENT:
265 case EXIT_THREAD_DEBUG_EVENT:
269 case EXIT_PROCESS_DEBUG_EVENT:
272 should_debug =
false;
274 case LOAD_DLL_DEBUG_EVENT:
277 case UNLOAD_DLL_DEBUG_EVENT:
280 case OUTPUT_DEBUG_STRING_EVENT:
281 continue_status =
HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
285 if (dbe.u.RipInfo.dwType == SLE_ERROR)
286 should_debug =
false;
291 log,
"calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.",
292 dbe.dwProcessId, dbe.dwThreadId, continue_status,
293 ::GetCurrentThreadId());
295 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
304 (dbe.u.Exception.ExceptionRecord.ExceptionCode ==
305 EXCEPTION_BREAKPOINT ||
306 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
309 "Breakpoint exception is cue to detach from process {0:x}",
317 while (WaitForDebugEvent(&dbe, 0)) {
318 continue_status = DBG_CONTINUE;
319 if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
320 !(dbe.u.Exception.ExceptionRecord.ExceptionCode ==
321 EXCEPTION_BREAKPOINT ||
322 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
324 dbe.u.Exception.ExceptionRecord.ExceptionCode ==
325 EXCEPTION_SINGLE_STEP))
326 continue_status = DBG_EXCEPTION_NOT_HANDLED;
327 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId,
337 should_debug =
false;
340 LLDB_LOG(log,
"returned FALSE from WaitForDebugEvent. Error = {0}",
343 should_debug =
false;
348 LLDB_LOG(log,
"WaitForDebugEvent loop completed, exiting.");
354 DWORD thread_id,
bool shutting_down) {
358 (info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ||
368 bool first_chance = (info.dwFirstChance != 0);
372 LLDB_LOG(log,
"encountered {0} chance exception {1:x} on thread {2:x}",
373 first_chance ?
"first" :
"second",
374 info.ExceptionRecord.ExceptionCode, thread_id);
380 LLDB_LOG(log,
"waiting for ExceptionPred != BreakInDebugger");
392 LLDB_LOG(log,
"Thread {0} spawned in process {1}", thread_id,
395 thread.GetNativeThread().SetOwnsHandle(
false);
404 uint32_t process_id = ::GetProcessId(info.hProcess);
406 LLDB_LOG(log,
"process {0} spawned", process_id);
408 std::string thread_name;
409 llvm::raw_string_ostream name_stream(thread_name);
410 name_stream <<
"lldb.plugin.process-windows.secondary[" << process_id <<
"]";
411 llvm::set_thread_name(thread_name);
431 LLDB_LOG(log,
"Thread {0} exited with code {1} in process {2}", thread_id,
432 info.dwExitCode,
m_process.GetProcessId());
451 DWORD dwFileSizeHi = 0;
452 DWORD dwFileSizeLo = ::GetFileSize(hFile, &dwFileSizeHi);
453 if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
457 ::CreateFileMappingW(hFile,
nullptr, PAGE_READONLY, 0, 1, NULL),
nullptr);
461 auto view_deleter = [](
void *pMem) { ::UnmapViewOfFile(pMem); };
462 std::unique_ptr<void,
decltype(view_deleter)> pMem(
463 ::MapViewOfFile(filemap.
get(), FILE_MAP_READ, 0, 0, 1), view_deleter);
467 std::array<wchar_t, MAX_PATH + 1> mapped_filename;
468 if (!::GetMappedFileNameW(::GetCurrentProcess(), pMem.get(),
469 mapped_filename.data(), mapped_filename.size()))
473 std::array<wchar_t, 512> drive_strings;
474 drive_strings[0] = L
'\0';
475 if (!::GetLogicalDriveStringsW(drive_strings.size(), drive_strings.data()))
478 std::array<wchar_t, 3> drive = {L
"_:"};
479 for (
const wchar_t *it = drive_strings.data(); *it != L
'\0';
480 it += wcslen(it) + 1) {
483 std::array<wchar_t, MAX_PATH> device_name;
484 if (::QueryDosDeviceW(drive.data(), device_name.data(),
485 device_name.size())) {
486 size_t device_name_len = wcslen(device_name.data());
487 if (device_name_len < mapped_filename.size()) {
488 bool match = _wcsnicmp(mapped_filename.data(), device_name.data(),
489 device_name_len) == 0;
490 if (match && mapped_filename[device_name_len] == L
'\\') {
492 std::wstring rebuilt_path(drive.data());
493 rebuilt_path.append(&mapped_filename[device_name_len]);
494 std::string path_utf8;
495 llvm::convertWideToUTF8(rebuilt_path, path_utf8);
508 if (info.hFile ==
nullptr) {
510 LLDB_LOG(log,
"Warning: Inferior {0} has a NULL file handle, returning...",
515 auto on_load_dll = [&](llvm::StringRef path) {
520 LLDB_LOG(log,
"Inferior {0} - DLL '{1}' loaded at address {2:x}...",
521 m_process.GetProcessId(), path, info.lpBaseOfDll);
526 std::vector<wchar_t> buffer(1);
527 DWORD required_size =
528 GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
529 if (required_size > 0) {
530 buffer.resize(required_size + 1);
531 required_size = GetFinalPathNameByHandleW(info.hFile, &buffer[0],
532 required_size, VOLUME_NAME_DOS);
533 std::string path_str_utf8;
534 llvm::convertWideToUTF8(buffer.data(), path_str_utf8);
535 llvm::StringRef path_str = path_str_utf8;
536 const char *path = path_str.data();
537 if (path_str.starts_with(
"\\\\?\\"))
541 }
else if (std::optional<std::string> path =
547 "Inferior {0} - Error {1} occurred calling GetFinalPathNameByHandle",
548 m_process.GetProcessId(), ::GetLastError());
551 ::CloseHandle(info.hFile);
559 LLDB_LOG(log,
"process {0} unloading DLL at addr {1:x}.",
560 m_process.GetProcessId(), info.lpBaseOfDll);
576 LLDB_LOG(log,
"encountered error {0} (type={1}) in process {2} thread {3}",
577 info.dwError, info.dwType,
m_process.GetProcessId(), thread_id);
static llvm::raw_ostream & error(Stream &strm)
static std::optional< std::string > GetFileNameFromHandleFallback(HANDLE hFile)
#define STATUS_WX86_BREAKPOINT
#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
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()
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)
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::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.
@ eBroadcastNever
No broadcast will be sent when the value is modified.
@ eBroadcastAlways
Always send a broadcast when the value is modified.
std::shared_ptr< IDebugDelegate > DebugDelegateSP
@ eErrorTypeWin32
Standard Win32 error codes.