118a9135dSAdrian McCarthy //===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===//
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 
1518a9135dSAdrian McCarthy #include "lldb/Core/Module.h"
1618a9135dSAdrian McCarthy #include "lldb/Core/ModuleSpec.h"
1718a9135dSAdrian McCarthy #include "lldb/Core/PluginManager.h"
1818a9135dSAdrian McCarthy #include "lldb/Core/Section.h"
1960cf3f82SJonas Devlieghere #include "lldb/Host/FileSystem.h"
204ad5def9SAdrian McCarthy #include "lldb/Host/HostNativeProcessBase.h"
214ad5def9SAdrian McCarthy #include "lldb/Host/HostProcess.h"
224ad5def9SAdrian McCarthy #include "lldb/Host/windows/HostThreadWindows.h"
230c35cde9SAdrian McCarthy #include "lldb/Host/windows/windows.h"
242f3df613SZachary Turner #include "lldb/Symbol/ObjectFile.h"
2518a9135dSAdrian McCarthy #include "lldb/Target/DynamicLoader.h"
2618a9135dSAdrian McCarthy #include "lldb/Target/MemoryRegionInfo.h"
274ad5def9SAdrian McCarthy #include "lldb/Target/StopInfo.h"
2818a9135dSAdrian McCarthy #include "lldb/Target/Target.h"
29d821c997SPavel Labath #include "lldb/Utility/State.h"
3018a9135dSAdrian McCarthy 
314ad5def9SAdrian McCarthy #include "llvm/Support/ConvertUTF.h"
324ad5def9SAdrian McCarthy #include "llvm/Support/Format.h"
33c5f28e2aSKamil Rytarowski #include "llvm/Support/Threading.h"
344ad5def9SAdrian McCarthy #include "llvm/Support/raw_ostream.h"
354ad5def9SAdrian McCarthy 
364ad5def9SAdrian McCarthy #include "DebuggerThread.h"
374ad5def9SAdrian McCarthy #include "ExceptionRecord.h"
384ad5def9SAdrian McCarthy #include "ForwardDecl.h"
394ad5def9SAdrian McCarthy #include "LocalDebugDelegate.h"
404ad5def9SAdrian McCarthy #include "ProcessWindowsLog.h"
414ad5def9SAdrian McCarthy #include "TargetThreadWindows.h"
424ad5def9SAdrian McCarthy 
4318a9135dSAdrian McCarthy using namespace lldb;
4418a9135dSAdrian McCarthy using namespace lldb_private;
4518a9135dSAdrian McCarthy 
464ad5def9SAdrian McCarthy namespace {
474ad5def9SAdrian McCarthy std::string GetProcessExecutableName(HANDLE process_handle) {
484ad5def9SAdrian McCarthy   std::vector<wchar_t> file_name;
494ad5def9SAdrian McCarthy   DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit
504ad5def9SAdrian McCarthy   DWORD copied = 0;
514ad5def9SAdrian McCarthy   do {
524ad5def9SAdrian McCarthy     file_name_size *= 2;
534ad5def9SAdrian McCarthy     file_name.resize(file_name_size);
544ad5def9SAdrian McCarthy     copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(),
554ad5def9SAdrian McCarthy                                     file_name_size);
564ad5def9SAdrian McCarthy   } while (copied >= file_name_size);
574ad5def9SAdrian McCarthy   file_name.resize(copied);
584ad5def9SAdrian McCarthy   std::string result;
594ad5def9SAdrian McCarthy   llvm::convertWideToUTF8(file_name.data(), result);
604ad5def9SAdrian McCarthy   return result;
614ad5def9SAdrian McCarthy }
624ad5def9SAdrian McCarthy 
634ad5def9SAdrian McCarthy std::string GetProcessExecutableName(DWORD pid) {
644ad5def9SAdrian McCarthy   std::string file_name;
654ad5def9SAdrian McCarthy   HANDLE process_handle =
664ad5def9SAdrian McCarthy       ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
674ad5def9SAdrian McCarthy   if (process_handle != NULL) {
684ad5def9SAdrian McCarthy     file_name = GetProcessExecutableName(process_handle);
694ad5def9SAdrian McCarthy     ::CloseHandle(process_handle);
704ad5def9SAdrian McCarthy   }
714ad5def9SAdrian McCarthy   return file_name;
724ad5def9SAdrian McCarthy }
734ad5def9SAdrian McCarthy } // anonymous namespace
744ad5def9SAdrian McCarthy 
75b9c1b51eSKate Stone namespace lldb_private {
7618a9135dSAdrian McCarthy 
774ad5def9SAdrian McCarthy ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
784ad5def9SAdrian McCarthy                                          lldb::ListenerSP listener_sp,
794ad5def9SAdrian McCarthy                                          const FileSpec *) {
804ad5def9SAdrian McCarthy   return ProcessSP(new ProcessWindows(target_sp, listener_sp));
814ad5def9SAdrian McCarthy }
824ad5def9SAdrian McCarthy 
834ad5def9SAdrian McCarthy void ProcessWindows::Initialize() {
84c5f28e2aSKamil Rytarowski   static llvm::once_flag g_once_flag;
854ad5def9SAdrian McCarthy 
86c5f28e2aSKamil Rytarowski   llvm::call_once(g_once_flag, []() {
874ad5def9SAdrian McCarthy     PluginManager::RegisterPlugin(GetPluginNameStatic(),
884ad5def9SAdrian McCarthy                                   GetPluginDescriptionStatic(), CreateInstance);
894ad5def9SAdrian McCarthy   });
904ad5def9SAdrian McCarthy }
914ad5def9SAdrian McCarthy 
924ad5def9SAdrian McCarthy void ProcessWindows::Terminate() {}
934ad5def9SAdrian McCarthy 
944ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginNameStatic() {
954ad5def9SAdrian McCarthy   static ConstString g_name("windows");
964ad5def9SAdrian McCarthy   return g_name;
974ad5def9SAdrian McCarthy }
984ad5def9SAdrian McCarthy 
994ad5def9SAdrian McCarthy const char *ProcessWindows::GetPluginDescriptionStatic() {
1004ad5def9SAdrian McCarthy   return "Process plugin for Windows";
1014ad5def9SAdrian McCarthy }
1024ad5def9SAdrian McCarthy 
10318a9135dSAdrian McCarthy // Constructors and destructors.
10418a9135dSAdrian McCarthy 
105b9c1b51eSKate Stone ProcessWindows::ProcessWindows(lldb::TargetSP target_sp,
106b9c1b51eSKate Stone                                lldb::ListenerSP listener_sp)
107b9c1b51eSKate Stone     : lldb_private::Process(target_sp, listener_sp) {}
10818a9135dSAdrian McCarthy 
109b9c1b51eSKate Stone ProcessWindows::~ProcessWindows() {}
11018a9135dSAdrian McCarthy 
11197206d57SZachary Turner size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
11218a9135dSAdrian McCarthy   error.SetErrorString("GetSTDOUT unsupported on Windows");
11318a9135dSAdrian McCarthy   return 0;
11418a9135dSAdrian McCarthy }
11518a9135dSAdrian McCarthy 
11697206d57SZachary Turner size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) {
11718a9135dSAdrian McCarthy   error.SetErrorString("GetSTDERR unsupported on Windows");
11818a9135dSAdrian McCarthy   return 0;
11918a9135dSAdrian McCarthy }
12018a9135dSAdrian McCarthy 
121b9c1b51eSKate Stone size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size,
12297206d57SZachary Turner                                 Status &error) {
12318a9135dSAdrian McCarthy   error.SetErrorString("PutSTDIN unsupported on Windows");
12418a9135dSAdrian McCarthy   return 0;
12518a9135dSAdrian McCarthy }
12618a9135dSAdrian McCarthy 
12718a9135dSAdrian McCarthy // ProcessInterface protocol.
12818a9135dSAdrian McCarthy 
1294ad5def9SAdrian McCarthy lldb_private::ConstString ProcessWindows::GetPluginName() {
1304ad5def9SAdrian McCarthy   return GetPluginNameStatic();
1314ad5def9SAdrian McCarthy }
1324ad5def9SAdrian McCarthy 
1334ad5def9SAdrian McCarthy uint32_t ProcessWindows::GetPluginVersion() { return 1; }
1344ad5def9SAdrian McCarthy 
13597206d57SZachary Turner Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) {
136a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
137a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
138a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1394ad5def9SAdrian McCarthy 
14097206d57SZachary Turner   Status error = EnableSoftwareBreakpoint(bp_site);
141a385d2c1SPavel Labath   if (!error.Success())
142a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1434ad5def9SAdrian McCarthy   return error;
1444ad5def9SAdrian McCarthy }
1454ad5def9SAdrian McCarthy 
14697206d57SZachary Turner Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) {
147a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS);
148a385d2c1SPavel Labath   LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site,
149a385d2c1SPavel Labath            bp_site->GetID(), bp_site->GetLoadAddress());
1504ad5def9SAdrian McCarthy 
15197206d57SZachary Turner   Status error = DisableSoftwareBreakpoint(bp_site);
1524ad5def9SAdrian McCarthy 
153a385d2c1SPavel Labath   if (!error.Success())
154a385d2c1SPavel Labath     LLDB_LOG(log, "error: {0}", error);
1554ad5def9SAdrian McCarthy   return error;
1564ad5def9SAdrian McCarthy }
1574ad5def9SAdrian McCarthy 
15897206d57SZachary Turner Status ProcessWindows::DoDetach(bool keep_stopped) {
159ed499a36SStella Stamenova   Status error;
160053eb356SAaron Smith   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
161053eb356SAaron Smith   StateType private_state = GetPrivateState();
162ed499a36SStella Stamenova   if (private_state != eStateExited && private_state != eStateDetached) {
163053eb356SAaron Smith     error = DetachProcess();
164053eb356SAaron Smith     if (error.Success())
165ed499a36SStella Stamenova       SetPrivateState(eStateDetached);
166053eb356SAaron Smith     else
167053eb356SAaron Smith       LLDB_LOG(log, "Detaching process error: {0}", error);
168ed499a36SStella Stamenova   } else {
169053eb356SAaron Smith     error.SetErrorStringWithFormat("error: process {0} in state = {1}, but "
170053eb356SAaron Smith                                    "cannot detach it in this state.",
171053eb356SAaron Smith                                    GetID(), private_state);
172053eb356SAaron Smith     LLDB_LOG(log, "error: {0}", error);
173ed499a36SStella Stamenova   }
1744ad5def9SAdrian McCarthy   return error;
1754ad5def9SAdrian McCarthy }
1764ad5def9SAdrian McCarthy 
17797206d57SZachary Turner Status ProcessWindows::DoLaunch(Module *exe_module,
1784ad5def9SAdrian McCarthy                                 ProcessLaunchInfo &launch_info) {
179053eb356SAaron Smith   Status error;
1804ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
181053eb356SAaron Smith   error = LaunchProcess(launch_info, delegate);
182053eb356SAaron Smith   if (error.Success())
183053eb356SAaron Smith     SetID(launch_info.GetProcessID());
1844ad5def9SAdrian McCarthy   return error;
1854ad5def9SAdrian McCarthy }
1864ad5def9SAdrian McCarthy 
18797206d57SZachary Turner Status
18897206d57SZachary Turner ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
18997206d57SZachary Turner                                         const ProcessAttachInfo &attach_info) {
1904ad5def9SAdrian McCarthy   DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
191053eb356SAaron Smith   Status error = AttachProcess(pid, attach_info, delegate);
192053eb356SAaron Smith   if (error.Success())
193053eb356SAaron Smith     SetID(GetDebuggedProcessId());
1944ad5def9SAdrian McCarthy   return error;
1954ad5def9SAdrian McCarthy }
1964ad5def9SAdrian McCarthy 
19797206d57SZachary Turner Status ProcessWindows::DoResume() {
198a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
1994ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
20097206d57SZachary Turner   Status error;
2014ad5def9SAdrian McCarthy 
2024ad5def9SAdrian McCarthy   StateType private_state = GetPrivateState();
2034ad5def9SAdrian McCarthy   if (private_state == eStateStopped || private_state == eStateCrashed) {
204a385d2c1SPavel Labath     LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",
2054ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
2064ad5def9SAdrian McCarthy              GetPrivateState());
2074ad5def9SAdrian McCarthy 
208a385d2c1SPavel Labath     LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize());
2094ad5def9SAdrian McCarthy 
2100fd67b53SStella Stamenova     bool failed = false;
2114ad5def9SAdrian McCarthy     for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) {
2124ad5def9SAdrian McCarthy       auto thread = std::static_pointer_cast<TargetThreadWindows>(
2134ad5def9SAdrian McCarthy           m_thread_list.GetThreadAtIndex(i));
2140fd67b53SStella Stamenova       Status result = thread->DoResume();
2150fd67b53SStella Stamenova       if (result.Fail()) {
2160fd67b53SStella Stamenova         failed = true;
21762c76db4SStella Stamenova         LLDB_LOG(
21862c76db4SStella Stamenova             log,
21962c76db4SStella Stamenova             "Trying to resume thread at index {0}, but failed with error {1}.",
22062c76db4SStella Stamenova             i, result);
2210fd67b53SStella Stamenova       }
2224ad5def9SAdrian McCarthy     }
2234ad5def9SAdrian McCarthy 
2240fd67b53SStella Stamenova     if (failed) {
2250fd67b53SStella Stamenova       error.SetErrorString("ProcessWindows::DoResume failed");
2260fd67b53SStella Stamenova     } else {
2274ad5def9SAdrian McCarthy       SetPrivateState(eStateRunning);
2280fd67b53SStella Stamenova     }
229*3f062102SAdrian McCarthy 
230*3f062102SAdrian McCarthy     ExceptionRecordSP active_exception =
231*3f062102SAdrian McCarthy         m_session_data->m_debugger->GetActiveException().lock();
232*3f062102SAdrian McCarthy     if (active_exception) {
233*3f062102SAdrian McCarthy       // Resume the process and continue processing debug events.  Mask the
234*3f062102SAdrian McCarthy       // exception so that from the process's view, there is no indication that
235*3f062102SAdrian McCarthy       // anything happened.
236*3f062102SAdrian McCarthy       m_session_data->m_debugger->ContinueAsyncException(
237*3f062102SAdrian McCarthy           ExceptionResult::MaskException);
238*3f062102SAdrian McCarthy     }
2394ad5def9SAdrian McCarthy   } else {
240c28daec5SAaron Smith     LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",
2414ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId(),
2424ad5def9SAdrian McCarthy              GetPrivateState());
2434ad5def9SAdrian McCarthy   }
2444ad5def9SAdrian McCarthy   return error;
2454ad5def9SAdrian McCarthy }
2464ad5def9SAdrian McCarthy 
24797206d57SZachary Turner Status ProcessWindows::DoDestroy() {
248053eb356SAaron Smith   StateType private_state = GetPrivateState();
249053eb356SAaron Smith   return DestroyProcess(private_state);
2504ad5def9SAdrian McCarthy }
2514ad5def9SAdrian McCarthy 
25297206d57SZachary Turner Status ProcessWindows::DoHalt(bool &caused_stop) {
2534ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
254053eb356SAaron Smith   if (state != eStateStopped)
255053eb356SAaron Smith     return HaltProcess(caused_stop);
2564ad5def9SAdrian McCarthy   caused_stop = false;
257053eb356SAaron Smith   return Status();
2584ad5def9SAdrian McCarthy }
2594ad5def9SAdrian McCarthy 
2604ad5def9SAdrian McCarthy void ProcessWindows::DidLaunch() {
2614ad5def9SAdrian McCarthy   ArchSpec arch_spec;
2624ad5def9SAdrian McCarthy   DidAttach(arch_spec);
2634ad5def9SAdrian McCarthy }
2644ad5def9SAdrian McCarthy 
2654ad5def9SAdrian McCarthy void ProcessWindows::DidAttach(ArchSpec &arch_spec) {
2664ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
2674ad5def9SAdrian McCarthy 
2684ad5def9SAdrian McCarthy   // The initial stop won't broadcast the state change event, so account for
2694ad5def9SAdrian McCarthy   // that here.
2704ad5def9SAdrian McCarthy   if (m_session_data && GetPrivateState() == eStateStopped &&
2714ad5def9SAdrian McCarthy       m_session_data->m_stop_at_entry)
2724ad5def9SAdrian McCarthy     RefreshStateAfterStop();
2734ad5def9SAdrian McCarthy }
2744ad5def9SAdrian McCarthy 
27526366c3eSAleksandr Urakov static void
27626366c3eSAleksandr Urakov DumpAdditionalExceptionInformation(llvm::raw_ostream &stream,
27726366c3eSAleksandr Urakov                                    const ExceptionRecordSP &exception) {
27826366c3eSAleksandr Urakov   // Decode additional exception information for specific exception types based
27926366c3eSAleksandr Urakov   // on
28026366c3eSAleksandr Urakov   // https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record
28126366c3eSAleksandr Urakov 
28226366c3eSAleksandr Urakov   const int addr_min_width = 2 + 8; // "0x" + 4 address bytes
28326366c3eSAleksandr Urakov 
28426366c3eSAleksandr Urakov   const std::vector<ULONG_PTR> &args = exception->GetExceptionArguments();
28526366c3eSAleksandr Urakov   switch (exception->GetExceptionCode()) {
28626366c3eSAleksandr Urakov   case EXCEPTION_ACCESS_VIOLATION: {
28726366c3eSAleksandr Urakov     if (args.size() < 2)
28826366c3eSAleksandr Urakov       break;
28926366c3eSAleksandr Urakov 
29026366c3eSAleksandr Urakov     stream << ": ";
29126366c3eSAleksandr Urakov     const int access_violation_code = args[0];
29226366c3eSAleksandr Urakov     const lldb::addr_t access_violation_address = args[1];
29326366c3eSAleksandr Urakov     switch (access_violation_code) {
29426366c3eSAleksandr Urakov     case 0:
29526366c3eSAleksandr Urakov       stream << "Access violation reading";
29626366c3eSAleksandr Urakov       break;
29726366c3eSAleksandr Urakov     case 1:
29826366c3eSAleksandr Urakov       stream << "Access violation writing";
29926366c3eSAleksandr Urakov       break;
30026366c3eSAleksandr Urakov     case 8:
30126366c3eSAleksandr Urakov       stream << "User-mode data execution prevention (DEP) violation at";
30226366c3eSAleksandr Urakov       break;
30326366c3eSAleksandr Urakov     default:
30426366c3eSAleksandr Urakov       stream << "Unknown access violation (code " << access_violation_code
30526366c3eSAleksandr Urakov              << ") at";
30626366c3eSAleksandr Urakov       break;
30726366c3eSAleksandr Urakov     }
30826366c3eSAleksandr Urakov     stream << " location "
30926366c3eSAleksandr Urakov            << llvm::format_hex(access_violation_address, addr_min_width);
31026366c3eSAleksandr Urakov     break;
31126366c3eSAleksandr Urakov   }
31226366c3eSAleksandr Urakov   case EXCEPTION_IN_PAGE_ERROR: {
31326366c3eSAleksandr Urakov     if (args.size() < 3)
31426366c3eSAleksandr Urakov       break;
31526366c3eSAleksandr Urakov 
31626366c3eSAleksandr Urakov     stream << ": ";
31726366c3eSAleksandr Urakov     const int page_load_error_code = args[0];
31826366c3eSAleksandr Urakov     const lldb::addr_t page_load_error_address = args[1];
31926366c3eSAleksandr Urakov     const DWORD underlying_code = args[2];
32026366c3eSAleksandr Urakov     switch (page_load_error_code) {
32126366c3eSAleksandr Urakov     case 0:
32226366c3eSAleksandr Urakov       stream << "In page error reading";
32326366c3eSAleksandr Urakov       break;
32426366c3eSAleksandr Urakov     case 1:
32526366c3eSAleksandr Urakov       stream << "In page error writing";
32626366c3eSAleksandr Urakov       break;
32726366c3eSAleksandr Urakov     case 8:
32826366c3eSAleksandr Urakov       stream << "User-mode data execution prevention (DEP) violation at";
32926366c3eSAleksandr Urakov       break;
33026366c3eSAleksandr Urakov     default:
33126366c3eSAleksandr Urakov       stream << "Unknown page loading error (code " << page_load_error_code
33226366c3eSAleksandr Urakov              << ") at";
33326366c3eSAleksandr Urakov       break;
33426366c3eSAleksandr Urakov     }
33526366c3eSAleksandr Urakov     stream << " location "
33626366c3eSAleksandr Urakov            << llvm::format_hex(page_load_error_address, addr_min_width)
33726366c3eSAleksandr Urakov            << " (status code " << llvm::format_hex(underlying_code, 8) << ")";
33826366c3eSAleksandr Urakov     break;
33926366c3eSAleksandr Urakov   }
34026366c3eSAleksandr Urakov   }
34126366c3eSAleksandr Urakov }
34226366c3eSAleksandr Urakov 
3434ad5def9SAdrian McCarthy void ProcessWindows::RefreshStateAfterStop() {
344a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
3454ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
3464ad5def9SAdrian McCarthy 
3474ad5def9SAdrian McCarthy   if (!m_session_data) {
348a385d2c1SPavel Labath     LLDB_LOG(log, "no active session.  Returning...");
3494ad5def9SAdrian McCarthy     return;
3504ad5def9SAdrian McCarthy   }
3514ad5def9SAdrian McCarthy 
3524ad5def9SAdrian McCarthy   m_thread_list.RefreshStateAfterStop();
3534ad5def9SAdrian McCarthy 
3544ad5def9SAdrian McCarthy   std::weak_ptr<ExceptionRecord> exception_record =
3554ad5def9SAdrian McCarthy       m_session_data->m_debugger->GetActiveException();
3564ad5def9SAdrian McCarthy   ExceptionRecordSP active_exception = exception_record.lock();
3574ad5def9SAdrian McCarthy   if (!active_exception) {
35862c76db4SStella Stamenova     LLDB_LOG(log,
35962c76db4SStella Stamenova              "there is no active exception in process {0}.  Why is the "
360a385d2c1SPavel Labath              "process stopped?",
3614ad5def9SAdrian McCarthy              m_session_data->m_debugger->GetProcess().GetProcessId());
3624ad5def9SAdrian McCarthy     return;
3634ad5def9SAdrian McCarthy   }
3644ad5def9SAdrian McCarthy 
3654ad5def9SAdrian McCarthy   StopInfoSP stop_info;
3664ad5def9SAdrian McCarthy   m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID());
3674ad5def9SAdrian McCarthy   ThreadSP stop_thread = m_thread_list.GetSelectedThread();
3684ad5def9SAdrian McCarthy   if (!stop_thread)
3694ad5def9SAdrian McCarthy     return;
3704ad5def9SAdrian McCarthy 
3714ad5def9SAdrian McCarthy   switch (active_exception->GetExceptionCode()) {
3724ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP: {
3734ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
3744ad5def9SAdrian McCarthy     const uint64_t pc = register_context->GetPC();
3754ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
3764ad5def9SAdrian McCarthy     if (site && site->ValidForThisThread(stop_thread.get())) {
37762c76db4SStella Stamenova       LLDB_LOG(log,
37862c76db4SStella Stamenova                "Single-stepped onto a breakpoint in process {0} at "
379a385d2c1SPavel Labath                "address {1:x} with breakpoint site {2}",
3804ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
3814ad5def9SAdrian McCarthy                site->GetID());
3824ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread,
3834ad5def9SAdrian McCarthy                                                                  site->GetID());
3844ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
3854ad5def9SAdrian McCarthy     } else {
386a385d2c1SPavel Labath       LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID());
3874ad5def9SAdrian McCarthy       stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
3884ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
3894ad5def9SAdrian McCarthy     }
3904ad5def9SAdrian McCarthy     return;
3914ad5def9SAdrian McCarthy   }
3924ad5def9SAdrian McCarthy 
3934ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT: {
3944ad5def9SAdrian McCarthy     RegisterContextSP register_context = stop_thread->GetRegisterContext();
3954ad5def9SAdrian McCarthy 
3964ad5def9SAdrian McCarthy     // The current EIP is AFTER the BP opcode, which is one byte.
3974ad5def9SAdrian McCarthy     uint64_t pc = register_context->GetPC() - 1;
3984ad5def9SAdrian McCarthy 
3994ad5def9SAdrian McCarthy     BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
4004ad5def9SAdrian McCarthy     if (site) {
40162c76db4SStella Stamenova       LLDB_LOG(log,
40262c76db4SStella Stamenova                "detected breakpoint in process {0} at address {1:x} with "
403a385d2c1SPavel Labath                "breakpoint site {2}",
4044ad5def9SAdrian McCarthy                m_session_data->m_debugger->GetProcess().GetProcessId(), pc,
4054ad5def9SAdrian McCarthy                site->GetID());
4064ad5def9SAdrian McCarthy 
4074ad5def9SAdrian McCarthy       if (site->ValidForThisThread(stop_thread.get())) {
40862c76db4SStella Stamenova         LLDB_LOG(log,
40962c76db4SStella Stamenova                  "Breakpoint site {0} is valid for this thread ({1:x}), "
4104ad5def9SAdrian McCarthy                  "creating stop info.",
4114ad5def9SAdrian McCarthy                  site->GetID(), stop_thread->GetID());
4124ad5def9SAdrian McCarthy 
4134ad5def9SAdrian McCarthy         stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(
4144ad5def9SAdrian McCarthy             *stop_thread, site->GetID());
4154ad5def9SAdrian McCarthy         register_context->SetPC(pc);
4164ad5def9SAdrian McCarthy       } else {
41762c76db4SStella Stamenova         LLDB_LOG(log,
41862c76db4SStella Stamenova                  "Breakpoint site {0} is not valid for this thread, "
4194ad5def9SAdrian McCarthy                  "creating empty stop info.",
4204ad5def9SAdrian McCarthy                  site->GetID());
4214ad5def9SAdrian McCarthy       }
4224ad5def9SAdrian McCarthy       stop_thread->SetStopInfo(stop_info);
4234ad5def9SAdrian McCarthy       return;
4244ad5def9SAdrian McCarthy     } else {
4254ad5def9SAdrian McCarthy       // The thread hit a hard-coded breakpoint like an `int 3` or
4264ad5def9SAdrian McCarthy       // `__debugbreak()`.
427a385d2c1SPavel Labath       LLDB_LOG(log,
4284ad5def9SAdrian McCarthy                "No breakpoint site matches for this thread. __debugbreak()?  "
4294ad5def9SAdrian McCarthy                "Creating stop info with the exception.");
4304ad5def9SAdrian McCarthy       // FALLTHROUGH:  We'll treat this as a generic exception record in the
4314ad5def9SAdrian McCarthy       // default case.
432b0717666SAlexandre Ganea       LLVM_FALLTHROUGH;
4334ad5def9SAdrian McCarthy     }
4344ad5def9SAdrian McCarthy   }
4354ad5def9SAdrian McCarthy 
4364ad5def9SAdrian McCarthy   default: {
4374ad5def9SAdrian McCarthy     std::string desc;
4384ad5def9SAdrian McCarthy     llvm::raw_string_ostream desc_stream(desc);
4394ad5def9SAdrian McCarthy     desc_stream << "Exception "
4404ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionCode(), 8)
4414ad5def9SAdrian McCarthy                 << " encountered at address "
4424ad5def9SAdrian McCarthy                 << llvm::format_hex(active_exception->GetExceptionAddress(), 8);
44326366c3eSAleksandr Urakov     DumpAdditionalExceptionInformation(desc_stream, active_exception);
44426366c3eSAleksandr Urakov 
4454ad5def9SAdrian McCarthy     stop_info = StopInfo::CreateStopReasonWithException(
4464ad5def9SAdrian McCarthy         *stop_thread, desc_stream.str().c_str());
4474ad5def9SAdrian McCarthy     stop_thread->SetStopInfo(stop_info);
448a385d2c1SPavel Labath     LLDB_LOG(log, "{0}", desc_stream.str());
4494ad5def9SAdrian McCarthy     return;
4504ad5def9SAdrian McCarthy   }
4514ad5def9SAdrian McCarthy   }
4524ad5def9SAdrian McCarthy }
4534ad5def9SAdrian McCarthy 
4544ad5def9SAdrian McCarthy bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
4554ad5def9SAdrian McCarthy                               bool plugin_specified_by_name) {
4564ad5def9SAdrian McCarthy   if (plugin_specified_by_name)
4574ad5def9SAdrian McCarthy     return true;
4584ad5def9SAdrian McCarthy 
4594ad5def9SAdrian McCarthy   // For now we are just making sure the file exists for a given module
4604ad5def9SAdrian McCarthy   ModuleSP exe_module_sp(target_sp->GetExecutableModule());
4614ad5def9SAdrian McCarthy   if (exe_module_sp.get())
46260cf3f82SJonas Devlieghere     return FileSystem::Instance().Exists(exe_module_sp->GetFileSpec());
46305097246SAdrian Prantl   // However, if there is no executable module, we return true since we might
46405097246SAdrian Prantl   // be preparing to attach.
4654ad5def9SAdrian McCarthy   return true;
4664ad5def9SAdrian McCarthy }
4674ad5def9SAdrian McCarthy 
4684ad5def9SAdrian McCarthy bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list,
4694ad5def9SAdrian McCarthy                                       ThreadList &new_thread_list) {
470a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD);
4714ad5def9SAdrian McCarthy   // Add all the threads that were previously running and for which we did not
4724ad5def9SAdrian McCarthy   // detect a thread exited event.
4734ad5def9SAdrian McCarthy   int new_size = 0;
4744ad5def9SAdrian McCarthy   int continued_threads = 0;
4754ad5def9SAdrian McCarthy   int exited_threads = 0;
4764ad5def9SAdrian McCarthy   int new_threads = 0;
4774ad5def9SAdrian McCarthy 
4784ad5def9SAdrian McCarthy   for (ThreadSP old_thread : old_thread_list.Threads()) {
4794ad5def9SAdrian McCarthy     lldb::tid_t old_thread_id = old_thread->GetID();
4804ad5def9SAdrian McCarthy     auto exited_thread_iter =
4814ad5def9SAdrian McCarthy         m_session_data->m_exited_threads.find(old_thread_id);
4824ad5def9SAdrian McCarthy     if (exited_thread_iter == m_session_data->m_exited_threads.end()) {
4834ad5def9SAdrian McCarthy       new_thread_list.AddThread(old_thread);
4844ad5def9SAdrian McCarthy       ++new_size;
4854ad5def9SAdrian McCarthy       ++continued_threads;
486a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and is still running.",
4874ad5def9SAdrian McCarthy                 old_thread_id);
4884ad5def9SAdrian McCarthy     } else {
489a385d2c1SPavel Labath       LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id);
4904ad5def9SAdrian McCarthy       ++exited_threads;
4914ad5def9SAdrian McCarthy     }
4924ad5def9SAdrian McCarthy   }
4934ad5def9SAdrian McCarthy 
49405097246SAdrian Prantl   // Also add all the threads that are new since the last time we broke into
49505097246SAdrian Prantl   // the debugger.
4964ad5def9SAdrian McCarthy   for (const auto &thread_info : m_session_data->m_new_threads) {
4974ad5def9SAdrian McCarthy     ThreadSP thread(new TargetThreadWindows(*this, thread_info.second));
4984ad5def9SAdrian McCarthy     thread->SetID(thread_info.first);
4994ad5def9SAdrian McCarthy     new_thread_list.AddThread(thread);
5004ad5def9SAdrian McCarthy     ++new_size;
5014ad5def9SAdrian McCarthy     ++new_threads;
502a385d2c1SPavel Labath     LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first);
5034ad5def9SAdrian McCarthy   }
5044ad5def9SAdrian McCarthy 
505a385d2c1SPavel Labath   LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.",
5064ad5def9SAdrian McCarthy            new_threads, continued_threads, exited_threads);
5074ad5def9SAdrian McCarthy 
5084ad5def9SAdrian McCarthy   m_session_data->m_new_threads.clear();
5094ad5def9SAdrian McCarthy   m_session_data->m_exited_threads.clear();
5104ad5def9SAdrian McCarthy 
5114ad5def9SAdrian McCarthy   return new_size > 0;
5124ad5def9SAdrian McCarthy }
5134ad5def9SAdrian McCarthy 
5144ad5def9SAdrian McCarthy bool ProcessWindows::IsAlive() {
5154ad5def9SAdrian McCarthy   StateType state = GetPrivateState();
5164ad5def9SAdrian McCarthy   switch (state) {
5174ad5def9SAdrian McCarthy   case eStateCrashed:
5184ad5def9SAdrian McCarthy   case eStateDetached:
5194ad5def9SAdrian McCarthy   case eStateUnloaded:
5204ad5def9SAdrian McCarthy   case eStateExited:
5214ad5def9SAdrian McCarthy   case eStateInvalid:
5224ad5def9SAdrian McCarthy     return false;
5234ad5def9SAdrian McCarthy   default:
5244ad5def9SAdrian McCarthy     return true;
5254ad5def9SAdrian McCarthy   }
5264ad5def9SAdrian McCarthy }
5274ad5def9SAdrian McCarthy 
5284ad5def9SAdrian McCarthy size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf,
52997206d57SZachary Turner                                     size_t size, Status &error) {
530053eb356SAaron Smith   size_t bytes_read = 0;
531053eb356SAaron Smith   error = ProcessDebugger::ReadMemory(vm_addr, buf, size, bytes_read);
5324ad5def9SAdrian McCarthy   return bytes_read;
5334ad5def9SAdrian McCarthy }
5344ad5def9SAdrian McCarthy 
5354ad5def9SAdrian McCarthy size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
53697206d57SZachary Turner                                      size_t size, Status &error) {
537053eb356SAaron Smith   size_t bytes_written = 0;
538053eb356SAaron Smith   error = ProcessDebugger::WriteMemory(vm_addr, buf, size, bytes_written);
5394ad5def9SAdrian McCarthy   return bytes_written;
5404ad5def9SAdrian McCarthy }
5414ad5def9SAdrian McCarthy 
5429d5b2d4aSAleksandr Urakov lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions,
5439d5b2d4aSAleksandr Urakov                                               Status &error) {
544053eb356SAaron Smith   lldb::addr_t vm_addr = LLDB_INVALID_ADDRESS;
545053eb356SAaron Smith   error = ProcessDebugger::AllocateMemory(size, permissions, vm_addr);
546053eb356SAaron Smith   return vm_addr;
5479d5b2d4aSAleksandr Urakov }
5489d5b2d4aSAleksandr Urakov 
5499d5b2d4aSAleksandr Urakov Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) {
550053eb356SAaron Smith   return ProcessDebugger::DeallocateMemory(ptr);
5519d5b2d4aSAleksandr Urakov }
5529d5b2d4aSAleksandr Urakov 
55397206d57SZachary Turner Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr,
5544ad5def9SAdrian McCarthy                                            MemoryRegionInfo &info) {
555053eb356SAaron Smith   return ProcessDebugger::GetMemoryRegionInfo(vm_addr, info);
5564ad5def9SAdrian McCarthy }
5574ad5def9SAdrian McCarthy 
558b9c1b51eSKate Stone lldb::addr_t ProcessWindows::GetImageInfoAddress() {
55918a9135dSAdrian McCarthy   Target &target = GetTarget();
56018a9135dSAdrian McCarthy   ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile();
56118a9135dSAdrian McCarthy   Address addr = obj_file->GetImageInfoAddress(&target);
56218a9135dSAdrian McCarthy   if (addr.IsValid())
56318a9135dSAdrian McCarthy     return addr.GetLoadAddress(&target);
56418a9135dSAdrian McCarthy   else
56518a9135dSAdrian McCarthy     return LLDB_INVALID_ADDRESS;
56618a9135dSAdrian McCarthy }
56718a9135dSAdrian McCarthy 
568eb6671e7SAaron Smith DynamicLoaderWindowsDYLD *ProcessWindows::GetDynamicLoader() {
56996b82107SAaron Smith   if (m_dyld_up.get() == NULL)
57096b82107SAaron Smith     m_dyld_up.reset(DynamicLoader::FindPlugin(
571eb6671e7SAaron Smith         this, DynamicLoaderWindowsDYLD::GetPluginNameStatic().GetCString()));
57296b82107SAaron Smith   return static_cast<DynamicLoaderWindowsDYLD *>(m_dyld_up.get());
573eb6671e7SAaron Smith }
574eb6671e7SAaron Smith 
5754ad5def9SAdrian McCarthy void ProcessWindows::OnExitProcess(uint32_t exit_code) {
5764ad5def9SAdrian McCarthy   // No need to acquire the lock since m_session_data isn't accessed.
577a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
578a385d2c1SPavel Labath   LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);
5794ad5def9SAdrian McCarthy 
580d7e126c4SJim Ingham   TargetSP target = CalculateTarget();
5814ad5def9SAdrian McCarthy   if (target) {
5824ad5def9SAdrian McCarthy     ModuleSP executable_module = target->GetExecutableModule();
5834ad5def9SAdrian McCarthy     ModuleList unloaded_modules;
5844ad5def9SAdrian McCarthy     unloaded_modules.Append(executable_module);
5854ad5def9SAdrian McCarthy     target->ModulesDidUnload(unloaded_modules, true);
5864ad5def9SAdrian McCarthy   }
5874ad5def9SAdrian McCarthy 
5884ad5def9SAdrian McCarthy   SetProcessExitStatus(GetID(), true, 0, exit_code);
5894ad5def9SAdrian McCarthy   SetPrivateState(eStateExited);
590e3037904SAaron Smith 
591e3037904SAaron Smith   // If the process exits before any initial stop then notify the debugger
592e3037904SAaron Smith   // of the error otherwise WaitForDebuggerConnection() will be blocked.
593e3037904SAaron Smith   // An example of this issue is when a process fails to load a dependent DLL.
594c28daec5SAaron Smith   if (m_session_data && !m_session_data->m_initial_stop_received) {
595e3037904SAaron Smith     Status error(exit_code, eErrorTypeWin32);
596e3037904SAaron Smith     OnDebuggerError(error, 0);
597e3037904SAaron Smith   }
598053eb356SAaron Smith 
599053eb356SAaron Smith   // Reset the session.
600053eb356SAaron Smith   m_session_data.reset();
6014ad5def9SAdrian McCarthy }
6024ad5def9SAdrian McCarthy 
6034ad5def9SAdrian McCarthy void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
6044ad5def9SAdrian McCarthy   DebuggerThreadSP debugger = m_session_data->m_debugger;
605a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
606a385d2c1SPavel Labath   LLDB_LOG(log, "Debugger connected to process {0}.  Image base = {1:x}",
6074ad5def9SAdrian McCarthy            debugger->GetProcess().GetProcessId(), image_base);
6084ad5def9SAdrian McCarthy 
6094ad5def9SAdrian McCarthy   ModuleSP module = GetTarget().GetExecutableModule();
6104ad5def9SAdrian McCarthy   if (!module) {
6114ad5def9SAdrian McCarthy     // During attach, we won't have the executable module, so find it now.
6124ad5def9SAdrian McCarthy     const DWORD pid = debugger->GetProcess().GetProcessId();
6134ad5def9SAdrian McCarthy     const std::string file_name = GetProcessExecutableName(pid);
6144ad5def9SAdrian McCarthy     if (file_name.empty()) {
6154ad5def9SAdrian McCarthy       return;
6164ad5def9SAdrian McCarthy     }
6174ad5def9SAdrian McCarthy 
61854bb3161SAleksandr Urakov     FileSpec executable_file(file_name);
61954bb3161SAleksandr Urakov     FileSystem::Instance().Resolve(executable_file);
6204ad5def9SAdrian McCarthy     ModuleSpec module_spec(executable_file);
62197206d57SZachary Turner     Status error;
6221724a179SJason Molenda     module = GetTarget().GetOrCreateModule(module_spec,
6231724a179SJason Molenda                                            true /* notify */, &error);
6244ad5def9SAdrian McCarthy     if (!module) {
6254ad5def9SAdrian McCarthy       return;
6264ad5def9SAdrian McCarthy     }
6274ad5def9SAdrian McCarthy 
628d54ee88aSTatyana Krasnukha     GetTarget().SetExecutableModule(module, eLoadDependentsNo);
6294ad5def9SAdrian McCarthy   }
6304ad5def9SAdrian McCarthy 
631eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
632a2d9fdf5SStella Stamenova     dyld->OnLoadModule(module, ModuleSpec(), image_base);
6334ad5def9SAdrian McCarthy 
6344ad5def9SAdrian McCarthy   // Add the main executable module to the list of pending module loads.  We
63505097246SAdrian Prantl   // can't call GetTarget().ModulesDidLoad() here because we still haven't
63605097246SAdrian Prantl   // returned from DoLaunch() / DoAttach() yet so the target may not have set
63705097246SAdrian Prantl   // the process instance to `this` yet.
6384ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
6394ad5def9SAdrian McCarthy   const HostThreadWindows &wmain_thread =
6404ad5def9SAdrian McCarthy       debugger->GetMainThread().GetNativeThread();
6414ad5def9SAdrian McCarthy   m_session_data->m_new_threads[wmain_thread.GetThreadId()] =
6424ad5def9SAdrian McCarthy       debugger->GetMainThread();
6434ad5def9SAdrian McCarthy }
6444ad5def9SAdrian McCarthy 
6454ad5def9SAdrian McCarthy ExceptionResult
6464ad5def9SAdrian McCarthy ProcessWindows::OnDebugException(bool first_chance,
6474ad5def9SAdrian McCarthy                                  const ExceptionRecord &record) {
648a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION);
6494ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
6504ad5def9SAdrian McCarthy 
6514ad5def9SAdrian McCarthy   // FIXME: Without this check, occasionally when running the test suite there
6524ad5def9SAdrian McCarthy   // is
6534ad5def9SAdrian McCarthy   // an issue where m_session_data can be null.  It's not clear how this could
65405097246SAdrian Prantl   // happen but it only surfaces while running the test suite.  In order to
65505097246SAdrian Prantl   // properly diagnose this, we probably need to first figure allow the test
65605097246SAdrian Prantl   // suite to print out full lldb logs, and then add logging to the process
65705097246SAdrian Prantl   // plugin.
6584ad5def9SAdrian McCarthy   if (!m_session_data) {
65962c76db4SStella Stamenova     LLDB_LOG(log,
66062c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x}, "
661a385d2c1SPavel Labath              "but there is no session.",
6624ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress());
6634ad5def9SAdrian McCarthy     return ExceptionResult::SendToApplication;
6644ad5def9SAdrian McCarthy   }
6654ad5def9SAdrian McCarthy 
6664ad5def9SAdrian McCarthy   if (!first_chance) {
667a5235af9SAleksandr Urakov     // Not any second chance exception is an application crash by definition.
668a5235af9SAleksandr Urakov     // It may be an expression evaluation crash.
669a5235af9SAleksandr Urakov     SetPrivateState(eStateStopped);
6704ad5def9SAdrian McCarthy   }
6714ad5def9SAdrian McCarthy 
6724ad5def9SAdrian McCarthy   ExceptionResult result = ExceptionResult::SendToApplication;
6734ad5def9SAdrian McCarthy   switch (record.GetExceptionCode()) {
6744ad5def9SAdrian McCarthy   case EXCEPTION_BREAKPOINT:
6754ad5def9SAdrian McCarthy     // Handle breakpoints at the first chance.
6764ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
6774ad5def9SAdrian McCarthy 
6784ad5def9SAdrian McCarthy     if (!m_session_data->m_initial_stop_received) {
679a385d2c1SPavel Labath       LLDB_LOG(
680a385d2c1SPavel Labath           log,
681a385d2c1SPavel Labath           "Hit loader breakpoint at address {0:x}, setting initial stop event.",
6824ad5def9SAdrian McCarthy           record.GetExceptionAddress());
6834ad5def9SAdrian McCarthy       m_session_data->m_initial_stop_received = true;
6844ad5def9SAdrian McCarthy       ::SetEvent(m_session_data->m_initial_stop_event);
6854ad5def9SAdrian McCarthy     } else {
686a385d2c1SPavel Labath       LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",
6874ad5def9SAdrian McCarthy                record.GetExceptionAddress());
6884ad5def9SAdrian McCarthy     }
6894ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
6904ad5def9SAdrian McCarthy     break;
6914ad5def9SAdrian McCarthy   case EXCEPTION_SINGLE_STEP:
6924ad5def9SAdrian McCarthy     result = ExceptionResult::BreakInDebugger;
6934ad5def9SAdrian McCarthy     SetPrivateState(eStateStopped);
6944ad5def9SAdrian McCarthy     break;
6954ad5def9SAdrian McCarthy   default:
69662c76db4SStella Stamenova     LLDB_LOG(log,
69762c76db4SStella Stamenova              "Debugger thread reported exception {0:x} at address {1:x} "
698a385d2c1SPavel Labath              "(first_chance={2})",
6994ad5def9SAdrian McCarthy              record.GetExceptionCode(), record.GetExceptionAddress(),
700a385d2c1SPavel Labath              first_chance);
7014ad5def9SAdrian McCarthy     // For non-breakpoints, give the application a chance to handle the
7024ad5def9SAdrian McCarthy     // exception first.
7034ad5def9SAdrian McCarthy     if (first_chance)
7044ad5def9SAdrian McCarthy       result = ExceptionResult::SendToApplication;
7054ad5def9SAdrian McCarthy     else
7064ad5def9SAdrian McCarthy       result = ExceptionResult::BreakInDebugger;
7074ad5def9SAdrian McCarthy   }
7084ad5def9SAdrian McCarthy 
7094ad5def9SAdrian McCarthy   return result;
7104ad5def9SAdrian McCarthy }
7114ad5def9SAdrian McCarthy 
7124ad5def9SAdrian McCarthy void ProcessWindows::OnCreateThread(const HostThread &new_thread) {
7134ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
7144ad5def9SAdrian McCarthy   const HostThreadWindows &wnew_thread = new_thread.GetNativeThread();
7154ad5def9SAdrian McCarthy   m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread;
7164ad5def9SAdrian McCarthy }
7174ad5def9SAdrian McCarthy 
7184ad5def9SAdrian McCarthy void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) {
7194ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
7204ad5def9SAdrian McCarthy 
7214ad5def9SAdrian McCarthy   // On a forced termination, we may get exit thread events after the session
7224ad5def9SAdrian McCarthy   // data has been cleaned up.
7234ad5def9SAdrian McCarthy   if (!m_session_data)
7244ad5def9SAdrian McCarthy     return;
7254ad5def9SAdrian McCarthy 
7264ad5def9SAdrian McCarthy   // A thread may have started and exited before the debugger stopped allowing a
7274ad5def9SAdrian McCarthy   // refresh.
7284ad5def9SAdrian McCarthy   // Just remove it from the new threads list in that case.
7294ad5def9SAdrian McCarthy   auto iter = m_session_data->m_new_threads.find(thread_id);
7304ad5def9SAdrian McCarthy   if (iter != m_session_data->m_new_threads.end())
7314ad5def9SAdrian McCarthy     m_session_data->m_new_threads.erase(iter);
7324ad5def9SAdrian McCarthy   else
7334ad5def9SAdrian McCarthy     m_session_data->m_exited_threads.insert(thread_id);
7344ad5def9SAdrian McCarthy }
7354ad5def9SAdrian McCarthy 
7364ad5def9SAdrian McCarthy void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
7374ad5def9SAdrian McCarthy                                lldb::addr_t module_addr) {
738eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
739a2d9fdf5SStella Stamenova     dyld->OnLoadModule(nullptr, module_spec, module_addr);
7404ad5def9SAdrian McCarthy }
7414ad5def9SAdrian McCarthy 
7424ad5def9SAdrian McCarthy void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {
743eb6671e7SAaron Smith   if (auto dyld = GetDynamicLoader())
744eb6671e7SAaron Smith     dyld->OnUnloadModule(module_addr);
7454ad5def9SAdrian McCarthy }
7464ad5def9SAdrian McCarthy 
7474ad5def9SAdrian McCarthy void ProcessWindows::OnDebugString(const std::string &string) {}
7484ad5def9SAdrian McCarthy 
74997206d57SZachary Turner void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) {
7504ad5def9SAdrian McCarthy   llvm::sys::ScopedLock lock(m_mutex);
751a385d2c1SPavel Labath   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS);
7524ad5def9SAdrian McCarthy 
7534ad5def9SAdrian McCarthy   if (m_session_data->m_initial_stop_received) {
75405097246SAdrian Prantl     // This happened while debugging.  Do we shutdown the debugging session,
75505097246SAdrian Prantl     // try to continue, or do something else?
75662c76db4SStella Stamenova     LLDB_LOG(log,
75762c76db4SStella Stamenova              "Error {0} occurred during debugging.  Unexpected behavior "
758a385d2c1SPavel Labath              "may result.  {1}",
759a385d2c1SPavel Labath              error.GetError(), error);
7604ad5def9SAdrian McCarthy   } else {
7614ad5def9SAdrian McCarthy     // If we haven't actually launched the process yet, this was an error
76205097246SAdrian Prantl     // launching the process.  Set the internal error and signal the initial
76305097246SAdrian Prantl     // stop event so that the DoLaunch method wakes up and returns a failure.
7644ad5def9SAdrian McCarthy     m_session_data->m_launch_error = error;
7654ad5def9SAdrian McCarthy     ::SetEvent(m_session_data->m_initial_stop_event);
766a385d2c1SPavel Labath     LLDB_LOG(
767a385d2c1SPavel Labath         log,
768a385d2c1SPavel Labath         "Error {0} occurred launching the process before the initial stop. {1}",
769a385d2c1SPavel Labath         error.GetError(), error);
7704ad5def9SAdrian McCarthy     return;
7714ad5def9SAdrian McCarthy   }
7724ad5def9SAdrian McCarthy }
7734ad5def9SAdrian McCarthy } // namespace lldb_private
774