24#include "llvm/Support/ConvertUTF.h"
25#include "llvm/Support/Error.h"
47 static const std::string windows_prefix = []() {
50 UINT len = ::GetWindowsDirectoryW(buf,
MAX_PATH);
53 llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
55 if (!prefix.empty() && prefix.back() !=
'\\')
60 if (windows_prefix.empty())
67 return llvm::StringRef(normalized).starts_with_insensitive(windows_prefix);
79 MEMORY_BASIC_INFORMATION mbi = {};
80 if (::VirtualQueryEx(handle,
reinterpret_cast<LPCVOID
>(addr), &mbi,
81 sizeof(mbi)) !=
sizeof(mbi))
83 if (mbi.AllocationBase ==
nullptr)
89 DWORD len = ::GetModuleFileNameExW(
90 handle,
reinterpret_cast<HMODULE
>(mbi.AllocationBase), module_path,
95 std::string path_utf8;
96 llvm::convertWideToUTF8(std::wstring_view(module_path, len), path_utf8);
108 if (protect & ePermissionsExecutable)
109 return PAGE_EXECUTE_READWRITE;
111 return PAGE_READWRITE;
119 return (protect & PAGE_NOACCESS) == 0;
123 return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY |
124 PAGE_READWRITE | PAGE_WRITECOPY)) != 0;
128 return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
129 PAGE_EXECUTE_WRITECOPY)) != 0;
132namespace lldb_private {
150 llvm::sys::ScopedLock lock(
m_mutex);
153 LLDB_LOG(log,
"there is no active session.");
162 LLDB_LOG(log,
"detaching from process {0}.",
163 debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
164 error = debugger_thread->StopDebugging(
false);
183 namespace fs = llvm::sys::fs;
188 "No such file or directory: %s", working_dir.
GetPath().c_str());
195 stream.
Printf(
"ProcessDebugger unable to launch '%s'. ProcessDebugger can "
196 "only be used for debug launches.",
198 std::string message = stream.
GetString().str();
201 LLDB_LOG(log,
"error: {0}", message);
205 bool stop_at_entry = launch_info.
GetFlags().
Test(eLaunchFlagStopAtEntry);
211 result = debugger->DebugLaunch(launch_info);
213 LLDB_LOG(log,
"failed launching '{0}'. {1}",
221 LLDB_LOG(log,
"failed launching '{0}'. {1}",
226 LLDB_LOG(log,
"successfully launched '{0}'",
249 DWORD process_id =
static_cast<DWORD
>(pid);
250 Status error = debugger->DebugAttach(process_id, attach_info);
254 "encountered an error occurred initiating the asynchronous attach. {0}",
263 "encountered an error waiting for the debugger to connect. {0}",
268 LLDB_LOG(log,
"successfully attached to process with pid={0}", process_id);
287 llvm::sys::ScopedLock lock(
m_mutex);
290 LLDB_LOG(log,
"warning: state = {0}, but there is no active session.",
299 LLDB_LOG(log,
"warning: cannot destroy process {0} while state = {1}.",
304 LLDB_LOG(log,
"Shutting down process {0}.",
305 debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle());
306 auto error = debugger_thread->StopDebugging(
true);
318 llvm::sys::ScopedLock lock(
m_mutex);
321 LLDB_LOG(log,
"HaltProcess called with no active session.");
323 "HaltProcess called with no active debugger session.");
325 caused_stop = ::DebugBreakProcess(
m_session_data->m_debugger->GetProcess()
330 LLDB_LOG(log,
"DebugBreakProcess failed with error {0}",
error);
337 size_t &bytes_read) {
341 llvm::sys::ScopedLock lock(
m_mutex);
345 "cannot read, there is no active debugger connection.");
350 LLDB_LOG(log,
"attempting to read {0} bytes from address {1:x}", size,
356 void *addr =
reinterpret_cast<void *
>(vm_addr);
357 SIZE_T num_of_bytes_read = 0;
359 bytes_read = num_of_bytes_read;
368 LLDB_LOG(log,
"retrying the read with size {0:x}", size);
370 LLDB_LOG(log,
"success: read {0:x} bytes", num_of_bytes_read);
371 bytes_read = num_of_bytes_read;
380 size_t size,
size_t &bytes_written) {
384 llvm::sys::ScopedLock lock(
m_mutex);
385 LLDB_LOG(log,
"attempting to write {0} bytes into address {1:x}", size,
390 "cannot write, there is no active debugger connection.");
396 void *addr =
reinterpret_cast<void *
>(vm_addr);
397 SIZE_T num_of_bytes_written = 0;
399 if (::WriteProcessMemory(handle, addr, buf, size, &num_of_bytes_written)) {
400 FlushInstructionCache(handle, addr, num_of_bytes_written);
401 bytes_written = num_of_bytes_written;
414 llvm::sys::ScopedLock lock(
m_mutex);
415 LLDB_LOG(log,
"attempting to allocate {0} bytes with permissions {1}", size,
420 "cannot allocate, there is no active debugger connection");
428 auto result = ::VirtualAllocEx(handle,
nullptr, size, MEM_COMMIT, protect);
433 addr =
reinterpret_cast<addr_t>(result);
442 llvm::sys::ScopedLock lock(
m_mutex);
443 LLDB_LOG(log,
"attempting to deallocate bytes at address {0:x}", vm_addr);
447 "cannot deallocate, there is no active debugger connection");
448 LLDB_LOG(log,
"error: {0}", result);
454 if (!::VirtualFreeEx(handle,
reinterpret_cast<LPVOID
>(vm_addr), 0,
457 LLDB_LOG(log,
"deallocating failed with error: {0}", result);
467 llvm::sys::ScopedLock lock(
m_mutex);
472 "GetMemoryRegionInfo called with no debugging session.");
480 "GetMemoryRegionInfo called with an invalid target process.");
485 LLDB_LOG(log,
"getting info for address {0:x}", vm_addr);
487 void *addr =
reinterpret_cast<void *
>(vm_addr);
488 MEMORY_BASIC_INFORMATION mem_info = {};
489 SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info,
sizeof(mem_info));
491 DWORD last_error = ::GetLastError();
492 if (last_error == ERROR_INVALID_PARAMETER) {
506 "VirtualQueryEx returned error {0} while getting memory "
507 "region info for address {1:x}",
514 if (mem_info.State == MEM_COMMIT) {
528 if (mem_info.State != MEM_FREE) {
530 reinterpret_cast<addr_t>(mem_info.BaseAddress));
532 mem_info.RegionSize);
539 ::GetSystemInfo(&data);
540 DWORD page_offset = vm_addr % data.dwPageSize;
547 "Memory region info for address {0:x}: readable={1}, "
548 "executable={2}, writable={3}",
560 "Process prematurely exited with {0:x}", exit_code);
571 llvm::sys::ScopedLock lock(
m_mutex);
580 "Debugger thread reported exception {0:x} at address {1:x}, but "
581 "there is no session.",
595 "Hit loader breakpoint at address {0:x}, setting initial stop event.",
624 uint16_t length_lower_word) {
630 bool is_unicode, uint16_t length_lower_word,
632 if (is_unicode && length_lower_word % 2 != 0)
633 return llvm::createStringError(
634 "Utf16 string can't have uneven size in bytes");
636 const auto is_zero_terminated = [&] {
639 return output.size() >= 2 && output.back() == 0 &&
640 output[output.size() - 2] == 0;
642 return !output.empty() && output.back() == 0;
650 size_t start = length_lower_word == 0 ? 1 : 0;
651 for (
size_t i = start; i < 16; ++i) {
652 output.resize_for_overwrite(length_lower_word + i * (1 << 16));
653 size_t chunk_size = i == 0 ? length_lower_word : (1 << 16);
654 lldb::addr_t addr = debug_string_addr + output.size_in_bytes() - chunk_size;
656 size_t bytes_read = 0;
658 ReadMemory(addr, output.end() - chunk_size, chunk_size, bytes_read);
660 return error.takeError();
662 if (bytes_read != chunk_size) {
663 return llvm::createStringErrorV(
664 "Expected to read {0} bytes, but read {1}", chunk_size, bytes_read);
667 if (is_zero_terminated())
671 if (!is_zero_terminated())
672 return llvm::createStringError(
"String is 1 MiB or larger");
675 output.pop_back_n(is_unicode ? 2 : 1);
676 return llvm::Error::success();
680 llvm::sys::ScopedLock lock(
m_mutex);
685 "OnDebuggerError called with no active session: error {0}: {1}",
694 "Error {0} occurred during debugging. Unexpected behavior "
704 "Error {0} occurred launching the process before the initial "
715 LLDB_LOG(log,
"Waiting for loader breakpoint.");
718 if (::WaitForSingleObject(
m_session_data->m_initial_stop_event, INFINITE) ==
720 LLDB_LOG(log,
"hit loader breakpoint, returning.");
722 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::string StripExtendedLengthPrefix(llvm::StringRef path)
Convert an extended-length path to a regular DOS path: "\\?\C:\a" becomes "C:\a" and "\\?...
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)