summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Windows
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:09:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:09:23 +0000
commitf73363f1dd94996356cefbf24388f561891acf0b (patch)
treee3c31248bdb36eaec5fd833490d4278162dba2a0 /source/Plugins/Process/Windows
parent160ee69dd7ae18978f4068116777639ea98dc951 (diff)
Notes
Diffstat (limited to 'source/Plugins/Process/Windows')
-rw-r--r--source/Plugins/Process/Windows/Common/CMakeLists.txt3
-rw-r--r--source/Plugins/Process/Windows/Common/DebuggerThread.cpp62
-rw-r--r--source/Plugins/Process/Windows/Common/ProcessWindows.cpp196
-rw-r--r--source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp76
-rw-r--r--source/Plugins/Process/Windows/Common/TargetThreadWindows.h7
-rw-r--r--source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp61
-rw-r--r--source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp29
7 files changed, 233 insertions, 201 deletions
diff --git a/source/Plugins/Process/Windows/Common/CMakeLists.txt b/source/Plugins/Process/Windows/Common/CMakeLists.txt
index 009a289bae399..0926290861833 100644
--- a/source/Plugins/Process/Windows/Common/CMakeLists.txt
+++ b/source/Plugins/Process/Windows/Common/CMakeLists.txt
@@ -1,6 +1,3 @@
-include_directories(.)
-include_directories(../../Utility)
-
set(PROC_WINDOWS_COMMON_SOURCES
DebuggerThread.cpp
LocalDebugDelegate.cpp
diff --git a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
index ac9e65c3c1083..ad43551a4c6db 100644
--- a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
+++ b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
@@ -112,8 +112,7 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine(void *data) {
lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine(
const ProcessLaunchInfo &launch_info) {
// Grab a shared_ptr reference to this so that we know it won't get deleted
- // until after the
- // thread routine has exited.
+ // until after the thread routine has exited.
std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
@@ -124,14 +123,11 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine(
ProcessLauncherWindows launcher;
HostProcess process(launcher.LaunchProcess(launch_info, error));
// If we couldn't create the process, notify waiters immediately. Otherwise
- // enter the debug
- // loop and wait until we get the create process debug notification. Note
- // that if the process
- // was created successfully, we can throw away the process handle we got from
- // CreateProcess
- // because Windows will give us another (potentially more useful?) handle when
- // it sends us the
- // CREATE_PROCESS_DEBUG_EVENT.
+ // enter the debug loop and wait until we get the create process debug
+ // notification. Note that if the process was created successfully, we can
+ // throw away the process handle we got from CreateProcess because Windows
+ // will give us another (potentially more useful?) handle when it sends us
+ // the CREATE_PROCESS_DEBUG_EVENT.
if (error.Success())
DebugLoop();
else
@@ -143,8 +139,7 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine(
lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine(
lldb::pid_t pid, const ProcessAttachInfo &attach_info) {
// Grab a shared_ptr reference to this so that we know it won't get deleted
- // until after the
- // thread routine has exited.
+ // until after the thread routine has exited.
std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
@@ -157,11 +152,9 @@ lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine(
return 0;
}
- // The attach was successful, enter the debug loop. From here on out, this is
- // no different than
- // a create process operation, so all the same comments in DebugLaunch should
- // apply from this
- // point out.
+ // The attach was successful, enter the debug loop. From here on out, this
+ // is no different than a create process operation, so all the same comments
+ // in DebugLaunch should apply from this point out.
DebugLoop();
return 0;
@@ -188,21 +181,25 @@ Status DebuggerThread::StopDebugging(bool terminate) {
lldb::process_t handle = m_process.GetNativeProcess().GetSystemHandle();
if (terminate) {
- // Initiate the termination before continuing the exception, so that the
- // next debug
- // event we get is the exit process event, and not some other event.
- BOOL terminate_suceeded = TerminateProcess(handle, 0);
- LLDB_LOG(log,
- "calling TerminateProcess({0}, 0) (inferior={1}), success={2}",
- handle, pid, terminate_suceeded);
+ if (handle != nullptr && handle != LLDB_INVALID_PROCESS) {
+ // Initiate the termination before continuing the exception, so that the
+ // next debug event we get is the exit process event, and not some other
+ // event.
+ BOOL terminate_suceeded = TerminateProcess(handle, 0);
+ LLDB_LOG(log,
+ "calling TerminateProcess({0}, 0) (inferior={1}), success={2}",
+ handle, pid, terminate_suceeded);
+ } else {
+ LLDB_LOG(log,
+ "NOT calling TerminateProcess because the inferior is not valid ({0}, 0) (inferior={1})",
+ handle, pid);
+ }
}
// If we're stuck waiting for an exception to continue (e.g. the user is at a
- // breakpoint
- // messing around in the debugger), continue it now. But only AFTER calling
- // TerminateProcess
- // to make sure that the very next call to WaitForDebugEvent is an exit
- // process event.
+ // breakpoint messing around in the debugger), continue it now. But only
+ // AFTER calling TerminateProcess to make sure that the very next call to
+ // WaitForDebugEvent is an exit process event.
if (m_active_exception.get()) {
LLDB_LOG(log, "masking active exception");
ContinueAsyncException(ExceptionResult::MaskException);
@@ -355,8 +352,7 @@ DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info,
}
// Don't perform any blocking operations while we're shutting down. That
- // will
- // cause TerminateProcess -> WaitForSingleObject to time out.
+ // will cause TerminateProcess -> WaitForSingleObject to time out.
return ExceptionResult::SendToApplication;
}
@@ -373,8 +369,8 @@ DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info,
m_exception_pred.SetValue(result, eBroadcastNever);
LLDB_LOG(log, "waiting for ExceptionPred != BreakInDebugger");
- m_exception_pred.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger,
- result);
+ result = *m_exception_pred.WaitForValueNotEqualTo(
+ ExceptionResult::BreakInDebugger);
LLDB_LOG(log, "got ExceptionPred = {0}", (int)m_exception_pred.GetValue());
return result;
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;
}
diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
index a4d60303877e0..3903280918cc8 100644
--- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
+++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp
@@ -16,10 +16,10 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h"
+#include "Plugins/Process/Utility/UnwindLLDB.h"
#include "ProcessWindows.h"
#include "ProcessWindowsLog.h"
#include "TargetThreadWindows.h"
-#include "UnwindLLDB.h"
#if defined(_WIN64)
#include "x64/RegisterContextWindows_x64.h"
@@ -33,7 +33,7 @@ using namespace lldb_private;
TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
const HostThread &thread)
: Thread(process, thread.GetNativeThread().GetThreadId()),
- m_host_thread(thread) {}
+ m_thread_reg_ctx_sp(), m_host_thread(thread) {}
TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); }
@@ -49,40 +49,53 @@ void TargetThreadWindows::DidStop() {}
RegisterContextSP TargetThreadWindows::GetRegisterContext() {
if (!m_reg_context_sp)
- m_reg_context_sp = CreateRegisterContextForFrameIndex(0);
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
return m_reg_context_sp;
}
RegisterContextSP
TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) {
- return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex());
-}
-
-RegisterContextSP
-TargetThreadWindows::CreateRegisterContextForFrameIndex(uint32_t idx) {
- if (!m_reg_context_sp) {
- ArchSpec arch = HostInfo::GetArchitecture();
- switch (arch.GetMachine()) {
- case llvm::Triple::x86:
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0) {
+ if (!m_thread_reg_ctx_sp) {
+ ArchSpec arch = HostInfo::GetArchitecture();
+ switch (arch.GetMachine()) {
+ case llvm::Triple::x86:
#if defined(_WIN64)
-// FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64
+ // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64
+ LLDB_LOG(log, "This is a Wow64 process, we should create a "
+ "RegisterContextWindows_Wow64, but we don't.");
#else
- m_reg_context_sp.reset(new RegisterContextWindows_x86(*this, idx));
+ m_thread_reg_ctx_sp.reset(
+ new RegisterContextWindows_x86(*this, concrete_frame_idx));
#endif
- break;
- case llvm::Triple::x86_64:
+ break;
+ case llvm::Triple::x86_64:
#if defined(_WIN64)
- m_reg_context_sp.reset(new RegisterContextWindows_x64(*this, idx));
+ m_thread_reg_ctx_sp.reset(
+ new RegisterContextWindows_x64(*this, concrete_frame_idx));
#else
-// LLDB is 32-bit, but the target process is 64-bit. We probably can't debug
-// this.
+ LLDB_LOG(log, "LLDB is 32-bit, but the target process is 64-bit.");
#endif
- default:
- break;
+ default:
+ break;
+ }
}
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ } else {
+ Unwind *unwinder = GetUnwinder();
+ if (unwinder != nullptr)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame);
}
- return m_reg_context_sp;
+
+ return reg_ctx_sp;
}
bool TargetThreadWindows::CalculateStopInfo() {
@@ -93,16 +106,16 @@ bool TargetThreadWindows::CalculateStopInfo() {
Unwind *TargetThreadWindows::GetUnwinder() {
// FIXME: Implement an unwinder based on the Windows unwinder exposed through
// DIA SDK.
- if (m_unwinder_ap.get() == NULL)
+ if (!m_unwinder_ap)
m_unwinder_ap.reset(new UnwindLLDB(*this));
return m_unwinder_ap.get();
}
-bool TargetThreadWindows::DoResume() {
+Status TargetThreadWindows::DoResume() {
StateType resume_state = GetTemporaryResumeState();
StateType current_state = GetState();
if (resume_state == current_state)
- return true;
+ return Status();
if (resume_state == eStateStepping) {
uint32_t flags_index =
@@ -118,8 +131,17 @@ bool TargetThreadWindows::DoResume() {
DWORD previous_suspend_count = 0;
HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
do {
+ // ResumeThread returns -1 on error, or the thread's *previous* suspend
+ // count on success. This means that the return value is 1 when the thread
+ // was restarted. Note that DWORD is an unsigned int, so we need to
+ // explicitly compare with -1.
previous_suspend_count = ::ResumeThread(thread_handle);
- } while (previous_suspend_count > 0);
+
+ if (previous_suspend_count == (DWORD)-1)
+ return Status(::GetLastError(), eErrorTypeWin32);
+
+ } while (previous_suspend_count > 1);
}
- return true;
+
+ return Status();
}
diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h
index 8b4e3dfdda4a9..952c0f55b57f3 100644
--- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h
+++ b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h
@@ -37,15 +37,14 @@ public:
bool CalculateStopInfo() override;
Unwind *GetUnwinder() override;
- bool DoResume();
+ Status DoResume();
HostThread GetHostThread() const { return m_host_thread; }
private:
- lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx);
-
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
HostThread m_host_thread;
};
-}
+} // namespace lldb_private
#endif
diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
index e64bade5ff907..4aa6c785f83c4 100644
--- a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
+++ b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp
@@ -14,9 +14,9 @@
#include "lldb/lldb-private-types.h"
#include "RegisterContextWindows_x64.h"
-#include "RegisterContext_x86.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
#include "TargetThreadWindows.h"
-#include "lldb-x86-register-enums.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
#include "llvm/ADT/STLExtras.h"
@@ -29,14 +29,11 @@ using namespace lldb_private;
namespace {
// This enum defines the layout of the global RegisterInfo array. This is
-// necessary because
-// lldb register sets are defined in terms of indices into the register array.
-// As such, the
-// order of RegisterInfos defined in global registers array must match the order
-// defined here.
-// When defining the register set layouts, these values can appear in an
-// arbitrary order, and that
-// determines the order that register values are displayed in a dump.
+// necessary because lldb register sets are defined in terms of indices into
+// the register array. As such, the order of RegisterInfos defined in global
+// registers array must match the order defined here. When defining the
+// register set layouts, these values can appear in an arbitrary order, and
+// that determines the order that register values are displayed in a dump.
enum RegisterIndex {
eRegisterIndexRax,
eRegisterIndexRbx,
@@ -44,6 +41,8 @@ enum RegisterIndex {
eRegisterIndexRdx,
eRegisterIndexRdi,
eRegisterIndexRsi,
+ eRegisterIndexRbp,
+ eRegisterIndexRsp,
eRegisterIndexR8,
eRegisterIndexR9,
eRegisterIndexR10,
@@ -52,8 +51,6 @@ enum RegisterIndex {
eRegisterIndexR13,
eRegisterIndexR14,
eRegisterIndexR15,
- eRegisterIndexRbp,
- eRegisterIndexRsp,
eRegisterIndexRip,
eRegisterIndexRflags
};
@@ -96,6 +93,16 @@ RegisterInfo g_register_infos[] = {
LLDB_INVALID_REGNUM, lldb_rsi_x86_64},
nullptr,
nullptr},
+ {DEFINE_GPR(rbp, "fp"),
+ {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP,
+ LLDB_INVALID_REGNUM, lldb_rbp_x86_64},
+ nullptr,
+ nullptr},
+ {DEFINE_GPR(rsp, "sp"),
+ {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP,
+ LLDB_INVALID_REGNUM, lldb_rsp_x86_64},
+ nullptr,
+ nullptr},
{DEFINE_GPR(r8, nullptr),
{dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM, lldb_r8_x86_64},
@@ -136,16 +143,6 @@ RegisterInfo g_register_infos[] = {
LLDB_INVALID_REGNUM, lldb_r15_x86_64},
nullptr,
nullptr},
- {DEFINE_GPR(rbp, "fp"),
- {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP,
- LLDB_INVALID_REGNUM, lldb_rbp_x86_64},
- nullptr,
- nullptr},
- {DEFINE_GPR(rsp, "sp"),
- {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP,
- LLDB_INVALID_REGNUM, lldb_rsp_x86_64},
- nullptr,
- nullptr},
{DEFINE_GPR(rip, "pc"),
{dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC,
LLDB_INVALID_REGNUM, lldb_rip_x86_64},
@@ -165,10 +162,10 @@ static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
uint32_t g_gpr_reg_indices[] = {
eRegisterIndexRax, eRegisterIndexRbx, eRegisterIndexRcx,
eRegisterIndexRdx, eRegisterIndexRdi, eRegisterIndexRsi,
- eRegisterIndexR8, eRegisterIndexR9, eRegisterIndexR10,
- eRegisterIndexR11, eRegisterIndexR12, eRegisterIndexR13,
- eRegisterIndexR14, eRegisterIndexR15, eRegisterIndexRbp,
- eRegisterIndexRsp, eRegisterIndexRip, eRegisterIndexRflags};
+ eRegisterIndexRbp, eRegisterIndexRsp, eRegisterIndexR8,
+ eRegisterIndexR9, eRegisterIndexR10, eRegisterIndexR11,
+ eRegisterIndexR12, eRegisterIndexR13, eRegisterIndexR14,
+ eRegisterIndexR15, eRegisterIndexRip, eRegisterIndexRflags};
RegisterSet g_register_sets[] = {
{"General Purpose Registers", "gpr",
@@ -209,6 +206,9 @@ bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info,
if (!CacheAllRegisterValues())
return false;
+ if (reg_info == nullptr)
+ return false;
+
switch (reg_info->kinds[eRegisterKindLLDB]) {
case lldb_rax_x86_64:
reg_value.SetUInt64(m_context.Rax);
@@ -270,11 +270,10 @@ bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info,
bool RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) {
- // Since we cannot only write a single register value to the inferior, we need
- // to make sure
- // our cached copy of the register values are fresh. Otherwise when writing
- // EAX, for example,
- // we may also overwrite some other register with a stale value.
+ // Since we cannot only write a single register value to the inferior, we
+ // need to make sure our cached copy of the register values are fresh.
+ // Otherwise when writing EAX, for example, we may also overwrite some other
+ // register with a stale value.
if (!CacheAllRegisterValues())
return false;
diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
index f56836de4a673..fd486f3d08298 100644
--- a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
+++ b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp
@@ -15,9 +15,9 @@
#include "ProcessWindowsLog.h"
#include "RegisterContextWindows_x86.h"
-#include "RegisterContext_x86.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
#include "TargetThreadWindows.h"
-#include "lldb-x86-register-enums.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
#include "llvm/ADT/STLExtras.h"
@@ -30,14 +30,11 @@ using namespace lldb_private;
namespace {
// This enum defines the layout of the global RegisterInfo array. This is
-// necessary because
-// lldb register sets are defined in terms of indices into the register array.
-// As such, the
-// order of RegisterInfos defined in global registers array must match the order
-// defined here.
-// When defining the register set layouts, these values can appear in an
-// arbitrary order, and that
-// determines the order that register values are displayed in a dump.
+// necessary because lldb register sets are defined in terms of indices into
+// the register array. As such, the order of RegisterInfos defined in global
+// registers array must match the order defined here. When defining the
+// register set layouts, these values can appear in an arbitrary order, and
+// that determines the order that register values are displayed in a dump.
enum RegisterIndex {
eRegisterIndexEax,
eRegisterIndexEbx,
@@ -179,6 +176,9 @@ bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info,
if (!CacheAllRegisterValues())
return false;
+ if (reg_info == nullptr)
+ return false;
+
uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
switch (reg) {
case lldb_eax_i386:
@@ -212,11 +212,10 @@ bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info,
bool RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) {
- // Since we cannot only write a single register value to the inferior, we need
- // to make sure
- // our cached copy of the register values are fresh. Otherwise when writing
- // EAX, for example,
- // we may also overwrite some other register with a stale value.
+ // Since we cannot only write a single register value to the inferior, we
+ // need to make sure our cached copy of the register values are fresh.
+ // Otherwise when writing EAX, for example, we may also overwrite some other
+ // register with a stale value.
if (!CacheAllRegisterValues())
return false;