xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1*81ad6265SDimitry Andric //===-- LibiptDecoder.cpp --======-----------------------------------------===//
2*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
4*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5*81ad6265SDimitry Andric //
6*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
7*81ad6265SDimitry Andric 
8*81ad6265SDimitry Andric #include "LibiptDecoder.h"
9*81ad6265SDimitry Andric 
10*81ad6265SDimitry Andric #include "TraceIntelPT.h"
11*81ad6265SDimitry Andric 
12*81ad6265SDimitry Andric #include "lldb/Target/Process.h"
13*81ad6265SDimitry Andric 
14*81ad6265SDimitry Andric using namespace lldb;
15*81ad6265SDimitry Andric using namespace lldb_private;
16*81ad6265SDimitry Andric using namespace lldb_private::trace_intel_pt;
17*81ad6265SDimitry Andric using namespace llvm;
18*81ad6265SDimitry Andric 
19*81ad6265SDimitry Andric /// Class that decodes a raw buffer for a single thread using the low level
20*81ad6265SDimitry Andric /// libipt library.
21*81ad6265SDimitry Andric ///
22*81ad6265SDimitry Andric /// Throughout this code, the status of the decoder will be used to identify
23*81ad6265SDimitry Andric /// events needed to be processed or errors in the decoder. The values can be
24*81ad6265SDimitry Andric /// - negative: actual errors
25*81ad6265SDimitry Andric /// - positive or zero: not an error, but a list of bits signaling the status
26*81ad6265SDimitry Andric /// of the decoder, e.g. whether there are events that need to be decoded or
27*81ad6265SDimitry Andric /// not.
28*81ad6265SDimitry Andric class LibiptDecoder {
29*81ad6265SDimitry Andric public:
30*81ad6265SDimitry Andric   /// \param[in] decoder
31*81ad6265SDimitry Andric   ///     A well configured decoder. Using the current state of that decoder,
32*81ad6265SDimitry Andric   ///     decoding will start at its next valid PSB. It's not assumed that the
33*81ad6265SDimitry Andric   ///     decoder is already pointing at a valid PSB.
34*81ad6265SDimitry Andric   ///
35*81ad6265SDimitry Andric   /// \param[in] decoded_thread
36*81ad6265SDimitry Andric   ///     A \a DecodedThread object where the decoded instructions will be
37*81ad6265SDimitry Andric   ///     appended to. It might have already some instructions.
38*81ad6265SDimitry Andric   LibiptDecoder(pt_insn_decoder &decoder, DecodedThread &decoded_thread)
39*81ad6265SDimitry Andric       : m_decoder(decoder), m_decoded_thread(decoded_thread) {}
40*81ad6265SDimitry Andric 
41*81ad6265SDimitry Andric   /// Decode all the instructions until the end of the trace.
42*81ad6265SDimitry Andric   /// The decoding flow is based on
43*81ad6265SDimitry Andric   /// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop.
44*81ad6265SDimitry Andric   void DecodeUntilEndOfTrace() {
45*81ad6265SDimitry Andric     // Multiple loops indicate gaps in the trace, which are found by the inner
46*81ad6265SDimitry Andric     // call to DecodeInstructionsAndEvents.
47*81ad6265SDimitry Andric     while (true) {
48*81ad6265SDimitry Andric       int status = pt_insn_sync_forward(&m_decoder);
49*81ad6265SDimitry Andric 
50*81ad6265SDimitry Andric       if (IsLibiptError(status)) {
51*81ad6265SDimitry Andric         m_decoded_thread.AppendError(IntelPTError(status));
52*81ad6265SDimitry Andric         break;
53*81ad6265SDimitry Andric       }
54*81ad6265SDimitry Andric 
55*81ad6265SDimitry Andric       DecodeInstructionsAndEvents(status);
56*81ad6265SDimitry Andric     }
57*81ad6265SDimitry Andric   }
58*81ad6265SDimitry Andric 
59*81ad6265SDimitry Andric   /// Decode all the instructions that belong to the same PSB packet given its
60*81ad6265SDimitry Andric   /// offset.
61*81ad6265SDimitry Andric   void DecodePSB(uint64_t psb_offset) {
62*81ad6265SDimitry Andric     int status = pt_insn_sync_set(&m_decoder, psb_offset);
63*81ad6265SDimitry Andric     if (IsLibiptError(status)) {
64*81ad6265SDimitry Andric       m_decoded_thread.AppendError(IntelPTError(status));
65*81ad6265SDimitry Andric       return;
66*81ad6265SDimitry Andric     }
67*81ad6265SDimitry Andric     DecodeInstructionsAndEvents(status, /*stop_on_psb_change=*/true);
68*81ad6265SDimitry Andric   }
69*81ad6265SDimitry Andric 
70*81ad6265SDimitry Andric private:
71*81ad6265SDimitry Andric   /// Decode all the instructions and events until an error is found, the end
72*81ad6265SDimitry Andric   /// of the trace is reached, or optionally a new PSB is reached.
73*81ad6265SDimitry Andric   ///
74*81ad6265SDimitry Andric   /// \param[in] status
75*81ad6265SDimitry Andric   ///   The status that was result of synchronizing to the most recent PSB.
76*81ad6265SDimitry Andric   ///
77*81ad6265SDimitry Andric   /// \param[in] stop_on_psb_change
78*81ad6265SDimitry Andric   ///   If \b true, decoding stops if a different PSB is reached.
79*81ad6265SDimitry Andric   void DecodeInstructionsAndEvents(int status,
80*81ad6265SDimitry Andric                                    bool stop_on_psb_change = false) {
81*81ad6265SDimitry Andric     uint64_t psb_offset;
82*81ad6265SDimitry Andric     pt_insn_get_sync_offset(&m_decoder,
83*81ad6265SDimitry Andric                             &psb_offset); // this can't fail because we got here
84*81ad6265SDimitry Andric 
85*81ad6265SDimitry Andric     while (ProcessPTEvents(status)) {
86*81ad6265SDimitry Andric       if (stop_on_psb_change) {
87*81ad6265SDimitry Andric         uint64_t cur_psb_offset;
88*81ad6265SDimitry Andric         // this can't fail because we got here
89*81ad6265SDimitry Andric         pt_insn_get_sync_offset(&m_decoder, &cur_psb_offset);
90*81ad6265SDimitry Andric         if (cur_psb_offset != psb_offset)
91*81ad6265SDimitry Andric           break;
92*81ad6265SDimitry Andric       }
93*81ad6265SDimitry Andric 
94*81ad6265SDimitry Andric       // The status returned by pt_insn_next will need to be processed
95*81ad6265SDimitry Andric       // by ProcessPTEvents in the next loop if it is not an error.
96*81ad6265SDimitry Andric       pt_insn insn;
97*81ad6265SDimitry Andric       std::memset(&insn, 0, sizeof insn);
98*81ad6265SDimitry Andric       if (IsLibiptError(status =
99*81ad6265SDimitry Andric                             pt_insn_next(&m_decoder, &insn, sizeof(insn)))) {
100*81ad6265SDimitry Andric         m_decoded_thread.AppendError(IntelPTError(status, insn.ip));
101*81ad6265SDimitry Andric         break;
102*81ad6265SDimitry Andric       }
103*81ad6265SDimitry Andric       m_decoded_thread.AppendInstruction(insn);
104*81ad6265SDimitry Andric     }
105*81ad6265SDimitry Andric   }
106*81ad6265SDimitry Andric 
107*81ad6265SDimitry Andric   /// Move the decoder forward to the next synchronization point (i.e. next PSB
108*81ad6265SDimitry Andric   /// packet).
109*81ad6265SDimitry Andric   ///
110*81ad6265SDimitry Andric   /// Once the decoder is at that synchronization point, it can start decoding
111*81ad6265SDimitry Andric   /// instructions.
112*81ad6265SDimitry Andric   ///
113*81ad6265SDimitry Andric   /// If errors are found, they will be appended to the trace.
114*81ad6265SDimitry Andric   ///
115*81ad6265SDimitry Andric   /// \return
116*81ad6265SDimitry Andric   ///   The libipt decoder status after moving to the next PSB. Negative if
117*81ad6265SDimitry Andric   ///   no PSB was found.
118*81ad6265SDimitry Andric   int FindNextSynchronizationPoint() {
119*81ad6265SDimitry Andric     // Try to sync the decoder. If it fails, then get the decoder_offset and
120*81ad6265SDimitry Andric     // try to sync again from the next synchronization point. If the
121*81ad6265SDimitry Andric     // new_decoder_offset is same as decoder_offset then we can't move to the
122*81ad6265SDimitry Andric     // next synchronization point. Otherwise, keep resyncing until either end
123*81ad6265SDimitry Andric     // of trace stream (eos) is reached or pt_insn_sync_forward() passes.
124*81ad6265SDimitry Andric     int status = pt_insn_sync_forward(&m_decoder);
125*81ad6265SDimitry Andric 
126*81ad6265SDimitry Andric     // We make this call to record any synchronization errors.
127*81ad6265SDimitry Andric     if (IsLibiptError(status))
128*81ad6265SDimitry Andric       m_decoded_thread.AppendError(IntelPTError(status));
129*81ad6265SDimitry Andric 
130*81ad6265SDimitry Andric     return status;
131*81ad6265SDimitry Andric   }
132*81ad6265SDimitry Andric 
133*81ad6265SDimitry Andric   /// Before querying instructions, we need to query the events associated that
134*81ad6265SDimitry Andric   /// instruction e.g. timing events like ptev_tick, or paging events like
135*81ad6265SDimitry Andric   /// ptev_paging.
136*81ad6265SDimitry Andric   ///
137*81ad6265SDimitry Andric   /// \param[in] status
138*81ad6265SDimitry Andric   ///   The status gotten from the previous instruction decoding or PSB
139*81ad6265SDimitry Andric   ///   synchronization.
140*81ad6265SDimitry Andric   ///
141*81ad6265SDimitry Andric   /// \return
142*81ad6265SDimitry Andric   ///   \b true if no errors were found processing the events.
143*81ad6265SDimitry Andric   bool ProcessPTEvents(int status) {
144*81ad6265SDimitry Andric     while (status & pts_event_pending) {
145*81ad6265SDimitry Andric       pt_event event;
146*81ad6265SDimitry Andric       status = pt_insn_event(&m_decoder, &event, sizeof(event));
147*81ad6265SDimitry Andric       if (IsLibiptError(status)) {
148*81ad6265SDimitry Andric         m_decoded_thread.AppendError(IntelPTError(status));
149*81ad6265SDimitry Andric         return false;
150*81ad6265SDimitry Andric       }
151*81ad6265SDimitry Andric 
152*81ad6265SDimitry Andric       if (event.has_tsc)
153*81ad6265SDimitry Andric         m_decoded_thread.NotifyTsc(event.tsc);
154*81ad6265SDimitry Andric 
155*81ad6265SDimitry Andric       switch (event.type) {
156*81ad6265SDimitry Andric       case ptev_enabled:
157*81ad6265SDimitry Andric         // The kernel started or resumed tracing the program.
158*81ad6265SDimitry Andric         break;
159*81ad6265SDimitry Andric       case ptev_disabled:
160*81ad6265SDimitry Andric         // The CPU paused tracing the program, e.g. due to ip filtering.
161*81ad6265SDimitry Andric         m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledHW);
162*81ad6265SDimitry Andric         break;
163*81ad6265SDimitry Andric       case ptev_async_disabled:
164*81ad6265SDimitry Andric         // The kernel or user code paused tracing the program, e.g.
165*81ad6265SDimitry Andric         // a breakpoint or a ioctl invocation pausing the trace, or a
166*81ad6265SDimitry Andric         // context switch happened.
167*81ad6265SDimitry Andric         m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledSW);
168*81ad6265SDimitry Andric         break;
169*81ad6265SDimitry Andric       case ptev_overflow:
170*81ad6265SDimitry Andric         // The CPU internal buffer had an overflow error and some instructions
171*81ad6265SDimitry Andric         // were lost.
172*81ad6265SDimitry Andric         m_decoded_thread.AppendError(IntelPTError(-pte_overflow));
173*81ad6265SDimitry Andric         break;
174*81ad6265SDimitry Andric       default:
175*81ad6265SDimitry Andric         break;
176*81ad6265SDimitry Andric       }
177*81ad6265SDimitry Andric     }
178*81ad6265SDimitry Andric 
179*81ad6265SDimitry Andric     return true;
180*81ad6265SDimitry Andric   }
181*81ad6265SDimitry Andric 
182*81ad6265SDimitry Andric private:
183*81ad6265SDimitry Andric   pt_insn_decoder &m_decoder;
184*81ad6265SDimitry Andric   DecodedThread &m_decoded_thread;
185*81ad6265SDimitry Andric };
186*81ad6265SDimitry Andric 
187*81ad6265SDimitry Andric /// Callback used by libipt for reading the process memory.
188*81ad6265SDimitry Andric ///
189*81ad6265SDimitry Andric /// More information can be found in
190*81ad6265SDimitry Andric /// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md
191*81ad6265SDimitry Andric static int ReadProcessMemory(uint8_t *buffer, size_t size,
192*81ad6265SDimitry Andric                              const pt_asid * /* unused */, uint64_t pc,
193*81ad6265SDimitry Andric                              void *context) {
194*81ad6265SDimitry Andric   Process *process = static_cast<Process *>(context);
195*81ad6265SDimitry Andric 
196*81ad6265SDimitry Andric   Status error;
197*81ad6265SDimitry Andric   int bytes_read = process->ReadMemory(pc, buffer, size, error);
198*81ad6265SDimitry Andric   if (error.Fail())
199*81ad6265SDimitry Andric     return -pte_nomap;
200*81ad6265SDimitry Andric   return bytes_read;
201*81ad6265SDimitry Andric }
202*81ad6265SDimitry Andric 
203*81ad6265SDimitry Andric // RAII deleter for libipt's decoder
204*81ad6265SDimitry Andric auto DecoderDeleter = [](pt_insn_decoder *decoder) {
205*81ad6265SDimitry Andric   pt_insn_free_decoder(decoder);
206*81ad6265SDimitry Andric };
207*81ad6265SDimitry Andric 
208*81ad6265SDimitry Andric using PtInsnDecoderUP =
209*81ad6265SDimitry Andric     std::unique_ptr<pt_insn_decoder, decltype(DecoderDeleter)>;
210*81ad6265SDimitry Andric 
211*81ad6265SDimitry Andric static Expected<PtInsnDecoderUP>
212*81ad6265SDimitry Andric CreateInstructionDecoder(TraceIntelPT &trace_intel_pt,
213*81ad6265SDimitry Andric                          ArrayRef<uint8_t> buffer) {
214*81ad6265SDimitry Andric   Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
215*81ad6265SDimitry Andric   if (!cpu_info)
216*81ad6265SDimitry Andric     return cpu_info.takeError();
217*81ad6265SDimitry Andric 
218*81ad6265SDimitry Andric   pt_config config;
219*81ad6265SDimitry Andric   pt_config_init(&config);
220*81ad6265SDimitry Andric   config.cpu = *cpu_info;
221*81ad6265SDimitry Andric   int status = pte_ok;
222*81ad6265SDimitry Andric 
223*81ad6265SDimitry Andric   if (IsLibiptError(status = pt_cpu_errata(&config.errata, &config.cpu)))
224*81ad6265SDimitry Andric     return make_error<IntelPTError>(status);
225*81ad6265SDimitry Andric 
226*81ad6265SDimitry Andric   // The libipt library does not modify the trace buffer, hence the
227*81ad6265SDimitry Andric   // following casts are safe.
228*81ad6265SDimitry Andric   config.begin = const_cast<uint8_t *>(buffer.data());
229*81ad6265SDimitry Andric   config.end = const_cast<uint8_t *>(buffer.data() + buffer.size());
230*81ad6265SDimitry Andric 
231*81ad6265SDimitry Andric   pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&config);
232*81ad6265SDimitry Andric   if (!decoder_ptr)
233*81ad6265SDimitry Andric     return make_error<IntelPTError>(-pte_nomem);
234*81ad6265SDimitry Andric 
235*81ad6265SDimitry Andric   return PtInsnDecoderUP(decoder_ptr, DecoderDeleter);
236*81ad6265SDimitry Andric }
237*81ad6265SDimitry Andric 
238*81ad6265SDimitry Andric static Error SetupMemoryImage(PtInsnDecoderUP &decoder_up, Process &process) {
239*81ad6265SDimitry Andric   pt_image *image = pt_insn_get_image(decoder_up.get());
240*81ad6265SDimitry Andric 
241*81ad6265SDimitry Andric   int status = pte_ok;
242*81ad6265SDimitry Andric   if (IsLibiptError(
243*81ad6265SDimitry Andric           status = pt_image_set_callback(image, ReadProcessMemory, &process)))
244*81ad6265SDimitry Andric     return make_error<IntelPTError>(status);
245*81ad6265SDimitry Andric   return Error::success();
246*81ad6265SDimitry Andric }
247*81ad6265SDimitry Andric 
248*81ad6265SDimitry Andric Error lldb_private::trace_intel_pt::DecodeSingleTraceForThread(
249*81ad6265SDimitry Andric     DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
250*81ad6265SDimitry Andric     ArrayRef<uint8_t> buffer) {
251*81ad6265SDimitry Andric   Expected<PtInsnDecoderUP> decoder_up =
252*81ad6265SDimitry Andric       CreateInstructionDecoder(trace_intel_pt, buffer);
253*81ad6265SDimitry Andric   if (!decoder_up)
254*81ad6265SDimitry Andric     return decoder_up.takeError();
255*81ad6265SDimitry Andric 
256*81ad6265SDimitry Andric   if (Error err = SetupMemoryImage(*decoder_up,
257*81ad6265SDimitry Andric                                    *decoded_thread.GetThread()->GetProcess()))
258*81ad6265SDimitry Andric     return err;
259*81ad6265SDimitry Andric 
260*81ad6265SDimitry Andric   LibiptDecoder libipt_decoder(*decoder_up.get(), decoded_thread);
261*81ad6265SDimitry Andric   libipt_decoder.DecodeUntilEndOfTrace();
262*81ad6265SDimitry Andric   return Error::success();
263*81ad6265SDimitry Andric }
264*81ad6265SDimitry Andric 
265*81ad6265SDimitry Andric Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
266*81ad6265SDimitry Andric     DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
267*81ad6265SDimitry Andric     const DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> &buffers,
268*81ad6265SDimitry Andric     const std::vector<IntelPTThreadContinousExecution> &executions) {
269*81ad6265SDimitry Andric   DenseMap<lldb::cpu_id_t, LibiptDecoder> decoders;
270*81ad6265SDimitry Andric   for (auto &cpu_id_buffer : buffers) {
271*81ad6265SDimitry Andric     Expected<PtInsnDecoderUP> decoder_up =
272*81ad6265SDimitry Andric         CreateInstructionDecoder(trace_intel_pt, cpu_id_buffer.second);
273*81ad6265SDimitry Andric     if (!decoder_up)
274*81ad6265SDimitry Andric       return decoder_up.takeError();
275*81ad6265SDimitry Andric 
276*81ad6265SDimitry Andric     if (Error err = SetupMemoryImage(*decoder_up,
277*81ad6265SDimitry Andric                                      *decoded_thread.GetThread()->GetProcess()))
278*81ad6265SDimitry Andric       return err;
279*81ad6265SDimitry Andric 
280*81ad6265SDimitry Andric     decoders.try_emplace(cpu_id_buffer.first,
281*81ad6265SDimitry Andric                          LibiptDecoder(*decoder_up->release(), decoded_thread));
282*81ad6265SDimitry Andric   }
283*81ad6265SDimitry Andric 
284*81ad6265SDimitry Andric   bool has_seen_psbs = false;
285*81ad6265SDimitry Andric   for (size_t i = 0; i < executions.size(); i++) {
286*81ad6265SDimitry Andric     const IntelPTThreadContinousExecution &execution = executions[i];
287*81ad6265SDimitry Andric 
288*81ad6265SDimitry Andric     auto variant = execution.thread_execution.variant;
289*81ad6265SDimitry Andric     // If we haven't seen a PSB yet, then it's fine not to show errors
290*81ad6265SDimitry Andric     if (has_seen_psbs) {
291*81ad6265SDimitry Andric       if (execution.intelpt_subtraces.empty()) {
292*81ad6265SDimitry Andric         decoded_thread.AppendCustomError(
293*81ad6265SDimitry Andric             formatv("Unable to find intel pt data for thread "
294*81ad6265SDimitry Andric                     "execution on cpu id = {0}",
295*81ad6265SDimitry Andric                     execution.thread_execution.cpu_id)
296*81ad6265SDimitry Andric                 .str());
297*81ad6265SDimitry Andric       }
298*81ad6265SDimitry Andric 
299*81ad6265SDimitry Andric       // If the first execution is incomplete because it doesn't have a previous
300*81ad6265SDimitry Andric       // context switch in its cpu, all good.
301*81ad6265SDimitry Andric       if (variant == ThreadContinuousExecution::Variant::OnlyEnd ||
302*81ad6265SDimitry Andric           variant == ThreadContinuousExecution::Variant::HintedStart) {
303*81ad6265SDimitry Andric         decoded_thread.AppendCustomError(
304*81ad6265SDimitry Andric             formatv("Thread execution starting on cpu id = {0} doesn't "
305*81ad6265SDimitry Andric                     "have a matching context switch in.",
306*81ad6265SDimitry Andric                     execution.thread_execution.cpu_id)
307*81ad6265SDimitry Andric                 .str());
308*81ad6265SDimitry Andric       }
309*81ad6265SDimitry Andric     }
310*81ad6265SDimitry Andric 
311*81ad6265SDimitry Andric     LibiptDecoder &decoder =
312*81ad6265SDimitry Andric         decoders.find(execution.thread_execution.cpu_id)->second;
313*81ad6265SDimitry Andric     for (const IntelPTThreadSubtrace &intel_pt_execution :
314*81ad6265SDimitry Andric          execution.intelpt_subtraces) {
315*81ad6265SDimitry Andric       has_seen_psbs = true;
316*81ad6265SDimitry Andric       decoder.DecodePSB(intel_pt_execution.psb_offset);
317*81ad6265SDimitry Andric     }
318*81ad6265SDimitry Andric 
319*81ad6265SDimitry Andric     // If we haven't seen a PSB yet, then it's fine not to show errors
320*81ad6265SDimitry Andric     if (has_seen_psbs) {
321*81ad6265SDimitry Andric       // If the last execution is incomplete because it doesn't have a following
322*81ad6265SDimitry Andric       // context switch in its cpu, all good.
323*81ad6265SDimitry Andric       if ((variant == ThreadContinuousExecution::Variant::OnlyStart &&
324*81ad6265SDimitry Andric            i + 1 != executions.size()) ||
325*81ad6265SDimitry Andric           variant == ThreadContinuousExecution::Variant::HintedEnd) {
326*81ad6265SDimitry Andric         decoded_thread.AppendCustomError(
327*81ad6265SDimitry Andric             formatv("Thread execution on cpu id = {0} doesn't have a "
328*81ad6265SDimitry Andric                     "matching context switch out",
329*81ad6265SDimitry Andric                     execution.thread_execution.cpu_id)
330*81ad6265SDimitry Andric                 .str());
331*81ad6265SDimitry Andric       }
332*81ad6265SDimitry Andric     }
333*81ad6265SDimitry Andric   }
334*81ad6265SDimitry Andric   return Error::success();
335*81ad6265SDimitry Andric }
336*81ad6265SDimitry Andric 
337*81ad6265SDimitry Andric bool IntelPTThreadContinousExecution::operator<(
338*81ad6265SDimitry Andric     const IntelPTThreadContinousExecution &o) const {
339*81ad6265SDimitry Andric   // As the context switch might be incomplete, we look first for the first real
340*81ad6265SDimitry Andric   // PSB packet, which is a valid TSC. Otherwise, We query the thread execution
341*81ad6265SDimitry Andric   // itself for some tsc.
342*81ad6265SDimitry Andric   auto get_tsc = [](const IntelPTThreadContinousExecution &exec) {
343*81ad6265SDimitry Andric     return exec.intelpt_subtraces.empty()
344*81ad6265SDimitry Andric                ? exec.thread_execution.GetLowestKnownTSC()
345*81ad6265SDimitry Andric                : exec.intelpt_subtraces.front().tsc;
346*81ad6265SDimitry Andric   };
347*81ad6265SDimitry Andric 
348*81ad6265SDimitry Andric   return get_tsc(*this) < get_tsc(o);
349*81ad6265SDimitry Andric }
350*81ad6265SDimitry Andric 
351*81ad6265SDimitry Andric Expected<std::vector<IntelPTThreadSubtrace>>
352*81ad6265SDimitry Andric lldb_private::trace_intel_pt::SplitTraceInContinuousExecutions(
353*81ad6265SDimitry Andric     TraceIntelPT &trace_intel_pt, llvm::ArrayRef<uint8_t> buffer) {
354*81ad6265SDimitry Andric   Expected<PtInsnDecoderUP> decoder_up =
355*81ad6265SDimitry Andric       CreateInstructionDecoder(trace_intel_pt, buffer);
356*81ad6265SDimitry Andric   if (!decoder_up)
357*81ad6265SDimitry Andric     return decoder_up.takeError();
358*81ad6265SDimitry Andric 
359*81ad6265SDimitry Andric   pt_insn_decoder *decoder = decoder_up.get().get();
360*81ad6265SDimitry Andric 
361*81ad6265SDimitry Andric   std::vector<IntelPTThreadSubtrace> executions;
362*81ad6265SDimitry Andric 
363*81ad6265SDimitry Andric   int status = pte_ok;
364*81ad6265SDimitry Andric   while (!IsLibiptError(status = pt_insn_sync_forward(decoder))) {
365*81ad6265SDimitry Andric     uint64_t tsc;
366*81ad6265SDimitry Andric     if (IsLibiptError(pt_insn_time(decoder, &tsc, nullptr, nullptr)))
367*81ad6265SDimitry Andric       return createStringError(inconvertibleErrorCode(),
368*81ad6265SDimitry Andric                                "intel pt trace doesn't have TSC timestamps");
369*81ad6265SDimitry Andric 
370*81ad6265SDimitry Andric     uint64_t psb_offset;
371*81ad6265SDimitry Andric     pt_insn_get_sync_offset(decoder,
372*81ad6265SDimitry Andric                             &psb_offset); // this can't fail because we got here
373*81ad6265SDimitry Andric 
374*81ad6265SDimitry Andric     executions.push_back({
375*81ad6265SDimitry Andric         psb_offset,
376*81ad6265SDimitry Andric         tsc,
377*81ad6265SDimitry Andric     });
378*81ad6265SDimitry Andric   }
379*81ad6265SDimitry Andric   return executions;
380*81ad6265SDimitry Andric }
381