1 | //===-- NativeProcessWindows.cpp ------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Host/windows/windows.h" |
10 | #include <psapi.h> |
11 | |
12 | #include "NativeProcessWindows.h" |
13 | #include "NativeThreadWindows.h" |
14 | #include "lldb/Host/FileSystem.h" |
15 | #include "lldb/Host/HostNativeProcessBase.h" |
16 | #include "lldb/Host/HostProcess.h" |
17 | #include "lldb/Host/ProcessLaunchInfo.h" |
18 | #include "lldb/Host/windows/AutoHandle.h" |
19 | #include "lldb/Host/windows/HostThreadWindows.h" |
20 | #include "lldb/Host/windows/ProcessLauncherWindows.h" |
21 | #include "lldb/Target/MemoryRegionInfo.h" |
22 | #include "lldb/Target/Process.h" |
23 | #include "lldb/Utility/State.h" |
24 | #include "llvm/Support/ConvertUTF.h" |
25 | #include "llvm/Support/Errc.h" |
26 | #include "llvm/Support/Error.h" |
27 | #include "llvm/Support/Format.h" |
28 | #include "llvm/Support/Threading.h" |
29 | #include "llvm/Support/raw_ostream.h" |
30 | |
31 | #include "DebuggerThread.h" |
32 | #include "ExceptionRecord.h" |
33 | #include "ProcessWindowsLog.h" |
34 | |
35 | #include <tlhelp32.h> |
36 | |
37 | #pragma warning(disable : 4005) |
38 | #include "winternl.h" |
39 | #include <ntstatus.h> |
40 | |
41 | using namespace lldb; |
42 | using namespace lldb_private; |
43 | using namespace llvm; |
44 | |
45 | namespace lldb_private { |
46 | |
47 | NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info, |
48 | NativeDelegate &delegate, |
49 | llvm::Error &E) |
50 | : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID, |
51 | launch_info.GetPTY().ReleasePrimaryFileDescriptor(), |
52 | delegate), |
53 | ProcessDebugger(), m_arch(launch_info.GetArchitecture()) { |
54 | ErrorAsOutParameter EOut(&E); |
55 | DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this)); |
56 | E = LaunchProcess(launch_info, delegate: delegate_sp).ToError(); |
57 | if (E) |
58 | return; |
59 | |
60 | SetID(GetDebuggedProcessId()); |
61 | } |
62 | |
63 | NativeProcessWindows::NativeProcessWindows(lldb::pid_t pid, int terminal_fd, |
64 | NativeDelegate &delegate, |
65 | llvm::Error &E) |
66 | : NativeProcessProtocol(pid, terminal_fd, delegate), ProcessDebugger() { |
67 | ErrorAsOutParameter EOut(&E); |
68 | DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this)); |
69 | ProcessAttachInfo attach_info; |
70 | attach_info.SetProcessID(pid); |
71 | E = AttachProcess(pid, attach_info, delegate: delegate_sp).ToError(); |
72 | if (E) |
73 | return; |
74 | |
75 | SetID(GetDebuggedProcessId()); |
76 | |
77 | ProcessInstanceInfo info; |
78 | if (!Host::GetProcessInfo(pid, proc_info&: info)) { |
79 | E = createStringError(EC: inconvertibleErrorCode(), |
80 | S: "Cannot get process information" ); |
81 | return; |
82 | } |
83 | m_arch = info.GetArchitecture(); |
84 | } |
85 | |
86 | Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) { |
87 | Log *log = GetLog(mask: WindowsLog::Process); |
88 | Status error; |
89 | llvm::sys::ScopedLock lock(m_mutex); |
90 | |
91 | StateType state = GetState(); |
92 | if (state == eStateStopped || state == eStateCrashed) { |
93 | LLDB_LOG(log, "process {0} is in state {1}. Resuming..." , |
94 | GetDebuggedProcessId(), state); |
95 | LLDB_LOG(log, "resuming {0} threads." , m_threads.size()); |
96 | |
97 | bool failed = false; |
98 | for (uint32_t i = 0; i < m_threads.size(); ++i) { |
99 | auto thread = static_cast<NativeThreadWindows *>(m_threads[i].get()); |
100 | const ResumeAction *const action = |
101 | resume_actions.GetActionForThread(tid: thread->GetID(), default_ok: true); |
102 | if (action == nullptr) |
103 | continue; |
104 | |
105 | switch (action->state) { |
106 | case eStateRunning: |
107 | case eStateStepping: { |
108 | Status result = thread->DoResume(resume_state: action->state); |
109 | if (result.Fail()) { |
110 | failed = true; |
111 | LLDB_LOG(log, |
112 | "Trying to resume thread at index {0}, but failed with " |
113 | "error {1}." , |
114 | i, result); |
115 | } |
116 | break; |
117 | } |
118 | case eStateSuspended: |
119 | case eStateStopped: |
120 | break; |
121 | |
122 | default: |
123 | return Status::FromErrorStringWithFormat( |
124 | format: "NativeProcessWindows::%s (): unexpected state %s specified " |
125 | "for pid %" PRIu64 ", tid %" PRIu64, |
126 | __FUNCTION__, StateAsCString(state: action->state), GetID(), |
127 | thread->GetID()); |
128 | } |
129 | } |
130 | |
131 | if (failed) { |
132 | error = Status::FromErrorString(str: "NativeProcessWindows::DoResume failed" ); |
133 | } else { |
134 | SetState(state: eStateRunning); |
135 | } |
136 | |
137 | // Resume the debug loop. |
138 | ExceptionRecordSP active_exception = |
139 | m_session_data->m_debugger->GetActiveException().lock(); |
140 | if (active_exception) { |
141 | // Resume the process and continue processing debug events. Mask the |
142 | // exception so that from the process's view, there is no indication that |
143 | // anything happened. |
144 | m_session_data->m_debugger->ContinueAsyncException( |
145 | result: ExceptionResult::MaskException); |
146 | } |
147 | } else { |
148 | LLDB_LOG(log, "error: process {0} is in state {1}. Returning..." , |
149 | GetDebuggedProcessId(), GetState()); |
150 | } |
151 | |
152 | return error; |
153 | } |
154 | |
155 | NativeThreadWindows * |
156 | NativeProcessWindows::GetThreadByID(lldb::tid_t thread_id) { |
157 | return static_cast<NativeThreadWindows *>( |
158 | NativeProcessProtocol::GetThreadByID(tid: thread_id)); |
159 | } |
160 | |
161 | Status NativeProcessWindows::Halt() { |
162 | bool caused_stop = false; |
163 | StateType state = GetState(); |
164 | if (state != eStateStopped) |
165 | return HaltProcess(caused_stop); |
166 | return Status(); |
167 | } |
168 | |
169 | Status NativeProcessWindows::Detach() { |
170 | Status error; |
171 | Log *log = GetLog(mask: WindowsLog::Process); |
172 | StateType state = GetState(); |
173 | if (state != eStateExited && state != eStateDetached) { |
174 | error = DetachProcess(); |
175 | if (error.Success()) |
176 | SetState(state: eStateDetached); |
177 | else |
178 | LLDB_LOG(log, "Detaching process error: {0}" , error); |
179 | } else { |
180 | error = Status::FromErrorStringWithFormatv( |
181 | format: "error: process {0} in state = {1}, but " |
182 | "cannot detach it in this state." , |
183 | args: GetID(), args&: state); |
184 | LLDB_LOG(log, "error: {0}" , error); |
185 | } |
186 | return error; |
187 | } |
188 | |
189 | Status NativeProcessWindows::Signal(int signo) { |
190 | Status error; |
191 | error = Status::FromErrorString( |
192 | str: "Windows does not support sending signals to processes" ); |
193 | return error; |
194 | } |
195 | |
196 | Status NativeProcessWindows::Interrupt() { return Halt(); } |
197 | |
198 | Status NativeProcessWindows::Kill() { |
199 | StateType state = GetState(); |
200 | return DestroyProcess(process_state: state); |
201 | } |
202 | |
203 | Status NativeProcessWindows::IgnoreSignals(llvm::ArrayRef<int> signals) { |
204 | return Status(); |
205 | } |
206 | |
207 | Status NativeProcessWindows::GetMemoryRegionInfo(lldb::addr_t load_addr, |
208 | MemoryRegionInfo &range_info) { |
209 | return ProcessDebugger::GetMemoryRegionInfo(load_addr, range_info); |
210 | } |
211 | |
212 | Status NativeProcessWindows::ReadMemory(lldb::addr_t addr, void *buf, |
213 | size_t size, size_t &bytes_read) { |
214 | return ProcessDebugger::ReadMemory(addr, buf, size, bytes_read); |
215 | } |
216 | |
217 | Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf, |
218 | size_t size, size_t &bytes_written) { |
219 | return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written); |
220 | } |
221 | |
222 | llvm::Expected<lldb::addr_t> |
223 | NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions) { |
224 | lldb::addr_t addr; |
225 | Status ST = ProcessDebugger::AllocateMemory(size, permissions, addr); |
226 | if (ST.Success()) |
227 | return addr; |
228 | return ST.ToError(); |
229 | } |
230 | |
231 | llvm::Error NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) { |
232 | return ProcessDebugger::DeallocateMemory(addr).ToError(); |
233 | } |
234 | |
235 | lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; } |
236 | |
237 | bool NativeProcessWindows::IsAlive() const { |
238 | StateType state = GetState(); |
239 | switch (state) { |
240 | case eStateCrashed: |
241 | case eStateDetached: |
242 | case eStateExited: |
243 | case eStateInvalid: |
244 | case eStateUnloaded: |
245 | return false; |
246 | default: |
247 | return true; |
248 | } |
249 | } |
250 | |
251 | void NativeProcessWindows::SetStopReasonForThread(NativeThreadWindows &thread, |
252 | lldb::StopReason reason, |
253 | std::string description) { |
254 | SetCurrentThreadID(thread.GetID()); |
255 | |
256 | ThreadStopInfo stop_info; |
257 | stop_info.reason = reason; |
258 | // No signal support on Windows but required to provide a 'valid' signum. |
259 | stop_info.signo = SIGTRAP; |
260 | |
261 | if (reason == StopReason::eStopReasonException) { |
262 | stop_info.details.exception.type = 0; |
263 | stop_info.details.exception.data_count = 0; |
264 | } |
265 | |
266 | thread.SetStopReason(stop_info, description); |
267 | } |
268 | |
269 | void NativeProcessWindows::StopThread(lldb::tid_t thread_id, |
270 | lldb::StopReason reason, |
271 | std::string description) { |
272 | NativeThreadWindows *thread = GetThreadByID(thread_id); |
273 | if (!thread) |
274 | return; |
275 | |
276 | for (uint32_t i = 0; i < m_threads.size(); ++i) { |
277 | auto t = static_cast<NativeThreadWindows *>(m_threads[i].get()); |
278 | Status error = t->DoStop(); |
279 | if (error.Fail()) |
280 | exit(status: 1); |
281 | } |
282 | SetStopReasonForThread(thread&: *thread, reason, description); |
283 | } |
284 | |
285 | size_t NativeProcessWindows::UpdateThreads() { return m_threads.size(); } |
286 | |
287 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> |
288 | NativeProcessWindows::GetAuxvData() const { |
289 | // Not available on this target. |
290 | return llvm::errc::not_supported; |
291 | } |
292 | |
293 | llvm::Expected<llvm::ArrayRef<uint8_t>> |
294 | NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { |
295 | static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, |
296 | 0xd4}; // brk #0xf000 |
297 | static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe |
298 | |
299 | switch (GetArchitecture().GetMachine()) { |
300 | case llvm::Triple::aarch64: |
301 | return llvm::ArrayRef(g_aarch64_opcode); |
302 | |
303 | case llvm::Triple::arm: |
304 | case llvm::Triple::thumb: |
305 | return llvm::ArrayRef(g_thumb_opcode); |
306 | |
307 | default: |
308 | return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); |
309 | } |
310 | } |
311 | |
312 | size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() { |
313 | // Windows always reports an incremented PC after a breakpoint is hit, |
314 | // even on ARM. |
315 | return cantFail(ValOrErr: GetSoftwareBreakpointTrapOpcode(size_hint: 0)).size(); |
316 | } |
317 | |
318 | bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) { |
319 | auto it = m_software_breakpoints.find(x: addr); |
320 | if (it == m_software_breakpoints.end()) |
321 | return false; |
322 | return true; |
323 | } |
324 | |
325 | Status NativeProcessWindows::SetBreakpoint(lldb::addr_t addr, uint32_t size, |
326 | bool hardware) { |
327 | if (hardware) |
328 | return SetHardwareBreakpoint(addr, size); |
329 | return SetSoftwareBreakpoint(addr, size_hint: size); |
330 | } |
331 | |
332 | Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr, |
333 | bool hardware) { |
334 | if (hardware) |
335 | return RemoveHardwareBreakpoint(addr); |
336 | return RemoveSoftwareBreakpoint(addr); |
337 | } |
338 | |
339 | Status NativeProcessWindows::CacheLoadedModules() { |
340 | Status error; |
341 | if (!m_loaded_modules.empty()) |
342 | return Status(); |
343 | |
344 | // Retrieve loaded modules by a Target/Module free implemenation. |
345 | AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID())); |
346 | if (snapshot.IsValid()) { |
347 | MODULEENTRY32W me; |
348 | me.dwSize = sizeof(MODULEENTRY32W); |
349 | if (Module32FirstW(snapshot.get(), &me)) { |
350 | do { |
351 | std::string path; |
352 | if (!llvm::convertWideToUTF8(Source: me.szExePath, Result&: path)) |
353 | continue; |
354 | |
355 | FileSpec file_spec(path); |
356 | FileSystem::Instance().Resolve(file_spec); |
357 | m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr; |
358 | } while (Module32Next(snapshot.get(), &me)); |
359 | } |
360 | |
361 | if (!m_loaded_modules.empty()) |
362 | return Status(); |
363 | } |
364 | |
365 | error = Status(::GetLastError(), lldb::ErrorType::eErrorTypeWin32); |
366 | return error; |
367 | } |
368 | |
369 | Status NativeProcessWindows::GetLoadedModuleFileSpec(const char *module_path, |
370 | FileSpec &file_spec) { |
371 | Status error = CacheLoadedModules(); |
372 | if (error.Fail()) |
373 | return error; |
374 | |
375 | FileSpec module_file_spec(module_path); |
376 | FileSystem::Instance().Resolve(file_spec&: module_file_spec); |
377 | for (auto &it : m_loaded_modules) { |
378 | if (it.first == module_file_spec) { |
379 | file_spec = it.first; |
380 | return Status(); |
381 | } |
382 | } |
383 | return Status::FromErrorStringWithFormat( |
384 | format: "Module (%s) not found in process %" PRIu64 "!" , |
385 | module_file_spec.GetPath().c_str(), GetID()); |
386 | } |
387 | |
388 | Status |
389 | NativeProcessWindows::GetFileLoadAddress(const llvm::StringRef &file_name, |
390 | lldb::addr_t &load_addr) { |
391 | Status error = CacheLoadedModules(); |
392 | if (error.Fail()) |
393 | return error; |
394 | |
395 | load_addr = LLDB_INVALID_ADDRESS; |
396 | FileSpec file_spec(file_name); |
397 | FileSystem::Instance().Resolve(file_spec); |
398 | for (auto &it : m_loaded_modules) { |
399 | if (it.first == file_spec) { |
400 | load_addr = it.second; |
401 | return Status(); |
402 | } |
403 | } |
404 | return Status::FromErrorStringWithFormat( |
405 | format: "Can't get loaded address of file (%s) in process %" PRIu64 "!" , |
406 | file_spec.GetPath().c_str(), GetID()); |
407 | } |
408 | |
409 | void NativeProcessWindows::OnExitProcess(uint32_t exit_code) { |
410 | Log *log = GetLog(mask: WindowsLog::Process); |
411 | LLDB_LOG(log, "Process {0} exited with code {1}" , GetID(), exit_code); |
412 | |
413 | ProcessDebugger::OnExitProcess(exit_code); |
414 | |
415 | // No signal involved. It is just an exit event. |
416 | WaitStatus wait_status(WaitStatus::Exit, exit_code); |
417 | SetExitStatus(status: wait_status, bNotifyStateChange: true); |
418 | |
419 | // Notify the native delegate. |
420 | SetState(state: eStateExited, notify_delegates: true); |
421 | } |
422 | |
423 | void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { |
424 | Log *log = GetLog(mask: WindowsLog::Process); |
425 | LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}" , |
426 | GetDebuggedProcessId(), image_base); |
427 | |
428 | // This is the earliest chance we can resolve the process ID and |
429 | // architecture if we don't know them yet. |
430 | if (GetID() == LLDB_INVALID_PROCESS_ID) |
431 | SetID(GetDebuggedProcessId()); |
432 | |
433 | if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) { |
434 | ProcessInstanceInfo process_info; |
435 | if (!Host::GetProcessInfo(pid: GetDebuggedProcessId(), proc_info&: process_info)) { |
436 | LLDB_LOG(log, "Cannot get process information during debugger connecting " |
437 | "to process" ); |
438 | return; |
439 | } |
440 | SetArchitecture(process_info.GetArchitecture()); |
441 | } |
442 | |
443 | // The very first one shall always be the main thread. |
444 | assert(m_threads.empty()); |
445 | m_threads.push_back(x: std::make_unique<NativeThreadWindows>( |
446 | args&: *this, args: m_session_data->m_debugger->GetMainThread())); |
447 | } |
448 | |
449 | ExceptionResult |
450 | NativeProcessWindows::OnDebugException(bool first_chance, |
451 | const ExceptionRecord &record) { |
452 | Log *log = GetLog(mask: WindowsLog::Exception); |
453 | llvm::sys::ScopedLock lock(m_mutex); |
454 | |
455 | // Let the debugger establish the internal status. |
456 | ProcessDebugger::OnDebugException(first_chance, record); |
457 | |
458 | static bool initial_stop = false; |
459 | if (!first_chance) { |
460 | SetState(state: eStateStopped, notify_delegates: false); |
461 | } |
462 | |
463 | ExceptionResult result = ExceptionResult::SendToApplication; |
464 | switch (record.GetExceptionCode()) { |
465 | case DWORD(STATUS_SINGLE_STEP): |
466 | case STATUS_WX86_SINGLE_STEP: { |
467 | #ifndef __aarch64__ |
468 | uint32_t wp_id = LLDB_INVALID_INDEX32; |
469 | if (NativeThreadWindows *thread = GetThreadByID(thread_id: record.GetThreadID())) { |
470 | NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext(); |
471 | Status error = |
472 | reg_ctx.GetWatchpointHitIndex(wp_index&: wp_id, trap_addr: record.GetExceptionAddress()); |
473 | if (error.Fail()) |
474 | LLDB_LOG(log, |
475 | "received error while checking for watchpoint hits, pid = " |
476 | "{0}, error = {1}" , |
477 | thread->GetID(), error); |
478 | if (wp_id != LLDB_INVALID_INDEX32) { |
479 | addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_index: wp_id); |
480 | addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_index: wp_id); |
481 | std::string desc = |
482 | formatv(Fmt: "{0} {1} {2}" , Vals&: wp_addr, Vals&: wp_id, Vals&: wp_hit_addr).str(); |
483 | StopThread(thread_id: record.GetThreadID(), reason: StopReason::eStopReasonWatchpoint, |
484 | description: desc); |
485 | } |
486 | } |
487 | if (wp_id == LLDB_INVALID_INDEX32) |
488 | #endif |
489 | StopThread(thread_id: record.GetThreadID(), reason: StopReason::eStopReasonTrace); |
490 | |
491 | SetState(state: eStateStopped, notify_delegates: true); |
492 | |
493 | // Continue the debugger. |
494 | return ExceptionResult::MaskException; |
495 | } |
496 | case DWORD(STATUS_BREAKPOINT): |
497 | case STATUS_WX86_BREAKPOINT: |
498 | |
499 | if (NativeThreadWindows *stop_thread = |
500 | GetThreadByID(thread_id: record.GetThreadID())) { |
501 | auto ®_ctx = stop_thread->GetRegisterContext(); |
502 | const auto exception_addr = record.GetExceptionAddress(); |
503 | const auto thread_id = record.GetThreadID(); |
504 | |
505 | if (FindSoftwareBreakpoint(addr: exception_addr)) { |
506 | LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}." , |
507 | exception_addr); |
508 | // The current PC is AFTER the BP opcode, on all architectures. |
509 | reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset()); |
510 | StopThread(thread_id, reason: StopReason::eStopReasonBreakpoint); |
511 | SetState(state: eStateStopped, notify_delegates: true); |
512 | return ExceptionResult::MaskException; |
513 | } else { |
514 | // This block of code will only be entered in case of a hardware |
515 | // watchpoint or breakpoint hit on AArch64. However, we only handle |
516 | // hardware watchpoints below as breakpoints are not yet supported. |
517 | const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); |
518 | // Check that the ExceptionInformation array of EXCEPTION_RECORD |
519 | // contains at least two elements: the first is a read-write flag |
520 | // indicating the type of data access operation (read or write) while |
521 | // the second contains the virtual address of the accessed data. |
522 | if (args.size() >= 2) { |
523 | uint32_t hw_id = LLDB_INVALID_INDEX32; |
524 | Status error = reg_ctx.GetWatchpointHitIndex(wp_index&: hw_id, trap_addr: args[1]); |
525 | if (error.Fail()) |
526 | LLDB_LOG(log, |
527 | "received error while checking for watchpoint hits, pid = " |
528 | "{0}, error = {1}" , |
529 | thread_id, error); |
530 | |
531 | if (hw_id != LLDB_INVALID_INDEX32) { |
532 | std::string desc = |
533 | formatv(Fmt: "{0} {1} {2}" , Vals: reg_ctx.GetWatchpointAddress(wp_index: hw_id), |
534 | Vals&: hw_id, Vals: exception_addr) |
535 | .str(); |
536 | StopThread(thread_id, reason: StopReason::eStopReasonWatchpoint, description: desc); |
537 | SetState(state: eStateStopped, notify_delegates: true); |
538 | return ExceptionResult::MaskException; |
539 | } |
540 | } |
541 | } |
542 | } |
543 | |
544 | if (!initial_stop) { |
545 | initial_stop = true; |
546 | LLDB_LOG(log, |
547 | "Hit loader breakpoint at address {0:x}, setting initial stop " |
548 | "event." , |
549 | record.GetExceptionAddress()); |
550 | |
551 | // We are required to report the reason for the first stop after |
552 | // launching or being attached. |
553 | if (NativeThreadWindows *thread = GetThreadByID(thread_id: record.GetThreadID())) |
554 | SetStopReasonForThread(thread&: *thread, reason: StopReason::eStopReasonBreakpoint); |
555 | |
556 | // Do not notify the native delegate (e.g. llgs) since at this moment |
557 | // the program hasn't returned from Manager::Launch() and the delegate |
558 | // might not have an valid native process to operate on. |
559 | SetState(state: eStateStopped, notify_delegates: false); |
560 | |
561 | // Hit the initial stop. Continue the application. |
562 | return ExceptionResult::BreakInDebugger; |
563 | } |
564 | |
565 | [[fallthrough]]; |
566 | default: |
567 | LLDB_LOG(log, |
568 | "Debugger thread reported exception {0:x} at address {1:x} " |
569 | "(first_chance={2})" , |
570 | record.GetExceptionCode(), record.GetExceptionAddress(), |
571 | first_chance); |
572 | |
573 | { |
574 | std::string desc; |
575 | llvm::raw_string_ostream desc_stream(desc); |
576 | desc_stream << "Exception " |
577 | << llvm::format_hex(N: record.GetExceptionCode(), Width: 8) |
578 | << " encountered at address " |
579 | << llvm::format_hex(N: record.GetExceptionAddress(), Width: 8); |
580 | StopThread(thread_id: record.GetThreadID(), reason: StopReason::eStopReasonException, |
581 | description: desc.c_str()); |
582 | |
583 | SetState(state: eStateStopped, notify_delegates: true); |
584 | } |
585 | |
586 | // For non-breakpoints, give the application a chance to handle the |
587 | // exception first. |
588 | if (first_chance) |
589 | result = ExceptionResult::SendToApplication; |
590 | else |
591 | result = ExceptionResult::BreakInDebugger; |
592 | } |
593 | |
594 | return result; |
595 | } |
596 | |
597 | void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) { |
598 | llvm::sys::ScopedLock lock(m_mutex); |
599 | |
600 | auto thread = std::make_unique<NativeThreadWindows>(args&: *this, args: new_thread); |
601 | thread->GetRegisterContext().ClearAllHardwareWatchpoints(); |
602 | for (const auto &pair : GetWatchpointMap()) { |
603 | const NativeWatchpoint &wp = pair.second; |
604 | thread->SetWatchpoint(addr: wp.m_addr, size: wp.m_size, watch_flags: wp.m_watch_flags, |
605 | hardware: wp.m_hardware); |
606 | } |
607 | |
608 | m_threads.push_back(x: std::move(thread)); |
609 | } |
610 | |
611 | void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id, |
612 | uint32_t exit_code) { |
613 | llvm::sys::ScopedLock lock(m_mutex); |
614 | NativeThreadWindows *thread = GetThreadByID(thread_id); |
615 | if (!thread) |
616 | return; |
617 | |
618 | for (auto t = m_threads.begin(); t != m_threads.end();) { |
619 | if ((*t)->GetID() == thread_id) { |
620 | t = m_threads.erase(position: t); |
621 | } else { |
622 | ++t; |
623 | } |
624 | } |
625 | } |
626 | |
627 | void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, |
628 | lldb::addr_t module_addr) { |
629 | // Simply invalidate the cached loaded modules. |
630 | if (!m_loaded_modules.empty()) |
631 | m_loaded_modules.clear(); |
632 | } |
633 | |
634 | void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { |
635 | if (!m_loaded_modules.empty()) |
636 | m_loaded_modules.clear(); |
637 | } |
638 | |
639 | llvm::Expected<std::unique_ptr<NativeProcessProtocol>> |
640 | NativeProcessWindows::Manager::Launch( |
641 | ProcessLaunchInfo &launch_info, |
642 | NativeProcessProtocol::NativeDelegate &native_delegate) { |
643 | Error E = Error::success(); |
644 | auto process_up = std::unique_ptr<NativeProcessWindows>( |
645 | new NativeProcessWindows(launch_info, native_delegate, E)); |
646 | if (E) |
647 | return std::move(E); |
648 | return std::move(process_up); |
649 | } |
650 | |
651 | llvm::Expected<std::unique_ptr<NativeProcessProtocol>> |
652 | NativeProcessWindows::Manager::Attach( |
653 | lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) { |
654 | Error E = Error::success(); |
655 | // Set pty primary fd invalid since it is not available. |
656 | auto process_up = std::unique_ptr<NativeProcessWindows>( |
657 | new NativeProcessWindows(pid, -1, native_delegate, E)); |
658 | if (E) |
659 | return std::move(E); |
660 | return std::move(process_up); |
661 | } |
662 | } // namespace lldb_private |
663 | |