29#include "llvm/ADT/StringRef.h"
30#include "llvm/Support/ConvertUTF.h"
31#include "llvm/Support/Errc.h"
32#include "llvm/Support/Error.h"
33#include "llvm/Support/Format.h"
34#include "llvm/Support/Threading.h"
35#include "llvm/Support/raw_ostream.h"
43#pragma warning(disable : 4005)
55void NormalizeWindowsPath(std::string &s) {
60 c = std::tolower(
static_cast<unsigned char>(c));
64bool IsSystemDLL(
const FileSpec &spec) {
68 static const std::string windows_prefix = []() {
71 UINT len = ::GetWindowsDirectoryW(buf,
MAX_PATH);
74 llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
75 NormalizeWindowsPath(prefix);
76 if (!prefix.empty() && prefix.back() !=
'\\')
81 if (windows_prefix.empty())
84 std::string path = spec.
GetPath();
85 NormalizeWindowsPath(path);
86 return llvm::StringRef(path).starts_with(windows_prefix);
100 ErrorAsOutParameter EOut(&E);
117 ErrorAsOutParameter EOut(&E);
129 E = createStringError(inconvertibleErrorCode(),
130 "Cannot get process information");
139 llvm::sys::ScopedLock lock(
m_mutex);
143 LLDB_LOG(log,
"process {0} is in state {1}. Resuming...",
150 for (uint32_t i = 0; i <
m_threads.size(); ++i) {
154 if (action ==
nullptr)
157 switch (action->
state) {
164 "Trying to resume thread at index {0}, but failed with "
176 "NativeProcessWindows::%s (): unexpected state %s specified "
177 "for pid %" PRIu64
", tid %" PRIu64,
192 if (active_exception) {
202 LLDB_LOG(log,
"error: process {0} is in state {1}. Returning...",
216 bool caused_stop =
false;
221 if (err.
Fail() || !caused_stop)
240 "error: process {0} in state = {1}, but "
241 "cannot detach it in this state.",
251 "Windows does not support sending signals to processes");
272 size_t size,
size_t &bytes_read) {
277 size_t size,
size_t &bytes_written) {
281llvm::Expected<lldb::addr_t>
312 std::string description) {
316 stop_info.
reason = reason;
325 thread.SetStopReason(stop_info, description);
330 std::string description) {
336 for (uint32_t i = 0; i <
m_threads.size(); ++i) {
339 LLDB_LOG(log,
"failed to stop thread {0}: {1}", t->GetID(),
error);
346llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
349 return llvm::errc::not_supported;
352llvm::Expected<llvm::ArrayRef<uint8_t>>
354 static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e,
356 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde};
359 case llvm::Triple::aarch64:
360 return llvm::ArrayRef(g_aarch64_opcode);
362 case llvm::Triple::arm:
363 case llvm::Triple::thumb:
364 return llvm::ArrayRef(g_thumb_opcode);
401 AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
GetID()));
404 me.dwSize =
sizeof(MODULEENTRY32W);
405 if (Module32FirstW(snapshot.
get(), &me)) {
408 if (!llvm::convertWideToUTF8(me.szExePath, path))
414 }
while (Module32Next(snapshot.
get(), &me));
431 FileSpec module_file_spec(module_path);
434 if (it.first == module_file_spec) {
435 file_spec = it.first;
440 "Module (%s) not found in process %" PRIu64
"!",
455 if (it.first == file_spec) {
456 load_addr = it.second;
461 "Can't get loaded address of file (%s) in process %" PRIu64
"!",
465llvm::Expected<std::vector<LoadedLibraryInfo>>
468 return error.ToError();
470 std::vector<LoadedLibraryInfo> libs;
474 info.
name = file_spec.GetPath();
476 libs.push_back(std::move(info));
487 LLDB_LOG(log,
"Process {0} exited with code {1}",
GetID(), exit_code);
505 LLDB_LOG(log,
"Debugger connected to process {0}. Image base = {1:x}",
518 LLDB_LOG(log,
"Cannot get process information during debugger connecting "
535 m_threads.push_back(std::make_unique<NativeThreadWindows>(
550 "received error while checking for watchpoint hits, pid = "
552 thread->GetID(),
error);
557 formatv(
"{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str();
576 auto ®_ctx = stop_thread->GetRegisterContext();
579 LLDB_LOG(log,
"Hit non-loader breakpoint at address {0:x}.",
596 if (args.size() >= 2) {
598 Status error = reg_ctx.GetWatchpointHitIndex(hw_id, args[1]);
601 "received error while checking for watchpoint hits, pid = "
607 formatv(
"{0} {1} {2}", reg_ctx.GetWatchpointAddress(hw_id), hw_id,
620 "Hit loader breakpoint at address {0:x}, setting initial stop "
643 "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
649 signal_info.
signo = 19;
652 for (uint32_t i = 0; i <
m_threads.size(); ++i) {
655 LLDB_LOG(log,
"Failed to stop thread {1:x}: {0}", t->GetID(),
662 injected->SetStopReason(signal_info,
"interrupt");
667 std::string desc = formatv(
"Exception {0:x8} encountered at address {1:x8}",
680 "Debugger thread reported exception {0:x} at address {1:x} "
681 "(first_chance={2})",
689 llvm::raw_string_ostream desc_stream(desc);
691 <<
" encountered at address "
693 record.
Dump(desc_stream);
704 llvm::sys::ScopedLock lock(
m_mutex);
709 case DWORD(STATUS_SINGLE_STEP):
710 case STATUS_WX86_SINGLE_STEP:
713 case DWORD(STATUS_BREAKPOINT):
729 llvm::sys::ScopedLock lock(
m_mutex);
731 auto thread = std::make_unique<NativeThreadWindows>(*
this, new_thread);
732 thread->GetRegisterContext().ClearAllHardwareWatchpoints();
743 LLDB_LOG(log,
"failed to suspend newly-created thread {0}: {1}",
744 thread->GetID(),
error);
748 thread->SetStopReason(stop_info,
"");
755 uint32_t exit_code) {
757 llvm::erase_if(
m_threads, [thread_id](
const auto &t) {
758 return t->GetID() == thread_id;
766 llvm::sys::ScopedLock lock(
m_mutex);
779 if (!resolved || IsSystemDLL(resolved))
783 if (!loader_thread && !
m_threads.empty()) {
784 LLDB_LOG(log,
"LOAD_DLL on unknown tid {0:x}. Falling back to main thread.",
791 LLDB_LOG(log,
"Failed to suspend thread {0} on LOAD_DLL.",
792 loader_thread->
GetID());
806 llvm::sys::ScopedLock lock(
m_mutex);
810 if (it->second == module_addr) {
811 unloaded_spec = it->first;
822 if (!unloaded_spec || IsSystemDLL(unloaded_spec))
826 if (!unloader_thread && !
m_threads.empty()) {
828 "UNLOAD_DLL on unknown tid {0:x}. Falling back to main thread.",
832 if (unloader_thread) {
835 LLDB_LOG(log,
"Failed to suspend thread {0} on UNLOAD_DLL.",
836 unloader_thread->
GetID());
848 uint16_t length_lower_word) {
851 llvm::SmallVector<char, 256> buffer;
853 debug_string_addr, is_unicode, length_lower_word, buffer)) {
854 std::string err_str = llvm::toString(std::move(err));
856 llvm::formatv(
"Failed to read debug string at {0:x} "
857 "(size & 0xffff={1}, unicode={2}): {3}\n",
858 debug_string_addr, length_lower_word, is_unicode, err_str)
861 m_delegate.NewProcessOutput(
this, llvm::StringRef(msg));
868 assert(buffer.size() % 2 == 0);
869 llvm::ArrayRef<unsigned short> utf16(
870 reinterpret_cast<const unsigned short *
>(buffer.data()),
873 if (!llvm::convertUTF16ToUTF8String(utf16, out)) {
874 LLDB_LOG(log,
"Debug string is not valid Utf 16");
877 m_delegate.NewProcessOutput(
this, llvm::StringRef(out.data(), out.size()));
880 llvm::StringRef(buffer.data(), buffer.size()));
884llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
888 Error E = Error::success();
889 auto process_up = std::unique_ptr<NativeProcessWindows>(
893 return std::move(process_up);
896llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
899 Error E = Error::success();
901 auto process_up = std::unique_ptr<NativeProcessWindows>(
905 return std::move(process_up);
915 std::make_unique<ConnectionConPTY>(
m_pty));
943 self->m_delegate.NewProcessOutput(
944 self, llvm::StringRef(
static_cast<const char *
>(src), src_len));
951 "no ConPTY connection on this NativeProcessWindows");
958 "ConPTY stdin write returned status {0}",
static_cast<int>(status));
static llvm::raw_ostream & error(Stream &strm)
#define STATUS_WX86_BREAKPOINT
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
lldb::tid_t GetThreadID() const
void Dump(llvm::raw_ostream &stream) const
unsigned long GetExceptionValue() const
llvm::ArrayRef< uint64_t > GetExceptionArguments() 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.
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info)
NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, NativeDelegate &delegate)
lldb::pid_t GetID() const
Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint)
virtual const NativeWatchpointList::WatchpointMap & GetWatchpointMap() const
lldb::StateType GetState() const
void SetState(lldb::StateType state, bool notify_delegates=true)
NativeThreadProtocol * GetThreadByID(lldb::tid_t tid)
void SetCurrentThreadID(lldb::tid_t tid)
std::recursive_mutex m_threads_mutex
std::vector< std::unique_ptr< NativeThreadProtocol > > m_threads
virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange)
void SetID(lldb::pid_t pid)
NativeDelegate & m_delegate
Status RemoveSoftwareBreakpoint(lldb::addr_t addr)
virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size)
virtual llvm::Expected< llvm::ArrayRef< uint8_t > > GetSoftwareBreakpointTrapOpcode(size_t size_hint)
virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr)
std::unordered_map< lldb::addr_t, SoftwareBreakpoint > m_software_breakpoints
llvm::Expected< std::unique_ptr< NativeProcessProtocol > > Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate) override
Launch a process for debugging.
llvm::Expected< std::unique_ptr< NativeProcessProtocol > > Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override
Attach to an existing process.
Status GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) override
ExceptionResult HandleBreakpointException(const ExceptionRecord &record)
llvm::Error DeallocateMemory(lldb::addr_t addr) override
Status Resume(const ResumeActionList &resume_actions) override
void OnCreateThread(const HostThread &thread) override
void OnExitProcess(uint32_t exit_code) override
Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) override
void StartStdioForwarding()
Wire up m_stdio_communication on m_pty's STDOUT HANDLE.
static void STDIOReadThreadBytesReceived(void *baton, const void *src, size_t src_len)
Bridge between m_stdio_communication's read thread and NativeDelegate::NewProcessOutput.
llvm::Expected< llvm::ArrayRef< uint8_t > > GetSoftwareBreakpointTrapOpcode(size_t size_hint) override
void OnDebuggerConnected(lldb::addr_t image_base) override
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) override
~NativeProcessWindows() override
NativeProcessWindows(ProcessLaunchInfo &launch_info, NativeDelegate &delegate, llvm::Error &E)
bool IsAlive() const override
Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override
Status CacheLoadedModules()
void StopStdioForwarding()
Tear down the read thread and disconnect m_stdio_communication.
size_t WriteStdin(const void *buf, size_t len, Status &error) override
Forward bytes from the gdb-remote I packet into the inferior's ConPTY-backed stdin via m_stdio_commun...
bool m_pending_halt
Set when Halt() / Interrupt() schedules a DebugBreakProcess injection.
ExceptionResult HandleGenericException(bool first_chance, const ExceptionRecord &record)
void SetArchitecture(const ArchSpec &arch_spec)
ExceptionResult OnDebugException(bool first_chance, const ExceptionRecord &record) override
void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, uint16_t length_lower_word) override
size_t GetSoftwareBreakpointPCOffset() override
Return the offset of the PC relative to the software breakpoint that was hit.
std::shared_ptr< PseudoConsole > m_pty
PseudoConsole for the lldb-server stdio-forwarding path.
ThreadedCommunication m_stdio_communication
Wraps a ConnectionConPTY around the PTY's parent-side STDOUT HANDLE.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > GetAuxvData() const override
DllEventAction OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) override
Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) override
NativeThreadWindows * GetThreadByID(lldb::tid_t thread_id)
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override
void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override
llvm::Expected< lldb::addr_t > AllocateMemory(size_t size, uint32_t permissions) override
DllEventAction OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override
Status Signal(int signo) override
Sends a process a UNIX signal signal.
Status RemoveBreakpoint(lldb::addr_t addr, bool hardware=false) override
const ArchSpec & GetArchitecture() const override
void SetStopReasonForThread(NativeThreadWindows &thread, lldb::StopReason reason, std::string description="")
Status Interrupt() override
Tells a process to interrupt all operations as if by a Ctrl-C.
bool FindSoftwareBreakpoint(lldb::addr_t addr)
void StopThread(lldb::tid_t thread_id, lldb::StopReason reason, std::string description="")
size_t UpdateThreads() override
ExceptionResult HandleSingleStepException(const ExceptionRecord &record)
bool m_client_supports_libraries_read
bool m_initial_stop_seen
Whether we've seen the loader breakpoint that fires once per process at launch / attach.
bool HasPendingLibraryEvents() override
bool m_pending_library_events
Set whenever an OS DLL load/unload event has been seen since the last stop reply.
llvm::Expected< std::vector< LoadedLibraryInfo > > GetLoadedLibraries() override
Return the currently loaded libraries of the target in the qXfer:libraries:read form (generic name + ...
lldb::addr_t GetSharedLibraryInfoAddress() override
Status IgnoreSignals(llvm::ArrayRef< int > signals) override
std::map< lldb_private::FileSpec, lldb::addr_t > m_loaded_modules
virtual Status GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
virtual lldb::addr_t GetWatchpointAddress(uint32_t wp_index)
virtual lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index)
lldb::tid_t GetID() const
void SetStopReason(ThreadStopInfo stop_info, std::string description)
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 GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info)
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
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read)
virtual void OnExitProcess(uint32_t exit_code)
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)
Status DeallocateMemory(lldb::addr_t addr)
void SetProcessID(lldb::pid_t pid)
FileSpec & GetExecutableFile()
ArchSpec & GetArchitecture()
std::shared_ptr< PTY > TakePTY()
A pseudo terminal helper class.
const ResumeAction * GetActionForThread(lldb::tid_t tid, bool default_ok) const
llvm::Error ToError() const
FIXME: Replace all uses with takeError() instead.
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)
bool Success() const
Test for success condition.
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_PROCESS_ID
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< IDebugDelegate > DebugDelegateSP
std::shared_ptr< ExceptionRecord > ExceptionRecordSP
const char * StateAsCString(lldb::StateType state)
Converts a StateType to a C string.
ConnectionStatus
Connection Status Types.
@ eConnectionStatusSuccess
Success.
StateType
Process and Thread States.
@ eStateUnloaded
Process is object is valid, but not currently loaded.
@ eStateDetached
Process has been detached and can't be examined.
@ eStateStopped
Process or thread is stopped and can be examined.
@ eStateSuspended
Process or thread is in a suspended state as far as the debugger is concerned while other processes o...
@ eStateRunning
Process or thread is running and can't be examined.
@ eStateExited
Process has exited and can't be examined.
@ eStateStepping
Process or thread is in the process of stepping and can not be examined.
@ eStateCrashed
Process or thread has crashed and can be examined.
@ eErrorTypeWin32
Standard Win32 error codes.
StopReason
Thread stop reasons.
Generic loaded-library entry used by the non-SVR4 qXfer:libraries:read form of the GDB remote library...
struct lldb_private::ThreadStopInfo::@116236113001137253323017204263037302160273237376::@034237007264067231263360140073224264215170222231 exception
union lldb_private::ThreadStopInfo::@116236113001137253323017204263037302160273237376 details