118a9135dSAdrian McCarthy //===-- TargetThreadWindows.cpp----------------------------------*- C++ -*-===//
218a9135dSAdrian McCarthy //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618a9135dSAdrian McCarthy //
718a9135dSAdrian McCarthy //===----------------------------------------------------------------------===//
818a9135dSAdrian McCarthy 
918a9135dSAdrian McCarthy #include "lldb/Host/HostInfo.h"
1018a9135dSAdrian McCarthy #include "lldb/Host/HostNativeThreadBase.h"
1118a9135dSAdrian McCarthy #include "lldb/Host/windows/HostThreadWindows.h"
1218a9135dSAdrian McCarthy #include "lldb/Host/windows/windows.h"
1318a9135dSAdrian McCarthy #include "lldb/Target/RegisterContext.h"
146f9e6901SZachary Turner #include "lldb/Utility/Log.h"
156f9e6901SZachary Turner #include "lldb/Utility/Logging.h"
16d821c997SPavel Labath #include "lldb/Utility/State.h"
1718a9135dSAdrian McCarthy 
1845d8134cSStella Stamenova #include "Plugins/Process/Utility/UnwindLLDB.h"
1918a9135dSAdrian McCarthy #include "ProcessWindows.h"
2018a9135dSAdrian McCarthy #include "ProcessWindowsLog.h"
21b9c1b51eSKate Stone #include "TargetThreadWindows.h"
2218a9135dSAdrian McCarthy 
234ad5def9SAdrian McCarthy #if defined(_WIN64)
2465abfb11SHafiz Abid Qadeer #include "x64/RegisterContextWindows_x64.h"
254ad5def9SAdrian McCarthy #else
264ad5def9SAdrian McCarthy #include "x86/RegisterContextWindows_x86.h"
274ad5def9SAdrian McCarthy #endif
284ad5def9SAdrian McCarthy 
2918a9135dSAdrian McCarthy using namespace lldb;
3018a9135dSAdrian McCarthy using namespace lldb_private;
3118a9135dSAdrian McCarthy 
32b9c1b51eSKate Stone TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
33b9c1b51eSKate Stone                                          const HostThread &thread)
34b9c1b51eSKate Stone     : Thread(process, thread.GetNativeThread().GetThreadId()),
3545d8134cSStella Stamenova       m_thread_reg_ctx_sp(), m_host_thread(thread) {}
3618a9135dSAdrian McCarthy 
37b9c1b51eSKate Stone TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); }
3818a9135dSAdrian McCarthy 
39b9c1b51eSKate Stone void TargetThreadWindows::RefreshStateAfterStop() {
4018a9135dSAdrian McCarthy   ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle());
4118a9135dSAdrian McCarthy   SetState(eStateStopped);
4218a9135dSAdrian McCarthy   GetRegisterContext()->InvalidateIfNeeded(false);
4318a9135dSAdrian McCarthy }
4418a9135dSAdrian McCarthy 
45b9c1b51eSKate Stone void TargetThreadWindows::WillResume(lldb::StateType resume_state) {}
4618a9135dSAdrian McCarthy 
47b9c1b51eSKate Stone void TargetThreadWindows::DidStop() {}
4818a9135dSAdrian McCarthy 
494ad5def9SAdrian McCarthy RegisterContextSP TargetThreadWindows::GetRegisterContext() {
504ad5def9SAdrian McCarthy   if (!m_reg_context_sp)
5145d8134cSStella Stamenova     m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
524ad5def9SAdrian McCarthy 
534ad5def9SAdrian McCarthy   return m_reg_context_sp;
544ad5def9SAdrian McCarthy }
554ad5def9SAdrian McCarthy 
564ad5def9SAdrian McCarthy RegisterContextSP
574ad5def9SAdrian McCarthy TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) {
5845d8134cSStella Stamenova   RegisterContextSP reg_ctx_sp;
5945d8134cSStella Stamenova   uint32_t concrete_frame_idx = 0;
6045d8134cSStella Stamenova   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
614ad5def9SAdrian McCarthy 
6245d8134cSStella Stamenova   if (frame)
6345d8134cSStella Stamenova     concrete_frame_idx = frame->GetConcreteFrameIndex();
6445d8134cSStella Stamenova 
6545d8134cSStella Stamenova   if (concrete_frame_idx == 0) {
6645d8134cSStella Stamenova     if (!m_thread_reg_ctx_sp) {
674ad5def9SAdrian McCarthy       ArchSpec arch = HostInfo::GetArchitecture();
684ad5def9SAdrian McCarthy       switch (arch.GetMachine()) {
694ad5def9SAdrian McCarthy       case llvm::Triple::x86:
704ad5def9SAdrian McCarthy #if defined(_WIN64)
714ad5def9SAdrian McCarthy         // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64
7245d8134cSStella Stamenova         LLDB_LOG(log, "This is a Wow64 process, we should create a "
7345d8134cSStella Stamenova                       "RegisterContextWindows_Wow64, but we don't.");
744ad5def9SAdrian McCarthy #else
7545d8134cSStella Stamenova         m_thread_reg_ctx_sp.reset(
7645d8134cSStella Stamenova             new RegisterContextWindows_x86(*this, concrete_frame_idx));
774ad5def9SAdrian McCarthy #endif
784ad5def9SAdrian McCarthy         break;
794ad5def9SAdrian McCarthy       case llvm::Triple::x86_64:
804ad5def9SAdrian McCarthy #if defined(_WIN64)
8145d8134cSStella Stamenova         m_thread_reg_ctx_sp.reset(
8245d8134cSStella Stamenova             new RegisterContextWindows_x64(*this, concrete_frame_idx));
834ad5def9SAdrian McCarthy #else
8445d8134cSStella Stamenova         LLDB_LOG(log, "LLDB is 32-bit, but the target process is 64-bit.");
854ad5def9SAdrian McCarthy #endif
864ad5def9SAdrian McCarthy       default:
874ad5def9SAdrian McCarthy         break;
884ad5def9SAdrian McCarthy       }
894ad5def9SAdrian McCarthy     }
9045d8134cSStella Stamenova     reg_ctx_sp = m_thread_reg_ctx_sp;
9145d8134cSStella Stamenova   } else {
9245d8134cSStella Stamenova     Unwind *unwinder = GetUnwinder();
9345d8134cSStella Stamenova     if (unwinder != nullptr)
9445d8134cSStella Stamenova       reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame);
9545d8134cSStella Stamenova   }
9645d8134cSStella Stamenova 
9745d8134cSStella Stamenova   return reg_ctx_sp;
984ad5def9SAdrian McCarthy }
994ad5def9SAdrian McCarthy 
100b9c1b51eSKate Stone bool TargetThreadWindows::CalculateStopInfo() {
10118a9135dSAdrian McCarthy   SetStopInfo(m_stop_info_sp);
10218a9135dSAdrian McCarthy   return true;
10318a9135dSAdrian McCarthy }
10418a9135dSAdrian McCarthy 
105b9c1b51eSKate Stone Unwind *TargetThreadWindows::GetUnwinder() {
106b9c1b51eSKate Stone   // FIXME: Implement an unwinder based on the Windows unwinder exposed through
107b9c1b51eSKate Stone   // DIA SDK.
10845d8134cSStella Stamenova   if (!m_unwinder_ap)
10918a9135dSAdrian McCarthy     m_unwinder_ap.reset(new UnwindLLDB(*this));
11018a9135dSAdrian McCarthy   return m_unwinder_ap.get();
11118a9135dSAdrian McCarthy }
11218a9135dSAdrian McCarthy 
1130fd67b53SStella Stamenova Status TargetThreadWindows::DoResume() {
11418a9135dSAdrian McCarthy   StateType resume_state = GetTemporaryResumeState();
11518a9135dSAdrian McCarthy   StateType current_state = GetState();
11618a9135dSAdrian McCarthy   if (resume_state == current_state)
1170fd67b53SStella Stamenova     return Status();
11818a9135dSAdrian McCarthy 
119b9c1b51eSKate Stone   if (resume_state == eStateStepping) {
120b9c1b51eSKate Stone     uint32_t flags_index =
121b9c1b51eSKate Stone         GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
122b9c1b51eSKate Stone             eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
123b9c1b51eSKate Stone     uint64_t flags_value =
124b9c1b51eSKate Stone         GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
12518a9135dSAdrian McCarthy     flags_value |= 0x100; // Set the trap flag on the CPU
12618a9135dSAdrian McCarthy     GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
12718a9135dSAdrian McCarthy   }
12818a9135dSAdrian McCarthy 
129b9c1b51eSKate Stone   if (resume_state == eStateStepping || resume_state == eStateRunning) {
13018a9135dSAdrian McCarthy     DWORD previous_suspend_count = 0;
13118a9135dSAdrian McCarthy     HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle();
132b9c1b51eSKate Stone     do {
13345d8134cSStella Stamenova       // ResumeThread returns -1 on error, or the thread's *previous* suspend
13445d8134cSStella Stamenova       // count on success. This means that the return value is 1 when the thread
13545d8134cSStella Stamenova       // was restarted. Note that DWORD is an unsigned int, so we need to
13645d8134cSStella Stamenova       // explicitly compare with -1.
13718a9135dSAdrian McCarthy       previous_suspend_count = ::ResumeThread(thread_handle);
1380fd67b53SStella Stamenova 
1390fd67b53SStella Stamenova       if (previous_suspend_count == (DWORD)-1)
1400fd67b53SStella Stamenova         return Status(::GetLastError(), eErrorTypeWin32);
1410fd67b53SStella Stamenova 
1420fd67b53SStella Stamenova     } while (previous_suspend_count > 1);
14318a9135dSAdrian McCarthy   }
1440fd67b53SStella Stamenova 
1450fd67b53SStella Stamenova   return Status();
14618a9135dSAdrian McCarthy }
147