@@ -2,52 +2,138 @@ use std::{
2
2
borrow:: Borrow ,
3
3
fmt:: { Display , Formatter } ,
4
4
hash:: { Hash , Hasher } ,
5
+ rc:: Rc ,
6
+ sync:: {
7
+ atomic:: { AtomicU64 , Ordering } ,
8
+ OnceLock ,
9
+ } ,
5
10
} ;
6
11
12
+ use libafl:: state:: { HasExecutions , State } ;
7
13
use libafl_qemu_sys:: GuestAddr ;
8
14
9
- use crate :: { command:: Command , Qemu } ;
15
+ use crate :: {
16
+ command:: { CommandManager , IsCommand } ,
17
+ EmulatorExitHandler , Qemu , QemuHelperTuple ,
18
+ } ;
19
+
20
+ #[ repr( transparent) ]
21
+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
22
+ pub struct BreakpointId ( u64 ) ;
10
23
11
24
// TODO: distinguish breakpoints with IDs instead of addresses to avoid collisions.
12
- #[ derive( Debug , Clone ) ]
13
- pub struct Breakpoint {
25
+ #[ derive( Debug ) ]
26
+ pub struct Breakpoint < CM , E , QT , S >
27
+ where
28
+ CM : CommandManager < E , QT , S > ,
29
+ E : EmulatorExitHandler < QT , S > ,
30
+ QT : QemuHelperTuple < S > ,
31
+ S : State + HasExecutions ,
32
+ {
33
+ id : BreakpointId ,
14
34
addr : GuestAddr ,
15
- cmd : Option < Command > ,
35
+ cmd : Option < Rc < dyn IsCommand < CM , E , QT , S > > > ,
16
36
disable_on_trigger : bool ,
17
37
enabled : bool ,
18
38
}
19
39
20
- impl Hash for Breakpoint {
40
+ impl BreakpointId {
41
+ pub fn new ( ) -> Self {
42
+ static mut BREAKPOINT_ID_COUNTER : OnceLock < AtomicU64 > = OnceLock :: new ( ) ;
43
+
44
+ let counter = unsafe { BREAKPOINT_ID_COUNTER . get_or_init ( || AtomicU64 :: new ( 0 ) ) } ;
45
+
46
+ BreakpointId ( counter. fetch_add ( 1 , Ordering :: SeqCst ) )
47
+ }
48
+ }
49
+
50
+ impl Default for BreakpointId {
51
+ fn default ( ) -> Self {
52
+ Self :: new ( )
53
+ }
54
+ }
55
+
56
+ impl < CM , E , QT , S > Hash for Breakpoint < CM , E , QT , S >
57
+ where
58
+ CM : CommandManager < E , QT , S > ,
59
+ E : EmulatorExitHandler < QT , S > ,
60
+ QT : QemuHelperTuple < S > ,
61
+ S : State + HasExecutions ,
62
+ {
21
63
fn hash < H : Hasher > ( & self , state : & mut H ) {
22
- self . addr . hash ( state) ;
64
+ self . id . hash ( state) ;
23
65
}
24
66
}
25
67
26
- impl PartialEq for Breakpoint {
68
+ impl < CM , E , QT , S > PartialEq for Breakpoint < CM , E , QT , S >
69
+ where
70
+ CM : CommandManager < E , QT , S > ,
71
+ E : EmulatorExitHandler < QT , S > ,
72
+ QT : QemuHelperTuple < S > ,
73
+ S : State + HasExecutions ,
74
+ {
27
75
fn eq ( & self , other : & Self ) -> bool {
28
- self . addr == other. addr
76
+ self . id == other. id
29
77
}
30
78
}
31
79
32
- impl Eq for Breakpoint { }
80
+ impl < CM , E , QT , S > Eq for Breakpoint < CM , E , QT , S >
81
+ where
82
+ CM : CommandManager < E , QT , S > ,
83
+ E : EmulatorExitHandler < QT , S > ,
84
+ QT : QemuHelperTuple < S > ,
85
+ S : State + HasExecutions ,
86
+ {
87
+ }
33
88
34
- impl Display for Breakpoint {
89
+ impl < CM , E , QT , S > Display for Breakpoint < CM , E , QT , S >
90
+ where
91
+ CM : CommandManager < E , QT , S > ,
92
+ E : EmulatorExitHandler < QT , S > ,
93
+ QT : QemuHelperTuple < S > ,
94
+ S : State + HasExecutions ,
95
+ {
35
96
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
36
97
write ! ( f, "Breakpoint @vaddr 0x{:x}" , self . addr)
37
98
}
38
99
}
39
100
40
- impl Borrow < GuestAddr > for Breakpoint {
101
+ impl < CM , E , QT , S > Borrow < BreakpointId > for Breakpoint < CM , E , QT , S >
102
+ where
103
+ CM : CommandManager < E , QT , S > ,
104
+ E : EmulatorExitHandler < QT , S > ,
105
+ QT : QemuHelperTuple < S > ,
106
+ S : State + HasExecutions ,
107
+ {
108
+ fn borrow ( & self ) -> & BreakpointId {
109
+ & self . id
110
+ }
111
+ }
112
+
113
+ impl < CM , E , QT , S > Borrow < GuestAddr > for Breakpoint < CM , E , QT , S >
114
+ where
115
+ CM : CommandManager < E , QT , S > ,
116
+ E : EmulatorExitHandler < QT , S > ,
117
+ QT : QemuHelperTuple < S > ,
118
+ S : State + HasExecutions ,
119
+ {
41
120
fn borrow ( & self ) -> & GuestAddr {
42
121
& self . addr
43
122
}
44
123
}
45
124
46
- impl Breakpoint {
125
+ impl < CM , E , QT , S > Breakpoint < CM , E , QT , S >
126
+ where
127
+ CM : CommandManager < E , QT , S > ,
128
+ E : EmulatorExitHandler < QT , S > ,
129
+ QT : QemuHelperTuple < S > ,
130
+ S : State + HasExecutions ,
131
+ {
47
132
// Emu will return with the breakpoint as exit reason.
48
133
#[ must_use]
49
134
pub fn without_command ( addr : GuestAddr , disable_on_trigger : bool ) -> Self {
50
135
Self {
136
+ id : BreakpointId :: new ( ) ,
51
137
addr,
52
138
cmd : None ,
53
139
disable_on_trigger,
@@ -57,15 +143,25 @@ impl Breakpoint {
57
143
58
144
// Emu will execute the command when it meets the breakpoint.
59
145
#[ must_use]
60
- pub fn with_command ( addr : GuestAddr , cmd : Command , disable_on_trigger : bool ) -> Self {
146
+ pub fn with_command < C : IsCommand < CM , E , QT , S > + ' static > (
147
+ addr : GuestAddr ,
148
+ cmd : C ,
149
+ disable_on_trigger : bool ,
150
+ ) -> Self {
61
151
Self {
152
+ id : BreakpointId :: new ( ) ,
62
153
addr,
63
- cmd : Some ( cmd) ,
154
+ cmd : Some ( Rc :: new ( cmd) ) ,
64
155
disable_on_trigger,
65
156
enabled : false ,
66
157
}
67
158
}
68
159
160
+ #[ must_use]
161
+ pub fn id ( & self ) -> BreakpointId {
162
+ self . id
163
+ }
164
+
69
165
#[ must_use]
70
166
pub fn addr ( & self ) -> GuestAddr {
71
167
self . addr
@@ -85,11 +181,11 @@ impl Breakpoint {
85
181
}
86
182
}
87
183
88
- pub fn trigger ( & mut self , qemu : & Qemu ) -> Option < & Command > {
184
+ pub fn trigger ( & mut self , qemu : & Qemu ) -> Option < Rc < dyn IsCommand < CM , E , QT , S > > > {
89
185
if self . disable_on_trigger {
90
186
self . disable ( qemu) ;
91
187
}
92
188
93
- self . cmd . as_ref ( )
189
+ self . cmd . clone ( )
94
190
}
95
191
}
0 commit comments