Summary: A *.cpp file header in LLDB (and in LLDB) should like this: ``` //===-- TestUtilities.cpp -------------------------------------------------===// ``` However in LLDB most of our source files have arbitrary changes to this format and these changes are spreading through LLDB as folks usually just use the existing source files as templates for their new files (most notably the unnecessary editor language indicator `-*- C++ -*-` is spreading and in every review someone is pointing out that this is wrong, resulting in people pointing out that this is done in the same way in other files). This patch removes most of these inconsistencies including the editor language indicators, all the different missing/additional '-' characters, files that center the file name, missing trailing `===//` (mostly caused by clang-format breaking the line). Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere Reviewed By: JDevlieghere Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D73258
603 lines
20 KiB
C++
603 lines
20 KiB
C++
//===-- NativeProcessWindows.cpp ------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Host/windows/windows.h"
|
|
#include <psapi.h>
|
|
|
|
#include "NativeProcessWindows.h"
|
|
#include "NativeThreadWindows.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostNativeProcessBase.h"
|
|
#include "lldb/Host/HostProcess.h"
|
|
#include "lldb/Host/ProcessLaunchInfo.h"
|
|
#include "lldb/Host/windows/AutoHandle.h"
|
|
#include "lldb/Host/windows/HostThreadWindows.h"
|
|
#include "lldb/Host/windows/ProcessLauncherWindows.h"
|
|
#include "lldb/Target/MemoryRegionInfo.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Utility/State.h"
|
|
#include "llvm/Support/ConvertUTF.h"
|
|
#include "llvm/Support/Errc.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/Threading.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "DebuggerThread.h"
|
|
#include "ExceptionRecord.h"
|
|
#include "ProcessWindowsLog.h"
|
|
|
|
#include <tlhelp32.h>
|
|
|
|
#pragma warning(disable : 4005)
|
|
#include "winternl.h"
|
|
#include <ntstatus.h>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace llvm;
|
|
|
|
namespace lldb_private {
|
|
|
|
NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
|
|
NativeDelegate &delegate,
|
|
llvm::Error &E)
|
|
: NativeProcessProtocol(LLDB_INVALID_PROCESS_ID,
|
|
launch_info.GetPTY().ReleaseMasterFileDescriptor(),
|
|
delegate),
|
|
ProcessDebugger(), m_arch(launch_info.GetArchitecture()) {
|
|
ErrorAsOutParameter EOut(&E);
|
|
DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
|
|
E = LaunchProcess(launch_info, delegate_sp).ToError();
|
|
if (E)
|
|
return;
|
|
|
|
SetID(GetDebuggedProcessId());
|
|
}
|
|
|
|
NativeProcessWindows::NativeProcessWindows(lldb::pid_t pid, int terminal_fd,
|
|
NativeDelegate &delegate,
|
|
llvm::Error &E)
|
|
: NativeProcessProtocol(pid, terminal_fd, delegate), ProcessDebugger() {
|
|
ErrorAsOutParameter EOut(&E);
|
|
DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));
|
|
ProcessAttachInfo attach_info;
|
|
attach_info.SetProcessID(pid);
|
|
E = AttachProcess(pid, attach_info, delegate_sp).ToError();
|
|
if (E)
|
|
return;
|
|
|
|
SetID(GetDebuggedProcessId());
|
|
|
|
ProcessInstanceInfo info;
|
|
if (!Host::GetProcessInfo(pid, info)) {
|
|
E = createStringError(inconvertibleErrorCode(),
|
|
"Cannot get process information");
|
|
return;
|
|
}
|
|
m_arch = info.GetArchitecture();
|
|
}
|
|
|
|
Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {
|
|
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
|
|
Status error;
|
|
llvm::sys::ScopedLock lock(m_mutex);
|
|
|
|
StateType state = GetState();
|
|
if (state == eStateStopped || state == eStateCrashed) {
|
|
LLDB_LOG(log, "process {0} is in state {1}. Resuming...",
|
|
GetDebuggedProcessId(), state);
|
|
LLDB_LOG(log, "resuming {0} threads.", m_threads.size());
|
|
|
|
bool failed = false;
|
|
for (uint32_t i = 0; i < m_threads.size(); ++i) {
|
|
auto thread = static_cast<NativeThreadWindows *>(m_threads[i].get());
|
|
const ResumeAction *const action =
|
|
resume_actions.GetActionForThread(thread->GetID(), true);
|
|
if (action == nullptr)
|
|
continue;
|
|
|
|
switch (action->state) {
|
|
case eStateRunning:
|
|
case eStateStepping: {
|
|
Status result = thread->DoResume(action->state);
|
|
if (result.Fail()) {
|
|
failed = true;
|
|
LLDB_LOG(log,
|
|
"Trying to resume thread at index {0}, but failed with "
|
|
"error {1}.",
|
|
i, result);
|
|
}
|
|
break;
|
|
}
|
|
case eStateSuspended:
|
|
case eStateStopped:
|
|
llvm_unreachable("Unexpected state");
|
|
|
|
default:
|
|
return Status(
|
|
"NativeProcessWindows::%s (): unexpected state %s specified "
|
|
"for pid %" PRIu64 ", tid %" PRIu64,
|
|
__FUNCTION__, StateAsCString(action->state), GetID(),
|
|
thread->GetID());
|
|
}
|
|
}
|
|
|
|
if (failed) {
|
|
error.SetErrorString("NativeProcessWindows::DoResume failed");
|
|
} else {
|
|
SetState(eStateRunning);
|
|
}
|
|
|
|
// Resume the debug loop.
|
|
ExceptionRecordSP active_exception =
|
|
m_session_data->m_debugger->GetActiveException().lock();
|
|
if (active_exception) {
|
|
// Resume the process and continue processing debug events. Mask the
|
|
// exception so that from the process's view, there is no indication that
|
|
// anything happened.
|
|
m_session_data->m_debugger->ContinueAsyncException(
|
|
ExceptionResult::MaskException);
|
|
}
|
|
} else {
|
|
LLDB_LOG(log, "error: process {0} is in state {1}. Returning...",
|
|
GetDebuggedProcessId(), GetState());
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
NativeThreadWindows *
|
|
NativeProcessWindows::GetThreadByID(lldb::tid_t thread_id) {
|
|
return static_cast<NativeThreadWindows *>(
|
|
NativeProcessProtocol::GetThreadByID(thread_id));
|
|
}
|
|
|
|
Status NativeProcessWindows::Halt() {
|
|
bool caused_stop = false;
|
|
StateType state = GetState();
|
|
if (state != eStateStopped)
|
|
return HaltProcess(caused_stop);
|
|
return Status();
|
|
}
|
|
|
|
Status NativeProcessWindows::Detach() {
|
|
Status error;
|
|
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
|
|
StateType state = GetState();
|
|
if (state != eStateExited && state != eStateDetached) {
|
|
error = DetachProcess();
|
|
if (error.Success())
|
|
SetState(eStateDetached);
|
|
else
|
|
LLDB_LOG(log, "Detaching process error: {0}", error);
|
|
} else {
|
|
error.SetErrorStringWithFormatv("error: process {0} in state = {1}, but "
|
|
"cannot detach it in this state.",
|
|
GetID(), state);
|
|
LLDB_LOG(log, "error: {0}", error);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
Status NativeProcessWindows::Signal(int signo) {
|
|
Status error;
|
|
error.SetErrorString("Windows does not support sending signals to processes");
|
|
return error;
|
|
}
|
|
|
|
Status NativeProcessWindows::Interrupt() { return Halt(); }
|
|
|
|
Status NativeProcessWindows::Kill() {
|
|
StateType state = GetState();
|
|
return DestroyProcess(state);
|
|
}
|
|
|
|
Status NativeProcessWindows::IgnoreSignals(llvm::ArrayRef<int> signals) {
|
|
return Status();
|
|
}
|
|
|
|
Status NativeProcessWindows::GetMemoryRegionInfo(lldb::addr_t load_addr,
|
|
MemoryRegionInfo &range_info) {
|
|
return ProcessDebugger::GetMemoryRegionInfo(load_addr, range_info);
|
|
}
|
|
|
|
Status NativeProcessWindows::ReadMemory(lldb::addr_t addr, void *buf,
|
|
size_t size, size_t &bytes_read) {
|
|
return ProcessDebugger::ReadMemory(addr, buf, size, bytes_read);
|
|
}
|
|
|
|
Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf,
|
|
size_t size, size_t &bytes_written) {
|
|
return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written);
|
|
}
|
|
|
|
Status NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions,
|
|
lldb::addr_t &addr) {
|
|
return ProcessDebugger::AllocateMemory(size, permissions, addr);
|
|
}
|
|
|
|
Status NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {
|
|
return ProcessDebugger::DeallocateMemory(addr);
|
|
}
|
|
|
|
lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; }
|
|
|
|
bool NativeProcessWindows::IsAlive() const {
|
|
StateType state = GetState();
|
|
switch (state) {
|
|
case eStateCrashed:
|
|
case eStateDetached:
|
|
case eStateExited:
|
|
case eStateInvalid:
|
|
case eStateUnloaded:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void NativeProcessWindows::SetStopReasonForThread(NativeThreadWindows &thread,
|
|
lldb::StopReason reason,
|
|
std::string description) {
|
|
SetCurrentThreadID(thread.GetID());
|
|
|
|
ThreadStopInfo stop_info;
|
|
stop_info.reason = reason;
|
|
|
|
// No signal support on Windows but required to provide a 'valid' signum.
|
|
if (reason == StopReason::eStopReasonException) {
|
|
stop_info.details.exception.type = 0;
|
|
stop_info.details.exception.data_count = 0;
|
|
} else {
|
|
stop_info.details.signal.signo = SIGTRAP;
|
|
}
|
|
|
|
thread.SetStopReason(stop_info, description);
|
|
}
|
|
|
|
void NativeProcessWindows::StopThread(lldb::tid_t thread_id,
|
|
lldb::StopReason reason,
|
|
std::string description) {
|
|
NativeThreadWindows *thread = GetThreadByID(thread_id);
|
|
if (!thread)
|
|
return;
|
|
|
|
for (uint32_t i = 0; i < m_threads.size(); ++i) {
|
|
auto t = static_cast<NativeThreadWindows *>(m_threads[i].get());
|
|
Status error = t->DoStop();
|
|
if (error.Fail())
|
|
exit(1);
|
|
}
|
|
SetStopReasonForThread(*thread, reason, description);
|
|
}
|
|
|
|
size_t NativeProcessWindows::UpdateThreads() { return m_threads.size(); }
|
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
|
|
NativeProcessWindows::GetAuxvData() const {
|
|
// Not available on this target.
|
|
return llvm::errc::not_supported;
|
|
}
|
|
|
|
bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
|
|
auto it = m_software_breakpoints.find(addr);
|
|
if (it == m_software_breakpoints.end())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
Status NativeProcessWindows::SetBreakpoint(lldb::addr_t addr, uint32_t size,
|
|
bool hardware) {
|
|
if (hardware)
|
|
return SetHardwareBreakpoint(addr, size);
|
|
return SetSoftwareBreakpoint(addr, size);
|
|
}
|
|
|
|
Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,
|
|
bool hardware) {
|
|
if (hardware)
|
|
return RemoveHardwareBreakpoint(addr);
|
|
return RemoveSoftwareBreakpoint(addr);
|
|
}
|
|
|
|
Status NativeProcessWindows::CacheLoadedModules() {
|
|
Status error;
|
|
if (!m_loaded_modules.empty())
|
|
return Status();
|
|
|
|
// Retrieve loaded modules by a Target/Module free implemenation.
|
|
AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
|
|
if (snapshot.IsValid()) {
|
|
MODULEENTRY32W me;
|
|
me.dwSize = sizeof(MODULEENTRY32W);
|
|
if (Module32FirstW(snapshot.get(), &me)) {
|
|
do {
|
|
std::string path;
|
|
if (!llvm::convertWideToUTF8(me.szExePath, path))
|
|
continue;
|
|
|
|
FileSpec file_spec(path);
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr;
|
|
} while (Module32Next(snapshot.get(), &me));
|
|
}
|
|
|
|
if (!m_loaded_modules.empty())
|
|
return Status();
|
|
}
|
|
|
|
error.SetError(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);
|
|
return error;
|
|
}
|
|
|
|
Status NativeProcessWindows::GetLoadedModuleFileSpec(const char *module_path,
|
|
FileSpec &file_spec) {
|
|
Status error = CacheLoadedModules();
|
|
if (error.Fail())
|
|
return error;
|
|
|
|
FileSpec module_file_spec(module_path);
|
|
FileSystem::Instance().Resolve(module_file_spec);
|
|
for (auto &it : m_loaded_modules) {
|
|
if (it.first == module_file_spec) {
|
|
file_spec = it.first;
|
|
return Status();
|
|
}
|
|
}
|
|
return Status("Module (%s) not found in process %" PRIu64 "!",
|
|
module_file_spec.GetCString(), GetID());
|
|
}
|
|
|
|
Status
|
|
NativeProcessWindows::GetFileLoadAddress(const llvm::StringRef &file_name,
|
|
lldb::addr_t &load_addr) {
|
|
Status error = CacheLoadedModules();
|
|
if (error.Fail())
|
|
return error;
|
|
|
|
load_addr = LLDB_INVALID_ADDRESS;
|
|
FileSpec file_spec(file_name);
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
for (auto &it : m_loaded_modules) {
|
|
if (it.first == file_spec) {
|
|
load_addr = it.second;
|
|
return Status();
|
|
}
|
|
}
|
|
return Status("Can't get loaded address of file (%s) in process %" PRIu64 "!",
|
|
file_spec.GetCString(), GetID());
|
|
}
|
|
|
|
void NativeProcessWindows::OnExitProcess(uint32_t exit_code) {
|
|
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
|
|
LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
|
|
|
|
ProcessDebugger::OnExitProcess(exit_code);
|
|
|
|
// No signal involved. It is just an exit event.
|
|
WaitStatus wait_status(WaitStatus::Exit, exit_code);
|
|
SetExitStatus(wait_status, true);
|
|
|
|
// Notify the native delegate.
|
|
SetState(eStateExited, true);
|
|
}
|
|
|
|
void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
|
|
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
|
|
LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",
|
|
GetDebuggedProcessId(), image_base);
|
|
|
|
// This is the earliest chance we can resolve the process ID and
|
|
// architecutre if we don't know them yet.
|
|
if (GetID() == LLDB_INVALID_PROCESS_ID)
|
|
SetID(GetDebuggedProcessId());
|
|
|
|
if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) {
|
|
ProcessInstanceInfo process_info;
|
|
if (!Host::GetProcessInfo(GetDebuggedProcessId(), process_info)) {
|
|
LLDB_LOG(log, "Cannot get process information during debugger connecting "
|
|
"to process");
|
|
return;
|
|
}
|
|
SetArchitecture(process_info.GetArchitecture());
|
|
}
|
|
|
|
// The very first one shall always be the main thread.
|
|
assert(m_threads.empty());
|
|
m_threads.push_back(std::make_unique<NativeThreadWindows>(
|
|
*this, m_session_data->m_debugger->GetMainThread()));
|
|
}
|
|
|
|
ExceptionResult
|
|
NativeProcessWindows::OnDebugException(bool first_chance,
|
|
const ExceptionRecord &record) {
|
|
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
|
|
llvm::sys::ScopedLock lock(m_mutex);
|
|
|
|
// Let the debugger establish the internal status.
|
|
ProcessDebugger::OnDebugException(first_chance, record);
|
|
|
|
static bool initial_stop = false;
|
|
if (!first_chance) {
|
|
SetState(eStateStopped, false);
|
|
}
|
|
|
|
ExceptionResult result = ExceptionResult::SendToApplication;
|
|
switch (record.GetExceptionCode()) {
|
|
case DWORD(STATUS_SINGLE_STEP):
|
|
case STATUS_WX86_SINGLE_STEP: {
|
|
uint32_t wp_id = LLDB_INVALID_INDEX32;
|
|
if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) {
|
|
NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext();
|
|
Status error =
|
|
reg_ctx.GetWatchpointHitIndex(wp_id, record.GetExceptionAddress());
|
|
if (error.Fail())
|
|
LLDB_LOG(log,
|
|
"received error while checking for watchpoint hits, pid = "
|
|
"{0}, error = {1}",
|
|
thread->GetID(), error);
|
|
if (wp_id != LLDB_INVALID_INDEX32) {
|
|
addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_id);
|
|
addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_id);
|
|
std::string desc =
|
|
formatv("{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str();
|
|
StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint,
|
|
desc);
|
|
}
|
|
}
|
|
if (wp_id == LLDB_INVALID_INDEX32)
|
|
StopThread(record.GetThreadID(), StopReason::eStopReasonTrace);
|
|
|
|
SetState(eStateStopped, true);
|
|
|
|
// Continue the debugger.
|
|
return ExceptionResult::MaskException;
|
|
}
|
|
case DWORD(STATUS_BREAKPOINT):
|
|
case STATUS_WX86_BREAKPOINT:
|
|
if (FindSoftwareBreakpoint(record.GetExceptionAddress())) {
|
|
LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
|
|
record.GetExceptionAddress());
|
|
|
|
StopThread(record.GetThreadID(), StopReason::eStopReasonBreakpoint);
|
|
|
|
if (NativeThreadWindows *stop_thread =
|
|
GetThreadByID(record.GetThreadID())) {
|
|
auto ®ister_context = stop_thread->GetRegisterContext();
|
|
// The current EIP is AFTER the BP opcode, which is one byte '0xCC'
|
|
uint64_t pc = register_context.GetPC() - 1;
|
|
register_context.SetPC(pc);
|
|
}
|
|
|
|
SetState(eStateStopped, true);
|
|
return ExceptionResult::MaskException;
|
|
}
|
|
|
|
if (!initial_stop) {
|
|
initial_stop = true;
|
|
LLDB_LOG(log,
|
|
"Hit loader breakpoint at address {0:x}, setting initial stop "
|
|
"event.",
|
|
record.GetExceptionAddress());
|
|
|
|
// We are required to report the reason for the first stop after
|
|
// launching or being attached.
|
|
if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID()))
|
|
SetStopReasonForThread(*thread, StopReason::eStopReasonBreakpoint);
|
|
|
|
// Do not notify the native delegate (e.g. llgs) since at this moment
|
|
// the program hasn't returned from Factory::Launch() and the delegate
|
|
// might not have an valid native process to operate on.
|
|
SetState(eStateStopped, false);
|
|
|
|
// Hit the initial stop. Continue the application.
|
|
return ExceptionResult::BreakInDebugger;
|
|
}
|
|
|
|
LLVM_FALLTHROUGH;
|
|
default:
|
|
LLDB_LOG(log,
|
|
"Debugger thread reported exception {0:x} at address {1:x} "
|
|
"(first_chance={2})",
|
|
record.GetExceptionCode(), record.GetExceptionAddress(),
|
|
first_chance);
|
|
|
|
{
|
|
std::string desc;
|
|
llvm::raw_string_ostream desc_stream(desc);
|
|
desc_stream << "Exception "
|
|
<< llvm::format_hex(record.GetExceptionCode(), 8)
|
|
<< " encountered at address "
|
|
<< llvm::format_hex(record.GetExceptionAddress(), 8);
|
|
StopThread(record.GetThreadID(), StopReason::eStopReasonException,
|
|
desc_stream.str().c_str());
|
|
|
|
SetState(eStateStopped, true);
|
|
}
|
|
|
|
// For non-breakpoints, give the application a chance to handle the
|
|
// exception first.
|
|
if (first_chance)
|
|
result = ExceptionResult::SendToApplication;
|
|
else
|
|
result = ExceptionResult::BreakInDebugger;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {
|
|
llvm::sys::ScopedLock lock(m_mutex);
|
|
|
|
auto thread = std::make_unique<NativeThreadWindows>(*this, new_thread);
|
|
thread->GetRegisterContext().ClearAllHardwareWatchpoints();
|
|
for (const auto &pair : GetWatchpointMap()) {
|
|
const NativeWatchpoint &wp = pair.second;
|
|
thread->SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags,
|
|
wp.m_hardware);
|
|
}
|
|
|
|
m_threads.push_back(std::move(thread));
|
|
}
|
|
|
|
void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id,
|
|
uint32_t exit_code) {
|
|
llvm::sys::ScopedLock lock(m_mutex);
|
|
NativeThreadWindows *thread = GetThreadByID(thread_id);
|
|
if (!thread)
|
|
return;
|
|
|
|
for (auto t = m_threads.begin(); t != m_threads.end();) {
|
|
if ((*t)->GetID() == thread_id) {
|
|
t = m_threads.erase(t);
|
|
} else {
|
|
++t;
|
|
}
|
|
}
|
|
}
|
|
|
|
void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
|
|
lldb::addr_t module_addr) {
|
|
// Simply invalidate the cached loaded modules.
|
|
if (!m_loaded_modules.empty())
|
|
m_loaded_modules.clear();
|
|
}
|
|
|
|
void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
|
|
if (!m_loaded_modules.empty())
|
|
m_loaded_modules.clear();
|
|
}
|
|
|
|
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
|
|
NativeProcessWindows::Factory::Launch(
|
|
ProcessLaunchInfo &launch_info,
|
|
NativeProcessProtocol::NativeDelegate &native_delegate,
|
|
MainLoop &mainloop) const {
|
|
Error E = Error::success();
|
|
auto process_up = std::unique_ptr<NativeProcessWindows>(
|
|
new NativeProcessWindows(launch_info, native_delegate, E));
|
|
if (E)
|
|
return std::move(E);
|
|
return std::move(process_up);
|
|
}
|
|
|
|
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
|
|
NativeProcessWindows::Factory::Attach(
|
|
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
|
MainLoop &mainloop) const {
|
|
Error E = Error::success();
|
|
// Set pty master fd invalid since it is not available.
|
|
auto process_up = std::unique_ptr<NativeProcessWindows>(
|
|
new NativeProcessWindows(pid, -1, native_delegate, E));
|
|
if (E)
|
|
return std::move(E);
|
|
return std::move(process_up);
|
|
}
|
|
} // namespace lldb_private
|