Skip to content

Commit 4e82a88

Browse files
libipt: resync
Add pt_insn_resync() pt_blk_resync() for re-synchronizing onto the trace stream inside the current PSB segment after a decode error. The safe way to re-synchronize is via pt_insn_sync_forward() pt_blk_sync_forward() at the next PSB to guarantee that the decoder is properly initialized. In particular, deferred TIP packets are guaranteed to not span across PSB+, and IP compression is reset at PSB. This may, unfortunately, lose a fair amount of trace. Instead of searching for the next PSB, pt_*_resync() scans ahead for the next packet that provides a full or compressed IP. It applies packets that affect the decoder state like MODE, PIP, or timing packets, and it ignores TNT, assuming no deferred TIP. Signed-off-by: Markus Metzger <[email protected]>
1 parent 9bbdc7f commit 4e82a88

9 files changed

+484
-11
lines changed

doc/howto_libipt.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,57 @@ Intel PT shall be generated (for encoders). This allows implementing
237237
processor-specific behavior such as erratum workarounds.
238238

239239

240+
### Resync
241+
242+
In case of errors, re-synchronizing at the next PSB is the safest option
243+
and should be the default. This may lose a fair amount of trace, though,
244+
as PSB are infrequent. To avoid that, one may attempt to synchronize at a
245+
subsequent IP packet using:
246+
247+
* `pt_<lyr>_resync()` Synchronize at the next IP packet while keeping
248+
track of the execution state.
249+
250+
251+
It only skips packets that do not provide an IP, such as TNT. Decoders
252+
still keep track of the execution state via MODE, PIP, and VMCS packets.
253+
Since TNT are skipped, deferred TIPs may not get placed correctly, and may
254+
lead to subsequent errors when synchronizing at the TIP IP assuming the
255+
TIP has not been deferred.
256+
257+
An example of such an extended decode loop is given below:
258+
259+
~~~{.c}
260+
for (;;) {
261+
int errcode;
262+
263+
errcode = <use decoder>(decoder);
264+
if (errcode >= 0)
265+
continue;
266+
267+
if (errcode == -pte_eos)
268+
return;
269+
270+
<report error>(errcode);
271+
272+
errcode = pt_<lyr>_resync(decoder);
273+
if (errcode >= 0)
274+
continue;
275+
276+
if (errcode == -pte_eos)
277+
return;
278+
279+
do {
280+
errcode = pt_<lyr>_sync_forward(decoder);
281+
282+
if (errcode == -pte_eos)
283+
return;
284+
} while (errcode < 0);
285+
}
286+
~~~
287+
288+
This option is only supported for the block and instruction flow decoders.
289+
290+
240291
## The Packet Layer
241292

242293
This layer deals with Intel PT packet encoding and decoding. It can further be

doc/man/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ add_man_page_alias(3 pt_image_remove_by_filename pt_image_remove_by_asid)
133133
add_man_page_alias(3 pt_insn_alloc_decoder pt_insn_free_decoder)
134134
add_man_page_alias(3 pt_insn_sync_forward pt_insn_sync_backward)
135135
add_man_page_alias(3 pt_insn_sync_forward pt_insn_sync_set)
136+
add_man_page_alias(3 pt_insn_sync_forward pt_insn_resync)
136137
add_man_page_alias(3 pt_insn_get_offset pt_insn_get_sync_offset)
137138
add_man_page_alias(3 pt_insn_get_image pt_insn_set_image)
138139
add_man_page_alias(3 pt_insn_get_image pt_blk_get_image)
@@ -143,6 +144,7 @@ add_man_page_alias(3 pt_iscache_alloc pt_iscache_name)
143144
add_man_page_alias(3 pt_blk_alloc_decoder pt_blk_free_decoder)
144145
add_man_page_alias(3 pt_blk_sync_forward pt_blk_sync_backward)
145146
add_man_page_alias(3 pt_blk_sync_forward pt_blk_sync_set)
147+
add_man_page_alias(3 pt_blk_sync_forward pt_blk_resync)
146148
add_man_page_alias(3 pt_blk_get_offset pt_blk_get_sync_offset)
147149
add_man_page_alias(3 pt_blk_next pt_block)
148150

doc/man/pt_blk_next.3.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,5 +283,5 @@ pte_bad_query
283283

