1#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
4use core::arch::asm;
5use core::ops::Range;
6
7use bit_field::BitField;
8use bitflags::bitflags;
9
10pub trait DebugAddressRegister {
14 const NUM: DebugAddressRegisterNumber;
16
17 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
19 fn read() -> u64;
20
21 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
23 fn write(addr: u64);
24}
25
26macro_rules! debug_address_register {
27 ($Dr:ident, $name:literal) => {
28 #[derive(Debug)]
32 pub struct $Dr;
33
34 impl DebugAddressRegister for $Dr {
35 const NUM: DebugAddressRegisterNumber = DebugAddressRegisterNumber::$Dr;
36
37 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
38 #[inline]
39 fn read() -> u64 {
40 let addr;
41 unsafe {
42 asm!(concat!("mov {}, ", $name), out(reg) addr, options(nomem, nostack, preserves_flags));
43 }
44 addr
45 }
46
47 #[cfg(all(feature = "instructions", target_arch = "x86_64"))]
48 #[inline]
49 fn write(addr: u64) {
50 unsafe {
51 asm!(concat!("mov ", $name, ", {}"), in(reg) addr, options(nomem, nostack, preserves_flags));
52 }
53 }
54 }
55 };
56}
57
58debug_address_register!(Dr0, "dr0");
59debug_address_register!(Dr1, "dr1");
60debug_address_register!(Dr2, "dr2");
61debug_address_register!(Dr3, "dr3");
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub enum DebugAddressRegisterNumber {
68 Dr0,
70
71 Dr1,
73
74 Dr2,
76
77 Dr3,
79}
80
81impl DebugAddressRegisterNumber {
82 pub const fn new(n: u8) -> Option<Self> {
84 match n {
85 0 => Some(Self::Dr0),
86 1 => Some(Self::Dr1),
87 2 => Some(Self::Dr2),
88 3 => Some(Self::Dr3),
89 _ => None,
90 }
91 }
92
93 pub const fn get(self) -> u8 {
95 match self {
96 Self::Dr0 => 0,
97 Self::Dr1 => 1,
98 Self::Dr2 => 2,
99 Self::Dr3 => 3,
100 }
101 }
102}
103
104#[derive(Debug)]
108pub struct Dr6;
109
110bitflags! {
111 #[repr(transparent)]
113 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
114 pub struct Dr6Flags: u64 {
115 const TRAP0 = 1;
117
118 const TRAP1 = 1 << 1;
120
121 const TRAP2 = 1 << 2;
123
124 const TRAP3 = 1 << 3;
126
127 const TRAP = Self::TRAP0.bits() | Self::TRAP1.bits() | Self::TRAP2.bits() | Self::TRAP3.bits();
129
130 const ACCESS_DETECTED = 1 << 13;
134
135 const STEP = 1 << 14;
139
140 const SWITCH = 1 << 15;
144
145 const RTM = 1 << 16;
150 }
151}
152
153impl Dr6Flags {
154 pub fn trap(n: DebugAddressRegisterNumber) -> Self {
156 match n {
157 DebugAddressRegisterNumber::Dr0 => Self::TRAP0,
158 DebugAddressRegisterNumber::Dr1 => Self::TRAP1,
159 DebugAddressRegisterNumber::Dr2 => Self::TRAP2,
160 DebugAddressRegisterNumber::Dr3 => Self::TRAP3,
161 }
162 }
163}
164
165bitflags! {
166 #[repr(transparent)]
168 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
169 pub struct Dr7Flags: u64 {
170 const LOCAL_BREAKPOINT_0_ENABLE = 1;
172
173 const LOCAL_BREAKPOINT_1_ENABLE = 1 << 2;
175
176 const LOCAL_BREAKPOINT_2_ENABLE = 1 << 4;
178
179 const LOCAL_BREAKPOINT_3_ENABLE = 1 << 6;
181
182 const GLOBAL_BREAKPOINT_0_ENABLE = 1 << 1;
184
185 const GLOBAL_BREAKPOINT_1_ENABLE = 1 << 3;
187
188 const GLOBAL_BREAKPOINT_2_ENABLE = 1 << 5;
190
191 const GLOBAL_BREAKPOINT_3_ENABLE = 1 << 7;
193
194 const LOCAL_EXACT_BREAKPOINT_ENABLE = 1 << 8;
198
199 const GLOBAL_EXACT_BREAKPOINT_ENABLE = 1 << 9;
203
204 const RESTRICTED_TRANSACTIONAL_MEMORY = 1 << 11;
208
209 const GENERAL_DETECT_ENABLE = 1 << 13;
213 }
214}
215
216impl Dr7Flags {
217 pub fn local_breakpoint_enable(n: DebugAddressRegisterNumber) -> Self {
219 match n {
220 DebugAddressRegisterNumber::Dr0 => Self::LOCAL_BREAKPOINT_0_ENABLE,
221 DebugAddressRegisterNumber::Dr1 => Self::LOCAL_BREAKPOINT_1_ENABLE,
222 DebugAddressRegisterNumber::Dr2 => Self::LOCAL_BREAKPOINT_2_ENABLE,
223 DebugAddressRegisterNumber::Dr3 => Self::LOCAL_BREAKPOINT_3_ENABLE,
224 }
225 }
226
227 pub fn global_breakpoint_enable(n: DebugAddressRegisterNumber) -> Self {
229 match n {
230 DebugAddressRegisterNumber::Dr0 => Self::GLOBAL_BREAKPOINT_0_ENABLE,
231 DebugAddressRegisterNumber::Dr1 => Self::GLOBAL_BREAKPOINT_1_ENABLE,
232 DebugAddressRegisterNumber::Dr2 => Self::GLOBAL_BREAKPOINT_2_ENABLE,
233 DebugAddressRegisterNumber::Dr3 => Self::GLOBAL_BREAKPOINT_3_ENABLE,
234 }
235 }
236}
237
238#[derive(Clone, Copy, Debug, PartialEq, Eq)]
240#[repr(u8)]
241pub enum BreakpointCondition {
242 InstructionExecution = 0b00,
244
245 DataWrites = 0b01,
247
248 IoReadsWrites = 0b10,
250
251 DataReadsWrites = 0b11,
253}
254
255impl BreakpointCondition {
256 pub const fn from_bits(bits: u64) -> Option<Self> {
258 match bits {
259 0b00 => Some(Self::InstructionExecution),
260 0b01 => Some(Self::DataWrites),
261 0b10 => Some(Self::IoReadsWrites),
262 0b11 => Some(Self::DataReadsWrites),
263 _ => None,
264 }
265 }
266
267 const fn bit_range(n: DebugAddressRegisterNumber) -> Range<usize> {
268 let lsb = (16 + 4 * n.get()) as usize;
269 lsb..lsb + 2
270 }
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Eq)]
275#[repr(u8)]
276pub enum BreakpointSize {
277 Length1B = 0b00,
279
280 Length2B = 0b01,
282
283 Length8B = 0b10,
285
286 Length4B = 0b11,
288}
289
290impl BreakpointSize {
291 pub const fn new(size: usize) -> Option<Self> {
293 match size {
294 1 => Some(Self::Length1B),
295 2 => Some(Self::Length2B),
296 8 => Some(Self::Length8B),
297 4 => Some(Self::Length4B),
298 _ => None,
299 }
300 }
301
302 pub const fn from_bits(bits: u64) -> Option<Self> {
304 match bits {
305 0b00 => Some(Self::Length1B),
306 0b01 => Some(Self::Length2B),
307 0b10 => Some(Self::Length8B),
308 0b11 => Some(Self::Length4B),
309 _ => None,
310 }
311 }
312
313 const fn bit_range(n: DebugAddressRegisterNumber) -> Range<usize> {
314 let lsb = (18 + 4 * n.get()) as usize;
315 lsb..lsb + 2
316 }
317}
318
319#[derive(Clone, Copy, Debug, PartialEq, Eq)]
323#[repr(transparent)]
324pub struct Dr7Value {
325 bits: u64,
326}
327
328impl From<Dr7Flags> for Dr7Value {
329 fn from(dr7_flags: Dr7Flags) -> Self {
330 Self::from_bits_truncate(dr7_flags.bits())
331 }
332}
333
334impl Dr7Value {
335 const fn valid_bits() -> u64 {
336 let field_valid_bits = (1 << 32) - (1 << 16);
337 let flag_valid_bits = Dr7Flags::all().bits();
338 field_valid_bits | flag_valid_bits
339 }
340
341 #[inline]
343 pub const fn from_bits(bits: u64) -> Option<Self> {
344 if (bits & !Self::valid_bits()) == 0 {
345 Some(Self { bits })
346 } else {
347 None
348 }
349 }
350
351 #[inline]
353 pub const fn from_bits_truncate(bits: u64) -> Self {
354 Self {
355 bits: bits & Self::valid_bits(),
356 }
357 }
358
359 #[inline]
365 pub const unsafe fn from_bits_unchecked(bits: u64) -> Self {
366 Self { bits }
367 }
368
369 #[inline]
371 pub const fn bits(&self) -> u64 {
372 self.bits
373 }
374
375 #[inline]
377 pub const fn flags(self) -> Dr7Flags {
378 Dr7Flags::from_bits_truncate(self.bits)
379 }
380
381 #[inline]
383 pub fn insert_flags(&mut self, flags: Dr7Flags) {
384 self.bits |= flags.bits();
385 }
386
387 #[inline]
389 pub fn remove_flags(&mut self, flags: Dr7Flags) {
390 self.bits &= !flags.bits();
391 }
392
393 #[inline]
395 pub fn toggle_flags(&mut self, flags: Dr7Flags) {
396 self.bits ^= flags.bits();
397 }
398
399 #[inline]
401 pub fn set_flags(&mut self, flags: Dr7Flags, value: bool) {
402 if value {
403 self.insert_flags(flags);
404 } else {
405 self.remove_flags(flags);
406 }
407 }
408
409 pub fn condition(&self, n: DebugAddressRegisterNumber) -> BreakpointCondition {
411 let condition = self.bits.get_bits(BreakpointCondition::bit_range(n));
412 BreakpointCondition::from_bits(condition).expect("condition should be always valid")
413 }
414
415 pub fn set_condition(&mut self, n: DebugAddressRegisterNumber, condition: BreakpointCondition) {
417 self.bits
418 .set_bits(BreakpointCondition::bit_range(n), condition as u64);
419 }
420
421 pub fn size(&self, n: DebugAddressRegisterNumber) -> BreakpointSize {
423 let size = self.bits.get_bits(BreakpointSize::bit_range(n));
424 BreakpointSize::from_bits(size).expect("condition should be always valid")
425 }
426
427 pub fn set_size(&mut self, n: DebugAddressRegisterNumber, size: BreakpointSize) {
429 self.bits
430 .set_bits(BreakpointSize::bit_range(n), size as u64);
431 }
432}
433
434#[derive(Debug)]
438pub struct Dr7;
439
440#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
441mod x86_64 {
442 use super::*;
443
444 impl Dr6 {
445 #[inline]
447 pub fn read() -> Dr6Flags {
448 Dr6Flags::from_bits_truncate(Self::read_raw())
449 }
450
451 #[inline]
453 pub fn read_raw() -> u64 {
454 let value;
455
456 unsafe {
457 asm!("mov {}, dr6", out(reg) value, options(nomem, nostack, preserves_flags));
458 }
459
460 value
461 }
462 }
463
464 impl Dr7 {
465 #[inline]
467 pub fn read() -> Dr7Value {
468 Dr7Value::from_bits_truncate(Self::read_raw())
469 }
470
471 #[inline]
473 pub fn read_raw() -> u64 {
474 let value;
475
476 unsafe {
477 asm!("mov {}, dr7", out(reg) value, options(nomem, nostack, preserves_flags));
478 }
479
480 value
481 }
482
483 #[inline]
487 pub fn write(value: Dr7Value) {
488 let old_value = Self::read_raw();
489 let reserved = old_value & !Dr7Value::valid_bits();
490 let new_value = reserved | value.bits();
491
492 Self::write_raw(new_value)
493 }
494
495 #[inline]
497 pub fn write_raw(value: u64) {
498 unsafe {
499 asm!("mov dr7, {}", in(reg) value, options(nomem, nostack, preserves_flags));
500 }
501 }
502 }
503}