1 //===-- LibiptDecoder.cpp --======-----------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //===----------------------------------------------------------------------===//
8 #include "LibiptDecoder.h"
9 #include "TraceIntelPT.h"
10 #include "lldb/Target/Process.h"
14 using namespace lldb_private
;
15 using namespace lldb_private::trace_intel_pt
;
18 bool IsLibiptError(int status
) { return status
< 0; }
20 bool IsEndOfStream(int status
) {
21 assert(status
>= 0 && "We can't check if we reached the end of the stream if "
22 "we got a failed status");
23 return status
& pts_eos
;
26 bool HasEvents(int status
) {
27 assert(status
>= 0 && "We can't check for events if we got a failed status");
28 return status
& pts_event_pending
;
31 // RAII deleter for libipt's decoders
32 auto InsnDecoderDeleter
= [](pt_insn_decoder
*decoder
) {
33 pt_insn_free_decoder(decoder
);
36 auto QueryDecoderDeleter
= [](pt_query_decoder
*decoder
) {
37 pt_qry_free_decoder(decoder
);
40 using PtInsnDecoderUP
=
41 std::unique_ptr
<pt_insn_decoder
, decltype(InsnDecoderDeleter
)>;
43 using PtQueryDecoderUP
=
44 std::unique_ptr
<pt_query_decoder
, decltype(QueryDecoderDeleter
)>;
46 /// Create a basic configuration object limited to a given buffer that can be
47 /// used for many different decoders.
48 static Expected
<pt_config
> CreateBasicLibiptConfig(TraceIntelPT
&trace_intel_pt
,
49 ArrayRef
<uint8_t> buffer
) {
50 Expected
<pt_cpu
> cpu_info
= trace_intel_pt
.GetCPUInfo();
52 return cpu_info
.takeError();
55 pt_config_init(&config
);
56 config
.cpu
= *cpu_info
;
58 int status
= pt_cpu_errata(&config
.errata
, &config
.cpu
);
59 if (IsLibiptError(status
))
60 return make_error
<IntelPTError
>(status
);
62 // The libipt library does not modify the trace buffer, hence the
63 // following casts are safe.
64 config
.begin
= const_cast<uint8_t *>(buffer
.data());
65 config
.end
= const_cast<uint8_t *>(buffer
.data() + buffer
.size());
69 /// Callback used by libipt for reading the process memory.
71 /// More information can be found in
72 /// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md
73 static int ReadProcessMemory(uint8_t *buffer
, size_t size
,
74 const pt_asid
* /* unused */, uint64_t pc
,
76 Process
*process
= static_cast<Process
*>(context
);
79 int bytes_read
= process
->ReadMemory(pc
, buffer
, size
, error
);
85 /// Set up the memory image callback for the given decoder.
86 static Error
SetupMemoryImage(pt_insn_decoder
*decoder
, Process
&process
) {
87 pt_image
*image
= pt_insn_get_image(decoder
);
89 int status
= pt_image_set_callback(image
, ReadProcessMemory
, &process
);
90 if (IsLibiptError(status
))
91 return make_error
<IntelPTError
>(status
);
92 return Error::success();
95 /// Create an instruction decoder for the given buffer and the given process.
96 static Expected
<PtInsnDecoderUP
>
97 CreateInstructionDecoder(TraceIntelPT
&trace_intel_pt
, ArrayRef
<uint8_t> buffer
,
99 Expected
<pt_config
> config
= CreateBasicLibiptConfig(trace_intel_pt
, buffer
);
101 return config
.takeError();
103 pt_insn_decoder
*decoder_ptr
= pt_insn_alloc_decoder(&*config
);
105 return make_error
<IntelPTError
>(-pte_nomem
);
107 PtInsnDecoderUP
decoder_up(decoder_ptr
, InsnDecoderDeleter
);
109 if (Error err
= SetupMemoryImage(decoder_ptr
, process
))
110 return std::move(err
);
115 /// Create a query decoder for the given buffer. The query decoder is the
116 /// highest level decoder that operates directly on packets and doesn't perform
117 /// actual instruction decoding. That's why it can be useful for inspecting a
118 /// raw trace without pinning it to a particular process.
119 static Expected
<PtQueryDecoderUP
>
120 CreateQueryDecoder(TraceIntelPT
&trace_intel_pt
, ArrayRef
<uint8_t> buffer
) {
121 Expected
<pt_config
> config
= CreateBasicLibiptConfig(trace_intel_pt
, buffer
);
123 return config
.takeError();
125 pt_query_decoder
*decoder_ptr
= pt_qry_alloc_decoder(&*config
);
127 return make_error
<IntelPTError
>(-pte_nomem
);
129 return PtQueryDecoderUP(decoder_ptr
, QueryDecoderDeleter
);
132 /// Class used to identify anomalies in traces, which should often indicate a
133 /// fatal error in the trace.
134 class PSBBlockAnomalyDetector
{
136 PSBBlockAnomalyDetector(pt_insn_decoder
&decoder
,
137 TraceIntelPT
&trace_intel_pt
,
138 DecodedThread
&decoded_thread
)
139 : m_decoder(decoder
), m_decoded_thread(decoded_thread
) {
140 m_infinite_decoding_loop_threshold
=
141 trace_intel_pt
.GetGlobalProperties()
142 .GetInfiniteDecodingLoopVerificationThreshold();
143 m_extremely_large_decoding_threshold
=
144 trace_intel_pt
.GetGlobalProperties()
145 .GetExtremelyLargeDecodingThreshold();
146 m_next_infinite_decoding_loop_threshold
=
147 m_infinite_decoding_loop_threshold
;
151 /// An \a llvm::Error if an anomaly that includes the last instruction item
152 /// in the trace, or \a llvm::Error::success otherwise.
153 Error
DetectAnomaly() {
154 RefreshPacketOffset();
155 uint64_t insn_added_since_last_packet_offset
=
156 m_decoded_thread
.GetTotalInstructionCount() -
157 m_insn_count_at_last_packet_offset
;
159 // We want to check if we might have fallen in an infinite loop. As this
160 // check is not a no-op, we want to do it when we have a strong suggestion
161 // that things went wrong. First, we check how many instructions we have
162 // decoded since we processed an Intel PT packet for the last time. This
163 // number should be low, because at some point we should see branches, jumps
164 // or interrupts that require a new packet to be processed. Once we reach
165 // certain threshold we start analyzing the trace.
167 // We use the number of decoded instructions since the last Intel PT packet
168 // as a proxy because, in fact, we don't expect a single packet to give,
169 // say, 100k instructions. That would mean that there are 100k sequential
170 // instructions without any single branch, which is highly unlikely, or that
171 // we found an infinite loop using direct jumps, e.g.
173 // 0x0A: nop or pause
174 // 0x0C: jump to 0x0A
176 // which is indeed code that is found in the kernel. I presume we reach
177 // this kind of code in the decoder because we don't handle self-modified
178 // code in post-mortem kernel traces.
180 // We are right now only signaling the anomaly as a trace error, but it
181 // would be more conservative to also discard all the trace items found in
182 // this PSB. I prefer not to do that for the time being to give more
183 // exposure to this kind of anomalies and help debugging. Discarding the
184 // trace items would just make investigation harded.
186 // Finally, if the user wants to see if a specific thread has an anomaly,
187 // it's enough to run the `thread trace dump info` command and look for the
188 // count of this kind of errors.
190 if (insn_added_since_last_packet_offset
>=
191 m_extremely_large_decoding_threshold
) {
192 // In this case, we have decoded a massive amount of sequential
193 // instructions that don't loop. Honestly I wonder if this will ever
194 // happen, but better safe than sorry.
195 return createStringError(
196 inconvertibleErrorCode(),
197 "anomalous trace: possible infinite trace detected");
199 if (insn_added_since_last_packet_offset
==
200 m_next_infinite_decoding_loop_threshold
) {
201 if (std::optional
<uint64_t> loop_size
= TryIdentifyInfiniteLoop()) {
202 return createStringError(
203 inconvertibleErrorCode(),
204 "anomalous trace: possible infinite loop detected of size %" PRIu64
,
207 m_next_infinite_decoding_loop_threshold
*= 2;
209 return Error::success();
213 std::optional
<uint64_t> TryIdentifyInfiniteLoop() {
214 // The infinite decoding loops we'll encounter are due to sequential
215 // instructions that repeat themselves due to direct jumps, therefore in a
216 // cycle each individual address will only appear once. We use this
217 // information to detect cycles by finding the last 2 ocurrences of the last
218 // instruction added to the trace. Then we traverse the trace making sure
219 // that these two instructions where the ends of a repeating loop.
221 // This is a utility that returns the most recent instruction index given a
222 // position in the trace. If the given position is an instruction, that
223 // position is returned. It skips non-instruction items.
224 auto most_recent_insn_index
=
225 [&](uint64_t item_index
) -> std::optional
<uint64_t> {
227 if (m_decoded_thread
.GetItemKindByIndex(item_index
) ==
228 lldb::eTraceItemKindInstruction
) {
237 // Similar to most_recent_insn_index but skips the starting position.
238 auto prev_insn_index
= [&](uint64_t item_index
) -> std::optional
<uint64_t> {
241 return most_recent_insn_index(item_index
- 1);
244 // We first find the most recent instruction.
245 std::optional
<uint64_t> last_insn_index_opt
=
246 *prev_insn_index(m_decoded_thread
.GetItemsCount());
247 if (!last_insn_index_opt
)
249 uint64_t last_insn_index
= *last_insn_index_opt
;
251 // We then find the most recent previous occurrence of that last
253 std::optional
<uint64_t> last_insn_copy_index
=
254 prev_insn_index(last_insn_index
);
255 uint64_t loop_size
= 1;
256 while (last_insn_copy_index
&&
257 m_decoded_thread
.GetInstructionLoadAddress(*last_insn_copy_index
) !=
258 m_decoded_thread
.GetInstructionLoadAddress(last_insn_index
)) {
259 last_insn_copy_index
= prev_insn_index(*last_insn_copy_index
);
262 if (!last_insn_copy_index
)
265 // Now we check if the segment between these last positions of the last
266 // instruction address is in fact a repeating loop.
267 uint64_t loop_elements_visited
= 1;
268 uint64_t insn_index_a
= last_insn_index
,
269 insn_index_b
= *last_insn_copy_index
;
270 while (loop_elements_visited
< loop_size
) {
271 if (std::optional
<uint64_t> prev
= prev_insn_index(insn_index_a
))
272 insn_index_a
= *prev
;
275 if (std::optional
<uint64_t> prev
= prev_insn_index(insn_index_b
))
276 insn_index_b
= *prev
;
279 if (m_decoded_thread
.GetInstructionLoadAddress(insn_index_a
) !=
280 m_decoded_thread
.GetInstructionLoadAddress(insn_index_b
))
282 loop_elements_visited
++;
287 // Refresh the internal counters if a new packet offset has been visited
288 void RefreshPacketOffset() {
289 lldb::addr_t new_packet_offset
;
290 if (!IsLibiptError(pt_insn_get_offset(&m_decoder
, &new_packet_offset
)) &&
291 new_packet_offset
!= m_last_packet_offset
) {
292 m_last_packet_offset
= new_packet_offset
;
293 m_next_infinite_decoding_loop_threshold
=
294 m_infinite_decoding_loop_threshold
;
295 m_insn_count_at_last_packet_offset
=
296 m_decoded_thread
.GetTotalInstructionCount();
300 pt_insn_decoder
&m_decoder
;
301 DecodedThread
&m_decoded_thread
;
302 lldb::addr_t m_last_packet_offset
= LLDB_INVALID_ADDRESS
;
303 uint64_t m_insn_count_at_last_packet_offset
= 0;
304 uint64_t m_infinite_decoding_loop_threshold
;
305 uint64_t m_next_infinite_decoding_loop_threshold
;
306 uint64_t m_extremely_large_decoding_threshold
;
309 /// Class that decodes a raw buffer for a single PSB block using the low level
310 /// libipt library. It assumes that kernel and user mode instructions are not
311 /// mixed in the same PSB block.
313 /// Throughout this code, the status of the decoder will be used to identify
314 /// events needed to be processed or errors in the decoder. The values can be
315 /// - negative: actual errors
316 /// - positive or zero: not an error, but a list of bits signaling the status
317 /// of the decoder, e.g. whether there are events that need to be decoded or
319 class PSBBlockDecoder
{
321 /// \param[in] decoder
322 /// A decoder configured to start and end within the boundaries of the
323 /// given \p psb_block.
325 /// \param[in] psb_block
326 /// The PSB block to decode.
328 /// \param[in] next_block_ip
329 /// The starting ip at the next PSB block of the same thread if available.
331 /// \param[in] decoded_thread
332 /// A \a DecodedThread object where the decoded instructions will be
333 /// appended to. It might have already some instructions.
335 /// \param[in] tsc_upper_bound
336 /// Maximum allowed value of TSCs decoded from this PSB block.
337 /// Any of this PSB's data occurring after this TSC will be excluded.
338 PSBBlockDecoder(PtInsnDecoderUP
&&decoder_up
, const PSBBlock
&psb_block
,
339 std::optional
<lldb::addr_t
> next_block_ip
,
340 DecodedThread
&decoded_thread
, TraceIntelPT
&trace_intel_pt
,
341 std::optional
<DecodedThread::TSC
> tsc_upper_bound
)
342 : m_decoder_up(std::move(decoder_up
)), m_psb_block(psb_block
),
343 m_next_block_ip(next_block_ip
), m_decoded_thread(decoded_thread
),
344 m_anomaly_detector(*m_decoder_up
, trace_intel_pt
, decoded_thread
),
345 m_tsc_upper_bound(tsc_upper_bound
) {}
347 /// \param[in] trace_intel_pt
348 /// The main Trace object that own the PSB block.
350 /// \param[in] decoder
351 /// A decoder configured to start and end within the boundaries of the
352 /// given \p psb_block.
354 /// \param[in] psb_block
355 /// The PSB block to decode.
357 /// \param[in] buffer
358 /// The raw intel pt trace for this block.
360 /// \param[in] process
361 /// The process to decode. It provides the memory image to use for
364 /// \param[in] next_block_ip
365 /// The starting ip at the next PSB block of the same thread if available.
367 /// \param[in] decoded_thread
368 /// A \a DecodedThread object where the decoded instructions will be
369 /// appended to. It might have already some instructions.
370 static Expected
<PSBBlockDecoder
>
371 Create(TraceIntelPT
&trace_intel_pt
, const PSBBlock
&psb_block
,
372 ArrayRef
<uint8_t> buffer
, Process
&process
,
373 std::optional
<lldb::addr_t
> next_block_ip
,
374 DecodedThread
&decoded_thread
,
375 std::optional
<DecodedThread::TSC
> tsc_upper_bound
) {
376 Expected
<PtInsnDecoderUP
> decoder_up
=
377 CreateInstructionDecoder(trace_intel_pt
, buffer
, process
);
379 return decoder_up
.takeError();
381 return PSBBlockDecoder(std::move(*decoder_up
), psb_block
, next_block_ip
,
382 decoded_thread
, trace_intel_pt
, tsc_upper_bound
);
385 void DecodePSBBlock() {
386 int status
= pt_insn_sync_forward(m_decoder_up
.get());
387 assert(status
>= 0 &&
388 "Synchronization shouldn't fail because this PSB was previously "
389 "decoded correctly.");
391 // We emit a TSC before a sync event to more easily associate a timestamp to
392 // the sync event. If present, the current block's TSC would be the first
393 // TSC we'll see when processing events.
395 m_decoded_thread
.NotifyTsc(*m_psb_block
.tsc
);
397 m_decoded_thread
.NotifySyncPoint(m_psb_block
.psb_offset
);
399 DecodeInstructionsAndEvents(status
);
403 /// Append an instruction and return \b false if and only if a serious anomaly
404 /// has been detected.
405 bool AppendInstructionAndDetectAnomalies(const pt_insn
&insn
) {
406 m_decoded_thread
.AppendInstruction(insn
);
408 if (Error err
= m_anomaly_detector
.DetectAnomaly()) {
409 m_decoded_thread
.AppendCustomError(toString(std::move(err
)),
415 /// Decode all the instructions and events of the given PSB block. The
416 /// decoding loop might stop abruptly if an infinite decoding loop is
418 void DecodeInstructionsAndEvents(int status
) {
422 status
= ProcessPTEvents(status
);
424 if (IsLibiptError(status
))
426 else if (IsEndOfStream(status
))
429 // The status returned by pt_insn_next will need to be processed
430 // by ProcessPTEvents in the next loop if it is not an error.
431 std::memset(&insn
, 0, sizeof insn
);
432 status
= pt_insn_next(m_decoder_up
.get(), &insn
, sizeof(insn
));
434 if (IsLibiptError(status
)) {
435 m_decoded_thread
.AppendError(IntelPTError(status
, insn
.ip
));
437 } else if (IsEndOfStream(status
)) {
441 if (!AppendInstructionAndDetectAnomalies(insn
))
445 // We need to keep querying non-branching instructions until we hit the
446 // starting point of the next PSB. We won't see events at this point. This
448 // https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#parallel-decode
449 if (m_next_block_ip
&& insn
.ip
!= 0) {
450 while (insn
.ip
!= *m_next_block_ip
) {
451 if (!AppendInstructionAndDetectAnomalies(insn
))
454 status
= pt_insn_next(m_decoder_up
.get(), &insn
, sizeof(insn
));
456 if (IsLibiptError(status
)) {
457 m_decoded_thread
.AppendError(IntelPTError(status
, insn
.ip
));
464 /// Process the TSC of a decoded PT event. Specifically, check if this TSC
465 /// is below the TSC upper bound for this PSB. If the TSC exceeds the upper
466 /// bound, return an error to abort decoding. Otherwise add the it to the
467 /// underlying DecodedThread and decoding should continue as expected.
470 /// The TSC of the a decoded event.
471 Error
ProcessPTEventTSC(DecodedThread::TSC tsc
) {
472 if (m_tsc_upper_bound
&& tsc
>= *m_tsc_upper_bound
) {
473 // This event and all the remaining events of this PSB have a TSC
474 // outside the range of the "owning" ThreadContinuousExecution. For
475 // now we drop all of these events/instructions, future work can
476 // improve upon this by determining the "owning"
477 // ThreadContinuousExecution of the remaining PSB data.
478 std::string err_msg
= formatv("decoding truncated: TSC {0} exceeds "
479 "maximum TSC value {1}, will skip decoding"
480 " the remaining data of the PSB",
481 tsc
, *m_tsc_upper_bound
)
485 int status
= pt_insn_get_offset(m_decoder_up
.get(), &offset
);
486 if (!IsLibiptError(status
)) {
487 err_msg
= formatv("{2} (skipping {0} of {1} bytes)", offset
,
488 m_psb_block
.size
, err_msg
)
491 m_decoded_thread
.AppendCustomError(err_msg
);
492 return createStringError(inconvertibleErrorCode(), err_msg
);
494 m_decoded_thread
.NotifyTsc(tsc
);
495 return Error::success();
499 /// Before querying instructions, we need to query the events associated with
500 /// that instruction, e.g. timing and trace disablement events.
502 /// \param[in] status
503 /// The status gotten from the previous instruction decoding or PSB
507 /// The pte_status after decoding events.
508 int ProcessPTEvents(int status
) {
509 while (HasEvents(status
)) {
511 std::memset(&event
, 0, sizeof event
);
512 status
= pt_insn_event(m_decoder_up
.get(), &event
, sizeof(event
));
514 if (IsLibiptError(status
)) {
515 m_decoded_thread
.AppendError(IntelPTError(status
));
520 if (Error err
= ProcessPTEventTSC(event
.tsc
)) {
521 consumeError(std::move(err
));
522 return -pte_internal
;
526 switch (event
.type
) {
528 // The CPU paused tracing the program, e.g. due to ip filtering.
529 m_decoded_thread
.AppendEvent(lldb::eTraceEventDisabledHW
);
531 case ptev_async_disabled
:
532 // The kernel or user code paused tracing the program, e.g.
533 // a breakpoint or a ioctl invocation pausing the trace, or a
534 // context switch happened.
535 m_decoded_thread
.AppendEvent(lldb::eTraceEventDisabledSW
);
538 // The CPU internal buffer had an overflow error and some instructions
539 // were lost. A OVF packet comes with an FUP packet (harcoded address)
540 // according to the documentation, so we'll continue seeing instructions
542 m_decoded_thread
.AppendError(IntelPTError(-pte_overflow
));
553 PtInsnDecoderUP m_decoder_up
;
554 PSBBlock m_psb_block
;
555 std::optional
<lldb::addr_t
> m_next_block_ip
;
556 DecodedThread
&m_decoded_thread
;
557 PSBBlockAnomalyDetector m_anomaly_detector
;
558 std::optional
<DecodedThread::TSC
> m_tsc_upper_bound
;
561 Error
lldb_private::trace_intel_pt::DecodeSingleTraceForThread(
562 DecodedThread
&decoded_thread
, TraceIntelPT
&trace_intel_pt
,
563 ArrayRef
<uint8_t> buffer
) {
564 Expected
<std::vector
<PSBBlock
>> blocks
=
565 SplitTraceIntoPSBBlock(trace_intel_pt
, buffer
, /*expect_tscs=*/false);
567 return blocks
.takeError();
569 for (size_t i
= 0; i
< blocks
->size(); i
++) {
570 PSBBlock
&block
= blocks
->at(i
);
572 Expected
<PSBBlockDecoder
> decoder
= PSBBlockDecoder::Create(
573 trace_intel_pt
, block
, buffer
.slice(block
.psb_offset
, block
.size
),
574 *decoded_thread
.GetThread()->GetProcess(),
575 i
+ 1 < blocks
->size() ? blocks
->at(i
+ 1).starting_ip
: None
,
576 decoded_thread
, std::nullopt
);
578 return decoder
.takeError();
580 decoder
->DecodePSBBlock();
583 return Error::success();
586 Error
lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
587 DecodedThread
&decoded_thread
, TraceIntelPT
&trace_intel_pt
,
588 const DenseMap
<lldb::cpu_id_t
, llvm::ArrayRef
<uint8_t>> &buffers
,
589 const std::vector
<IntelPTThreadContinousExecution
> &executions
) {
590 bool has_seen_psbs
= false;
591 for (size_t i
= 0; i
< executions
.size(); i
++) {
592 const IntelPTThreadContinousExecution
&execution
= executions
[i
];
594 auto variant
= execution
.thread_execution
.variant
;
596 // We emit the first valid tsc
597 if (execution
.psb_blocks
.empty()) {
598 decoded_thread
.NotifyTsc(execution
.thread_execution
.GetLowestKnownTSC());
600 assert(execution
.psb_blocks
.front().tsc
&&
601 "per cpu decoding expects TSCs");
602 decoded_thread
.NotifyTsc(
603 std::min(execution
.thread_execution
.GetLowestKnownTSC(),
604 *execution
.psb_blocks
.front().tsc
));
607 // We then emit the CPU, which will be correctly associated with a tsc.
608 decoded_thread
.NotifyCPU(execution
.thread_execution
.cpu_id
);
610 // If we haven't seen a PSB yet, then it's fine not to show errors
612 if (execution
.psb_blocks
.empty()) {
613 decoded_thread
.AppendCustomError(
614 formatv("Unable to find intel pt data a thread "
615 "execution on cpu id = {0}",
616 execution
.thread_execution
.cpu_id
)
620 // A hinted start is a non-initial execution that doesn't have a switch
621 // in. An only end is an initial execution that doesn't have a switch in.
622 // Any of those cases represent a gap because we have seen a PSB before.
623 if (variant
== ThreadContinuousExecution::Variant::HintedStart
||
624 variant
== ThreadContinuousExecution::Variant::OnlyEnd
) {
625 decoded_thread
.AppendCustomError(
626 formatv("Unable to find the context switch in for a thread "
627 "execution on cpu id = {0}",
628 execution
.thread_execution
.cpu_id
)
633 for (size_t j
= 0; j
< execution
.psb_blocks
.size(); j
++) {
634 const PSBBlock
&psb_block
= execution
.psb_blocks
[j
];
636 Expected
<PSBBlockDecoder
> decoder
= PSBBlockDecoder::Create(
637 trace_intel_pt
, psb_block
,
638 buffers
.lookup(execution
.thread_execution
.cpu_id
)
639 .slice(psb_block
.psb_offset
, psb_block
.size
),
640 *decoded_thread
.GetThread()->GetProcess(),
641 j
+ 1 < execution
.psb_blocks
.size()
642 ? execution
.psb_blocks
[j
+ 1].starting_ip
644 decoded_thread
, execution
.thread_execution
.GetEndTSC());
646 return decoder
.takeError();
648 has_seen_psbs
= true;
649 decoder
->DecodePSBBlock();
652 // If we haven't seen a PSB yet, then it's fine not to show errors
654 // A hinted end is a non-ending execution that doesn't have a switch out.
655 // An only start is an ending execution that doesn't have a switch out.
656 // Any of those cases represent a gap if we still have executions to
657 // process and we have seen a PSB before.
658 if (i
+ 1 != executions
.size() &&
659 (variant
== ThreadContinuousExecution::Variant::OnlyStart
||
660 variant
== ThreadContinuousExecution::Variant::HintedEnd
)) {
661 decoded_thread
.AppendCustomError(
662 formatv("Unable to find the context switch out for a thread "
663 "execution on cpu id = {0}",
664 execution
.thread_execution
.cpu_id
)
669 return Error::success();
672 bool IntelPTThreadContinousExecution::operator<(
673 const IntelPTThreadContinousExecution
&o
) const {
674 // As the context switch might be incomplete, we look first for the first real
675 // PSB packet, which is a valid TSC. Otherwise, We query the thread execution
676 // itself for some tsc.
677 auto get_tsc
= [](const IntelPTThreadContinousExecution
&exec
) {
678 return exec
.psb_blocks
.empty() ? exec
.thread_execution
.GetLowestKnownTSC()
679 : exec
.psb_blocks
.front().tsc
;
682 return get_tsc(*this) < get_tsc(o
);
685 Expected
<std::vector
<PSBBlock
>>
686 lldb_private::trace_intel_pt::SplitTraceIntoPSBBlock(
687 TraceIntelPT
&trace_intel_pt
, llvm::ArrayRef
<uint8_t> buffer
,
690 // https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#parallel-decode
692 Expected
<PtQueryDecoderUP
> decoder_up
=
693 CreateQueryDecoder(trace_intel_pt
, buffer
);
695 return decoder_up
.takeError();
697 pt_query_decoder
*decoder
= decoder_up
.get().get();
699 std::vector
<PSBBlock
> executions
;
702 uint64_t maybe_ip
= LLDB_INVALID_ADDRESS
;
703 int decoding_status
= pt_qry_sync_forward(decoder
, &maybe_ip
);
704 if (IsLibiptError(decoding_status
))
708 int offset_status
= pt_qry_get_sync_offset(decoder
, &psb_offset
);
709 assert(offset_status
>= 0 &&
710 "This can't fail because we were able to synchronize");
712 std::optional
<uint64_t> ip
;
713 if (!(pts_ip_suppressed
& decoding_status
))
716 std::optional
<uint64_t> tsc
;
717 // Now we fetch the first TSC that comes after the PSB.
718 while (HasEvents(decoding_status
)) {
720 decoding_status
= pt_qry_event(decoder
, &event
, sizeof(event
));
721 if (IsLibiptError(decoding_status
))
728 if (IsLibiptError(decoding_status
)) {
729 // We continue to the next PSB. This effectively merges this PSB with the
730 // previous one, and that should be fine because this PSB might be the
731 // direct continuation of the previous thread and it's better to show an
732 // error in the decoded thread than to hide it. If this is the first PSB,
733 // we are okay losing it. Besides that, an error at processing events
734 // means that we wouldn't be able to get any instruction out of it.
738 if (expect_tscs
&& !tsc
)
739 return createStringError(inconvertibleErrorCode(),
740 "Found a PSB without TSC.");
742 executions
.push_back({
749 if (!executions
.empty()) {
750 // We now adjust the sizes of each block
751 executions
.back().size
= buffer
.size() - executions
.back().psb_offset
;
752 for (int i
= (int)executions
.size() - 2; i
>= 0; i
--) {
754 executions
[i
+ 1].psb_offset
- executions
[i
].psb_offset
;
760 Expected
<std::optional
<uint64_t>>
761 lldb_private::trace_intel_pt::FindLowestTSCInTrace(TraceIntelPT
&trace_intel_pt
,
762 ArrayRef
<uint8_t> buffer
) {
763 Expected
<PtQueryDecoderUP
> decoder_up
=
764 CreateQueryDecoder(trace_intel_pt
, buffer
);
766 return decoder_up
.takeError();
768 pt_query_decoder
*decoder
= decoder_up
.get().get();
769 uint64_t ip
= LLDB_INVALID_ADDRESS
;
770 int status
= pt_qry_sync_forward(decoder
, &ip
);
771 if (IsLibiptError(status
))
774 while (HasEvents(status
)) {
776 status
= pt_qry_event(decoder
, &event
, sizeof(event
));
777 if (IsLibiptError(status
))