284284
**pt_blk_alloc_decoder**(3), **pt_blk_free_decoder**(3),
285285
**pt_blk_sync_forward**(3), **pt_blk_sync_backward**(3),
286-
**pt_blk_sync_set**(3), **pt_blk_time**(3), **pt_blk_core_bus_ratio**(3),
287-
**pt_blk_event**(3)
286+
**pt_blk_sync_set**(3), **pt_blk_resync**(3), **pt_blk_time**(3),
287+
**pt_blk_core_bus_ratio**(3), **pt_blk_event**(3)

doc/man/pt_blk_sync_forward.3.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
pt_blk_sync_forward, pt_blk_sync_backward, pt_blk_sync_set - synchronize an
3535
Intel(R) Processor Trace block decoder
3636

37+
pt_blk_resync - resynchronize at the next IP
38+
3739

3840
# SYNOPSIS
3941

@@ -43,14 +45,18 @@ Intel(R) Processor Trace block decoder
4345
| **int pt_blk_sync_backward(struct pt_block_decoder \**decoder*);**
4446
| **int pt_blk_sync_set(struct pt_block_decoder \**decoder*,**
4547
| **uint64_t *offset*);**
48+
|
49+
| **int pt_blk_resync(struct pt_block_decoder \**decoder*);**
4650

4751
Link with *-lipt*.
4852

4953

5054
# DESCRIPTION
5155

52-
These functions synchronize an Intel Processor Trace (Intel PT) block decoder
53-
pointed to by *decoder* onto the trace stream in *decoder*'s trace buffer.
56+
**pt_blk_sync_forward**(), **pt_blk_sync_backward**() and
57+
**pt_blk_sync_set**() synchronize an Intel Processor Trace (Intel PT)
58+
block decoder pointed to by *decoder* onto the trace stream in *decoder*'s
59+
trace buffer.
5460

5561
They search for a Packet Stream Boundary (PSB) packet in the trace stream and,
5662
if successful, set *decoder*'s current position and synchronization position to
@@ -70,6 +76,10 @@ the end of the trace.
7076
**pt_blk_sync_set**() searches at *offset* bytes from the beginning of its
7177
trace buffer.
7278

79+
**pt_blk_resync**() resynchronizes *decoder* at the next IP packet,
80+
skipping packets that do not provide an IP, such as TNT. This may lead to
81+
subsequent errors when synchronizing at a deferred TIP.
82+
7383

7484
# RETURN VALUE
7585

@@ -138,7 +148,11 @@ int foo(struct pt_block_decoder *decoder) {
138148
return errcode;
139149
140150
do {
141-
errcode = decode(decoder);
151+
do {
152+
errcode = decode(decoder);
153+
} while (errcode >= 0);
154+
155+
errcode = pt_blk_resync(decoder);
142156
} while (errcode >= 0);
143157
}
144158
}

doc/man/pt_insn_next.3.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,5 +267,5 @@ pte_bad_query
267267

268268
**pt_insn_alloc_decoder**(3), **pt_insn_free_decoder**(3),
269269
**pt_insn_sync_forward**(3), **pt_insn_sync_backward**(3),
270-
**pt_insn_sync_set**(3), **pt_insn_time**(3), **pt_insn_core_bus_ratio**(3),
271-
**pt_insn_event**(3)
270+
**pt_insn_sync_set**(3), **pt_insn_resync**(3), **pt_insn_time**(3),
271+
**pt_insn_core_bus_ratio**(3), **pt_insn_event**(3)

doc/man/pt_insn_sync_forward.3.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
pt_insn_sync_forward, pt_insn_sync_backward, pt_insn_sync_set - synchronize an
3535
Intel(R) Processor Trace instruction flow decoder
3636

37+
pt_insn_resync - resynchronize at the next IP
38+
3739

3840
# SYNOPSIS
3941

@@ -43,15 +45,18 @@ Intel(R) Processor Trace instruction flow decoder
4345
| **int pt_insn_sync_backward(struct pt_insn_decoder \**decoder*);**
4446
| **int pt_insn_sync_set(struct pt_insn_decoder \**decoder*,**
4547
| **uint64_t *offset*);**
48+
|
49+
| **int pt_insn_resync(struct pt_insn_decoder \**decoder*);**
4650

4751
Link with *-lipt*.
4852

4953

5054
# DESCRIPTION
5155

52-
These functions synchronize an Intel Processor Trace (Intel PT) instruction flow
53-
decoder pointed to by *decoder* onto the trace stream in *decoder*'s trace
54-
buffer.
56+
**pt_insn_sync_forward**(), **pt_insn_sync_backward**() and
57+
**pt_insn_sync_set**() synchronize an Intel Processor Trace (Intel PT)
58+
instruction flow decoder pointed to by *decoder* onto the trace stream in
59+
*decoder*'s trace buffer.
5560

