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