23#include "llvm/Support/ConvertUTF.h"
24#include "llvm/Support/Error.h"
46 static const std::string windows_prefix = []() {
49 UINT len = ::GetWindowsDirectoryW(buf,
MAX_PATH);
52 llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
54 if (!prefix.empty() && prefix.back() !=
'\\')
59 if (windows_prefix.empty())
62 std::string normalized = path.str();
64 return llvm::StringRef(normalized).starts_with_insensitive(windows_prefix);
76 MEMORY_BASIC_INFORMATION mbi = {};
77 if (::VirtualQueryEx(handle,
reinterpret_cast<LPCVOID
>(addr), &mbi,
78 sizeof(mbi)) !=
sizeof(mbi))
80 if (mbi.AllocationBase ==
nullptr)
86 DWORD len = ::GetModuleFileNameExW(
87 handle,
reinterpret_cast<HMODULE
>(mbi.AllocationBase), module_path,
92 std::string path_utf8;
93 llvm::convertWideToUTF8(std::wstring_view(module_path, len), path_utf8);
105 if (protect & ePermissionsExecutable)
106 return PAGE_EXECUTE_READWRITE;
108 return PAGE_READWRITE;
116 return (protect & PAGE_NOACCESS) == 0;
120 return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
121 PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
125 return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
126 PAGE_EXECUTE_WRITECOPY)) != 0;
129namespace lldb_private {
147 llvm::sys::ScopedLock lock(
m_mutex);
150 LLDB_LOG(log,
"there is no active session.");
159 LLDB_LOG(log,
"detaching from process {0}.",
160 debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
161 error = debugger_thread->StopDebugging(
false);
180 namespace fs = llvm::sys::fs;
185 "No such file or directory: %s", working_dir.
GetPath().c_str());
192 stream.
Printf(
"ProcessDebugger unable to launch '%s'. ProcessDebugger can "
193 "only be used for debug launches.",
195 std::string message = stream.
GetString().str();
198 LLDB_LOG(log,
"error: {0}", message);
202 bool stop_at_entry = launch_info.
GetFlags().
Test(eLaunchFlagStopAtEntry);
208 result = debugger->DebugLaunch(launch_info);
210 LLDB_LOG(log,
"failed launching '{0}'. {1}",
218 LLDB_LOG(log,
"failed launching '{0}'. {1}",
223 LLDB_LOG(log,
"successfully launched '{0}'",
246 DWORD process_id =
static_cast<DWORD
>(pid);
247 Status error = debugger->DebugAttach(process_id, attach_info);
251 "encountered an error occurred initiating the asynchronous attach. {0}",
260 "encountered an error waiting for the debugger to connect. {0}",
265 LLDB_LOG(log,
"successfully attached to process with pid={0}", process_id);
284 llvm::sys::ScopedLock lock(
m_mutex);
287 LLDB_LOG(log,
"warning: state = {0}, but there is no active session.",
296 LLDB_LOG(log,
"warning: cannot destroy process {0} while state = {1}.",
301 LLDB_LOG(log,
"Shutting down process {0}.",
302 debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
303 auto error = debugger_thread->StopDebugging(
true);
315 llvm::sys::ScopedLock lock(
m_mutex);
318 LLDB_LOG(log,
"HaltProcess called with no active session.");
320 "HaltProcess called with no active debugger session.");
322 caused_stop = ::DebugBreakProcess(
m_session_data->m_debugger->GetProcess()
327 LLDB_LOG(log,
"DebugBreakProcess failed with error {0}",
error);
334 size_t &bytes_read) {
338 llvm::sys::ScopedLock lock(
m_mutex);
342 "cannot read, there is no active debugger connection.");
347 LLDB_LOG(log,
"attempting to read {0} bytes from address {1:x}", size,
353 void *addr =
reinterpret_cast<void *
>(vm_addr);
354 SIZE_T num_of_bytes_read = 0;
356 bytes_read = num_of_bytes_read;
365 LLDB_LOG(log,
"retrying the read with size {0:x}", size);
367 LLDB_LOG(log,
"success: read {0:x} bytes", num_of_bytes_read);
368 bytes_read = num_of_bytes_read;
377 size_t size,
size_t &bytes_written) {
381 llvm::sys::ScopedLock lock(
m_mutex);
382 LLDB_LOG(log,
"attempting to write {0} bytes into address {1:x}", size,
387 "cannot write, there is no active debugger connection.");
393 void *addr =
reinterpret_cast<void *
>(vm_addr);
394 SIZE_T num_of_bytes_written = 0;
396 if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) {
397 FlushInstructionCache(handle, addr, num_of_bytes_written);
398 bytes_written = num_of_bytes_written;
411 llvm::sys::ScopedLock lock(
m_mutex);
412 LLDB_LOG(log,
"attempting to allocate {0} bytes with permissions {1}", size,
417 "cannot allocate, there is no active debugger connection");
425 auto result = ::VirtualAllocEx(handle,
nullptr, size, MEM_COMMIT, protect);
430 addr =
reinterpret_cast<addr_t>(result);
439 llvm::sys::ScopedLock lock(
m_mutex);
440 LLDB_LOG(log,
"attempting to deallocate bytes at address {0}", vm_addr);
444 "cannot deallocate, there is no active debugger connection");
445 LLDB_LOG(log,
"error: {0}", result);
451 if (!::VirtualFreeEx(handle,
reinterpret_cast<LPVOID
>(vm_addr), 0,
454 LLDB_LOG(log,
"deallocating failed with error: {0}", result);
464 llvm::sys::ScopedLock lock(
m_mutex);
469 "GetMemoryRegionInfo called with no debugging session.");
477 "GetMemoryRegionInfo called with an invalid target process.");
482 LLDB_LOG(log,
"getting info for address {0:x}", vm_addr);
484 void *addr =
reinterpret_cast<void *
>(vm_addr);
485 MEMORY_BASIC_INFORMATION mem_info = {};
486 SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info,
sizeof(mem_info));
488 DWORD last_error = ::GetLastError();
489 if (last_error == ERROR_INVALID_PARAMETER) {
503 "VirtualQueryEx returned error {0} while getting memory "
504 "region info for address {1:x}",
511 if (mem_info.State == MEM_COMMIT) {
525 if (mem_info.State != MEM_FREE) {
527 reinterpret_cast<addr_t>(mem_info.BaseAddress));
529 mem_info.RegionSize);
536 ::GetSystemInfo(&data);
537 DWORD page_offset = vm_addr % data.dwPageSize;
544 "Memory region info for address {0}: readable={1}, "
545 "executable={2}, writable={3}",
557 "Process prematurely exited with {0:x}", exit_code);
568 llvm::sys::ScopedLock lock(
m_mutex);
577 "Debugger thread reported exception {0:x} at address {1:x}, but "
578 "there is no session.",
592 "Hit loader breakpoint at address {0:x}, setting initial stop event.",
621 uint16_t length_lower_word) {
627 bool is_unicode, uint16_t length_lower_word,
629 if (is_unicode && length_lower_word % 2 != 0)
630 return llvm::createStringError(
631 "Utf16 string can't have uneven size in bytes");
633 const auto is_zero_terminated = [&] {
636 return output.size() >= 2 && output.back() == 0 &&
637 output[output.size() - 2] == 0;
639 return !output.empty() && output.back() == 0;
647 size_t start = length_lower_word == 0 ? 1 : 0;
648 for (
size_t i = start; i < 16; ++i) {
649 output.resize_for_overwrite(length_lower_word + i * (1 << 16));
650 size_t chunk_size = i == 0 ? length_lower_word : (1 << 16);
651 lldb::addr_t addr = debug_string_addr + output.size_in_bytes() - chunk_size;
653 size_t bytes_read = 0;
655 ReadMemory(addr, output.end() - chunk_size, chunk_size, bytes_read);
657 return error.takeError();
659 if (bytes_read != chunk_size) {
660 return llvm::createStringErrorV(
661 "Expected to read {0} bytes, but read {1}", chunk_size, bytes_read);
664 if (is_zero_terminated())
668 if (!is_zero_terminated())
669 return llvm::createStringError(
"String is 1 MiB or larger");
672 output.pop_back_n(is_unicode ? 2 : 1);
673 return llvm::Error::success();
677 llvm::sys::ScopedLock lock(
m_mutex);
682 "OnDebuggerError called with no active session: error {0}: {1}",
691 "Error {0} occurred during debugging. Unexpected behavior "
701 "Error {0} occurred launching the process before the initial "
712 LLDB_LOG(log,
"Waiting for loader breakpoint.");
715 if (::WaitForSingleObject(
m_session_data->m_initial_stop_event, INFINITE) ==
717 LLDB_LOG(log,
"hit loader breakpoint, returning.");
719 process = debugger->GetProcess();
static llvm::raw_ostream & error(Stream &strm)
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,...)
static bool IsPageExecutable(uint32_t protect)
static bool IsPageWritable(uint32_t protect)
static bool IsPageReadable(uint32_t protect)
static DWORD ConvertLldbToWinApiProtect(uint32_t protect)
static void NormalizeWindowsPathSeparators(std::string &s)
unsigned long GetExceptionValue() const
lldb::addr_t GetExceptionAddress() const
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
static FileSystem & Instance()
void Resolve(llvm::SmallVectorImpl< char > &path, bool force_make_absolute=false)
Resolve path to make it canonical.
bool Test(ValueType bit) const
Test a single flag bit.
lldb::process_t GetSystemHandle() const
HostNativeProcessBase & GetNativeProcess()
lldb::pid_t GetProcessId() const
LazyBool GetMapped() const
void SetReadable(LazyBool val)
LazyBool GetReadable() const
LazyBool GetExecutable() const
LazyBool GetWritable() const
void SetMapped(LazyBool val)
void SetExecutable(LazyBool val)
void SetWritable(LazyBool val)
bool GetContinueOnceAttached() const
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written)
Status DestroyProcess(lldb::StateType process_state)
Status LaunchProcess(ProcessLaunchInfo &launch_info, DebugDelegateSP delegate)
Status WaitForDebuggerConnection(DebuggerThreadSP debugger, HostProcess &process)
virtual DllEventAction OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id)
Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info)
virtual void OnCreateThread(const HostThread &thread)
virtual void OnDebuggerError(const Status &error, uint32_t type)
virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code)
virtual void OnDebuggerConnected(lldb::addr_t image_base)
std::unique_ptr< ProcessWindowsData > m_session_data
Status AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr)
virtual ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record)
Status AttachProcess(lldb::pid_t pid, const ProcessAttachInfo &attach_info, DebugDelegateSP delegate)
lldb::pid_t GetDebuggedProcessId() const
virtual void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, uint16_t length_lower_word)
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read)
bool IsSystemModuleAddress(lldb::addr_t addr)
virtual void OnExitProcess(uint32_t exit_code)
virtual DllEventAction OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id)
static bool IsSystemDLL(llvm::StringRef path)
llvm::Error ReadDebugString(lldb::addr_t debug_string_addr, bool is_unicode, uint16_t length_lower_word, llvm::SmallVectorImpl< char > &output)
Read an OUTPUT_DEBUG_STRING_INFO payload from the inferior.
Status HaltProcess(bool &caused_stop)
virtual ~ProcessDebugger()
Status DeallocateMemory(lldb::addr_t addr)
void SetProcessID(lldb::pid_t pid)
FileSpec & GetExecutableFile()
const FileSpec & GetWorkingDirectory() const
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
static Status FromErrorString(const char *str)
bool Fail() const
Test for error condition.
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_PROCESS_ID
#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::shared_ptr< DebuggerThread > DebuggerThreadSP
std::shared_ptr< IDebugDelegate > DebugDelegateSP
StateType
Process and Thread States.
@ eStateDetached
Process has been detached and can't be examined.
@ eStateExited
Process has exited and can't be examined.
@ eErrorTypeWin32
Standard Win32 error codes.
void SetRangeEnd(BaseType end)
void SetRangeBase(BaseType b)
Set the start value for the range, and keep the same size.
BaseType GetRangeEnd() const
void SetByteSize(SizeType s)