1 //===-- RegisterContextPOSIXProcessMonitor_x86.h ---------------*- 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 "lldb/Core/DataBufferHeap.h"
11 #include "lldb/Core/RegisterValue.h"
12 #include "lldb/Target/Thread.h"
13 
14 #include "Plugins/Process/FreeBSD/ProcessPOSIX.h"
15 #include "RegisterContextPOSIXProcessMonitor_x86.h"
16 #include "Plugins/Process/FreeBSD/ProcessMonitor.h"
17 
18 using namespace lldb_private;
19 using namespace lldb;
20 
21 // Support ptrace extensions even when compiled without required kernel support
22 #ifndef NT_X86_XSTATE
23   #define NT_X86_XSTATE 0x202
24 #endif
25 
26 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR))
27 
28 static uint32_t
size_and_rw_bits(size_t size,bool read,bool write)29 size_and_rw_bits(size_t size, bool read, bool write)
30 {
31     uint32_t rw;
32 
33     if (read)
34         rw = 0x3; // READ or READ/WRITE
35     else if (write)
36         rw = 0x1; // WRITE
37     else
38         assert(0 && "read and write cannot both be false");
39 
40     switch (size)
41     {
42     case 1:
43         return rw;
44     case 2:
45         return (0x1 << 2) | rw;
46     case 4:
47         return (0x3 << 2) | rw;
48     case 8:
49         return (0x2 << 2) | rw;
50     default:
51         assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
52         return 0; // Unreachable. Just to silence compiler.
53     }
54 }
55 
RegisterContextPOSIXProcessMonitor_x86_64(Thread & thread,uint32_t concrete_frame_idx,lldb_private::RegisterInfoInterface * register_info)56 RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread,
57                                                                                      uint32_t concrete_frame_idx,
58                                                                                      lldb_private::RegisterInfoInterface *register_info)
59     : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info)
60 {
61 }
62 
63 ProcessMonitor &
GetMonitor()64 RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor()
65 {
66     ProcessSP base = CalculateProcess();
67     ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
68     return process->GetMonitor();
69 }
70 
71 bool
ReadGPR()72 RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR()
73 {
74      ProcessMonitor &monitor = GetMonitor();
75      return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize());
76 }
77 
78 bool
ReadFPR()79 RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR()
80 {
81     ProcessMonitor &monitor = GetMonitor();
82     if (GetFPRType() == eFXSAVE)
83         return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
84 
85     if (GetFPRType() == eXSAVE)
86         return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
87     return false;
88 }
89 
90 bool
WriteGPR()91 RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR()
92 {
93     ProcessMonitor &monitor = GetMonitor();
94     return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize());
95 }
96 
97 bool
WriteFPR()98 RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR()
99 {
100     ProcessMonitor &monitor = GetMonitor();
101     if (GetFPRType() == eFXSAVE)
102         return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
103 
104     if (GetFPRType() == eXSAVE)
105         return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
106     return false;
107 }
108 
109 bool
ReadRegister(const unsigned reg,RegisterValue & value)110 RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg,
111                                                         RegisterValue &value)
112 {
113     ProcessMonitor &monitor = GetMonitor();
114 
115 #if defined(__FreeBSD__)
116     if (reg >= m_reg_info.first_dr)
117         return monitor.ReadDebugRegisterValue(m_thread.GetID(),
118                                               GetRegisterOffset(reg),
119                                               GetRegisterName(reg),
120                                               GetRegisterSize(reg),
121                                               value);
122 #endif
123     return monitor.ReadRegisterValue(m_thread.GetID(),
124                                      GetRegisterOffset(reg),
125                                      GetRegisterName(reg),
126                                      GetRegisterSize(reg),
127                                      value);
128 }
129 
130 bool
WriteRegister(const unsigned reg,const RegisterValue & value)131 RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg,
132                                                          const RegisterValue &value)
133 {
134     unsigned reg_to_write = reg;
135     RegisterValue value_to_write = value;
136 
137     // Check if this is a subregister of a full register.
138     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
139     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
140     {
141         RegisterValue full_value;
142         uint32_t full_reg = reg_info->invalidate_regs[0];
143         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
144 
145         // Read the full register.
146         if (ReadRegister(full_reg_info, full_value))
147         {
148             Error error;
149             ByteOrder byte_order = GetByteOrder();
150             uint8_t dst[RegisterValue::kMaxRegisterByteSize];
151 
152             // Get the bytes for the full register.
153             const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
154                                                                    dst,
155                                                                    sizeof(dst),
156                                                                    byte_order,
157                                                                    error);
158             if (error.Success() && dest_size)
159             {
160                 uint8_t src[RegisterValue::kMaxRegisterByteSize];
161 
162                 // Get the bytes for the source data.
163                 const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
164                 if (error.Success() && src_size && (src_size < dest_size))
165                 {
166                     // Copy the src bytes to the destination.
167                     memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
168                     // Set this full register as the value to write.
169                     value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
170                     value_to_write.SetType(full_reg_info);
171                     reg_to_write = full_reg;
172                 }
173             }
174         }
175     }
176 
177     ProcessMonitor &monitor = GetMonitor();
178 #if defined(__FreeBSD__)
179     if (reg >= m_reg_info.first_dr)
180         return monitor.WriteDebugRegisterValue(m_thread.GetID(),
181                                                GetRegisterOffset(reg_to_write),
182                                                GetRegisterName(reg_to_write),
183                                                value_to_write);
184 #endif
185     return monitor.WriteRegisterValue(m_thread.GetID(),
186                                       GetRegisterOffset(reg_to_write),
187                                       GetRegisterName(reg_to_write),
188                                       value_to_write);
189 }
190 
191 bool
ReadRegister(const RegisterInfo * reg_info,RegisterValue & value)192 RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
193 {
194     if (!reg_info)
195         return false;
196 
197     const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
198 
199     if (IsFPR(reg, GetFPRType()))
200     {
201         if (!ReadFPR())
202             return false;
203     }
204     else
205     {
206         uint32_t full_reg = reg;
207         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
208 
209         if (is_subreg)
210         {
211             // Read the full aligned 64-bit register.
212             full_reg = reg_info->invalidate_regs[0];
213         }
214 
215         bool success = ReadRegister(full_reg, value);
216 
217         if (success)
218         {
219             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
220             if (is_subreg && (reg_info->byte_offset & 0x1))
221                 value.SetUInt64(value.GetAsUInt64() >> 8);
222 
223             // If our return byte size was greater than the return value reg size, then
224             // use the type specified by reg_info rather than the uint64_t default
225             if (value.GetByteSize() > reg_info->byte_size)
226                 value.SetType(reg_info);
227         }
228         return success;
229     }
230 
231     if (reg_info->encoding == eEncodingVector)
232     {
233         ByteOrder byte_order = GetByteOrder();
234 
235         if (byte_order != ByteOrder::eByteOrderInvalid)
236         {
237             if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
238                value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
239             if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
240                value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
241             if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
242                 value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
243             if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
244             {
245                 // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
246                 if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order))
247                     value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
248                 else
249                     return false;
250             }
251             return value.GetType() == RegisterValue::eTypeBytes;
252         }
253         return false;
254     }
255 
256     // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
257     assert (reg_info->byte_offset < sizeof(m_fpr));
258     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
259     switch (reg_info->byte_size)
260     {
261         case 2:
262             value.SetUInt16(*(uint16_t *)src);
263             return true;
264         case 4:
265             value.SetUInt32(*(uint32_t *)src);
266             return true;
267         case 8:
268             value.SetUInt64(*(uint64_t *)src);
269             return true;
270         default:
271             assert(false && "Unhandled data size.");
272             return false;
273     }
274 }
275 
276 bool
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & value)277 RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
278 {
279     const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
280 
281     if (IsGPR(reg))
282         return WriteRegister(reg, value);
283 
284     if (IsFPR(reg, GetFPRType()))
285     {
286         if (reg_info->encoding == eEncodingVector)
287         {
288             if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
289                ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, value.GetBytes(), value.GetByteSize());
290 
291             if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
292                ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, value.GetBytes(), value.GetByteSize());
293 
294             if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
295                ::memcpy (m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, value.GetBytes(), value.GetByteSize());
296 
297             if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
298             {
299                if (GetFPRType() != eXSAVE)
300                    return false; // the target processor does not support AVX
301 
302                // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
303                ::memcpy (m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, value.GetBytes(), value.GetByteSize());
304                if (false == CopyYMMtoXSTATE(reg, GetByteOrder()))
305                    return false;
306             }
307         }
308         else
309         {
310             // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
311             assert (reg_info->byte_offset < sizeof(m_fpr));
312             uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
313             switch (reg_info->byte_size)
314             {
315                 case 2:
316                     *(uint16_t *)dst = value.GetAsUInt16();
317                     break;
318                 case 4:
319                     *(uint32_t *)dst = value.GetAsUInt32();
320                     break;
321                 case 8:
322                     *(uint64_t *)dst = value.GetAsUInt64();
323                     break;
324                 default:
325                     assert(false && "Unhandled data size.");
326                     return false;
327             }
328         }
329 
330         if (WriteFPR())
331         {
332             if (IsAVX(reg))
333                 return CopyYMMtoXSTATE(reg, GetByteOrder());
334             return true;
335         }
336     }
337     return false;
338 }
339 
340 bool
ReadAllRegisterValues(DataBufferSP & data_sp)341 RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp)
342 {
343     bool success = false;
344     data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
345     if (data_sp && ReadGPR () && ReadFPR ())
346     {
347         uint8_t *dst = data_sp->GetBytes();
348         success = dst != 0;
349 
350         if (success)
351         {
352           ::memcpy (dst, &m_gpr_x86_64, GetGPRSize());
353           dst += GetGPRSize();
354           if (GetFPRType() == eFXSAVE)
355               ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
356         }
357 
358         if (GetFPRType() == eXSAVE)
359         {
360             ByteOrder byte_order = GetByteOrder();
361 
362             // Assemble the YMM register content from the register halves.
363             for (uint32_t reg  = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg)
364                 success = CopyXSTATEtoYMM(reg, byte_order);
365 
366             if (success)
367             {
368                 // Copy the extended register state including the assembled ymm registers.
369                 ::memcpy (dst, &m_fpr, sizeof(m_fpr));
370             }
371         }
372     }
373     return success;
374 }
375 
376 bool
WriteAllRegisterValues(const DataBufferSP & data_sp)377 RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp)
378 {
379     bool success = false;
380     if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
381     {
382         uint8_t *src = data_sp->GetBytes();
383         if (src)
384         {
385             ::memcpy (&m_gpr_x86_64, src, GetGPRSize());
386 
387             if (WriteGPR())
388             {
389                 src += GetGPRSize();
390                 if (GetFPRType() == eFXSAVE)
391                     ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
392                 if (GetFPRType() == eXSAVE)
393                     ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
394 
395                 success = WriteFPR();
396                 if (success)
397                 {
398                     if (GetFPRType() == eXSAVE)
399                     {
400                         ByteOrder byte_order = GetByteOrder();
401 
402                         // Parse the YMM register content from the register halves.
403                         for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg)
404                             success = CopyYMMtoXSTATE(reg, byte_order);
405                     }
406                 }
407             }
408         }
409     }
410     return success;
411 }
412 
413 uint32_t
SetHardwareWatchpoint(addr_t addr,size_t size,bool read,bool write)414 RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size,
415                                               bool read, bool write)
416 {
417     const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
418     uint32_t hw_index;
419 
420     for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
421     {
422         if (IsWatchpointVacant(hw_index))
423             return SetHardwareWatchpointWithIndex(addr, size,
424                                                   read, write,
425                                                   hw_index);
426     }
427 
428     return LLDB_INVALID_INDEX32;
429 }
430 
431 bool
ClearHardwareWatchpoint(uint32_t hw_index)432 RegisterContextPOSIXProcessMonitor_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
433 {
434     if (hw_index < NumSupportedHardwareWatchpoints())
435     {
436         RegisterValue current_dr7_bits;
437 
438         if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits))
439         {
440             uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
441 
442             if (WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits)))
443                 return true;
444         }
445     }
446 
447     return false;
448 }
449 
450 bool
HardwareSingleStep(bool enable)451 RegisterContextPOSIXProcessMonitor_x86_64::HardwareSingleStep(bool enable)
452 {
453     enum { TRACE_BIT = 0x100 };
454     uint64_t rflags;
455 
456     if ((rflags = ReadRegisterAsUnsigned(m_reg_info.gpr_flags, -1UL)) == -1UL)
457         return false;
458 
459     if (enable)
460     {
461         if (rflags & TRACE_BIT)
462             return true;
463 
464         rflags |= TRACE_BIT;
465     }
466     else
467     {
468         if (!(rflags & TRACE_BIT))
469             return false;
470 
471         rflags &= ~TRACE_BIT;
472     }
473 
474     return WriteRegisterFromUnsigned(m_reg_info.gpr_flags, rflags);
475 }
476 
477 bool
UpdateAfterBreakpoint()478 RegisterContextPOSIXProcessMonitor_x86_64::UpdateAfterBreakpoint()
479 {
480     // PC points one byte past the int3 responsible for the breakpoint.
481     lldb::addr_t pc;
482 
483     if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
484         return false;
485 
486     SetPC(pc - 1);
487     return true;
488 }
489 
490 unsigned
GetRegisterIndexFromOffset(unsigned offset)491 RegisterContextPOSIXProcessMonitor_x86_64::GetRegisterIndexFromOffset(unsigned offset)
492 {
493     unsigned reg;
494     for (reg = 0; reg < m_reg_info.num_registers; reg++)
495     {
496         if (GetRegisterInfo()[reg].byte_offset == offset)
497             break;
498     }
499     assert(reg < m_reg_info.num_registers && "Invalid register offset.");
500     return reg;
501 }
502 
503 bool
IsWatchpointHit(uint32_t hw_index)504 RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointHit(uint32_t hw_index)
505 {
506     bool is_hit = false;
507 
508     if (m_watchpoints_initialized == false)
509     {
510         // Reset the debug status and debug control registers
511         RegisterValue zero_bits = RegisterValue(uint64_t(0));
512         if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits))
513             assert(false && "Could not initialize watchpoint registers");
514         m_watchpoints_initialized = true;
515     }
516 
517     if (hw_index < NumSupportedHardwareWatchpoints())
518     {
519         RegisterValue value;
520 
521         if (ReadRegister(m_reg_info.first_dr + 6, value))
522         {
523             uint64_t val = value.GetAsUInt64();
524             is_hit = val & (1 << hw_index);
525         }
526     }
527 
528     return is_hit;
529 }
530 
531 bool
ClearWatchpointHits()532 RegisterContextPOSIXProcessMonitor_x86_64::ClearWatchpointHits()
533 {
534     return WriteRegister(m_reg_info.first_dr + 6, RegisterValue((uint64_t)0));
535 }
536 
537 addr_t
GetWatchpointAddress(uint32_t hw_index)538 RegisterContextPOSIXProcessMonitor_x86_64::GetWatchpointAddress(uint32_t hw_index)
539 {
540     addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
541 
542     if (hw_index < NumSupportedHardwareWatchpoints())
543     {
544         if (!IsWatchpointVacant(hw_index))
545         {
546             RegisterValue value;
547 
548             if (ReadRegister(m_reg_info.first_dr + hw_index, value))
549                 wp_monitor_addr = value.GetAsUInt64();
550         }
551     }
552 
553     return wp_monitor_addr;
554 }
555 
556 bool
IsWatchpointVacant(uint32_t hw_index)557 RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointVacant(uint32_t hw_index)
558 {
559     bool is_vacant = false;
560     RegisterValue value;
561 
562     assert(hw_index < NumSupportedHardwareWatchpoints());
563 
564     if (m_watchpoints_initialized == false)
565     {
566         // Reset the debug status and debug control registers
567         RegisterValue zero_bits = RegisterValue(uint64_t(0));
568         if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits))
569             assert(false && "Could not initialize watchpoint registers");
570         m_watchpoints_initialized = true;
571     }
572 
573     if (ReadRegister(m_reg_info.first_dr + 7, value))
574     {
575         uint64_t val = value.GetAsUInt64();
576         is_vacant = (val & (3 << 2*hw_index)) == 0;
577     }
578 
579     return is_vacant;
580 }
581 
582 bool
SetHardwareWatchpointWithIndex(addr_t addr,size_t size,bool read,bool write,uint32_t hw_index)583 RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
584                                                        bool read, bool write,
585                                                        uint32_t hw_index)
586 {
587     const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
588 
589     if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints)
590         return false;
591 
592     if (!(size == 1 || size == 2 || size == 4 || size == 8))
593         return false;
594 
595     if (read == false && write == false)
596         return false;
597 
598     if (!IsWatchpointVacant(hw_index))
599         return false;
600 
601     // Set both dr7 (debug control register) and dri (debug address register).
602 
603     // dr7{7-0} encodes the local/global enable bits:
604     //  global enable --. .-- local enable
605     //                  | |
606     //                  v v
607     //      dr0 -> bits{1-0}
608     //      dr1 -> bits{3-2}
609     //      dr2 -> bits{5-4}
610     //      dr3 -> bits{7-6}
611     //
612     // dr7{31-16} encodes the rw/len bits:
613     //  b_x+3, b_x+2, b_x+1, b_x
614     //      where bits{x+1, x} => rw
615     //            0b00: execute, 0b01: write, 0b11: read-or-write,
616     //            0b10: io read-or-write (unused)
617     //      and bits{x+3, x+2} => len
618     //            0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
619     //
620     //      dr0 -> bits{19-16}
621     //      dr1 -> bits{23-20}
622     //      dr2 -> bits{27-24}
623     //      dr3 -> bits{31-28}
624     if (hw_index < num_hw_watchpoints)
625     {
626         RegisterValue current_dr7_bits;
627 
628         if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits))
629         {
630             uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
631                                     (1 << (2*hw_index) |
632                                     size_and_rw_bits(size, read, write) <<
633                                     (16+4*hw_index));
634 
635             if (WriteRegister(m_reg_info.first_dr + hw_index, RegisterValue(addr)) &&
636                 WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits)))
637                 return true;
638         }
639     }
640 
641     return false;
642 }
643 
644 uint32_t
NumSupportedHardwareWatchpoints()645 RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints()
646 {
647     // Available debug address registers: dr0, dr1, dr2, dr3
648     return 4;
649 }
650 
651