summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Windows/Common/ProcessWindows.cpp')
-rw-r--r--source/Plugins/Process/Windows/Common/ProcessWindows.cpp196
1 files changed, 108 insertions, 88 deletions
diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index a1c9cfaed41cb..b14081f76617d 100644
--- a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -77,8 +77,8 @@ std::string GetProcessExecutableName(DWORD pid) {
namespace lldb_private {
// We store a pointer to this class in the ProcessWindows, so that we don't
-// expose Windows-specific types and implementation details from a public header
-// file.
+// expose Windows-specific types and implementation details from a public
+// header file.
class ProcessWindowsData {
public:
ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) {
@@ -186,9 +186,9 @@ Status ProcessWindows::DoDetach(bool keep_stopped) {
StateType private_state;
{
// Acquire the lock only long enough to get the DebuggerThread.
- // StopDebugging() will trigger a call back into ProcessWindows which
- // will also acquire the lock. Thus we have to release the lock before
- // calling StopDebugging().
+ // StopDebugging() will trigger a call back into ProcessWindows which will
+ // also acquire the lock. Thus we have to release the lock before calling
+ // StopDebugging().
llvm::sys::ScopedLock lock(m_mutex);
private_state = GetPrivateState();
@@ -228,14 +228,22 @@ Status ProcessWindows::DoDetach(bool keep_stopped) {
Status ProcessWindows::DoLaunch(Module *exe_module,
ProcessLaunchInfo &launch_info) {
- // Even though m_session_data is accessed here, it is before a debugger thread
- // has been
- // kicked off. So there's no race conditions, and it shouldn't be necessary
- // to acquire
- // the mutex.
+ // Even though m_session_data is accessed here, it is before a debugger
+ // thread has been kicked off. So there's no race conditions, and it
+ // shouldn't be necessary to acquire the mutex.
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
Status result;
+
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+ namespace fs = llvm::sys::fs;
+ if (working_dir && (!working_dir.ResolvePath() ||
+ !fs::is_directory(working_dir.GetPath()))) {
+ result.SetErrorStringWithFormat("No such file or directory: %s",
+ working_dir.GetCString());
+ return result;
+ }
+
if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) {
StreamString stream;
stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can "
@@ -251,7 +259,6 @@ Status ProcessWindows::DoLaunch(Module *exe_module,
bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
m_session_data.reset(new ProcessWindowsData(stop_at_entry));
- SetPrivateState(eStateLaunching);
DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
m_session_data->m_debugger.reset(new DebuggerThread(delegate));
DebuggerThreadSP debugger = m_session_data->m_debugger;
@@ -276,12 +283,10 @@ Status ProcessWindows::DoLaunch(Module *exe_module,
launch_info.GetExecutableFile().GetPath());
// We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the
- // private state
- // should already be set to eStateStopped as a result of hitting the initial
- // breakpoint. If
- // it was not set, the breakpoint should have already been resumed from and
- // the private state
- // should already be eStateRunning.
+ // private state should already be set to eStateStopped as a result of
+ // hitting the initial breakpoint. If it was not set, the breakpoint should
+ // have already been resumed from and the private state should already be
+ // eStateRunning.
launch_info.SetProcessID(process.GetProcessId());
SetID(process.GetProcessId());
@@ -322,12 +327,10 @@ ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
LLDB_LOG(log, "successfully attached to process with pid={0}", process_id);
// We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the
- // private state
- // should already be set to eStateStopped as a result of hitting the initial
- // breakpoint. If
- // it was not set, the breakpoint should have already been resumed from and
- // the private state
- // should already be eStateRunning.
+ // private state should already be set to eStateStopped as a result of
+ // hitting the initial breakpoint. If it was not set, the breakpoint should
+ // have already been resumed from and the private state should already be
+ // eStateRunning.
SetID(process.GetProcessId());
return error;
}
@@ -346,22 +349,35 @@ Status ProcessWindows::DoResume() {
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.
+ // 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);
}
LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
+ bool failed = false;
for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
auto thread = std::static_pointer_cast<TargetThreadWindows>(
m_thread_list.GetThreadAtIndex(i));
- thread->DoResume();
+ Status result = thread->DoResume();
+ if (result.Fail()) {
+ failed = true;
+ LLDB_LOG(
+ log,
+ "Trying to resume thread at index {0}, but failed with error {1}.",
+ i, result);
+ }
}
- SetPrivateState(eStateRunning);
+ if (failed) {
+ error.SetErrorString("ProcessWindows::DoResume failed");
+ return error;
+ } else {
+ SetPrivateState(eStateRunning);
+ }
} else {
LLDB_LOG(log, "error: process %I64u is in state %u. Returning...",
m_session_data->m_debugger->GetProcess().GetProcessId(),
@@ -376,10 +392,9 @@ Status ProcessWindows::DoDestroy() {
StateType private_state;
{
// Acquire this lock inside an inner scope, only long enough to get the
- // DebuggerThread.
- // StopDebugging() will trigger a call back into ProcessWindows which will
- // acquire the lock
- // again, so we need to not deadlock.
+ // DebuggerThread. StopDebugging() will trigger a call back into
+ // ProcessWindows which will acquire the lock again, so we need to not
+ // deadlock.
llvm::sys::ScopedLock lock(m_mutex);
private_state = GetPrivateState();
@@ -461,8 +476,9 @@ void ProcessWindows::RefreshStateAfterStop() {
m_session_data->m_debugger->GetActiveException();
ExceptionRecordSP active_exception = exception_record.lock();
if (!active_exception) {
- LLDB_LOG(log, "there is no active exception in process {0}. Why is the "
- "process stopped?",
+ LLDB_LOG(log,
+ "there is no active exception in process {0}. Why is the "
+ "process stopped?",
m_session_data->m_debugger->GetProcess().GetProcessId());
return;
}
@@ -479,8 +495,9 @@ void ProcessWindows::RefreshStateAfterStop() {
const uint64_t pc = register_context->GetPC();
BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
if (site && site->ValidForThisThread(stop_thread.get())) {
- LLDB_LOG(log, "Single-stepped onto a breakpoint in process {0} at "
- "address {1:x} with breakpoint site {2}",
+ LLDB_LOG(log,
+ "Single-stepped onto a breakpoint in process {0} at "
+ "address {1:x} with breakpoint site {2}",
m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
site->GetID());
stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
@@ -502,22 +519,25 @@ void ProcessWindows::RefreshStateAfterStop() {
BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
if (site) {
- LLDB_LOG(log, "detected breakpoint in process {0} at address {1:x} with "
- "breakpoint site {2}",
+ LLDB_LOG(log,
+ "detected breakpoint in process {0} at address {1:x} with "
+ "breakpoint site {2}",
m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
site->GetID());
if (site->ValidForThisThread(stop_thread.get())) {
- LLDB_LOG(log, "Breakpoint site {0} is valid for this thread ({1:x}), "
- "creating stop info.",
+ LLDB_LOG(log,
+ "Breakpoint site {0} is valid for this thread ({1:x}), "
+ "creating stop info.",
site->GetID(), stop_thread->GetID());
stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
*stop_thread, site->GetID());
register_context->SetPC(pc);
} else {
- LLDB_LOG(log, "Breakpoint site {0} is not valid for this thread, "
- "creating empty stop info.",
+ LLDB_LOG(log,
+ "Breakpoint site {0} is not valid for this thread, "
+ "creating empty stop info.",
site->GetID());
}
stop_thread->SetStopInfo(stop_info);
@@ -558,8 +578,8 @@ bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
ModuleSP exe_module_sp(target_sp->GetExecutableModule());
if (exe_module_sp.get())
return exe_module_sp->GetFileSpec().Exists();
- // However, if there is no executable module, we return true since we might be
- // preparing to attach.
+ // However, if there is no executable module, we return true since we might
+ // be preparing to attach.
return true;
}
@@ -589,8 +609,8 @@ bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list,
}
}
- // Also add all the threads that are new since the last time we broke into the
- // debugger.
+ // Also add all the threads that are new since the last time we broke into
+ // the debugger.
for (const auto &thread_info : m_session_data->m_new_threads) {
ThreadSP thread(new TargetThreadWindows(*this, thread_info.second));
thread->SetID(thread_info.first);
@@ -639,8 +659,13 @@ size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
SIZE_T bytes_read = 0;
if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr,
buf, size, &bytes_read)) {
+ // Reading from the process can fail for a number of reasons - set the
+ // error code and make sure that the number of bytes read is set back to 0
+ // because in some scenarios the value of bytes_read returned from the API
+ // is garbage.
error.SetError(GetLastError(), eErrorTypeWin32);
LLDB_LOG(log, "reading failed with error: {0}", error);
+ bytes_read = 0;
}
return bytes_read;
}
@@ -699,11 +724,9 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
if (result == 0) {
if (::GetLastError() == ERROR_INVALID_PARAMETER) {
- // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with an
- // address
- // past the highest accessible address. We should return a range from the
- // vm_addr
- // to LLDB_INVALID_ADDRESS
+ // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with
+ // an address past the highest accessible address. We should return a
+ // range from the vm_addr to LLDB_INVALID_ADDRESS
info.GetRange().SetRangeBase(vm_addr);
info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
info.SetReadable(MemoryRegionInfo::eNo);
@@ -713,8 +736,9 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
return error;
} else {
error.SetError(::GetLastError(), eErrorTypeWin32);
- LLDB_LOG(log, "VirtualQueryEx returned error {0} while getting memory "
- "region info for address {1:x}",
+ LLDB_LOG(log,
+ "VirtualQueryEx returned error {0} while getting memory "
+ "region info for address {1:x}",
error, vm_addr);
return error;
}
@@ -744,10 +768,8 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
info.SetMapped(MemoryRegionInfo::eYes);
} else {
// In the unmapped case we need to return the distance to the next block of
- // memory.
- // VirtualQueryEx nearly does that except that it gives the distance from
- // the start
- // of the page containing vm_addr.
+ // memory. VirtualQueryEx nearly does that except that it gives the
+ // distance from the start of the page containing vm_addr.
SYSTEM_INFO data;
GetSystemInfo(&data);
DWORD page_offset = vm_addr % data.dwPageSize;
@@ -757,8 +779,9 @@ Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
}
error.SetError(::GetLastError(), eErrorTypeWin32);
- LLDB_LOGV(log, "Memory region info for address {0}: readable={1}, "
- "executable={2}, writable={3}",
+ LLDB_LOGV(log,
+ "Memory region info for address {0}: readable={1}, "
+ "executable={2}, writable={3}",
vm_addr, info.GetReadable(), info.GetExecutable(),
info.GetWritable());
return error;
@@ -779,7 +802,7 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) {
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
- TargetSP target = m_target_sp.lock();
+ TargetSP target = CalculateTarget();
if (target) {
ModuleSP executable_module = target->GetExecutableModule();
ModuleList unloaded_modules;
@@ -825,10 +848,9 @@ void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
GetTarget().ModulesDidLoad(loaded_modules);
// Add the main executable module to the list of pending module loads. We
- // can't call
- // GetTarget().ModulesDidLoad() here because we still haven't returned from
- // DoLaunch() / DoAttach() yet
- // so the target may not have set the process instance to `this` yet.
+ // can't call GetTarget().ModulesDidLoad() here because we still haven't
+ // returned from DoLaunch() / DoAttach() yet so the target may not have set
+ // the process instance to `this` yet.
llvm::sys::ScopedLock lock(m_mutex);
const HostThreadWindows &wmain_thread =
debugger->GetMainThread().GetNativeThread();
@@ -845,15 +867,14 @@ ProcessWindows::OnDebugException(bool first_chance,
// FIXME: Without this check, occasionally when running the test suite there
// is
// an issue where m_session_data can be null. It's not clear how this could
- // happen
- // but it only surfaces while running the test suite. In order to properly
- // diagnose
- // this, we probably need to first figure allow the test suite to print out
- // full
- // lldb logs, and then add logging to the process plugin.
+ // happen but it only surfaces while running the test suite. In order to
+ // properly diagnose this, we probably need to first figure allow the test
+ // suite to print out full lldb logs, and then add logging to the process
+ // plugin.
if (!m_session_data) {
- LLDB_LOG(log, "Debugger thread reported exception {0:x} at address {1:x}, "
- "but there is no session.",
+ LLDB_LOG(log,
+ "Debugger thread reported exception {0:x} at address {1:x}, "
+ "but there is no session.",
record.GetExceptionCode(), record.GetExceptionAddress());
return ExceptionResult::SendToApplication;
}
@@ -887,8 +908,9 @@ ProcessWindows::OnDebugException(bool first_chance,
SetPrivateState(eStateStopped);
break;
default:
- LLDB_LOG(log, "Debugger thread reported exception {0:x} at address {1:x} "
- "(first_chance={2})",
+ LLDB_LOG(log,
+ "Debugger thread reported exception {0:x} at address {1:x} "
+ "(first_chance={2})",
record.GetExceptionCode(), record.GetExceptionAddress(),
first_chance);
// For non-breakpoints, give the application a chance to handle the
@@ -929,9 +951,8 @@ void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
lldb::addr_t module_addr) {
// Confusingly, there is no Target::AddSharedModule. Instead, calling
- // GetSharedModule() with
- // a new module will add it to the module list and return a corresponding
- // ModuleSP.
+ // GetSharedModule() with a new module will add it to the module list and
+ // return a corresponding ModuleSP.
Status error;
ModuleSP module = GetTarget().GetSharedModule(module_spec, &error);
bool load_addr_changed = false;
@@ -961,17 +982,16 @@ void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
if (m_session_data->m_initial_stop_received) {
- // This happened while debugging. Do we shutdown the debugging session, try
- // to continue, or do something else?
- LLDB_LOG(log, "Error {0} occurred during debugging. Unexpected behavior "
- "may result. {1}",
+ // This happened while debugging. Do we shutdown the debugging session,
+ // try to continue, or do something else?
+ LLDB_LOG(log,
+ "Error {0} occurred during debugging. Unexpected behavior "
+ "may result. {1}",
error.GetError(), error);
} else {
// If we haven't actually launched the process yet, this was an error
- // launching the
- // process. Set the internal error and signal the initial stop event so
- // that the DoLaunch
- // method wakes up and returns a failure.
+ // launching the process. Set the internal error and signal the initial
+ // stop event so that the DoLaunch method wakes up and returns a failure.
m_session_data->m_launch_error = error;
::SetEvent(m_session_data->m_initial_stop_event);
LLDB_LOG(
@@ -1001,9 +1021,9 @@ Status ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger,
}
// The Windows page protection bits are NOT independent masks that can be
-// bitwise-ORed together. For example, PAGE_EXECUTE_READ is not
-// (PAGE_EXECUTE | PAGE_READ). To test for an access type, it's necessary to
-// test for any of the bits that provide that access type.
+// bitwise-ORed together. For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE
+// | PAGE_READ). To test for an access type, it's necessary to test for any of
+// the bits that provide that access type.
bool ProcessWindows::IsPageReadable(uint32_t protect) {
return (protect & PAGE_NOACCESS) == 0;
}