1+ use crate :: error:: {
2+ PtError , deref_ptresult,
3+ ensure_ptok, extract_pterr,
4+ deref_ptresult_mut, PtErrorCode
5+ } ;
6+ use crate :: config:: Config ;
7+ use crate :: Status ;
8+ use crate :: event:: Event ;
9+
10+ use std:: convert:: TryFrom ;
11+ use std:: marker:: PhantomData ;
12+ use std:: mem;
13+
14+ use num_enum:: TryFromPrimitive ;
15+ use libipt_sys:: {
16+ pt_qry_alloc_decoder,
17+ pt_query_decoder,
18+ pt_qry_cond_branch,
19+ pt_qry_core_bus_ratio,
20+ pt_qry_event,
21+ pt_event,
22+ pt_qry_free_decoder,
23+ pt_qry_get_config,
24+ pt_qry_get_offset,
25+ pt_qry_get_sync_offset,
26+ pt_qry_indirect_branch,
27+ pt_qry_sync_backward,
28+ pt_qry_sync_forward,
29+ pt_qry_sync_set,
30+ pt_qry_time
31+ } ;
32+
33+ #[ cfg( test) ]
34+ mod test {
35+ use super :: * ;
36+ use crate :: config:: ConfigBuilder ;
37+
38+ #[ test]
39+ fn test_qrydec_alloc ( ) {
40+ QueryDecoder :: new ( & ConfigBuilder :: new ( & mut [ 0 ; 0 ] ) . finish ( ) ) . unwrap ( ) ;
41+ }
42+
43+ #[ test ]
44+ fn test_qrydec_props ( ) {
45+ // this just checks memory safety for property access
46+ // usage can be found in the integration tests
47+ let mut b = QueryDecoder :: new (
48+ & ConfigBuilder :: new ( & mut [ 0 ; 0 ] ) . finish ( ) ) . unwrap ( ) ;
49+
50+ assert ! ( b. cond_branch( ) . is_err( ) ) ;
51+ assert ! ( b. indirect_branch( ) . is_err( ) ) ;
52+ assert ! ( b. event( ) . is_err( ) ) ;
53+ assert ! ( b. core_bus_ratio( ) . is_err( ) ) ;
54+ assert ! ( b. event( ) . is_err( ) ) ;
55+ assert ! ( b. config( ) . is_ok( ) ) ;
56+ assert ! ( b. offset( ) . is_err( ) ) ;
57+ assert ! ( b. sync_offset( ) . is_err( ) ) ;
58+ assert ! ( b. sync_backward( ) . is_err( ) ) ;
59+ assert ! ( b. sync_forward( ) . is_err( ) ) ;
60+ assert ! ( b. time( ) . is_err( ) ) ;
61+ }
62+ }
63+
64+ #[ derive( Clone , Copy , TryFromPrimitive ) ]
65+ #[ repr( i32 ) ]
66+ pub enum CondBranch {
67+ Taken = 1 ,
68+ NotTaken = 0
69+ }
70+
71+ /// The decoder will work on the buffer defined in the config,
72+ /// it shall contain raw trace data and remain valid for the lifetime of the decoder.
73+ /// The decoder needs to be synchronized before it can be used.
74+ pub struct QueryDecoder < ' a , T > ( & ' a mut pt_query_decoder , PhantomData < T > ) ;
75+ impl < ' a , T > QueryDecoder < ' a , T > {
76+ /// Allocate an Intel PT query decoder.
77+ ///
78+ /// The decoder will work on the buffer defined in @config,
79+ /// it shall contain raw trace data and remain valid for the lifetime of the decoder.
80+ /// The decoder needs to be synchronized before it can be used.
81+ pub fn new ( cfg : & Config < T > ) -> Result < Self , PtError > {
82+ deref_ptresult_mut ( unsafe { pt_qry_alloc_decoder ( cfg. 0 . as_ref ( ) ) } )
83+ . map ( |d| QueryDecoder :: < T > ( d, PhantomData ) )
84+ }
85+
86+ /// Query whether the next unconditional branch has been taken.
87+ ///
88+ /// On success, provides Taken or NotTaken along with StatusFlags
89+ /// for the next conditional branch and updates decoder.
90+ /// Returns BadOpc if an unknown packet is encountered.
91+ /// Returns BadPacket if an unknown packet payload is encountered.
92+ /// Returns BadQuery if no conditional branch is found.
93+ /// Returns Eos if decoding reached the end of the Intel PT buffer.
94+ /// Returns Nosync if decoder is out of sync.
95+ pub fn cond_branch ( & mut self ) -> Result < ( CondBranch , Status ) , PtError > {
96+ let mut taken: i32 = 0 ;
97+ extract_pterr ( unsafe { pt_qry_cond_branch ( self . 0 , & mut taken) } )
98+ . map ( |s| (
99+ CondBranch :: try_from ( taken) . unwrap ( ) ,
100+ Status :: from_bits ( s) . unwrap ( ) ) )
101+ }
102+
103+ /// Return the current core bus ratio.
104+ ///
105+ /// On success, provides the current core:bus ratio
106+ /// The ratio is defined as core cycles per bus clock cycle.
107+ /// Returns NoCbr if there has not been a CBR packet.
108+ pub fn core_bus_ratio ( & mut self ) -> Result < u32 , PtError > {
109+ let mut cbr: u32 = 0 ;
110+ ensure_ptok ( unsafe { pt_qry_core_bus_ratio ( self . 0 , & mut cbr) } )
111+ . map ( |_| cbr)
112+ }
113+
114+ /// Query the next pending event.
115+ ///
116+ /// On success, provides the next event along with its status and updates the decoder.
117+ /// Returns BadOpc if an unknown packet is encountered.
118+ /// Returns BadPacket if an unknown packet payload is encountered.
119+ /// Returns BadQuery if no event is found.
120+ /// Returns Eos if decoding reached the end of the Intel PT buffer.
121+ /// Returns Nosync if decoder is out of sync.
122+ pub fn event ( & mut self ) -> Result < ( Event , Status ) , PtError > {
123+ let mut evt: pt_event = unsafe { mem:: zeroed ( ) } ;
124+ extract_pterr ( unsafe {
125+ pt_qry_event ( self . 0 ,
126+ & mut evt,
127+ mem:: size_of :: < pt_event > ( ) )
128+ } ) . map ( |s| ( Event ( evt) , Status :: from_bits ( s) . unwrap ( ) ) )
129+ }
130+
131+ pub fn config ( & self ) -> Result < Config < T > , PtError > {
132+ deref_ptresult ( unsafe { pt_qry_get_config ( self . 0 ) } )
133+ . map ( Config :: from)
134+ }
135+
136+ /// Get the current decoder position.
137+ ///
138+ /// Returns Nosync if decoder is out of sync.
139+ pub fn offset ( & self ) -> Result < u64 , PtError > {
140+ let mut off: u64 = 0 ;
141+ ensure_ptok ( unsafe { pt_qry_get_offset ( self . 0 , & mut off) } )
142+ . map ( |_| off)
143+ }
144+
145+ /// Get the position of the last synchronization point.
146+ ///
147+ /// This is useful for splitting a trace stream for parallel decoding.
148+ /// Returns Nosync if decoder is out of sync.
149+ pub fn sync_offset ( & self ) -> Result < u64 , PtError > {
150+ let mut off: u64 = 0 ;
151+ ensure_ptok ( unsafe { pt_qry_get_sync_offset ( self . 0 , & mut off) } )
152+ . map ( |_| off)
153+ }
154+
155+ /// Get the next indirect branch destination.
156+ ///
157+ /// On success, provides the linear destination address
158+ /// of the next indirect branch along with the status
159+ /// and updates the decoder.
160+ /// Returns BadOpc if an unknown packet is encountered.
161+ /// Returns BadPacket if an unknown packet payload is encountered.
162+ /// Returns BadQuery if no indirect branch is found.
163+ /// Returns Eos if decoding reached the end of the Intel PT buffer.
164+ /// Returns Nosync if decoder is out of sync.
165+ pub fn indirect_branch ( & mut self ) -> Result < u64 , PtError > {
166+ let mut ip: u64 = 0 ;
167+ ensure_ptok ( unsafe { pt_qry_indirect_branch ( self . 0 , & mut ip) } )
168+ . map ( |_| ip)
169+ }
170+
171+ /// Synchronize an Intel PT query decoder.
172+ ///
173+ /// Search for the next synchronization point in forward or backward direction.
174+ /// If decoder has not been synchronized, yet, the search is started at the beginning
175+ /// of the trace buffer in case of forward synchronization
176+ /// and at the end of the trace buffer in case of backward synchronization.
177+ /// Returns the last ip along with a non-negative Status on success
178+ /// Returns BadOpc if an unknown packet is encountered.
179+ /// Returns BadPacket if an unknown packet payload is encountered.
180+ /// Returns Eos if no further synchronization point is found.
181+ pub fn sync_backward ( & mut self ) -> Result < ( u64 , Status ) , PtError > {
182+ let mut ip: u64 = 0 ;
183+ extract_pterr ( unsafe { pt_qry_sync_backward ( self . 0 , & mut ip) } )
184+ . map ( |s| ( ip, Status :: from_bits ( s) . unwrap ( ) ) )
185+ }
186+
187+ /// Synchronize an Intel PT query decoder.
188+ ///
189+ /// Search for the next synchronization point in forward or backward direction.
190+ /// If decoder has not been synchronized, yet, the search is started at the beginning
191+ /// of the trace buffer in case of forward synchronization
192+ /// and at the end of the trace buffer in case of backward synchronization.
193+ /// Returns the last ip along with a non-negative Status on success
194+ /// Returns BadOpc if an unknown packet is encountered.
195+ /// Returns BadPacket if an unknown packet payload is encountered.
196+ /// Returns Eos if no further synchronization point is found.
197+ pub fn sync_forward ( & mut self ) -> Result < ( u64 , Status ) , PtError > {
198+ let mut ip: u64 = 0 ;
199+ extract_pterr ( unsafe { pt_qry_sync_forward ( self . 0 , & mut ip) } )
200+ . map ( |s| ( ip, Status :: from_bits ( s) . unwrap ( ) ) )
201+ }
202+
203+ /// Manually synchronize an Intel PT query decoder.
204+ ///
205+ /// Synchronize decoder on the syncpoint at @offset.
206+ /// There must be a PSB packet at @offset.
207+ /// Returns last ip along with a status.
208+ /// Returns BadOpc if an unknown packet is encountered.
209+ /// Returns BadPacket if an unknown packet payload is encountered.
210+ /// Returns Eos if @offset lies outside of decoder's trace buffer.
211+ /// Returns Eos if decoder reaches the end of its trace buffer.
212+ /// Returns Nosync if there is no syncpoint at @offset.
213+ pub fn sync_set ( & mut self , offset : u64 ) -> Result < ( u64 , Status ) , PtError > {
214+ let mut ip: u64 = 0 ;
215+ extract_pterr ( unsafe { pt_qry_sync_set ( self . 0 , & mut ip, offset) } )
216+ . map ( |s| ( ip, Status :: from_bits ( s) . unwrap ( ) ) )
217+ }
218+
219+ /// Query the current time.
220+ ///
221+ /// On success, provides the time at the last query.
222+ /// The time is similar to what a rdtsc instruction would return.
223+ /// Depending on the configuration, the time may not be fully accurate.
224+ /// If TSC is not enabled, the time is relative to the last synchronization
225+ /// and can't be used to correlate with other TSC-based time sources.
226+ /// In this case, NoTime is returned and the relative time is provided.
227+ /// Some timing-related packets may need to be dropped (mostly due to missing calibration or incomplete configuration).
228+ /// To get an idea about the quality of the estimated time, we record the number of dropped MTC and CYC packets.
229+ /// Returns time, number of lost mtc packets and number of lost cyc packets.
230+ /// Returns NoTime if there has not been a TSC packet.
231+ pub fn time ( & mut self ) -> Result < ( u64 , u32 , u32 ) , PtError > {
232+ let mut time: u64 = 0 ;
233+ let mut mtc: u32 = 0 ;
234+ let mut cyc: u32 = 0 ;
235+ ensure_ptok ( unsafe {
236+ pt_qry_time ( self . 0 ,
237+ & mut time,
238+ & mut mtc,
239+ & mut cyc)
240+ } ) . map ( |_| ( time, mtc, cyc) )
241+ }
242+ }
243+
244+ impl < ' a , T > Iterator for QueryDecoder < ' a , T > {
245+ type Item = Result < ( Event , Status ) , PtError > ;
246+
247+ fn next ( & mut self ) -> Option < Result < ( Event , Status ) , PtError > > {
248+ match self . event ( ) {
249+ // eos to stop iterating
250+ Err ( x) if x. code ( ) == PtErrorCode :: Eos => None ,
251+ x => Some ( x)
252+ }
253+ }
254+ }
255+
256+ impl < ' a , T > Drop for QueryDecoder < ' a , T > {
257+ fn drop ( & mut self ) { unsafe { pt_qry_free_decoder ( self . 0 ) } }
258+ }
0 commit comments