xref: /llvm-project/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp (revision 6ae657b08d624f9634fa6ebbf5d6fd7a22dc3b4d)
1 //===-- NativeRegisterContextWindows_x86_64.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 #if defined(__x86_64__) || defined(_M_X64)
10 
11 #include "NativeRegisterContextWindows_x86_64.h"
12 #include "NativeRegisterContextWindows_WoW64.h"
13 #include "NativeThreadWindows.h"
14 #include "Plugins/Process/Utility/RegisterContextWindows_i386.h"
15 #include "Plugins/Process/Utility/RegisterContextWindows_x86_64.h"
16 #include "ProcessWindowsLog.h"
17 #include "lldb/Host/HostInfo.h"
18 #include "lldb/Host/HostThread.h"
19 #include "lldb/Host/windows/HostThreadWindows.h"
20 #include "lldb/Host/windows/windows.h"
21 
22 #include "lldb/Utility/Log.h"
23 #include "lldb/Utility/RegisterValue.h"
24 #include "llvm/ADT/STLExtras.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 #define REG_CONTEXT_SIZE sizeof(::CONTEXT)
30 
31 namespace {
32 static const uint32_t g_gpr_regnums_x86_64[] = {
33     lldb_rax_x86_64,    lldb_rbx_x86_64,    lldb_rcx_x86_64, lldb_rdx_x86_64,
34     lldb_rdi_x86_64,    lldb_rsi_x86_64,    lldb_rbp_x86_64, lldb_rsp_x86_64,
35     lldb_r8_x86_64,     lldb_r9_x86_64,     lldb_r10_x86_64, lldb_r11_x86_64,
36     lldb_r12_x86_64,    lldb_r13_x86_64,    lldb_r14_x86_64, lldb_r15_x86_64,
37     lldb_rip_x86_64,    lldb_rflags_x86_64, lldb_cs_x86_64,  lldb_fs_x86_64,
38     lldb_gs_x86_64,     lldb_ss_x86_64,     lldb_ds_x86_64,  lldb_es_x86_64,
39     LLDB_INVALID_REGNUM // Register set must be terminated with this flag
40 };
41 
42 static const uint32_t g_fpr_regnums_x86_64[] = {
43     lldb_xmm0_x86_64,   lldb_xmm1_x86_64,  lldb_xmm2_x86_64,  lldb_xmm3_x86_64,
44     lldb_xmm4_x86_64,   lldb_xmm5_x86_64,  lldb_xmm6_x86_64,  lldb_xmm7_x86_64,
45     lldb_xmm8_x86_64,   lldb_xmm9_x86_64,  lldb_xmm10_x86_64, lldb_xmm11_x86_64,
46     lldb_xmm12_x86_64,  lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64,
47     LLDB_INVALID_REGNUM // Register set must be terminated with this flag
48 };
49 
50 static const RegisterSet g_reg_sets_x86_64[] = {
51     {"General Purpose Registers", "gpr", std::size(g_gpr_regnums_x86_64) - 1,
52      g_gpr_regnums_x86_64},
53     {"Floating Point Registers", "fpr", std::size(g_fpr_regnums_x86_64) - 1,
54      g_fpr_regnums_x86_64}};
55 
56 enum { k_num_register_sets = 2 };
57 
58 } // namespace
59 
60 static RegisterInfoInterface *
61 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
62   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
63          "Register setting path assumes this is a 64-bit host");
64   return new RegisterContextWindows_x86_64(target_arch);
65 }
66 
67 static Status GetThreadContextHelper(lldb::thread_t thread_handle,
68                                      PCONTEXT context_ptr,
69                                      const DWORD control_flag) {
70   Log *log = GetLog(WindowsLog::Registers);
71   Status error;
72 
73   memset(context_ptr, 0, sizeof(::CONTEXT));
74   context_ptr->ContextFlags = control_flag;
75   if (!::GetThreadContext(thread_handle, context_ptr)) {
76     error = Status(GetLastError(), eErrorTypeWin32);
77     LLDB_LOG(log, "{0} GetThreadContext failed with error {1}", __FUNCTION__,
78              error);
79     return error;
80   }
81   return Status();
82 }
83 
84 static Status SetThreadContextHelper(lldb::thread_t thread_handle,
85                                      PCONTEXT context_ptr) {
86   Log *log = GetLog(WindowsLog::Registers);
87   Status error;
88   // It's assumed that the thread has stopped.
89   if (!::SetThreadContext(thread_handle, context_ptr)) {
90     error = Status(GetLastError(), eErrorTypeWin32);
91     LLDB_LOG(log, "{0} SetThreadContext failed with error {1}", __FUNCTION__,
92              error);
93     return error;
94   }
95   return Status();
96 }
97 
98 std::unique_ptr<NativeRegisterContextWindows>
99 NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows(
100     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
101   // Register context for a WoW64 application.
102   if (target_arch.GetAddressByteSize() == 4)
103     return std::make_unique<NativeRegisterContextWindows_WoW64>(target_arch,
104                                                                 native_thread);
105 
106   // Register context for a native 64-bit application.
107   return std::make_unique<NativeRegisterContextWindows_x86_64>(target_arch,
108                                                                native_thread);
109 }
110 
111 NativeRegisterContextWindows_x86_64::NativeRegisterContextWindows_x86_64(
112     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
113     : NativeRegisterContextWindows(native_thread,
114                                    CreateRegisterInfoInterface(target_arch)) {}
115 
116 bool NativeRegisterContextWindows_x86_64::IsGPR(uint32_t reg_index) const {
117   return (reg_index >= k_first_gpr_x86_64 && reg_index < k_first_alias_x86_64);
118 }
119 
120 bool NativeRegisterContextWindows_x86_64::IsFPR(uint32_t reg_index) const {
121   return (reg_index >= lldb_xmm0_x86_64 && reg_index <= k_last_fpr_x86_64);
122 }
123 
124 bool NativeRegisterContextWindows_x86_64::IsDR(uint32_t reg_index) const {
125   return (reg_index >= lldb_dr0_x86_64 && reg_index <= lldb_dr7_x86_64);
126 }
127 
128 uint32_t NativeRegisterContextWindows_x86_64::GetRegisterSetCount() const {
129   return k_num_register_sets;
130 }
131 
132 const RegisterSet *
133 NativeRegisterContextWindows_x86_64::GetRegisterSet(uint32_t set_index) const {
134   if (set_index >= k_num_register_sets)
135     return nullptr;
136   return &g_reg_sets_x86_64[set_index];
137 }
138 
139 Status NativeRegisterContextWindows_x86_64::GPRRead(const uint32_t reg,
140                                                     RegisterValue &reg_value) {
141   ::CONTEXT tls_context;
142   DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
143   Status error =
144       GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag);
145   if (error.Fail())
146     return error;
147 
148   switch (reg) {
149   case lldb_rax_x86_64:
150     reg_value.SetUInt64(tls_context.Rax);
151     break;
152   case lldb_rbx_x86_64:
153     reg_value.SetUInt64(tls_context.Rbx);
154     break;
155   case lldb_rcx_x86_64:
156     reg_value.SetUInt64(tls_context.Rcx);
157     break;
158   case lldb_rdx_x86_64:
159     reg_value.SetUInt64(tls_context.Rdx);
160     break;
161   case lldb_rdi_x86_64:
162     reg_value.SetUInt64(tls_context.Rdi);
163     break;
164   case lldb_rsi_x86_64:
165     reg_value.SetUInt64(tls_context.Rsi);
166     break;
167   case lldb_rbp_x86_64:
168     reg_value.SetUInt64(tls_context.Rbp);
169     break;
170   case lldb_rsp_x86_64:
171     reg_value.SetUInt64(tls_context.Rsp);
172     break;
173   case lldb_r8_x86_64:
174     reg_value.SetUInt64(tls_context.R8);
175     break;
176   case lldb_r9_x86_64:
177     reg_value.SetUInt64(tls_context.R9);
178     break;
179   case lldb_r10_x86_64:
180     reg_value.SetUInt64(tls_context.R10);
181     break;
182   case lldb_r11_x86_64:
183     reg_value.SetUInt64(tls_context.R11);
184     break;
185   case lldb_r12_x86_64:
186     reg_value.SetUInt64(tls_context.R12);
187     break;
188   case lldb_r13_x86_64:
189     reg_value.SetUInt64(tls_context.R13);
190     break;
191   case lldb_r14_x86_64:
192     reg_value.SetUInt64(tls_context.R14);
193     break;
194   case lldb_r15_x86_64:
195     reg_value.SetUInt64(tls_context.R15);
196     break;
197   case lldb_rip_x86_64:
198     reg_value.SetUInt64(tls_context.Rip);
199     break;
200   case lldb_rflags_x86_64:
201     reg_value.SetUInt64(tls_context.EFlags | 0x2); // Bit #1 always 1
202     break;
203   case lldb_cs_x86_64:
204     reg_value.SetUInt16(tls_context.SegCs);
205     break;
206   case lldb_fs_x86_64:
207     reg_value.SetUInt16(tls_context.SegFs);
208     break;
209   case lldb_gs_x86_64:
210     reg_value.SetUInt16(tls_context.SegGs);
211     break;
212   case lldb_ss_x86_64:
213     reg_value.SetUInt16(tls_context.SegSs);
214     break;
215   case lldb_ds_x86_64:
216     reg_value.SetUInt16(tls_context.SegDs);
217     break;
218   case lldb_es_x86_64:
219     reg_value.SetUInt16(tls_context.SegEs);
220     break;
221   }
222 
223   return error;
224 }
225 
226 Status
227 NativeRegisterContextWindows_x86_64::GPRWrite(const uint32_t reg,
228                                               const RegisterValue &reg_value) {
229   ::CONTEXT tls_context;
230   DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
231   auto thread_handle = GetThreadHandle();
232   Status error =
233       GetThreadContextHelper(thread_handle, &tls_context, context_flag);
234   if (error.Fail())
235     return error;
236 
237   switch (reg) {
238   case lldb_rax_x86_64:
239     tls_context.Rax = reg_value.GetAsUInt64();
240     break;
241   case lldb_rbx_x86_64:
242     tls_context.Rbx = reg_value.GetAsUInt64();
243     break;
244   case lldb_rcx_x86_64:
245     tls_context.Rcx = reg_value.GetAsUInt64();
246     break;
247   case lldb_rdx_x86_64:
248     tls_context.Rdx = reg_value.GetAsUInt64();
249     break;
250   case lldb_rdi_x86_64:
251     tls_context.Rdi = reg_value.GetAsUInt64();
252     break;
253   case lldb_rsi_x86_64:
254     tls_context.Rsi = reg_value.GetAsUInt64();
255     break;
256   case lldb_rbp_x86_64:
257     tls_context.Rbp = reg_value.GetAsUInt64();
258     break;
259   case lldb_rsp_x86_64:
260     tls_context.Rsp = reg_value.GetAsUInt64();
261     break;
262   case lldb_r8_x86_64:
263     tls_context.R8 = reg_value.GetAsUInt64();
264     break;
265   case lldb_r9_x86_64:
266     tls_context.R9 = reg_value.GetAsUInt64();
267     break;
268   case lldb_r10_x86_64:
269     tls_context.R10 = reg_value.GetAsUInt64();
270     break;
271   case lldb_r11_x86_64:
272     tls_context.R11 = reg_value.GetAsUInt64();
273     break;
274   case lldb_r12_x86_64:
275     tls_context.R12 = reg_value.GetAsUInt64();
276     break;
277   case lldb_r13_x86_64:
278     tls_context.R13 = reg_value.GetAsUInt64();
279     break;
280   case lldb_r14_x86_64:
281     tls_context.R14 = reg_value.GetAsUInt64();
282     break;
283   case lldb_r15_x86_64:
284     tls_context.R15 = reg_value.GetAsUInt64();
285     break;
286   case lldb_rip_x86_64:
287     tls_context.Rip = reg_value.GetAsUInt64();
288     break;
289   case lldb_rflags_x86_64:
290     tls_context.EFlags = reg_value.GetAsUInt64();
291     break;
292   case lldb_cs_x86_64:
293     tls_context.SegCs = reg_value.GetAsUInt16();
294     break;
295   case lldb_fs_x86_64:
296     tls_context.SegFs = reg_value.GetAsUInt16();
297     break;
298   case lldb_gs_x86_64:
299     tls_context.SegGs = reg_value.GetAsUInt16();
300     break;
301   case lldb_ss_x86_64:
302     tls_context.SegSs = reg_value.GetAsUInt16();
303     break;
304   case lldb_ds_x86_64:
305     tls_context.SegDs = reg_value.GetAsUInt16();
306     break;
307   case lldb_es_x86_64:
308     tls_context.SegEs = reg_value.GetAsUInt16();
309     break;
310   }
311 
312   return SetThreadContextHelper(thread_handle, &tls_context);
313 }
314 
315 Status NativeRegisterContextWindows_x86_64::FPRRead(const uint32_t reg,
316                                                     RegisterValue &reg_value) {
317   ::CONTEXT tls_context;
318   DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT;
319   Status error =
320       GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag);
321   if (error.Fail())
322     return error;
323 
324   switch (reg) {
325   case lldb_xmm0_x86_64:
326     reg_value.SetBytes(&tls_context.Xmm0, 16, endian::InlHostByteOrder());
327     break;
328   case lldb_xmm1_x86_64:
329     reg_value.SetBytes(&tls_context.Xmm1, 16, endian::InlHostByteOrder());
330     break;
331   case lldb_xmm2_x86_64:
332     reg_value.SetBytes(&tls_context.Xmm2, 16, endian::InlHostByteOrder());
333     break;
334   case lldb_xmm3_x86_64:
335     reg_value.SetBytes(&tls_context.Xmm3, 16, endian::InlHostByteOrder());
336     break;
337   case lldb_xmm4_x86_64:
338     reg_value.SetBytes(&tls_context.Xmm4, 16, endian::InlHostByteOrder());
339     break;
340   case lldb_xmm5_x86_64:
341     reg_value.SetBytes(&tls_context.Xmm5, 16, endian::InlHostByteOrder());
342     break;
343   case lldb_xmm6_x86_64:
344     reg_value.SetBytes(&tls_context.Xmm6, 16, endian::InlHostByteOrder());
345     break;
346   case lldb_xmm7_x86_64:
347     reg_value.SetBytes(&tls_context.Xmm7, 16, endian::InlHostByteOrder());
348     break;
349   case lldb_xmm8_x86_64:
350     reg_value.SetBytes(&tls_context.Xmm8, 16, endian::InlHostByteOrder());
351     break;
352   case lldb_xmm9_x86_64:
353     reg_value.SetBytes(&tls_context.Xmm9, 16, endian::InlHostByteOrder());
354     break;
355   case lldb_xmm10_x86_64:
356     reg_value.SetBytes(&tls_context.Xmm10, 16, endian::InlHostByteOrder());
357     break;
358   case lldb_xmm11_x86_64:
359     reg_value.SetBytes(&tls_context.Xmm11, 16, endian::InlHostByteOrder());
360     break;
361   case lldb_xmm12_x86_64:
362     reg_value.SetBytes(&tls_context.Xmm12, 16, endian::InlHostByteOrder());
363     break;
364   case lldb_xmm13_x86_64:
365     reg_value.SetBytes(&tls_context.Xmm13, 16, endian::InlHostByteOrder());
366     break;
367   case lldb_xmm14_x86_64:
368     reg_value.SetBytes(&tls_context.Xmm14, 16, endian::InlHostByteOrder());
369     break;
370   case lldb_xmm15_x86_64:
371     reg_value.SetBytes(&tls_context.Xmm15, 16, endian::InlHostByteOrder());
372     break;
373   }
374 
375   return error;
376 }
377 
378 Status
379 NativeRegisterContextWindows_x86_64::FPRWrite(const uint32_t reg,
380                                               const RegisterValue &reg_value) {
381   ::CONTEXT tls_context;
382   DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT;
383   auto thread_handle = GetThreadHandle();
384   Status error =
385       GetThreadContextHelper(thread_handle, &tls_context, context_flag);
386   if (error.Fail())
387     return error;
388 
389   switch (reg) {
390   case lldb_xmm0_x86_64:
391     memcpy(&tls_context.Xmm0, reg_value.GetBytes(), 16);
392     break;
393   case lldb_xmm1_x86_64:
394     memcpy(&tls_context.Xmm1, reg_value.GetBytes(), 16);
395     break;
396   case lldb_xmm2_x86_64:
397     memcpy(&tls_context.Xmm2, reg_value.GetBytes(), 16);
398     break;
399   case lldb_xmm3_x86_64:
400     memcpy(&tls_context.Xmm3, reg_value.GetBytes(), 16);
401     break;
402   case lldb_xmm4_x86_64:
403     memcpy(&tls_context.Xmm4, reg_value.GetBytes(), 16);
404     break;
405   case lldb_xmm5_x86_64:
406     memcpy(&tls_context.Xmm5, reg_value.GetBytes(), 16);
407     break;
408   case lldb_xmm6_x86_64:
409     memcpy(&tls_context.Xmm6, reg_value.GetBytes(), 16);
410     break;
411   case lldb_xmm7_x86_64:
412     memcpy(&tls_context.Xmm7, reg_value.GetBytes(), 16);
413     break;
414   case lldb_xmm8_x86_64:
415     memcpy(&tls_context.Xmm8, reg_value.GetBytes(), 16);
416     break;
417   case lldb_xmm9_x86_64:
418     memcpy(&tls_context.Xmm9, reg_value.GetBytes(), 16);
419     break;
420   case lldb_xmm10_x86_64:
421     memcpy(&tls_context.Xmm10, reg_value.GetBytes(), 16);
422     break;
423   case lldb_xmm11_x86_64:
424     memcpy(&tls_context.Xmm11, reg_value.GetBytes(), 16);
425     break;
426   case lldb_xmm12_x86_64:
427     memcpy(&tls_context.Xmm12, reg_value.GetBytes(), 16);
428     break;
429   case lldb_xmm13_x86_64:
430     memcpy(&tls_context.Xmm13, reg_value.GetBytes(), 16);
431     break;
432   case lldb_xmm14_x86_64:
433     memcpy(&tls_context.Xmm14, reg_value.GetBytes(), 16);
434     break;
435   case lldb_xmm15_x86_64:
436     memcpy(&tls_context.Xmm15, reg_value.GetBytes(), 16);
437     break;
438   }
439 
440   return SetThreadContextHelper(thread_handle, &tls_context);
441 }
442 
443 Status NativeRegisterContextWindows_x86_64::DRRead(const uint32_t reg,
444                                                    RegisterValue &reg_value) {
445   ::CONTEXT tls_context;
446   DWORD context_flag = CONTEXT_DEBUG_REGISTERS;
447   Status error =
448       GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag);
449   if (error.Fail())
450     return error;
451 
452   switch (reg) {
453   case lldb_dr0_x86_64:
454     reg_value.SetUInt64(tls_context.Dr0);
455     break;
456   case lldb_dr1_x86_64:
457     reg_value.SetUInt64(tls_context.Dr1);
458     break;
459   case lldb_dr2_x86_64:
460     reg_value.SetUInt64(tls_context.Dr2);
461     break;
462   case lldb_dr3_x86_64:
463     reg_value.SetUInt64(tls_context.Dr3);
464     break;
465   case lldb_dr4_x86_64:
466     return Status::FromErrorString("register DR4 is obsolete");
467   case lldb_dr5_x86_64:
468     return Status::FromErrorString("register DR5 is obsolete");
469   case lldb_dr6_x86_64:
470     reg_value.SetUInt64(tls_context.Dr6);
471     break;
472   case lldb_dr7_x86_64:
473     reg_value.SetUInt64(tls_context.Dr7);
474     break;
475   }
476 
477   return {};
478 }
479 
480 Status
481 NativeRegisterContextWindows_x86_64::DRWrite(const uint32_t reg,
482                                              const RegisterValue &reg_value) {
483   ::CONTEXT tls_context;
484   DWORD context_flag = CONTEXT_DEBUG_REGISTERS;
485   auto thread_handle = GetThreadHandle();
486   Status error =
487       GetThreadContextHelper(thread_handle, &tls_context, context_flag);
488   if (error.Fail())
489     return error;
490 
491   switch (reg) {
492   case lldb_dr0_x86_64:
493     tls_context.Dr0 = reg_value.GetAsUInt64();
494     break;
495   case lldb_dr1_x86_64:
496     tls_context.Dr1 = reg_value.GetAsUInt64();
497     break;
498   case lldb_dr2_x86_64:
499     tls_context.Dr2 = reg_value.GetAsUInt64();
500     break;
501   case lldb_dr3_x86_64:
502     tls_context.Dr3 = reg_value.GetAsUInt64();
503     break;
504   case lldb_dr4_x86_64:
505     return Status::FromErrorString("register DR4 is obsolete");
506   case lldb_dr5_x86_64:
507     return Status::FromErrorString("register DR5 is obsolete");
508   case lldb_dr6_x86_64:
509     tls_context.Dr6 = reg_value.GetAsUInt64();
510     break;
511   case lldb_dr7_x86_64:
512     tls_context.Dr7 = reg_value.GetAsUInt64();
513     break;
514   }
515 
516   return SetThreadContextHelper(thread_handle, &tls_context);
517 }
518 
519 Status
520 NativeRegisterContextWindows_x86_64::ReadRegister(const RegisterInfo *reg_info,
521                                                   RegisterValue &reg_value) {
522   Status error;
523   if (!reg_info) {
524     error = Status::FromErrorString("reg_info NULL");
525     return error;
526   }
527 
528   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
529   if (reg == LLDB_INVALID_REGNUM) {
530     // This is likely an internal register for lldb use only and should not be
531     // directly queried.
532     error = Status::FromErrorStringWithFormat(
533         "register \"%s\" is an internal-only lldb "
534         "register, cannot read directly",
535         reg_info->name);
536     return error;
537   }
538 
539   if (IsGPR(reg))
540     return GPRRead(reg, reg_value);
541 
542   if (IsFPR(reg))
543     return FPRRead(reg, reg_value);
544 
545   if (IsDR(reg))
546     return DRRead(reg, reg_value);
547 
548   return Status::FromErrorString("unimplemented");
549 }
550 
551 Status NativeRegisterContextWindows_x86_64::WriteRegister(
552     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
553   Status error;
554 
555   if (!reg_info) {
556     error = Status::FromErrorString("reg_info NULL");
557     return error;
558   }
559 
560   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
561   if (reg == LLDB_INVALID_REGNUM) {
562     // This is likely an internal register for lldb use only and should not be
563     // directly written.
564     error = Status::FromErrorStringWithFormat(
565         "register \"%s\" is an internal-only lldb "
566         "register, cannot write directly",
567         reg_info->name);
568     return error;
569   }
570 
571   if (IsGPR(reg))
572     return GPRWrite(reg, reg_value);
573 
574   if (IsFPR(reg))
575     return FPRWrite(reg, reg_value);
576 
577   if (IsDR(reg))
578     return DRWrite(reg, reg_value);
579 
580   return Status::FromErrorString("unimplemented");
581 }
582 
583 Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues(
584     lldb::WritableDataBufferSP &data_sp) {
585   const size_t data_size = REG_CONTEXT_SIZE;
586   data_sp = std::make_shared<DataBufferHeap>(data_size, 0);
587   ::CONTEXT tls_context;
588   Status error =
589       GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL);
590   if (error.Fail())
591     return error;
592 
593   uint8_t *dst = data_sp->GetBytes();
594   ::memcpy(dst, &tls_context, data_size);
595   return error;
596 }
597 
598 Status NativeRegisterContextWindows_x86_64::WriteAllRegisterValues(
599     const lldb::DataBufferSP &data_sp) {
600   Status error;
601   const size_t data_size = REG_CONTEXT_SIZE;
602   if (!data_sp) {
603     error = Status::FromErrorStringWithFormat(
604         "NativeRegisterContextWindows_x86_64::%s invalid data_sp provided",
605         __FUNCTION__);
606     return error;
607   }
608 
609   if (data_sp->GetByteSize() != data_size) {
610     error = Status::FromErrorStringWithFormatv(
611         "data_sp contained mismatched data size, expected {0}, actual {1}",
612         data_size, data_sp->GetByteSize());
613     return error;
614   }
615 
616   ::CONTEXT tls_context;
617   memcpy(&tls_context, data_sp->GetBytes(), data_size);
618   return SetThreadContextHelper(GetThreadHandle(), &tls_context);
619 }
620 
621 Status NativeRegisterContextWindows_x86_64::IsWatchpointHit(uint32_t wp_index,
622                                                             bool &is_hit) {
623   is_hit = false;
624 
625   if (wp_index >= NumSupportedHardwareWatchpoints())
626     return Status::FromErrorString("watchpoint index out of range");
627 
628   RegisterValue reg_value;
629   Status error = DRRead(lldb_dr6_x86_64, reg_value);
630   if (error.Fail())
631     return error;
632 
633   is_hit = reg_value.GetAsUInt64() & (1ULL << wp_index);
634 
635   return {};
636 }
637 
638 Status NativeRegisterContextWindows_x86_64::GetWatchpointHitIndex(
639     uint32_t &wp_index, lldb::addr_t trap_addr) {
640   wp_index = LLDB_INVALID_INDEX32;
641 
642   for (uint32_t i = 0; i < NumSupportedHardwareWatchpoints(); i++) {
643     bool is_hit;
644     Status error = IsWatchpointHit(i, is_hit);
645     if (error.Fail())
646       return error;
647 
648     if (is_hit) {
649       wp_index = i;
650       return {};
651     }
652   }
653 
654   return {};
655 }
656 
657 Status
658 NativeRegisterContextWindows_x86_64::IsWatchpointVacant(uint32_t wp_index,
659                                                         bool &is_vacant) {
660   is_vacant = false;
661 
662   if (wp_index >= NumSupportedHardwareWatchpoints())
663     return Status::FromErrorString("Watchpoint index out of range");
664 
665   RegisterValue reg_value;
666   Status error = DRRead(lldb_dr7_x86_64, reg_value);
667   if (error.Fail())
668     return error;
669 
670   is_vacant = !(reg_value.GetAsUInt64() & (1ULL << (2 * wp_index)));
671 
672   return error;
673 }
674 
675 bool NativeRegisterContextWindows_x86_64::ClearHardwareWatchpoint(
676     uint32_t wp_index) {
677   if (wp_index >= NumSupportedHardwareWatchpoints())
678     return false;
679 
680   // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of
681   // the debug status register (DR6)
682 
683   RegisterValue reg_value;
684   Status error = DRRead(lldb_dr6_x86_64, reg_value);
685   if (error.Fail())
686     return false;
687 
688   uint64_t bit_mask = 1ULL << wp_index;
689   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
690   error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits));
691   if (error.Fail())
692     return false;
693 
694   // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19},
695   // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register
696   // (DR7)
697 
698   error = DRRead(lldb_dr7_x86_64, reg_value);
699   if (error.Fail())
700     return false;
701 
702   bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
703   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
704   return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)).Success();
705 }
706 
707 Status NativeRegisterContextWindows_x86_64::ClearAllHardwareWatchpoints() {
708   RegisterValue reg_value;
709 
710   // clear bits {0-4} of the debug status register (DR6)
711 
712   Status error = DRRead(lldb_dr6_x86_64, reg_value);
713   if (error.Fail())
714     return error;
715 
716   uint64_t status_bits = reg_value.GetAsUInt64() & ~0xFULL;
717   error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits));
718   if (error.Fail())
719     return error;
720 
721   // clear bits {0-7,16-31} of the debug control register (DR7)
722 
723   error = DRRead(lldb_dr7_x86_64, reg_value);
724   if (error.Fail())
725     return error;
726 
727   uint64_t control_bits = reg_value.GetAsUInt64() & ~0xFFFF00FFULL;
728   return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits));
729 }
730 
731 uint32_t NativeRegisterContextWindows_x86_64::SetHardwareWatchpoint(
732     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
733   switch (size) {
734   case 1:
735   case 2:
736   case 4:
737   case 8:
738     break;
739   default:
740     return LLDB_INVALID_INDEX32;
741   }
742 
743   if (watch_flags == 0x2)
744     watch_flags = 0x3;
745 
746   if (watch_flags != 0x1 && watch_flags != 0x3)
747     return LLDB_INVALID_INDEX32;
748 
749   for (uint32_t wp_index = 0; wp_index < NumSupportedHardwareWatchpoints();
750        ++wp_index) {
751     bool is_vacant;
752     if (IsWatchpointVacant(wp_index, is_vacant).Fail())
753       return LLDB_INVALID_INDEX32;
754 
755     if (is_vacant) {
756       if (!ClearHardwareWatchpoint(wp_index))
757         return LLDB_INVALID_INDEX32;
758 
759       if (ApplyHardwareBreakpoint(wp_index, addr, size, watch_flags).Fail())
760         return LLDB_INVALID_INDEX32;
761 
762       return wp_index;
763     }
764   }
765   return LLDB_INVALID_INDEX32;
766 }
767 
768 Status NativeRegisterContextWindows_x86_64::ApplyHardwareBreakpoint(
769     uint32_t wp_index, lldb::addr_t addr, size_t size, uint32_t flags) {
770   RegisterValue reg_value;
771   auto error = DRRead(lldb_dr7_x86_64, reg_value);
772   if (error.Fail())
773     return error;
774 
775   // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
776   uint64_t enable_bit = 1ULL << (2 * wp_index);
777 
778   // set bits 16-17, 20-21, 24-25, or 28-29
779   // with 0b01 for write, and 0b11 for read/write
780   uint64_t rw_bits = flags << (16 + 4 * wp_index);
781 
782   // set bits 18-19, 22-23, 26-27, or 30-31
783   // with 0b00, 0b01, 0b10, or 0b11
784   // for 1, 2, 8 (if supported), or 4 bytes, respectively
785   uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
786 
787   uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
788 
789   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
790   control_bits |= enable_bit | rw_bits | size_bits;
791 
792   error = DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits));
793   if (error.Fail())
794     return error;
795 
796   error = DRWrite(lldb_dr0_x86_64 + wp_index, RegisterValue(addr));
797   if (error.Fail())
798     return error;
799 
800   return {};
801 }
802 
803 lldb::addr_t
804 NativeRegisterContextWindows_x86_64::GetWatchpointAddress(uint32_t wp_index) {
805   if (wp_index >= NumSupportedHardwareWatchpoints())
806     return LLDB_INVALID_ADDRESS;
807 
808   RegisterValue reg_value;
809   if (DRRead(lldb_dr0_x86_64 + wp_index, reg_value).Fail())
810     return LLDB_INVALID_ADDRESS;
811 
812   return reg_value.GetAsUInt64();
813 }
814 
815 uint32_t
816 NativeRegisterContextWindows_x86_64::NumSupportedHardwareWatchpoints() {
817   return 4;
818 }
819 
820 #endif // defined(__x86_64__) || defined(_M_X64)
821