diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:09:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:09:23 +0000 |
commit | f73363f1dd94996356cefbf24388f561891acf0b (patch) | |
tree | e3c31248bdb36eaec5fd833490d4278162dba2a0 /source/Plugins/Process/Windows | |
parent | 160ee69dd7ae18978f4068116777639ea98dc951 (diff) |
Notes
Diffstat (limited to 'source/Plugins/Process/Windows')
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 ®_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 ®_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; |