5661
They search for a Packet Stream Boundary (PSB) packet in the trace stream and,
5762
if successful, set *decoder*'s current position and synchronization position to
@@ -71,6 +76,9 @@ the end of the trace.
7176
**pt_insn_sync_set**() searches at *offset* bytes from the beginning of its
7277
trace buffer.
7378

79+
**pt_insn_resync**() resynchronizes *decoder* at the next IP packet,
80+
skipping packets that do not provide an IP, such as TNT. This may lead to
81+
subsequent errors when synchronizing at a deferred TIP.
7482

7583
# RETURN VALUE
7684

@@ -139,7 +147,11 @@ int foo(struct pt_insn_decoder *decoder) {
139147
return status;
140148
141149
do {
142-
status = decode(decoder, status);
150+
do {
151+
status = decode(decoder, status);
152+
} while (status >= 0);
153+
154+
status = pt_insn_resync(decoder);
143155
} while (status >= 0);
144156
}
145157
}

libipt/include/intel-pt.h.in

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2652,6 +2652,30 @@ extern pt_export int pt_insn_sync_backward(struct pt_insn_decoder *decoder);
26522652
extern pt_export int pt_insn_sync_set(struct pt_insn_decoder *decoder,
26532653
uint64_t offset);
26542654

2655+
#if (LIBIPT_VERSION >= 0x202)
2656+
/** Re-synchronize an Intel PT instruction flow decoder.
2657+
*
2658+
* Scan ahead for the next IP providing packet. Apply state changing packets
2659+
* along the way, including timing packets, but ignore everything else.
2660+
*
2661+
* Returns a non-negative pt_status_flag bit-vector on success, a negative
2662+
* error code otherwise.
2663+
*
2664+
* Returns pts_ip_suppressed if re-synchronization succeeded with tracing
2665+
* disabled.
2666+
*
2667+
* Returns -pte_event_ignored if an event cannot safely be skipped
2668+
* (e.g. ptwrite). Use pt_insn_event() to read the event, then continue with
2669+
* pt_insn_resync() until re-synchronization completes or fails with an error.
2670+
*
2671+
* Returns -pte_bad_opc if an unknown packet is encountered.
2672+
* Returns -pte_bad_packet if an unknown packet payload is encountered.
2673+
* Returns -pte_eos if no further synchronization point is found.
2674+
* Returns -pte_invalid if \@decoder is NULL.
2675+
*/
2676+
extern pt_export int pt_insn_resync(struct pt_insn_decoder *decoder);
2677+
#endif
2678+
26552679
/** Get the current decoder position.
26562680
*
26572681
* Fills the current \@decoder position into \@offset.
@@ -2936,6 +2960,30 @@ extern pt_export int pt_blk_sync_backward(struct pt_block_decoder *decoder);
29362960
extern pt_export int pt_blk_sync_set(struct pt_block_decoder *decoder,
29372961
uint64_t offset);
29382962

2963+
#if (LIBIPT_VERSION >= 0x202)
2964+
/** Re-synchronize an Intel PT block decoder.
2965+
*
2966+
* Scan ahead for the next IP providing packet. Apply state changing packets
2967+
* along the way, including timing packets, but ignore everything else.
2968+
*
2969+
* Returns a non-negative pt_status_flag bit-vector on success, a negative
2970+
* error code otherwise.
2971+
*
2972+
* Returns pts_ip_suppressed if re-synchronization succeeded with tracing
2973+
* disabled.
2974+
*
2975+
* Returns -pte_event_ignored if an event cannot safely be skipped
2976+
* (e.g. ptwrite). Use pt_blk_event() to read the event, then continue with
2977+
* pt_blk_resync() until re-synchronization completes or fails with an error.
2978+
*
2979+
* Returns -pte_bad_opc if an unknown packet is encountered.
2980+
* Returns -pte_bad_packet if an unknown packet payload is encountered.
2981+
* Returns -pte_eos if no further synchronization point is found.
2982+
* Returns -pte_invalid if \@decoder is NULL.
2983+
*/
2984+
extern pt_export int pt_blk_resync(struct pt_block_decoder *decoder);
2985+
#endif
2986+
29392987
/** Get the current decoder position.
29402988
*
29412989
* Fills the current \@decoder position into \@offset.

0 commit comments

Comments
 (0)