blob: ac191c40e0621f21f16c3962b69afc230f29ef7e [file] [log] [blame]
Zachary Turner02862bc2014-11-07 23:44:13 +00001//===-- DebuggerThread.DebuggerThread --------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "DebuggerThread.h"
Zachary Turnerdcd80372014-11-11 00:00:14 +000011#include "ExceptionRecord.h"
Zachary Turner02862bc2014-11-07 23:44:13 +000012#include "IDebugDelegate.h"
Zachary Turner02862bc2014-11-07 23:44:13 +000013
14#include "lldb/Core/Error.h"
15#include "lldb/Core/Log.h"
Zachary Turnera32d2ce2014-11-12 19:31:56 +000016#include "lldb/Core/ModuleSpec.h"
17#include "lldb/Host/FileSpec.h"
Zachary Turner02862bc2014-11-07 23:44:13 +000018#include "lldb/Host/Predicate.h"
19#include "lldb/Host/ThisThread.h"
20#include "lldb/Host/ThreadLauncher.h"
21#include "lldb/Host/windows/HostProcessWindows.h"
22#include "lldb/Host/windows/HostThreadWindows.h"
23#include "lldb/Host/windows/ProcessLauncherWindows.h"
24#include "lldb/Target/ProcessLaunchInfo.h"
25
Zachary Turnera32d2ce2014-11-12 19:31:56 +000026#include "llvm/ADT/STLExtras.h"
Zachary Turner02862bc2014-11-07 23:44:13 +000027#include "llvm/Support/raw_ostream.h"
28
29using namespace lldb;
30using namespace lldb_private;
31
32namespace
33{
34struct DebugLaunchContext
35{
36 DebugLaunchContext(DebuggerThread *thread, const ProcessLaunchInfo &launch_info)
37 : m_thread(thread)
38 , m_launch_info(launch_info)
39 {
40 }
41 DebuggerThread *m_thread;
42 ProcessLaunchInfo m_launch_info;
43};
44}
45
46DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate)
47 : m_debug_delegate(debug_delegate)
48 , m_image_file(nullptr)
Zachary Turner02862bc2014-11-07 23:44:13 +000049{
Zachary Turner02862bc2014-11-07 23:44:13 +000050}
51
52DebuggerThread::~DebuggerThread()
53{
Zachary Turner02862bc2014-11-07 23:44:13 +000054}
55
Zachary Turner3985f892014-11-10 22:32:18 +000056Error
Zachary Turner02862bc2014-11-07 23:44:13 +000057DebuggerThread::DebugLaunch(const ProcessLaunchInfo &launch_info)
58{
59 Error error;
60
61 DebugLaunchContext *context = new DebugLaunchContext(this, launch_info);
62 HostThread slave_thread(ThreadLauncher::LaunchThread("lldb.plugin.process-windows.slave[?]", DebuggerThreadRoutine, context, &error));
Zachary Turner02862bc2014-11-07 23:44:13 +000063
Zachary Turner3985f892014-11-10 22:32:18 +000064 return error;
Zachary Turner02862bc2014-11-07 23:44:13 +000065}
66
67lldb::thread_result_t
68DebuggerThread::DebuggerThreadRoutine(void *data)
69{
70 DebugLaunchContext *context = static_cast<DebugLaunchContext *>(data);
71 lldb::thread_result_t result = context->m_thread->DebuggerThreadRoutine(context->m_launch_info);
72 delete context;
73 return result;
74}
75
76lldb::thread_result_t
77DebuggerThread::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info)
78{
79 // Grab a shared_ptr reference to this so that we know it won't get deleted until after the
80 // thread routine has exited.
81 std::shared_ptr<DebuggerThread> this_ref(shared_from_this());
82 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
83
84 Error error;
85 ProcessLauncherWindows launcher;
86 HostProcess process(launcher.LaunchProcess(launch_info, error));
87 // If we couldn't create the process, notify waiters immediately. Otherwise enter the debug
88 // loop and wait until we get the create process debug notification. Note that if the process
89 // was created successfully, we can throw away the process handle we got from CreateProcess
90 // because Windows will give us another (potentially more useful?) handle when it sends us the
91 // CREATE_PROCESS_DEBUG_EVENT.
92 if (error.Success())
93 DebugLoop();
94 else
Zachary Turnerd6a7b632014-11-12 19:31:39 +000095 m_debug_delegate->OnDebuggerError(error, 0);
Zachary Turner02862bc2014-11-07 23:44:13 +000096
97 return 0;
98}
99
100void
Zachary Turnerdcd80372014-11-11 00:00:14 +0000101DebuggerThread::ContinueAsyncException(ExceptionResult result)
102{
103 m_exception.SetValue(result, eBroadcastAlways);
104}
105
106void
Zachary Turner02862bc2014-11-07 23:44:13 +0000107DebuggerThread::DebugLoop()
108{
109 DEBUG_EVENT dbe = {0};
110 bool exit = false;
111 while (!exit && WaitForDebugEvent(&dbe, INFINITE))
112 {
113 DWORD continue_status = DBG_CONTINUE;
114 switch (dbe.dwDebugEventCode)
115 {
116 case EXCEPTION_DEBUG_EVENT:
Zachary Turnerdcd80372014-11-11 00:00:14 +0000117 {
118 ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId);
119 m_exception.SetValue(status, eBroadcastNever);
120 m_exception.WaitForValueNotEqualTo(ExceptionResult::WillHandle, status);
121
122 if (status == ExceptionResult::Handled)
123 continue_status = DBG_CONTINUE;
124 else if (status == ExceptionResult::NotHandled)
125 continue_status = DBG_EXCEPTION_NOT_HANDLED;
Zachary Turner02862bc2014-11-07 23:44:13 +0000126 break;
Zachary Turnerdcd80372014-11-11 00:00:14 +0000127 }
Zachary Turner02862bc2014-11-07 23:44:13 +0000128 case CREATE_THREAD_DEBUG_EVENT:
129 continue_status = HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId);
130 break;
131 case CREATE_PROCESS_DEBUG_EVENT:
132 continue_status = HandleCreateProcessEvent(dbe.u.CreateProcessInfo, dbe.dwThreadId);
133 break;
134 case EXIT_THREAD_DEBUG_EVENT:
135 continue_status = HandleExitThreadEvent(dbe.u.ExitThread, dbe.dwThreadId);
136 break;
137 case EXIT_PROCESS_DEBUG_EVENT:
138 continue_status = HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId);
139 exit = true;
140 break;
141 case LOAD_DLL_DEBUG_EVENT:
142 continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId);
143 break;
144 case UNLOAD_DLL_DEBUG_EVENT:
145 continue_status = HandleUnloadDllEvent(dbe.u.UnloadDll, dbe.dwThreadId);
146 break;
147 case OUTPUT_DEBUG_STRING_EVENT:
148 continue_status = HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId);
149 break;
150 case RIP_EVENT:
151 continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId);
152 if (dbe.u.RipInfo.dwType == SLE_ERROR)
153 exit = true;
154 break;
155 }
156
157 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status);
158 }
159}
160
Zachary Turnerdcd80372014-11-11 00:00:14 +0000161ExceptionResult
Zachary Turner02862bc2014-11-07 23:44:13 +0000162DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id)
163{
Zachary Turnerdcd80372014-11-11 00:00:14 +0000164 bool first_chance = (info.dwFirstChance != 0);
Zachary Turnerd6a7b632014-11-12 19:31:39 +0000165 return m_debug_delegate->OnDebugException(first_chance, ExceptionRecord(info.ExceptionRecord));
Zachary Turner02862bc2014-11-07 23:44:13 +0000166}
167
168DWORD
169DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id)
170{
171 return DBG_CONTINUE;
172}
173
174DWORD
175DebuggerThread::HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id)
176{
177 std::string thread_name;
178 llvm::raw_string_ostream name_stream(thread_name);
179 name_stream << "lldb.plugin.process-windows.slave[" << m_process.GetProcessId() << "]";
180 name_stream.flush();
181 ThisThread::SetName(thread_name.c_str());
182
183 // info.hProcess and info.hThread are closed automatically by Windows when
184 // EXIT_PROCESS_DEBUG_EVENT is received.
185 m_process = HostProcess(info.hProcess);
186 ((HostProcessWindows &)m_process.GetNativeProcess()).SetOwnsHandle(false);
187 m_main_thread = HostThread(info.hThread);
188 ((HostThreadWindows &)m_main_thread.GetNativeThread()).SetOwnsHandle(false);
189 m_image_file = info.hFile;
190
Zachary Turnera32d2ce2014-11-12 19:31:56 +0000191 lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfImage);
192 m_debug_delegate->OnDebuggerConnected(load_addr);
Zachary Turner02862bc2014-11-07 23:44:13 +0000193
194 return DBG_CONTINUE;
195}
196
197DWORD
198DebuggerThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id)
199{
200 return DBG_CONTINUE;
201}
202
203DWORD
204DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id)
205{
Zachary Turnerd6a7b632014-11-12 19:31:39 +0000206 m_debug_delegate->OnExitProcess(info.dwExitCode);
Zachary Turner02862bc2014-11-07 23:44:13 +0000207
208 m_process = HostProcess();
209 m_main_thread = HostThread();
210 ::CloseHandle(m_image_file);
211 m_image_file = nullptr;
212 return DBG_CONTINUE;
213}
214
215DWORD
216DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
217{
Zachary Turnera32d2ce2014-11-12 19:31:56 +0000218 if (info.hFile == nullptr)
219 {
220 // Not sure what this is, so just ignore it.
221 return DBG_CONTINUE;
222 }
223
224 std::vector<char> buffer(1);
225 DWORD required_size = GetFinalPathNameByHandle(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS);
226 if (required_size > 0)
227 {
228 buffer.resize(required_size + 1);
229 required_size = GetFinalPathNameByHandle(info.hFile, &buffer[0], required_size + 1, VOLUME_NAME_DOS);
230 llvm::StringRef path_str(&buffer[0]);
231 const char *path = path_str.data();
232 if (path_str.startswith("\\\\?\\"))
233 path += 4;
234
235 FileSpec file_spec(path, false);
236 ModuleSpec module_spec(file_spec);
237 lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll);
238 m_debug_delegate->OnLoadDll(module_spec, load_addr);
239 }
240 else
241 {
242 // An unknown error occurred getting the path name.
243 }
244 // Windows does not automatically close info.hFile, so we need to do it.
Zachary Turner02862bc2014-11-07 23:44:13 +0000245 ::CloseHandle(info.hFile);
246 return DBG_CONTINUE;
247}
248
249DWORD
250DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id)
251{
Zachary Turnera32d2ce2014-11-12 19:31:56 +0000252 m_debug_delegate->OnUnloadDll(reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll));
Zachary Turner02862bc2014-11-07 23:44:13 +0000253 return DBG_CONTINUE;
254}
255
256DWORD
257DebuggerThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id)
258{
259 return DBG_CONTINUE;
260}
261
262DWORD
263DebuggerThread::HandleRipEvent(const RIP_INFO &info, DWORD thread_id)
264{
265 Error error(info.dwError, eErrorTypeWin32);
Zachary Turnerd6a7b632014-11-12 19:31:39 +0000266 m_debug_delegate->OnDebuggerError(error, info.dwType);
Zachary Turner02862bc2014-11-07 23:44:13 +0000267
268 return DBG_CONTINUE;
269}