vmi_utils/bpm/
breakpoint.rs

1use std::{
2    collections::{HashMap, HashSet},
3    fmt::Debug,
4    hash::Hash,
5};
6
7use vmi_core::{AddressContext, View};
8
9/// Metadata key for breakpoints.
10pub trait KeyType: Debug + Copy + Eq + Hash {}
11impl<T> KeyType for T where T: Debug + Copy + Eq + Hash {}
12
13/// Metadata tag for breakpoints.
14///
15/// Tags are used to associate metadata with breakpoints, allowing users to
16/// easily track breakpoints during debugging.
17pub trait TagType: Debug + Copy + Eq + Hash {}
18impl<T> TagType for T where T: Debug + Copy + Eq + Hash {}
19
20pub(super) type ActiveBreakpoints<Key, Tag> =
21    HashMap<(Key, AddressContext), HashSet<Breakpoint<Key, Tag>>>;
22pub(super) type PendingBreakpoints<Key, Tag> = HashSet<Breakpoint<Key, Tag>>;
23
24/// A breakpoint definition.
25///
26/// A breakpoint is defined by its address context, view, and optional metadata
27/// in the form of a key and tag.
28///
29/// If the breakpoint is global, it will be triggered regardless of the
30/// translation root, e.g., only [`AddressContext::va`] will be considered
31/// during breakpoint matching.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct Breakpoint<Key, Tag>
34where
35    Key: KeyType,
36    Tag: TagType,
37{
38    pub(super) ctx: AddressContext,
39    pub(super) view: View,
40    pub(super) global: bool,
41    pub(super) key: Key,
42    pub(super) tag: Tag,
43}
44
45impl<Key, Tag> Breakpoint<Key, Tag>
46where
47    Key: KeyType,
48    Tag: TagType,
49{
50    /// Returns the address context of the breakpoint.
51    ///
52    /// If the breakpoint is global, only [`AddressContext::va`] will be
53    /// considered during breakpoint matching.
54    pub fn ctx(&self) -> AddressContext {
55        self.ctx
56    }
57
58    /// Returns the view in which the breakpoint is defined.
59    pub fn view(&self) -> View {
60        self.view
61    }
62
63    /// Returns whether the breakpoint is global.
64    ///
65    /// A global breakpoint will be triggered regardless of the translation
66    /// root, e.g., only [`AddressContext::va`] will be considered during
67    /// breakpoint matching.
68    pub fn global(&self) -> bool {
69        self.global
70    }
71
72    /// Returns the key of the breakpoint.
73    pub fn key(&self) -> Key {
74        self.key
75    }
76
77    /// Returns the tag of the breakpoint.
78    pub fn tag(&self) -> Tag {
79        self.tag
80    }
81}
82
83/// A builder for constructing breakpoint definitions.
84///
85/// This builder provides a fluent interface for creating [`Breakpoint`]
86/// instances, allowing for flexible configuration of breakpoint properties
87/// and metadata.
88#[derive(Debug)]
89pub struct BreakpointBuilder {
90    ctx: AddressContext,
91    view: View,
92    global: bool,
93}
94
95#[doc(hidden)]
96#[derive(Debug)]
97pub struct BreakpointBuilderWithKey<Key>
98where
99    Key: KeyType,
100{
101    ctx: AddressContext,
102    view: View,
103    global: bool,
104    key: Key,
105}
106
107#[doc(hidden)]
108#[derive(Debug)]
109pub struct BreakpointBuilderWithTag<Tag>
110where
111    Tag: TagType,
112{
113    ctx: AddressContext,
114    view: View,
115    global: bool,
116    tag: Tag,
117}
118
119#[doc(hidden)]
120#[derive(Debug)]
121pub struct BreakpointBuilderWithKeyTag<Key, Tag>
122where
123    Key: KeyType,
124    Tag: TagType,
125{
126    ctx: AddressContext,
127    view: View,
128    global: bool,
129    key: Key,
130    tag: Tag,
131}
132
133impl Breakpoint<(), ()> {
134    /// Creates a new breakpoint builder.
135    #[expect(clippy::new_ret_no_self)]
136    pub fn new(ctx: impl Into<AddressContext>, view: View) -> BreakpointBuilder {
137        BreakpointBuilder::new(ctx, view)
138    }
139}
140
141impl BreakpointBuilder {
142    /// Creates a new breakpoint builder.
143    pub fn new(ctx: impl Into<AddressContext>, view: View) -> Self {
144        Self {
145            ctx: ctx.into(),
146            view,
147            global: false,
148        }
149    }
150
151    /// Sets the breakpoint as global.
152    ///
153    /// A global breakpoint will be triggered regardless of the translation
154    /// root, e.g., only [`AddressContext::va`] will be considered during
155    /// breakpoint matching.
156    pub fn global(self) -> Self {
157        Self {
158            global: true,
159            ..self
160        }
161    }
162
163    /// Sets the key of the breakpoint.
164    pub fn with_key<Key>(self, key: Key) -> BreakpointBuilderWithKey<Key>
165    where
166        Key: KeyType,
167    {
168        BreakpointBuilderWithKey {
169            ctx: self.ctx,
170            view: self.view,
171            global: self.global,
172            key,
173        }
174    }
175
176    /// Sets the tag of the breakpoint.
177    pub fn with_tag<Tag>(self, tag: Tag) -> BreakpointBuilderWithTag<Tag>
178    where
179        Tag: TagType,
180    {
181        BreakpointBuilderWithTag {
182            ctx: self.ctx,
183            view: self.view,
184            global: self.global,
185            tag,
186        }
187    }
188}
189
190impl<Key> BreakpointBuilderWithKey<Key>
191where
192    Key: KeyType,
193{
194    /// Sets the tag of the breakpoint.
195    pub fn with_tag<Tag>(self, tag: Tag) -> BreakpointBuilderWithKeyTag<Key, Tag>
196    where
197        Tag: TagType,
198    {
199        BreakpointBuilderWithKeyTag {
200            ctx: self.ctx,
201            view: self.view,
202            global: self.global,
203            key: self.key,
204            tag,
205        }
206    }
207}
208
209impl<Tag> BreakpointBuilderWithTag<Tag>
210where
211    Tag: TagType,
212{
213    /// Sets the key of the breakpoint.
214    pub fn with_key<Key>(self, key: Key) -> BreakpointBuilderWithKeyTag<Key, Tag>
215    where
216        Key: KeyType,
217    {
218        BreakpointBuilderWithKeyTag {
219            ctx: self.ctx,
220            view: self.view,
221            global: self.global,
222            key,
223            tag: self.tag,
224        }
225    }
226}
227
228impl<Key, Tag> From<BreakpointBuilder> for Breakpoint<Key, Tag>
229where
230    Key: KeyType + Default,
231    Tag: TagType + Default,
232{
233    fn from(value: BreakpointBuilder) -> Self {
234        Self {
235            ctx: value.ctx,
236            view: value.view,
237            global: value.global,
238            key: Default::default(),
239            tag: Default::default(),
240        }
241    }
242}
243
244impl<Key, Tag> From<BreakpointBuilderWithKey<Key>> for Breakpoint<Key, Tag>
245where
246    Key: KeyType,
247    Tag: TagType + Default,
248{
249    fn from(value: BreakpointBuilderWithKey<Key>) -> Self {
250        Self {
251            ctx: value.ctx,
252            view: value.view,
253            global: value.global,
254            key: value.key,
255            tag: Default::default(),
256        }
257    }
258}
259
260impl<Key, Tag> From<BreakpointBuilderWithTag<Tag>> for Breakpoint<Key, Tag>
261where
262    Key: KeyType + Default,
263    Tag: TagType,
264{
265    fn from(value: BreakpointBuilderWithTag<Tag>) -> Self {
266        Self {
267            ctx: value.ctx,
268            view: value.view,
269            global: value.global,
270            key: Default::default(),
271            tag: value.tag,
272        }
273    }
274}
275
276impl<Key, Tag> From<BreakpointBuilderWithKeyTag<Key, Tag>> for Breakpoint<Key, Tag>
277where
278    Key: KeyType,
279    Tag: TagType,
280{
281    fn from(value: BreakpointBuilderWithKeyTag<Key, Tag>) -> Self {
282        Self {
283            ctx: value.ctx,
284            view: value.view,
285            global: value.global,
286            key: value.key,
287            tag: value.tag,
288        }
289    }
290}