• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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",
52      llvm::array_lengthof(g_gpr_regnums_x86_64) - 1, g_gpr_regnums_x86_64},
53     {"Floating Point Registers", "fpr",
54      llvm::array_lengthof(g_fpr_regnums_x86_64) - 1, g_fpr_regnums_x86_64}};
55 
56 enum { k_num_register_sets = 2 };
57 
58 } // namespace
59 
60 static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)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 
GetThreadContextHelper(lldb::thread_t thread_handle,PCONTEXT context_ptr,const DWORD control_flag)67 static Status GetThreadContextHelper(lldb::thread_t thread_handle,
68                                      PCONTEXT context_ptr,
69                                      const DWORD control_flag) {
70   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_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.SetError(GetLastError(), eErrorTypeWin32);
77     LLDB_LOG(log, "{0} GetThreadContext failed with error {1}", __FUNCTION__,
78              error);
79     return error;
80   }
81   return Status();
82 }
83 
SetThreadContextHelper(lldb::thread_t thread_handle,PCONTEXT context_ptr)84 static Status SetThreadContextHelper(lldb::thread_t thread_handle,
85                                      PCONTEXT context_ptr) {
86   Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS);
87   Status error;
88   // It's assumed that the thread has stopped.
89   if (!::SetThreadContext(thread_handle, context_ptr)) {
90     error.SetError(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>
CreateHostNativeRegisterContextWindows(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)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 
NativeRegisterContextWindows_x86_64(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)111 NativeRegisterContextWindows_x86_64::NativeRegisterContextWindows_x86_64(
112     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
113     : NativeRegisterContextWindows(native_thread,
114                                    CreateRegisterInfoInterface(target_arch)) {}
115 
IsGPR(uint32_t reg_index) const116 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 
IsFPR(uint32_t reg_index) const120 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 
IsDR(uint32_t reg_index) const124 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 
GetRegisterSetCount() const128 uint32_t NativeRegisterContextWindows_x86_64::GetRegisterSetCount() const {
129   return k_num_register_sets;
130 }
131 
132 const RegisterSet *
GetRegisterSet(uint32_t set_index) const133 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 
GPRRead(const uint32_t reg,RegisterValue & reg_value)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
GPRWrite(const uint32_t reg,const RegisterValue & reg_value)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 
FPRRead(const uint32_t reg,RegisterValue & reg_value)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
FPRWrite(const uint32_t reg,const RegisterValue & reg_value)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 
DRRead(const uint32_t reg,RegisterValue & reg_value)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("register DR4 is obsolete");
467   case lldb_dr5_x86_64:
468     return Status("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
DRWrite(const uint32_t reg,const RegisterValue & reg_value)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("register DR4 is obsolete");
506   case lldb_dr5_x86_64:
507     return Status("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
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)520 NativeRegisterContextWindows_x86_64::ReadRegister(const RegisterInfo *reg_info,
521                                                   RegisterValue &reg_value) {
522   Status error;
523   if (!reg_info) {
524     error.SetErrorString("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.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
533                                    "register, cannot read directly",
534                                    reg_info->name);
535     return error;
536   }
537 
538   if (IsGPR(reg))
539     return GPRRead(reg, reg_value);
540 
541   if (IsFPR(reg))
542     return FPRRead(reg, reg_value);
543 
544   if (IsDR(reg))
545     return DRRead(reg, reg_value);
546 
547   return Status("unimplemented");
548 }
549 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)550 Status NativeRegisterContextWindows_x86_64::WriteRegister(
551     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
552   Status error;
553 
554   if (!reg_info) {
555     error.SetErrorString("reg_info NULL");
556     return error;
557   }
558 
559   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
560   if (reg == LLDB_INVALID_REGNUM) {
561     // This is likely an internal register for lldb use only and should not be
562     // directly written.
563     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
564                                    "register, cannot write directly",
565                                    reg_info->name);
566     return error;
567   }
568 
569   if (IsGPR(reg))
570     return GPRWrite(reg, reg_value);
571 
572   if (IsFPR(reg))
573     return FPRWrite(reg, reg_value);
574 
575   if (IsDR(reg))
576     return DRWrite(reg, reg_value);
577 
578   return Status("unimplemented");
579 }
580 
ReadAllRegisterValues(lldb::DataBufferSP & data_sp)581 Status NativeRegisterContextWindows_x86_64::ReadAllRegisterValues(
582     lldb::DataBufferSP &data_sp) {
583   const size_t data_size = REG_CONTEXT_SIZE;
584   data_sp = std::make_shared<DataBufferHeap>(data_size, 0);
585   ::CONTEXT tls_context;
586   Status error =
587       GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL);
588   if (error.Fail())
589     return error;
590 
591   uint8_t *dst = data_sp->GetBytes();
592   ::memcpy(dst, &tls_context, data_size);
593   return error;
594 }
595 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)596 Status NativeRegisterContextWindows_x86_64::WriteAllRegisterValues(
597     const lldb::DataBufferSP &data_sp) {
598   Status error;
599   const size_t data_size = REG_CONTEXT_SIZE;
600   if (!data_sp) {
601     error.SetErrorStringWithFormat(
602         "NativeRegisterContextWindows_x86_64::%s invalid data_sp provided",
603         __FUNCTION__);
604     return error;
605   }
606 
607   if (data_sp->GetByteSize() != data_size) {
608     error.SetErrorStringWithFormatv(
609         "data_sp contained mismatched data size, expected {0}, actual {1}",
610         data_size, data_sp->GetByteSize());
611     return error;
612   }
613 
614   ::CONTEXT tls_context;
615   memcpy(&tls_context, data_sp->GetBytes(), data_size);
616   return SetThreadContextHelper(GetThreadHandle(), &tls_context);
617 }
618 
IsWatchpointHit(uint32_t wp_index,bool & is_hit)619 Status NativeRegisterContextWindows_x86_64::IsWatchpointHit(uint32_t wp_index,
620                                                             bool &is_hit) {
621   is_hit = false;
622 
623   if (wp_index >= NumSupportedHardwareWatchpoints())
624     return Status("watchpoint index out of range");
625 
626   RegisterValue reg_value;
627   Status error = DRRead(lldb_dr6_x86_64, reg_value);
628   if (error.Fail())
629     return error;
630 
631   is_hit = reg_value.GetAsUInt64() & (1ULL << wp_index);
632 
633   return {};
634 }
635 
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)636 Status NativeRegisterContextWindows_x86_64::GetWatchpointHitIndex(
637     uint32_t &wp_index, lldb::addr_t trap_addr) {
638   wp_index = LLDB_INVALID_INDEX32;
639 
640   for (uint32_t i = 0; i < NumSupportedHardwareWatchpoints(); i++) {
641     bool is_hit;
642     Status error = IsWatchpointHit(i, is_hit);
643     if (error.Fail())
644       return error;
645 
646     if (is_hit) {
647       wp_index = i;
648       return {};
649     }
650   }
651 
652   return {};
653 }
654 
655 Status
IsWatchpointVacant(uint32_t wp_index,bool & is_vacant)656 NativeRegisterContextWindows_x86_64::IsWatchpointVacant(uint32_t wp_index,
657                                                         bool &is_vacant) {
658   is_vacant = false;
659 
660   if (wp_index >= NumSupportedHardwareWatchpoints())
661     return Status("Watchpoint index out of range");
662 
663   RegisterValue reg_value;
664   Status error = DRRead(lldb_dr7_x86_64, reg_value);
665   if (error.Fail())
666     return error;
667 
668   is_vacant = !(reg_value.GetAsUInt64() & (1ULL << (2 * wp_index)));
669 
670   return error;
671 }
672 
ClearHardwareWatchpoint(uint32_t wp_index)673 bool NativeRegisterContextWindows_x86_64::ClearHardwareWatchpoint(
674     uint32_t wp_index) {
675   if (wp_index >= NumSupportedHardwareWatchpoints())
676     return false;
677 
678   // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of
679   // the debug status register (DR6)
680 
681   RegisterValue reg_value;
682   Status error = DRRead(lldb_dr6_x86_64, reg_value);
683   if (error.Fail())
684     return false;
685 
686   uint64_t bit_mask = 1ULL << wp_index;
687   uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
688   error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits));
689   if (error.Fail())
690     return false;
691 
692   // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19},
693   // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register
694   // (DR7)
695 
696   error = DRRead(lldb_dr7_x86_64, reg_value);
697   if (error.Fail())
698     return false;
699 
700   bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
701   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
702   return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits)).Success();
703 }
704 
ClearAllHardwareWatchpoints()705 Status NativeRegisterContextWindows_x86_64::ClearAllHardwareWatchpoints() {
706   RegisterValue reg_value;
707 
708   // clear bits {0-4} of the debug status register (DR6)
709 
710   Status error = DRRead(lldb_dr6_x86_64, reg_value);
711   if (error.Fail())
712     return error;
713 
714   uint64_t status_bits = reg_value.GetAsUInt64() & ~0xFULL;
715   error = DRWrite(lldb_dr6_x86_64, RegisterValue(status_bits));
716   if (error.Fail())
717     return error;
718 
719   // clear bits {0-7,16-31} of the debug control register (DR7)
720 
721   error = DRRead(lldb_dr7_x86_64, reg_value);
722   if (error.Fail())
723     return error;
724 
725   uint64_t control_bits = reg_value.GetAsUInt64() & ~0xFFFF00FFULL;
726   return DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits));
727 }
728 
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)729 uint32_t NativeRegisterContextWindows_x86_64::SetHardwareWatchpoint(
730     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
731   switch (size) {
732   case 1:
733   case 2:
734   case 4:
735   case 8:
736     break;
737   default:
738     return LLDB_INVALID_INDEX32;
739   }
740 
741   if (watch_flags == 0x2)
742     watch_flags = 0x3;
743 
744   if (watch_flags != 0x1 && watch_flags != 0x3)
745     return LLDB_INVALID_INDEX32;
746 
747   for (uint32_t wp_index = 0; wp_index < NumSupportedHardwareWatchpoints();
748        ++wp_index) {
749     bool is_vacant;
750     if (IsWatchpointVacant(wp_index, is_vacant).Fail())
751       return LLDB_INVALID_INDEX32;
752 
753     if (is_vacant) {
754       if (!ClearHardwareWatchpoint(wp_index))
755         return LLDB_INVALID_INDEX32;
756 
757       if (ApplyHardwareBreakpoint(wp_index, addr, size, watch_flags).Fail())
758         return LLDB_INVALID_INDEX32;
759 
760       return wp_index;
761     }
762   }
763   return LLDB_INVALID_INDEX32;
764 }
765 
ApplyHardwareBreakpoint(uint32_t wp_index,lldb::addr_t addr,size_t size,uint32_t flags)766 Status NativeRegisterContextWindows_x86_64::ApplyHardwareBreakpoint(
767     uint32_t wp_index, lldb::addr_t addr, size_t size, uint32_t flags) {
768   RegisterValue reg_value;
769   auto error = DRRead(lldb_dr7_x86_64, reg_value);
770   if (error.Fail())
771     return error;
772 
773   // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
774   uint64_t enable_bit = 1ULL << (2 * wp_index);
775 
776   // set bits 16-17, 20-21, 24-25, or 28-29
777   // with 0b01 for write, and 0b11 for read/write
778   uint64_t rw_bits = flags << (16 + 4 * wp_index);
779 
780   // set bits 18-19, 22-23, 26-27, or 30-31
781   // with 0b00, 0b01, 0b10, or 0b11
782   // for 1, 2, 8 (if supported), or 4 bytes, respectively
783   uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
784 
785   uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
786 
787   uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
788   control_bits |= enable_bit | rw_bits | size_bits;
789 
790   error = DRWrite(lldb_dr7_x86_64, RegisterValue(control_bits));
791   if (error.Fail())
792     return error;
793 
794   error = DRWrite(lldb_dr0_x86_64 + wp_index, RegisterValue(addr));
795   if (error.Fail())
796     return error;
797 
798   return {};
799 }
800 
801 lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)802 NativeRegisterContextWindows_x86_64::GetWatchpointAddress(uint32_t wp_index) {
803   if (wp_index >= NumSupportedHardwareWatchpoints())
804     return LLDB_INVALID_ADDRESS;
805 
806   RegisterValue reg_value;
807   if (DRRead(lldb_dr0_x86_64 + wp_index, reg_value).Fail())
808     return LLDB_INVALID_ADDRESS;
809 
810   return reg_value.GetAsUInt64();
811 }
812 
813 uint32_t
NumSupportedHardwareWatchpoints()814 NativeRegisterContextWindows_x86_64::NumSupportedHardwareWatchpoints() {
815   return 4;
816 }
817 
818 #endif // defined(__x86_64__) || defined(_M_X64)
819