180814287SRaphael Isemann //===-- ProcessWindows.cpp ------------------------------------------------===//
218a9135dSAdrian McCarthy //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618a9135dSAdrian McCarthy //
718a9135dSAdrian McCarthy //===----------------------------------------------------------------------===//
818a9135dSAdrian McCarthy 
918a9135dSAdrian McCarthy #include "ProcessWindows.h"
1018a9135dSAdrian McCarthy 
114ad5def9SAdrian McCarthy // Windows includes
124ad5def9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
134ad5def9SAdrian McCarthy #include <psapi.h>
144ad5def9SAdrian McCarthy 
156179c0ebSAleksandr Urakov #include "lldb/Breakpoint/Watchpoint.h"
1618a9135dSAdrian McCarthy #include "lldb/Core/Module.h"
1718a9135dSAdrian McCarthy #include "lldb/Core/ModuleSpec.h"
1818a9135dSAdrian McCarthy #include "lldb/Core/PluginManager.h"
1918a9135dSAdrian McCarthy #include "lldb/Core/Section.h"
2060cf3f82SJonas Devlieghere #include "lldb/Host/FileSystem.h"
214ad5def9SAdrian McCarthy #include "lldb/Host/HostNativeProcessBase.h"
224ad5def9SAdrian McCarthy #include "lldb/Host/HostProcess.h"
234ad5def9SAdrian McCarthy #include "lldb/Host/windows/HostThreadWindows.h"
240c35cde9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
252f3df613SZachary Turner #include "lldb/Symbol/ObjectFile.h"
2618a9135dSAdrian McCarthy #include "lldb/Target/DynamicLoader.h"
2718a9135dSAdrian McCarthy #include "lldb/Target/MemoryRegionInfo.h"
284ad5def9SAdrian McCarthy #include "lldb/Target/StopInfo.h"
2918a9135dSAdrian McCarthy #include "lldb/Target/Target.h"
30d821c997SPavel Labath #include "lldb/Utility/State.h"
3118a9135dSAdrian McCarthy 
324ad5def9SAdrian McCarthy #include "llvm/Support/ConvertUTF.h"
334ad5def9SAdrian McCarthy #include "llvm/Support/Format.h"
34c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
354ad5def9SAdrian McCarthy #include "llvm/Support/raw_ostream.h"
364ad5def9SAdrian McCarthy 
374ad5def9SAdrian McCarthy #include "DebuggerThread.h"
384ad5def9SAdrian McCarthy #include "ExceptionRecord.h"
394ad5def9SAdrian McCarthy #include "ForwardDecl.h"
404ad5def9SAdrian McCarthy #include "LocalDebugDelegate.h"
414ad5def9SAdrian McCarthy #include "ProcessWindowsLog.h"
424ad5def9SAdrian McCarthy #include "TargetThreadWindows.h"
434ad5def9SAdrian McCarthy 
4418a9135dSAdrian McCarthy using namespace lldb;
4518a9135dSAdrian McCarthy using namespace lldb_private;
4618a9135dSAdrian McCarthy 
47ccad1948SJonas Devlieghere LLDB_PLUGIN_DEFINE_ADV(ProcessWindows, ProcessWindowsCommon)
48fbb4d1e4SJonas Devlieghere 
494ad5def9SAdrian McCarthy namespace {
504ad5def9SAdrian McCarthy std::string GetProcessExecutableName(HANDLE process_handle) {
514ad5def9SAdrian McCarthy   std::vector<wchar_t> file_name;
524ad5def9SAdrian McCarthy   DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
534ad5def9SAdrian McCarthy   DWORD copied = 0;
544ad5def9SAdrian McCarthy   do {
554ad5def9SAdrian McCarthy     file_name_size *= 2;
564ad5def9SAdrian McCarthy     file_name.resize(file_name_size);
574ad5def9SAdrian McCarthy     copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(),
584ad5def9SAdrian McCarthy                                     file_name_size);
594ad5def9SAdrian McCarthy   } while (copied >= file_name_size);
604ad5def9SAdrian McCarthy   file_name.resize(copied);
614ad5def9SAdrian McCarthy   std::string result;
624ad5def9SAdrian McCarthy   llvm::convertWideToUTF8(file_name.data(), result);
634ad5def9SAdrian McCarthy   return result;
644ad5def9SAdrian McCarthy }
654ad5def9SAdrian McCarthy 
664ad5def9SAdrian McCarthy std::string GetProcessExecutableName(DWORD pid) {
674ad5def9SAdrian McCarthy   std::string file_name;
684ad5def9SAdrian McCarthy   HANDLE process_handle =
694ad5def9SAdrian McCarthy       ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
704ad5def9SAdrian McCarthy   if (process_handle != NULL) {
714ad5def9SAdrian McCarthy     file_name = GetProcessExecutableName(process_handle);
724ad5def9SAdrian McCarthy     ::CloseHandle(process_handle);
734ad5def9SAdrian McCarthy   }
744ad5def9SAdrian McCarthy   return file_name;
754ad5def9SAdrian McCarthy }
764ad5def9SAdrian McCarthy } // anonymous namespace
774ad5def9SAdrian McCarthy 
78b9c1b51eSKate Stone namespace lldb_private {
7918a9135dSAdrian McCarthy 
804ad5def9SAdrian McCarthy ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
814ad5def9SAdrian McCarthy                                          lldb::ListenerSP listener_sp,
8218e4272aSMichał Górny                                          const FileSpec *,
8318e4272aSMichał Górny                                          bool can_connect) {
844ad5def9SAdrian McCarthy   return ProcessSP(new ProcessWindows(target_sp, listener_sp));
854ad5def9SAdrian McCarthy }
864ad5def9SAdrian McCarthy 
8708913665SAleksandr Urakov static bool ShouldUseLLDBServer() {
8808913665SAleksandr Urakov   llvm::StringRef use_lldb_server = ::getenv("LLDB_USE_LLDB_SERVER");
89e50f9c41SMartin Storsjö   return use_lldb_server.equals_insensitive("on") ||
90e50f9c41SMartin Storsjö          use_lldb_server.equals_insensitive("yes") ||
91e50f9c41SMartin Storsjö          use_lldb_server.equals_insensitive("1") ||
92e50f9c41SMartin Storsjö          use_lldb_server.equals_insensitive("true");
9308913665SAleksandr Urakov }
9408913665SAleksandr Urakov 
954ad5def9SAdrian McCarthy void ProcessWindows::Initialize() {
9608913665SAleksandr Urakov   if (!ShouldUseLLDBServer()) {
97c5f28e2aSKamil Rytarowski     static llvm::once_flag g_once_flag;
984ad5def9SAdrian McCarthy 
99c5f28e2aSKamil Rytarowski     llvm::call_once(g_once_flag, []() {
1004ad5def9SAdrian McCarthy       PluginManager::RegisterPlugin(GetPluginNameStatic(),
10108913665SAleksandr Urakov                                     GetPluginDescriptionStatic(),
10208913665SAleksandr Urakov                                     CreateInstance);
1034ad5def9SAdrian McCarthy     });
1044ad5def9SAdrian McCarthy   }
10508913665SAleksandr Urakov }
1064ad5def9SAdrian McCarthy 
1074ad5def9SAdrian McCarthy void ProcessWindows::Terminate() {}
1084ad5def9SAdrian McCarthy 
1094ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginNameStatic() {
1104ad5def9SAdrian McCarthy   static ConstString g_name("windows");
1114ad5def9SAdrian McCarthy   return g_name;
1124ad5def9SAdrian McCarthy }
1134ad5def9SAdrian McCarthy 
1144ad5def9SAdrian McCarthy const char *ProcessWindows::GetPluginDescriptionStatic() {
1154ad5def9SAdrian McCarthy   return "Process plugin for Windows";
1164ad5def9SAdrian McCarthy }
1174ad5def9SAdrian McCarthy 
11818a9135dSAdrian McCarthy // Constructors and destructors.
11918a9135dSAdrian McCarthy 
120b9c1b51eSKate Stone ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
121b9c1b51eSKate Stone                                lldb::ListenerSP listener_sp)
1226179c0ebSAleksandr Urakov     : lldb_private::Process(target_sp, listener_sp),
1236179c0ebSAleksandr Urakov       m_watchpoint_ids(
1246179c0ebSAleksandr Urakov           RegisterContextWindows::GetNumHardwareBreakpointSlots(),
1256179c0ebSAleksandr Urakov           LLDB_INVALID_BREAK_ID) {}
12618a9135dSAdrian McCarthy 
127b9c1b51eSKate Stone ProcessWindows::~ProcessWindows() {}
12818a9135dSAdrian McCarthy 
12997206d57SZachary Turner size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
13018a9135dSAdrian McCarthy   error.SetErrorString("GetSTDOUT unsupported on Windows");
13118a9135dSAdrian McCarthy   return 0;
13218a9135dSAdrian McCarthy }
13318a9135dSAdrian McCarthy 
13497206d57SZachary Turner size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) {
13518a9135dSAdrian McCarthy   error.SetErrorString("GetSTDERR unsupported on Windows");
13618a9135dSAdrian McCarthy   return 0;
13718a9135dSAdrian McCarthy }
13818a9135dSAdrian McCarthy 
139b9c1b51eSKate Stone size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size,
14097206d57SZachary Turner                                 Status &error) {
14118a9135dSAdrian McCarthy   error.SetErrorString("PutSTDIN unsupported on Windows");
14218a9135dSAdrian McCarthy   return 0;
14318a9135dSAdrian McCarthy }
14418a9135dSAdrian McCarthy 
14518a9135dSAdrian McCarthy // ProcessInterface protocol.
14618a9135dSAdrian McCarthy 
1474ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginName() {
1484ad5def9SAdrian McCarthy   return GetPluginNameStatic();
1494ad5def9SAdrian McCarthy }
1504ad5def9SAdrian McCarthy 
15197206d57SZachary Turner Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) {
152b352e62fSTatyana Krasnukha   if (bp_site->HardwareRequired())
153b352e62fSTatyana Krasnukha     return Status("Hardware breakpoints are not supported.");
154b352e62fSTatyana Krasnukha 
155a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
156a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
157a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1584ad5def9SAdrian McCarthy 
15997206d57SZachary Turner   Status error = EnableSoftwareBreakpoint(bp_site);
160a385d2c1SPavel Labath   if (!error.Success())
161a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1624ad5def9SAdrian McCarthy   return error;
1634ad5def9SAdrian McCarthy }
1644ad5def9SAdrian McCarthy 
16597206d57SZachary Turner Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) {
166a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
167a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
168a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1694ad5def9SAdrian McCarthy 
17097206d57SZachary Turner   Status error = DisableSoftwareBreakpoint(bp_site);
1714ad5def9SAdrian McCarthy 
172a385d2c1SPavel Labath   if (!error.Success())
173a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1744ad5def9SAdrian McCarthy   return error;
1754ad5def9SAdrian McCarthy }
1764ad5def9SAdrian McCarthy 
17797206d57SZachary Turner Status ProcessWindows::DoDetach(bool keep_stopped) {
178ed499a36SStella Stamenova   Status error;
179053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
180053eb356SAaron Smith   StateType private_state = GetPrivateState();
181ed499a36SStella Stamenova   if (private_state != eStateExited && private_state != eStateDetached) {
182053eb356SAaron Smith     error = DetachProcess();
183053eb356SAaron Smith     if (error.Success())
184ed499a36SStella Stamenova       SetPrivateState(eStateDetached);
185053eb356SAaron Smith     else
186053eb356SAaron Smith       LLDB_LOG(log, "Detaching process error: {0}", error);
187ed499a36SStella Stamenova   } else {
188ed78dc8eSMartin Storsjo     error.SetErrorStringWithFormatv("error: process {0} in state = {1}, but "
189053eb356SAaron Smith                                     "cannot detach it in this state.",
190053eb356SAaron Smith                                     GetID(), private_state);
191053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
192ed499a36SStella Stamenova   }
1934ad5def9SAdrian McCarthy   return error;
1944ad5def9SAdrian McCarthy }
1954ad5def9SAdrian McCarthy 
19697206d57SZachary Turner Status ProcessWindows::DoLaunch(Module *exe_module,
1974ad5def9SAdrian McCarthy                                 ProcessLaunchInfo &launch_info) {
198053eb356SAaron Smith   Status error;
1994ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
200053eb356SAaron Smith   error = LaunchProcess(launch_info, delegate);
201053eb356SAaron Smith   if (error.Success())
202053eb356SAaron Smith     SetID(launch_info.GetProcessID());
2034ad5def9SAdrian McCarthy   return error;
2044ad5def9SAdrian McCarthy }
2054ad5def9SAdrian McCarthy 
20697206d57SZachary Turner Status
20797206d57SZachary Turner ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
20897206d57SZachary Turner                                         const ProcessAttachInfo &attach_info) {
2094ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
210053eb356SAaron Smith   Status error = AttachProcess(pid, attach_info, delegate);
211053eb356SAaron Smith   if (error.Success())
212053eb356SAaron Smith     SetID(GetDebuggedProcessId());
2134ad5def9SAdrian McCarthy   return error;
2144ad5def9SAdrian McCarthy }
2154ad5def9SAdrian McCarthy 
21697206d57SZachary Turner Status ProcessWindows::DoResume() {
217a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
2184ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
21997206d57SZachary Turner   Status error;
2204ad5def9SAdrian McCarthy 
2214ad5def9SAdrian McCarthy   StateType private_state = GetPrivateState();
2224ad5def9SAdrian McCarthy   if (private_state == eStateStopped || private_state == eStateCrashed) {
223a385d2c1SPavel Labath     LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
2244ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
2254ad5def9SAdrian McCarthy              GetPrivateState());
2264ad5def9SAdrian McCarthy 
227a385d2c1SPavel Labath     LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
2284ad5def9SAdrian McCarthy 
2290fd67b53SStella Stamenova     bool failed = false;
2304ad5def9SAdrian McCarthy     for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
2314ad5def9SAdrian McCarthy       auto thread = std::static_pointer_cast<TargetThreadWindows>(
2324ad5def9SAdrian McCarthy           m_thread_list.GetThreadAtIndex(i));
2330fd67b53SStella Stamenova       Status result = thread->DoResume();
2340fd67b53SStella Stamenova       if (result.Fail()) {
2350fd67b53SStella Stamenova         failed = true;
23662c76db4SStella Stamenova         LLDB_LOG(
23762c76db4SStella Stamenova             log,
23862c76db4SStella Stamenova             "Trying to resume thread at index {0}, but failed with error {1}.",
23962c76db4SStella Stamenova             i, result);
2400fd67b53SStella Stamenova       }
2414ad5def9SAdrian McCarthy     }
2424ad5def9SAdrian McCarthy 
2430fd67b53SStella Stamenova     if (failed) {
2440fd67b53SStella Stamenova       error.SetErrorString("ProcessWindows::DoResume failed");
2450fd67b53SStella Stamenova     } else {
2464ad5def9SAdrian McCarthy       SetPrivateState(eStateRunning);
2470fd67b53SStella Stamenova     }
2483f062102SAdrian McCarthy 
2493f062102SAdrian McCarthy     ExceptionRecordSP active_exception =
2503f062102SAdrian McCarthy         m_session_data->m_debugger->GetActiveException().lock();
2513f062102SAdrian McCarthy     if (active_exception) {
2523f062102SAdrian McCarthy       // Resume the process and continue processing debug events.  Mask the
2533f062102SAdrian McCarthy       // exception so that from the process's view, there is no indication that
2543f062102SAdrian McCarthy       // anything happened.
2553f062102SAdrian McCarthy       m_session_data->m_debugger->ContinueAsyncException(
2563f062102SAdrian McCarthy           ExceptionResult::MaskException);
2573f062102SAdrian McCarthy     }
2584ad5def9SAdrian McCarthy   } else {
259c28daec5SAaron Smith     LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
2604ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
2614ad5def9SAdrian McCarthy              GetPrivateState());
2624ad5def9SAdrian McCarthy   }
2634ad5def9SAdrian McCarthy   return error;
2644ad5def9SAdrian McCarthy }
2654ad5def9SAdrian McCarthy 
26697206d57SZachary Turner Status ProcessWindows::DoDestroy() {
267053eb356SAaron Smith   StateType private_state = GetPrivateState();
268053eb356SAaron Smith   return DestroyProcess(private_state);
2694ad5def9SAdrian McCarthy }
2704ad5def9SAdrian McCarthy 
27197206d57SZachary Turner Status ProcessWindows::DoHalt(bool &caused_stop) {
2724ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
273053eb356SAaron Smith   if (state != eStateStopped)
274053eb356SAaron Smith     return HaltProcess(caused_stop);
2754ad5def9SAdrian McCarthy   caused_stop = false;
276053eb356SAaron Smith   return Status();
2774ad5def9SAdrian McCarthy }
2784ad5def9SAdrian McCarthy 
2794ad5def9SAdrian McCarthy void ProcessWindows::DidLaunch() {
2804ad5def9SAdrian McCarthy   ArchSpec arch_spec;
2814ad5def9SAdrian McCarthy   DidAttach(arch_spec);
2824ad5def9SAdrian McCarthy }
2834ad5def9SAdrian McCarthy 
2844ad5def9SAdrian McCarthy void ProcessWindows::DidAttach(ArchSpec &arch_spec) {
2854ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
2864ad5def9SAdrian McCarthy 
2874ad5def9SAdrian McCarthy   // The initial stop won't broadcast the state change event, so account for
2884ad5def9SAdrian McCarthy   // that here.
2894ad5def9SAdrian McCarthy   if (m_session_data && GetPrivateState() == eStateStopped &&
2904ad5def9SAdrian McCarthy       m_session_data->m_stop_at_entry)
2914ad5def9SAdrian McCarthy     RefreshStateAfterStop();
2924ad5def9SAdrian McCarthy }
2934ad5def9SAdrian McCarthy 
29426366c3eSAleksandr Urakov static void
29526366c3eSAleksandr Urakov DumpAdditionalExceptionInformation(llvm::raw_ostream &stream,
29626366c3eSAleksandr Urakov                                    const ExceptionRecordSP &exception) {
29726366c3eSAleksandr Urakov   // Decode additional exception information for specific exception types based
29826366c3eSAleksandr Urakov   // on
29926366c3eSAleksandr Urakov   // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record
30026366c3eSAleksandr Urakov 
30126366c3eSAleksandr Urakov   const int addr_min_width = 2 + 8; // "0x" + 4 address bytes
30226366c3eSAleksandr Urakov 
30326366c3eSAleksandr Urakov   const std::vector<ULONG_PTR> &args = exception->GetExceptionArguments();
30426366c3eSAleksandr Urakov   switch (exception->GetExceptionCode()) {
30526366c3eSAleksandr Urakov   case EXCEPTION_ACCESS_VIOLATION: {
30626366c3eSAleksandr Urakov     if (args.size() < 2)
30726366c3eSAleksandr Urakov       break;
30826366c3eSAleksandr Urakov 
30926366c3eSAleksandr Urakov     stream << ": ";
31026366c3eSAleksandr Urakov     const int access_violation_code = args[0];
31126366c3eSAleksandr Urakov     const lldb::addr_t access_violation_address = args[1];
31226366c3eSAleksandr Urakov     switch (access_violation_code) {
31326366c3eSAleksandr Urakov     case 0:
31426366c3eSAleksandr Urakov       stream << "Access violation reading";
31526366c3eSAleksandr Urakov       break;
31626366c3eSAleksandr Urakov     case 1:
31726366c3eSAleksandr Urakov       stream << "Access violation writing";
31826366c3eSAleksandr Urakov       break;
31926366c3eSAleksandr Urakov     case 8:
32026366c3eSAleksandr Urakov       stream << "User-mode data execution prevention (DEP) violation at";
32126366c3eSAleksandr Urakov       break;
32226366c3eSAleksandr Urakov     default:
32326366c3eSAleksandr Urakov       stream << "Unknown access violation (code " << access_violation_code
32426366c3eSAleksandr Urakov              << ") at";
32526366c3eSAleksandr Urakov       break;
32626366c3eSAleksandr Urakov     }
32726366c3eSAleksandr Urakov     stream << " location "
32826366c3eSAleksandr Urakov            << llvm::format_hex(access_violation_address, addr_min_width);
32926366c3eSAleksandr Urakov     break;
33026366c3eSAleksandr Urakov   }
33126366c3eSAleksandr Urakov   case EXCEPTION_IN_PAGE_ERROR: {
33226366c3eSAleksandr Urakov     if (args.size() < 3)
33326366c3eSAleksandr Urakov       break;
33426366c3eSAleksandr Urakov 
33526366c3eSAleksandr Urakov     stream << ": ";
33626366c3eSAleksandr Urakov     const int page_load_error_code = args[0];
33726366c3eSAleksandr Urakov     const lldb::addr_t page_load_error_address = args[1];
33826366c3eSAleksandr Urakov     const DWORD underlying_code = args[2];
33926366c3eSAleksandr Urakov     switch (page_load_error_code) {
34026366c3eSAleksandr Urakov     case 0:
34126366c3eSAleksandr Urakov       stream << "In page error reading";
34226366c3eSAleksandr Urakov       break;
34326366c3eSAleksandr Urakov     case 1:
34426366c3eSAleksandr Urakov       stream << "In page error writing";
34526366c3eSAleksandr Urakov       break;
34626366c3eSAleksandr Urakov     case 8:
34726366c3eSAleksandr Urakov       stream << "User-mode data execution prevention (DEP) violation at";
34826366c3eSAleksandr Urakov       break;
34926366c3eSAleksandr Urakov     default:
35026366c3eSAleksandr Urakov       stream << "Unknown page loading error (code " << page_load_error_code
35126366c3eSAleksandr Urakov              << ") at";
35226366c3eSAleksandr Urakov       break;
35326366c3eSAleksandr Urakov     }
35426366c3eSAleksandr Urakov     stream << " location "
35526366c3eSAleksandr Urakov            << llvm::format_hex(page_load_error_address, addr_min_width)
35626366c3eSAleksandr Urakov            << " (status code " << llvm::format_hex(underlying_code, 8) << ")";
35726366c3eSAleksandr Urakov     break;
35826366c3eSAleksandr Urakov   }
35926366c3eSAleksandr Urakov   }
36026366c3eSAleksandr Urakov }
36126366c3eSAleksandr Urakov 
3624ad5def9SAdrian McCarthy void ProcessWindows::RefreshStateAfterStop() {
363a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
3644ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
3654ad5def9SAdrian McCarthy 
3664ad5def9SAdrian McCarthy   if (!m_session_data) {
367a385d2c1SPavel Labath     LLDB_LOG(log, "no active session.  Returning...");
3684ad5def9SAdrian McCarthy     return;
3694ad5def9SAdrian McCarthy   }
3704ad5def9SAdrian McCarthy 
3714ad5def9SAdrian McCarthy   m_thread_list.RefreshStateAfterStop();
3724ad5def9SAdrian McCarthy 
3734ad5def9SAdrian McCarthy   std::weak_ptr<ExceptionRecord> exception_record =
3744ad5def9SAdrian McCarthy       m_session_data->m_debugger->GetActiveException();
3754ad5def9SAdrian McCarthy   ExceptionRecordSP active_exception = exception_record.lock();
3764ad5def9SAdrian McCarthy   if (!active_exception) {
37762c76db4SStella Stamenova     LLDB_LOG(log,
37862c76db4SStella Stamenova              "there is no active exception in process {0}.  Why is the "
379a385d2c1SPavel Labath              "process stopped?",
3804ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId());
3814ad5def9SAdrian McCarthy     return;
3824ad5def9SAdrian McCarthy   }
3834ad5def9SAdrian McCarthy 
3844ad5def9SAdrian McCarthy   StopInfoSP stop_info;
3854ad5def9SAdrian McCarthy   m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
3864ad5def9SAdrian McCarthy   ThreadSP stop_thread = m_thread_list.GetSelectedThread();
3874ad5def9SAdrian McCarthy   if (!stop_thread)
3884ad5def9SAdrian McCarthy     return;
3894ad5def9SAdrian McCarthy 
3904ad5def9SAdrian McCarthy   switch (active_exception->GetExceptionCode()) {
3914ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP: {
3924ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
3934ad5def9SAdrian McCarthy     const uint64_t pc = register_context->GetPC();
3944ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
395479c3577SJim Ingham     if (site && site->ValidForThisThread(*stop_thread)) {
39662c76db4SStella Stamenova       LLDB_LOG(log,
39762c76db4SStella Stamenova                "Single-stepped onto a breakpoint in process {0} at "
398a385d2c1SPavel Labath                "address {1:x} with breakpoint site {2}",
3994ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
4004ad5def9SAdrian McCarthy                site->GetID());
4014ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
4024ad5def9SAdrian McCarthy                                                                  site->GetID());
4034ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
4046179c0ebSAleksandr Urakov 
4056179c0ebSAleksandr Urakov       return;
4066179c0ebSAleksandr Urakov     }
4076179c0ebSAleksandr Urakov 
4086179c0ebSAleksandr Urakov     auto *reg_ctx = static_cast<RegisterContextWindows *>(
4096179c0ebSAleksandr Urakov         stop_thread->GetRegisterContext().get());
4106179c0ebSAleksandr Urakov     uint32_t slot_id = reg_ctx->GetTriggeredHardwareBreakpointSlotId();
4116179c0ebSAleksandr Urakov     if (slot_id != LLDB_INVALID_INDEX32) {
4126179c0ebSAleksandr Urakov       int id = m_watchpoint_ids[slot_id];
4136179c0ebSAleksandr Urakov       LLDB_LOG(log,
4146179c0ebSAleksandr Urakov                "Single-stepped onto a watchpoint in process {0} at address "
4156179c0ebSAleksandr Urakov                "{1:x} with watchpoint {2}",
4166179c0ebSAleksandr Urakov                m_session_data->m_debugger->GetProcess().GetProcessId(), pc, id);
4176179c0ebSAleksandr Urakov 
4186179c0ebSAleksandr Urakov       if (lldb::WatchpointSP wp_sp =
4196179c0ebSAleksandr Urakov               GetTarget().GetWatchpointList().FindByID(id))
4206179c0ebSAleksandr Urakov         wp_sp->SetHardwareIndex(slot_id);
4216179c0ebSAleksandr Urakov 
4226179c0ebSAleksandr Urakov       stop_info = StopInfo::CreateStopReasonWithWatchpointID(
4236179c0ebSAleksandr Urakov           *stop_thread, id, m_watchpoints[id].address);
4246179c0ebSAleksandr Urakov       stop_thread->SetStopInfo(stop_info);
4256179c0ebSAleksandr Urakov 
4266179c0ebSAleksandr Urakov       return;
4276179c0ebSAleksandr Urakov     }
4286179c0ebSAleksandr Urakov 
429a385d2c1SPavel Labath     LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
4304ad5def9SAdrian McCarthy     stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
4314ad5def9SAdrian McCarthy     stop_thread->SetStopInfo(stop_info);
4326179c0ebSAleksandr Urakov 
4334ad5def9SAdrian McCarthy     return;
4344ad5def9SAdrian McCarthy   }
4354ad5def9SAdrian McCarthy 
4364ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT: {
4374ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
4384ad5def9SAdrian McCarthy 
439*9f34f75fSMartin Storsjö     int breakpoint_size = 1;
440*9f34f75fSMartin Storsjö     switch (GetTarget().GetArchitecture().GetMachine()) {
441*9f34f75fSMartin Storsjö     case llvm::Triple::aarch64:
442*9f34f75fSMartin Storsjö       breakpoint_size = 4;
443*9f34f75fSMartin Storsjö       break;
444*9f34f75fSMartin Storsjö 
445*9f34f75fSMartin Storsjö     case llvm::Triple::arm:
446*9f34f75fSMartin Storsjö     case llvm::Triple::thumb:
447*9f34f75fSMartin Storsjö       breakpoint_size = 2;
448*9f34f75fSMartin Storsjö       break;
449*9f34f75fSMartin Storsjö 
450*9f34f75fSMartin Storsjö     case llvm::Triple::x86:
451*9f34f75fSMartin Storsjö     case llvm::Triple::x86_64:
452*9f34f75fSMartin Storsjö       breakpoint_size = 1;
453*9f34f75fSMartin Storsjö       break;
454*9f34f75fSMartin Storsjö 
455*9f34f75fSMartin Storsjö     default:
456*9f34f75fSMartin Storsjö       LLDB_LOG(log, "Unknown breakpoint size for architecture");
457*9f34f75fSMartin Storsjö       break;
458*9f34f75fSMartin Storsjö     }
459*9f34f75fSMartin Storsjö 
460*9f34f75fSMartin Storsjö     // The current PC is AFTER the BP opcode, on all architectures.
461*9f34f75fSMartin Storsjö     uint64_t pc = register_context->GetPC() - breakpoint_size;
4624ad5def9SAdrian McCarthy 
4634ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
4644ad5def9SAdrian McCarthy     if (site) {
46562c76db4SStella Stamenova       LLDB_LOG(log,
46662c76db4SStella Stamenova                "detected breakpoint in process {0} at address {1:x} with "
467a385d2c1SPavel Labath                "breakpoint site {2}",
4684ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
4694ad5def9SAdrian McCarthy                site->GetID());
4704ad5def9SAdrian McCarthy 
471479c3577SJim Ingham       if (site->ValidForThisThread(*stop_thread)) {
47262c76db4SStella Stamenova         LLDB_LOG(log,
47362c76db4SStella Stamenova                  "Breakpoint site {0} is valid for this thread ({1:x}), "
4744ad5def9SAdrian McCarthy                  "creating stop info.",
4754ad5def9SAdrian McCarthy                  site->GetID(), stop_thread->GetID());
4764ad5def9SAdrian McCarthy 
4774ad5def9SAdrian McCarthy         stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
4784ad5def9SAdrian McCarthy             *stop_thread, site->GetID());
4794ad5def9SAdrian McCarthy         register_context->SetPC(pc);
4804ad5def9SAdrian McCarthy       } else {
48162c76db4SStella Stamenova         LLDB_LOG(log,
48262c76db4SStella Stamenova                  "Breakpoint site {0} is not valid for this thread, "
4834ad5def9SAdrian McCarthy                  "creating empty stop info.",
4844ad5def9SAdrian McCarthy                  site->GetID());
4854ad5def9SAdrian McCarthy       }
4864ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
4874ad5def9SAdrian McCarthy       return;
4884ad5def9SAdrian McCarthy     } else {
4894ad5def9SAdrian McCarthy       // The thread hit a hard-coded breakpoint like an `int 3` or
4904ad5def9SAdrian McCarthy       // `__debugbreak()`.
491a385d2c1SPavel Labath       LLDB_LOG(log,
4924ad5def9SAdrian McCarthy                "No breakpoint site matches for this thread. __debugbreak()?  "
4934ad5def9SAdrian McCarthy                "Creating stop info with the exception.");
4944ad5def9SAdrian McCarthy       // FALLTHROUGH:  We'll treat this as a generic exception record in the
4954ad5def9SAdrian McCarthy       // default case.
496b0717666SAlexandre Ganea       LLVM_FALLTHROUGH;
4974ad5def9SAdrian McCarthy     }
4984ad5def9SAdrian McCarthy   }
4994ad5def9SAdrian McCarthy 
5004ad5def9SAdrian McCarthy   default: {
5014ad5def9SAdrian McCarthy     std::string desc;
5024ad5def9SAdrian McCarthy     llvm::raw_string_ostream desc_stream(desc);
5034ad5def9SAdrian McCarthy     desc_stream << "Exception "
5044ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionCode(), 8)
5054ad5def9SAdrian McCarthy                 << " encountered at address "
5064ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
50726366c3eSAleksandr Urakov     DumpAdditionalExceptionInformation(desc_stream, active_exception);
50826366c3eSAleksandr Urakov 
5094ad5def9SAdrian McCarthy     stop_info = StopInfo::CreateStopReasonWithException(
5104ad5def9SAdrian McCarthy         *stop_thread, desc_stream.str().c_str());
5114ad5def9SAdrian McCarthy     stop_thread->SetStopInfo(stop_info);
512a385d2c1SPavel Labath     LLDB_LOG(log, "{0}", desc_stream.str());
5134ad5def9SAdrian McCarthy     return;
5144ad5def9SAdrian McCarthy   }
5154ad5def9SAdrian McCarthy   }
5164ad5def9SAdrian McCarthy }
5174ad5def9SAdrian McCarthy 
5184ad5def9SAdrian McCarthy bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
5194ad5def9SAdrian McCarthy                               bool plugin_specified_by_name) {
5204ad5def9SAdrian McCarthy   if (plugin_specified_by_name)
5214ad5def9SAdrian McCarthy     return true;
5224ad5def9SAdrian McCarthy 
5234ad5def9SAdrian McCarthy   // For now we are just making sure the file exists for a given module
5244ad5def9SAdrian McCarthy   ModuleSP exe_module_sp(target_sp->GetExecutableModule());
5254ad5def9SAdrian McCarthy   if (exe_module_sp.get())
52660cf3f82SJonas Devlieghere     return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec());
52705097246SAdrian Prantl   // However, if there is no executable module, we return true since we might
52805097246SAdrian Prantl   // be preparing to attach.
5294ad5def9SAdrian McCarthy   return true;
5304ad5def9SAdrian McCarthy }
5314ad5def9SAdrian McCarthy 
5324bb62448SWalter Erquinigo bool ProcessWindows::DoUpdateThreadList(ThreadList &old_thread_list,
5334ad5def9SAdrian McCarthy                                         ThreadList &new_thread_list) {
534a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD);
5354ad5def9SAdrian McCarthy   // Add all the threads that were previously running and for which we did not
5364ad5def9SAdrian McCarthy   // detect a thread exited event.
5374ad5def9SAdrian McCarthy   int new_size = 0;
5384ad5def9SAdrian McCarthy   int continued_threads = 0;
5394ad5def9SAdrian McCarthy   int exited_threads = 0;
5404ad5def9SAdrian McCarthy   int new_threads = 0;
5414ad5def9SAdrian McCarthy 
5424ad5def9SAdrian McCarthy   for (ThreadSP old_thread : old_thread_list.Threads()) {
5434ad5def9SAdrian McCarthy     lldb::tid_t old_thread_id = old_thread->GetID();
5444ad5def9SAdrian McCarthy     auto exited_thread_iter =
5454ad5def9SAdrian McCarthy         m_session_data->m_exited_threads.find(old_thread_id);
5464ad5def9SAdrian McCarthy     if (exited_thread_iter == m_session_data->m_exited_threads.end()) {
5474ad5def9SAdrian McCarthy       new_thread_list.AddThread(old_thread);
5484ad5def9SAdrian McCarthy       ++new_size;
5494ad5def9SAdrian McCarthy       ++continued_threads;
550a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and is still running.",
5514ad5def9SAdrian McCarthy                 old_thread_id);
5524ad5def9SAdrian McCarthy     } else {
553a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id);
5544ad5def9SAdrian McCarthy       ++exited_threads;
5554ad5def9SAdrian McCarthy     }
5564ad5def9SAdrian McCarthy   }
5574ad5def9SAdrian McCarthy 
55805097246SAdrian Prantl   // Also add all the threads that are new since the last time we broke into
55905097246SAdrian Prantl   // the debugger.
5604ad5def9SAdrian McCarthy   for (const auto &thread_info : m_session_data->m_new_threads) {
5616179c0ebSAleksandr Urakov     new_thread_list.AddThread(thread_info.second);
5624ad5def9SAdrian McCarthy     ++new_size;
5634ad5def9SAdrian McCarthy     ++new_threads;
564a385d2c1SPavel Labath     LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
5654ad5def9SAdrian McCarthy   }
5664ad5def9SAdrian McCarthy 
567a385d2c1SPavel Labath   LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.",
5684ad5def9SAdrian McCarthy            new_threads, continued_threads, exited_threads);
5694ad5def9SAdrian McCarthy 
5704ad5def9SAdrian McCarthy   m_session_data->m_new_threads.clear();
5714ad5def9SAdrian McCarthy   m_session_data->m_exited_threads.clear();
5724ad5def9SAdrian McCarthy 
5734ad5def9SAdrian McCarthy   return new_size > 0;
5744ad5def9SAdrian McCarthy }
5754ad5def9SAdrian McCarthy 
5764ad5def9SAdrian McCarthy bool ProcessWindows::IsAlive() {
5774ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
5784ad5def9SAdrian McCarthy   switch (state) {
5794ad5def9SAdrian McCarthy   case eStateCrashed:
5804ad5def9SAdrian McCarthy   case eStateDetached:
5814ad5def9SAdrian McCarthy   case eStateUnloaded:
5824ad5def9SAdrian McCarthy   case eStateExited:
5834ad5def9SAdrian McCarthy   case eStateInvalid:
5844ad5def9SAdrian McCarthy     return false;
5854ad5def9SAdrian McCarthy   default:
5864ad5def9SAdrian McCarthy     return true;
5874ad5def9SAdrian McCarthy   }
5884ad5def9SAdrian McCarthy }
5894ad5def9SAdrian McCarthy 
5904ad5def9SAdrian McCarthy size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
59197206d57SZachary Turner                                     size_t size, Status &error) {
592053eb356SAaron Smith   size_t bytes_read = 0;
593053eb356SAaron Smith   error = ProcessDebugger::ReadMemory(vm_addr, buf, size, bytes_read);
5944ad5def9SAdrian McCarthy   return bytes_read;
5954ad5def9SAdrian McCarthy }
5964ad5def9SAdrian McCarthy 
5974ad5def9SAdrian McCarthy size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
59897206d57SZachary Turner                                      size_t size, Status &error) {
599053eb356SAaron Smith   size_t bytes_written = 0;
600053eb356SAaron Smith   error = ProcessDebugger::WriteMemory(vm_addr, buf, size, bytes_written);
6014ad5def9SAdrian McCarthy   return bytes_written;
6024ad5def9SAdrian McCarthy }
6034ad5def9SAdrian McCarthy 
6049d5b2d4aSAleksandr Urakov lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
6059d5b2d4aSAleksandr Urakov                                               Status &error) {
606053eb356SAaron Smith   lldb::addr_t vm_addr = LLDB_INVALID_ADDRESS;
607053eb356SAaron Smith   error = ProcessDebugger::AllocateMemory(size, permissions, vm_addr);
608053eb356SAaron Smith   return vm_addr;
6099d5b2d4aSAleksandr Urakov }
6109d5b2d4aSAleksandr Urakov 
6119d5b2d4aSAleksandr Urakov Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) {
612053eb356SAaron Smith   return ProcessDebugger::DeallocateMemory(ptr);
6139d5b2d4aSAleksandr Urakov }
6149d5b2d4aSAleksandr Urakov 
61597206d57SZachary Turner Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
6164ad5def9SAdrian McCarthy                                            MemoryRegionInfo &info) {
617053eb356SAaron Smith   return ProcessDebugger::GetMemoryRegionInfo(vm_addr, info);
6184ad5def9SAdrian McCarthy }
6194ad5def9SAdrian McCarthy 
620b9c1b51eSKate Stone lldb::addr_t ProcessWindows::GetImageInfoAddress() {
62118a9135dSAdrian McCarthy   Target &target = GetTarget();
62218a9135dSAdrian McCarthy   ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
62318a9135dSAdrian McCarthy   Address addr = obj_file->GetImageInfoAddress(&target);
62418a9135dSAdrian McCarthy   if (addr.IsValid())
62518a9135dSAdrian McCarthy     return addr.GetLoadAddress(&target);
62618a9135dSAdrian McCarthy   else
62718a9135dSAdrian McCarthy     return LLDB_INVALID_ADDRESS;
62818a9135dSAdrian McCarthy }
62918a9135dSAdrian McCarthy 
630eb6671e7SAaron Smith DynamicLoaderWindowsDYLD *ProcessWindows::GetDynamicLoader() {
63196b82107SAaron Smith   if (m_dyld_up.get() == NULL)
63296b82107SAaron Smith     m_dyld_up.reset(DynamicLoader::FindPlugin(
633eb6671e7SAaron Smith         this, DynamicLoaderWindowsDYLD::GetPluginNameStatic().GetCString()));
63496b82107SAaron Smith   return static_cast<DynamicLoaderWindowsDYLD *>(m_dyld_up.get());
635eb6671e7SAaron Smith }
636eb6671e7SAaron Smith 
6374ad5def9SAdrian McCarthy void ProcessWindows::OnExitProcess(uint32_t exit_code) {
6384ad5def9SAdrian McCarthy   // No need to acquire the lock since m_session_data isn't accessed.
639a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
640a385d2c1SPavel Labath   LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
6414ad5def9SAdrian McCarthy 
642d7e126c4SJim Ingham   TargetSP target = CalculateTarget();
6434ad5def9SAdrian McCarthy   if (target) {
6444ad5def9SAdrian McCarthy     ModuleSP executable_module = target->GetExecutableModule();
6454ad5def9SAdrian McCarthy     ModuleList unloaded_modules;
6464ad5def9SAdrian McCarthy     unloaded_modules.Append(executable_module);
6474ad5def9SAdrian McCarthy     target->ModulesDidUnload(unloaded_modules, true);
6484ad5def9SAdrian McCarthy   }
6494ad5def9SAdrian McCarthy 
6504ad5def9SAdrian McCarthy   SetProcessExitStatus(GetID(), true, 0, exit_code);
6514ad5def9SAdrian McCarthy   SetPrivateState(eStateExited);
652e3037904SAaron Smith 
653403cd574SMartin Storsjö   ProcessDebugger::OnExitProcess(exit_code);
6544ad5def9SAdrian McCarthy }
6554ad5def9SAdrian McCarthy 
6564ad5def9SAdrian McCarthy void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
6574ad5def9SAdrian McCarthy   DebuggerThreadSP debugger = m_session_data->m_debugger;
658a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
659a385d2c1SPavel Labath   LLDB_LOG(log, "Debugger connected to process {0}.  Image base = {1:x}",
6604ad5def9SAdrian McCarthy            debugger->GetProcess().GetProcessId(), image_base);
6614ad5def9SAdrian McCarthy 
6624ad5def9SAdrian McCarthy   ModuleSP module = GetTarget().GetExecutableModule();
6634ad5def9SAdrian McCarthy   if (!module) {
6644ad5def9SAdrian McCarthy     // During attach, we won't have the executable module, so find it now.
6654ad5def9SAdrian McCarthy     const DWORD pid = debugger->GetProcess().GetProcessId();
6664ad5def9SAdrian McCarthy     const std::string file_name = GetProcessExecutableName(pid);
6674ad5def9SAdrian McCarthy     if (file_name.empty()) {
6684ad5def9SAdrian McCarthy       return;
6694ad5def9SAdrian McCarthy     }
6704ad5def9SAdrian McCarthy 
67154bb3161SAleksandr Urakov     FileSpec executable_file(file_name);
67254bb3161SAleksandr Urakov     FileSystem::Instance().Resolve(executable_file);
6734ad5def9SAdrian McCarthy     ModuleSpec module_spec(executable_file);
67497206d57SZachary Turner     Status error;
6756179c0ebSAleksandr Urakov     module =
6766179c0ebSAleksandr Urakov         GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
6774ad5def9SAdrian McCarthy     if (!module) {
6784ad5def9SAdrian McCarthy       return;
6794ad5def9SAdrian McCarthy     }
6804ad5def9SAdrian McCarthy 
681d54ee88aSTatyana Krasnukha     GetTarget().SetExecutableModule(module, eLoadDependentsNo);
6824ad5def9SAdrian McCarthy   }
6834ad5def9SAdrian McCarthy 
684eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
685a2d9fdf5SStella Stamenova     dyld->OnLoadModule(module, ModuleSpec(), image_base);
6864ad5def9SAdrian McCarthy 
6874ad5def9SAdrian McCarthy   // Add the main executable module to the list of pending module loads.  We
68805097246SAdrian Prantl   // can't call GetTarget().ModulesDidLoad() here because we still haven't
68905097246SAdrian Prantl   // returned from DoLaunch() / DoAttach() yet so the target may not have set
69005097246SAdrian Prantl   // the process instance to `this` yet.
6914ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
6926179c0ebSAleksandr Urakov 
6936179c0ebSAleksandr Urakov   const HostThread &host_main_thread = debugger->GetMainThread();
6946179c0ebSAleksandr Urakov   ThreadSP main_thread =
6956179c0ebSAleksandr Urakov       std::make_shared<TargetThreadWindows>(*this, host_main_thread);
6966179c0ebSAleksandr Urakov 
6976179c0ebSAleksandr Urakov   tid_t id = host_main_thread.GetNativeThread().GetThreadId();
6986179c0ebSAleksandr Urakov   main_thread->SetID(id);
6996179c0ebSAleksandr Urakov 
7006179c0ebSAleksandr Urakov   m_session_data->m_new_threads[id] = main_thread;
7014ad5def9SAdrian McCarthy }
7024ad5def9SAdrian McCarthy 
7034ad5def9SAdrian McCarthy ExceptionResult
7044ad5def9SAdrian McCarthy ProcessWindows::OnDebugException(bool first_chance,
7054ad5def9SAdrian McCarthy                                  const ExceptionRecord &record) {
706a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
7074ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
7084ad5def9SAdrian McCarthy 
7094ad5def9SAdrian McCarthy   // FIXME: Without this check, occasionally when running the test suite there
7104ad5def9SAdrian McCarthy   // is
7114ad5def9SAdrian McCarthy   // an issue where m_session_data can be null.  It's not clear how this could
71205097246SAdrian Prantl   // happen but it only surfaces while running the test suite.  In order to
71305097246SAdrian Prantl   // properly diagnose this, we probably need to first figure allow the test
71405097246SAdrian Prantl   // suite to print out full lldb logs, and then add logging to the process
71505097246SAdrian Prantl   // plugin.
7164ad5def9SAdrian McCarthy   if (!m_session_data) {
71762c76db4SStella Stamenova     LLDB_LOG(log,
71862c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x}, "
719a385d2c1SPavel Labath              "but there is no session.",
7204ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress());
7214ad5def9SAdrian McCarthy     return ExceptionResult::SendToApplication;
7224ad5def9SAdrian McCarthy   }
7234ad5def9SAdrian McCarthy 
7244ad5def9SAdrian McCarthy   if (!first_chance) {
725a5235af9SAleksandr Urakov     // Not any second chance exception is an application crash by definition.
726a5235af9SAleksandr Urakov     // It may be an expression evaluation crash.
727a5235af9SAleksandr Urakov     SetPrivateState(eStateStopped);
7284ad5def9SAdrian McCarthy   }
7294ad5def9SAdrian McCarthy 
7304ad5def9SAdrian McCarthy   ExceptionResult result = ExceptionResult::SendToApplication;
7314ad5def9SAdrian McCarthy   switch (record.GetExceptionCode()) {
7324ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT:
7334ad5def9SAdrian McCarthy     // Handle breakpoints at the first chance.
7344ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
7354ad5def9SAdrian McCarthy 
7364ad5def9SAdrian McCarthy     if (!m_session_data->m_initial_stop_received) {
737a385d2c1SPavel Labath       LLDB_LOG(
738a385d2c1SPavel Labath           log,
739a385d2c1SPavel Labath           "Hit loader breakpoint at address {0:x}, setting initial stop event.",
7404ad5def9SAdrian McCarthy           record.GetExceptionAddress());
7414ad5def9SAdrian McCarthy       m_session_data->m_initial_stop_received = true;
7424ad5def9SAdrian McCarthy       ::SetEvent(m_session_data->m_initial_stop_event);
7434ad5def9SAdrian McCarthy     } else {
744a385d2c1SPavel Labath       LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
7454ad5def9SAdrian McCarthy                record.GetExceptionAddress());
7464ad5def9SAdrian McCarthy     }
7474ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
7484ad5def9SAdrian McCarthy     break;
7494ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP:
7504ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
7514ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
7524ad5def9SAdrian McCarthy     break;
7534ad5def9SAdrian McCarthy   default:
75462c76db4SStella Stamenova     LLDB_LOG(log,
75562c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x} "
756a385d2c1SPavel Labath              "(first_chance={2})",
7574ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress(),
758a385d2c1SPavel Labath              first_chance);
7594ad5def9SAdrian McCarthy     // For non-breakpoints, give the application a chance to handle the
7604ad5def9SAdrian McCarthy     // exception first.
7614ad5def9SAdrian McCarthy     if (first_chance)
7624ad5def9SAdrian McCarthy       result = ExceptionResult::SendToApplication;
7634ad5def9SAdrian McCarthy     else
7644ad5def9SAdrian McCarthy       result = ExceptionResult::BreakInDebugger;
7654ad5def9SAdrian McCarthy   }
7664ad5def9SAdrian McCarthy 
7674ad5def9SAdrian McCarthy   return result;
7684ad5def9SAdrian McCarthy }
7694ad5def9SAdrian McCarthy 
7704ad5def9SAdrian McCarthy void ProcessWindows::OnCreateThread(const HostThread &new_thread) {
7714ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
7726179c0ebSAleksandr Urakov 
7736179c0ebSAleksandr Urakov   ThreadSP thread = std::make_shared<TargetThreadWindows>(*this, new_thread);
7746179c0ebSAleksandr Urakov 
7756179c0ebSAleksandr Urakov   const HostNativeThread &native_new_thread = new_thread.GetNativeThread();
7766179c0ebSAleksandr Urakov   tid_t id = native_new_thread.GetThreadId();
7776179c0ebSAleksandr Urakov   thread->SetID(id);
7786179c0ebSAleksandr Urakov 
7796179c0ebSAleksandr Urakov   m_session_data->m_new_threads[id] = thread;
7806179c0ebSAleksandr Urakov 
7816179c0ebSAleksandr Urakov   for (const std::map<int, WatchpointInfo>::value_type &p : m_watchpoints) {
7826179c0ebSAleksandr Urakov     auto *reg_ctx = static_cast<RegisterContextWindows *>(
7836179c0ebSAleksandr Urakov         thread->GetRegisterContext().get());
7846179c0ebSAleksandr Urakov     reg_ctx->AddHardwareBreakpoint(p.second.slot_id, p.second.address,
7856179c0ebSAleksandr Urakov                                    p.second.size, p.second.read,
7866179c0ebSAleksandr Urakov                                    p.second.write);
7876179c0ebSAleksandr Urakov   }
7884ad5def9SAdrian McCarthy }
7894ad5def9SAdrian McCarthy 
7904ad5def9SAdrian McCarthy void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
7914ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
7924ad5def9SAdrian McCarthy 
7934ad5def9SAdrian McCarthy   // On a forced termination, we may get exit thread events after the session
7944ad5def9SAdrian McCarthy   // data has been cleaned up.
7954ad5def9SAdrian McCarthy   if (!m_session_data)
7964ad5def9SAdrian McCarthy     return;
7974ad5def9SAdrian McCarthy 
7984ad5def9SAdrian McCarthy   // A thread may have started and exited before the debugger stopped allowing a
7994ad5def9SAdrian McCarthy   // refresh.
8004ad5def9SAdrian McCarthy   // Just remove it from the new threads list in that case.
8014ad5def9SAdrian McCarthy   auto iter = m_session_data->m_new_threads.find(thread_id);
8024ad5def9SAdrian McCarthy   if (iter != m_session_data->m_new_threads.end())
8034ad5def9SAdrian McCarthy     m_session_data->m_new_threads.erase(iter);
8044ad5def9SAdrian McCarthy   else
8054ad5def9SAdrian McCarthy     m_session_data->m_exited_threads.insert(thread_id);
8064ad5def9SAdrian McCarthy }
8074ad5def9SAdrian McCarthy 
8084ad5def9SAdrian McCarthy void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
8094ad5def9SAdrian McCarthy                                lldb::addr_t module_addr) {
810eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
811a2d9fdf5SStella Stamenova     dyld->OnLoadModule(nullptr, module_spec, module_addr);
8124ad5def9SAdrian McCarthy }
8134ad5def9SAdrian McCarthy 
8144ad5def9SAdrian McCarthy void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
815eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
816eb6671e7SAaron Smith     dyld->OnUnloadModule(module_addr);
8174ad5def9SAdrian McCarthy }
8184ad5def9SAdrian McCarthy 
8194ad5def9SAdrian McCarthy void ProcessWindows::OnDebugString(const std::string &string) {}
8204ad5def9SAdrian McCarthy 
82197206d57SZachary Turner void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
8224ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
823a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
8244ad5def9SAdrian McCarthy 
8254ad5def9SAdrian McCarthy   if (m_session_data->m_initial_stop_received) {
82605097246SAdrian Prantl     // This happened while debugging.  Do we shutdown the debugging session,
82705097246SAdrian Prantl     // try to continue, or do something else?
82862c76db4SStella Stamenova     LLDB_LOG(log,
82962c76db4SStella Stamenova              "Error {0} occurred during debugging.  Unexpected behavior "
830a385d2c1SPavel Labath              "may result.  {1}",
831a385d2c1SPavel Labath              error.GetError(), error);
8324ad5def9SAdrian McCarthy   } else {
8334ad5def9SAdrian McCarthy     // If we haven't actually launched the process yet, this was an error
83405097246SAdrian Prantl     // launching the process.  Set the internal error and signal the initial
83505097246SAdrian Prantl     // stop event so that the DoLaunch method wakes up and returns a failure.
8364ad5def9SAdrian McCarthy     m_session_data->m_launch_error = error;
8374ad5def9SAdrian McCarthy     ::SetEvent(m_session_data->m_initial_stop_event);
838a385d2c1SPavel Labath     LLDB_LOG(
839a385d2c1SPavel Labath         log,
840a385d2c1SPavel Labath         "Error {0} occurred launching the process before the initial stop. {1}",
841a385d2c1SPavel Labath         error.GetError(), error);
8424ad5def9SAdrian McCarthy     return;
8434ad5def9SAdrian McCarthy   }
8444ad5def9SAdrian McCarthy }
8456179c0ebSAleksandr Urakov 
8466179c0ebSAleksandr Urakov Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num) {
8476179c0ebSAleksandr Urakov   num = RegisterContextWindows::GetNumHardwareBreakpointSlots();
8486179c0ebSAleksandr Urakov   return {};
8496179c0ebSAleksandr Urakov }
8506179c0ebSAleksandr Urakov 
8516179c0ebSAleksandr Urakov Status ProcessWindows::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
8526179c0ebSAleksandr Urakov   num = RegisterContextWindows::GetNumHardwareBreakpointSlots();
8536179c0ebSAleksandr Urakov   after = RegisterContextWindows::DoHardwareBreakpointsTriggerAfter();
8546179c0ebSAleksandr Urakov   return {};
8556179c0ebSAleksandr Urakov }
8566179c0ebSAleksandr Urakov 
8576179c0ebSAleksandr Urakov Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
8586179c0ebSAleksandr Urakov   Status error;
8596179c0ebSAleksandr Urakov 
8606179c0ebSAleksandr Urakov   if (wp->IsEnabled()) {
8616179c0ebSAleksandr Urakov     wp->SetEnabled(true, notify);
8626179c0ebSAleksandr Urakov     return error;
8636179c0ebSAleksandr Urakov   }
8646179c0ebSAleksandr Urakov 
8656179c0ebSAleksandr Urakov   WatchpointInfo info;
8666179c0ebSAleksandr Urakov   for (info.slot_id = 0;
8676179c0ebSAleksandr Urakov        info.slot_id < RegisterContextWindows::GetNumHardwareBreakpointSlots();
8686179c0ebSAleksandr Urakov        info.slot_id++)
8696179c0ebSAleksandr Urakov     if (m_watchpoint_ids[info.slot_id] == LLDB_INVALID_BREAK_ID)
8706179c0ebSAleksandr Urakov       break;
8716179c0ebSAleksandr Urakov   if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) {
8726179c0ebSAleksandr Urakov     error.SetErrorStringWithFormat("Can't find free slot for watchpoint %i",
8736179c0ebSAleksandr Urakov                                    wp->GetID());
8746179c0ebSAleksandr Urakov     return error;
8756179c0ebSAleksandr Urakov   }
8766179c0ebSAleksandr Urakov   info.address = wp->GetLoadAddress();
8776179c0ebSAleksandr Urakov   info.size = wp->GetByteSize();
8786179c0ebSAleksandr Urakov   info.read = wp->WatchpointRead();
8796179c0ebSAleksandr Urakov   info.write = wp->WatchpointWrite();
8806179c0ebSAleksandr Urakov 
8816179c0ebSAleksandr Urakov   for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
8826179c0ebSAleksandr Urakov     Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
8836179c0ebSAleksandr Urakov     auto *reg_ctx = static_cast<RegisterContextWindows *>(
8846179c0ebSAleksandr Urakov         thread->GetRegisterContext().get());
8856179c0ebSAleksandr Urakov     if (!reg_ctx->AddHardwareBreakpoint(info.slot_id, info.address, info.size,
8866179c0ebSAleksandr Urakov                                         info.read, info.write)) {
8876179c0ebSAleksandr Urakov       error.SetErrorStringWithFormat(
8886179c0ebSAleksandr Urakov           "Can't enable watchpoint %i on thread 0x%llx", wp->GetID(),
8896179c0ebSAleksandr Urakov           thread->GetID());
8906179c0ebSAleksandr Urakov       break;
8916179c0ebSAleksandr Urakov     }
8926179c0ebSAleksandr Urakov   }
8936179c0ebSAleksandr Urakov   if (error.Fail()) {
8946179c0ebSAleksandr Urakov     for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
8956179c0ebSAleksandr Urakov       Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
8966179c0ebSAleksandr Urakov       auto *reg_ctx = static_cast<RegisterContextWindows *>(
8976179c0ebSAleksandr Urakov           thread->GetRegisterContext().get());
8986179c0ebSAleksandr Urakov       reg_ctx->RemoveHardwareBreakpoint(info.slot_id);
8996179c0ebSAleksandr Urakov     }
9006179c0ebSAleksandr Urakov     return error;
9016179c0ebSAleksandr Urakov   }
9026179c0ebSAleksandr Urakov 
9036179c0ebSAleksandr Urakov   m_watchpoints[wp->GetID()] = info;
9046179c0ebSAleksandr Urakov   m_watchpoint_ids[info.slot_id] = wp->GetID();
9056179c0ebSAleksandr Urakov 
9066179c0ebSAleksandr Urakov   wp->SetEnabled(true, notify);
9076179c0ebSAleksandr Urakov 
9086179c0ebSAleksandr Urakov   return error;
9096179c0ebSAleksandr Urakov }
9106179c0ebSAleksandr Urakov 
9116179c0ebSAleksandr Urakov Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) {
9126179c0ebSAleksandr Urakov   Status error;
9136179c0ebSAleksandr Urakov 
9146179c0ebSAleksandr Urakov   if (!wp->IsEnabled()) {
9156179c0ebSAleksandr Urakov     wp->SetEnabled(false, notify);
9166179c0ebSAleksandr Urakov     return error;
9176179c0ebSAleksandr Urakov   }
9186179c0ebSAleksandr Urakov 
9196179c0ebSAleksandr Urakov   auto it = m_watchpoints.find(wp->GetID());
9206179c0ebSAleksandr Urakov   if (it == m_watchpoints.end()) {
9216179c0ebSAleksandr Urakov     error.SetErrorStringWithFormat("Info about watchpoint %i is not found",
9226179c0ebSAleksandr Urakov                                    wp->GetID());
9236179c0ebSAleksandr Urakov     return error;
9246179c0ebSAleksandr Urakov   }
9256179c0ebSAleksandr Urakov 
9266179c0ebSAleksandr Urakov   for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
9276179c0ebSAleksandr Urakov     Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
9286179c0ebSAleksandr Urakov     auto *reg_ctx = static_cast<RegisterContextWindows *>(
9296179c0ebSAleksandr Urakov         thread->GetRegisterContext().get());
9306179c0ebSAleksandr Urakov     if (!reg_ctx->RemoveHardwareBreakpoint(it->second.slot_id)) {
9316179c0ebSAleksandr Urakov       error.SetErrorStringWithFormat(
9326179c0ebSAleksandr Urakov           "Can't disable watchpoint %i on thread 0x%llx", wp->GetID(),
9336179c0ebSAleksandr Urakov           thread->GetID());
9346179c0ebSAleksandr Urakov       break;
9356179c0ebSAleksandr Urakov     }
9366179c0ebSAleksandr Urakov   }
9376179c0ebSAleksandr Urakov   if (error.Fail())
9386179c0ebSAleksandr Urakov     return error;
9396179c0ebSAleksandr Urakov 
9406179c0ebSAleksandr Urakov   m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID;
9416179c0ebSAleksandr Urakov   m_watchpoints.erase(it);
9426179c0ebSAleksandr Urakov 
9436179c0ebSAleksandr Urakov   wp->SetEnabled(false, notify);
9446179c0ebSAleksandr Urakov 
9456179c0ebSAleksandr Urakov   return error;
9466179c0ebSAleksandr Urakov }
9474ad5def9SAdrian McCarthy } // namespace lldb_private
948