1*f6aab3d8Srobert //===-- LibiptDecoder.cpp --======-----------------------------------------===//
2*f6aab3d8Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3*f6aab3d8Srobert // See https://llvm.org/LICENSE.txt for license information.
4*f6aab3d8Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5*f6aab3d8Srobert //
6*f6aab3d8Srobert //===----------------------------------------------------------------------===//
7*f6aab3d8Srobert 
8*f6aab3d8Srobert #include "LibiptDecoder.h"
9*f6aab3d8Srobert #include "TraceIntelPT.h"
10*f6aab3d8Srobert #include "lldb/Target/Process.h"
11*f6aab3d8Srobert #include <optional>
12*f6aab3d8Srobert 
13*f6aab3d8Srobert using namespace lldb;
14*f6aab3d8Srobert using namespace lldb_private;
15*f6aab3d8Srobert using namespace lldb_private::trace_intel_pt;
16*f6aab3d8Srobert using namespace llvm;
17*f6aab3d8Srobert 
IsLibiptError(int status)18*f6aab3d8Srobert bool IsLibiptError(int status) { return status < 0; }
19*f6aab3d8Srobert 
IsEndOfStream(int status)20*f6aab3d8Srobert bool IsEndOfStream(int status) {
21*f6aab3d8Srobert   assert(status >= 0 && "We can't check if we reached the end of the stream if "
22*f6aab3d8Srobert                         "we got a failed status");
23*f6aab3d8Srobert   return status & pts_eos;
24*f6aab3d8Srobert }
25*f6aab3d8Srobert 
HasEvents(int status)26*f6aab3d8Srobert bool HasEvents(int status) {
27*f6aab3d8Srobert   assert(status >= 0 && "We can't check for events if we got a failed status");
28*f6aab3d8Srobert   return status & pts_event_pending;
29*f6aab3d8Srobert }
30*f6aab3d8Srobert 
31*f6aab3d8Srobert // RAII deleter for libipt's decoders
__anon9d18f15f0102(pt_insn_decoder *decoder) 32*f6aab3d8Srobert auto InsnDecoderDeleter = [](pt_insn_decoder *decoder) {
33*f6aab3d8Srobert   pt_insn_free_decoder(decoder);
34*f6aab3d8Srobert };
35*f6aab3d8Srobert 
__anon9d18f15f0202(pt_query_decoder *decoder) 36*f6aab3d8Srobert auto QueryDecoderDeleter = [](pt_query_decoder *decoder) {
37*f6aab3d8Srobert   pt_qry_free_decoder(decoder);
38*f6aab3d8Srobert };
39*f6aab3d8Srobert 
40*f6aab3d8Srobert using PtInsnDecoderUP =
41*f6aab3d8Srobert     std::unique_ptr<pt_insn_decoder, decltype(InsnDecoderDeleter)>;
42*f6aab3d8Srobert 
43*f6aab3d8Srobert using PtQueryDecoderUP =
44*f6aab3d8Srobert     std::unique_ptr<pt_query_decoder, decltype(QueryDecoderDeleter)>;
45*f6aab3d8Srobert 
46*f6aab3d8Srobert /// Create a basic configuration object limited to a given buffer that can be
47*f6aab3d8Srobert /// used for many different decoders.
CreateBasicLibiptConfig(TraceIntelPT & trace_intel_pt,ArrayRef<uint8_t> buffer)48*f6aab3d8Srobert static Expected<pt_config> CreateBasicLibiptConfig(TraceIntelPT &trace_intel_pt,
49*f6aab3d8Srobert                                                    ArrayRef<uint8_t> buffer) {
50*f6aab3d8Srobert   Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
51*f6aab3d8Srobert   if (!cpu_info)
52*f6aab3d8Srobert     return cpu_info.takeError();
53*f6aab3d8Srobert 
54*f6aab3d8Srobert   pt_config config;
55*f6aab3d8Srobert   pt_config_init(&config);
56*f6aab3d8Srobert   config.cpu = *cpu_info;
57*f6aab3d8Srobert 
58*f6aab3d8Srobert   int status = pt_cpu_errata(&config.errata, &config.cpu);
59*f6aab3d8Srobert   if (IsLibiptError(status))
60*f6aab3d8Srobert     return make_error<IntelPTError>(status);
61*f6aab3d8Srobert 
62*f6aab3d8Srobert   // The libipt library does not modify the trace buffer, hence the
63*f6aab3d8Srobert   // following casts are safe.
64*f6aab3d8Srobert   config.begin = const_cast<uint8_t *>(buffer.data());
65*f6aab3d8Srobert   config.end = const_cast<uint8_t *>(buffer.data() + buffer.size());
66*f6aab3d8Srobert   return config;
67*f6aab3d8Srobert }
68*f6aab3d8Srobert 
69*f6aab3d8Srobert /// Callback used by libipt for reading the process memory.
70*f6aab3d8Srobert ///
71*f6aab3d8Srobert /// More information can be found in
72*f6aab3d8Srobert /// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md
ReadProcessMemory(uint8_t * buffer,size_t size,const pt_asid *,uint64_t pc,void * context)73*f6aab3d8Srobert static int ReadProcessMemory(uint8_t *buffer, size_t size,
74*f6aab3d8Srobert                              const pt_asid * /* unused */, uint64_t pc,
75*f6aab3d8Srobert                              void *context) {
76*f6aab3d8Srobert   Process *process = static_cast<Process *>(context);
77*f6aab3d8Srobert 
78*f6aab3d8Srobert   Status error;
79*f6aab3d8Srobert   int bytes_read = process->ReadMemory(pc, buffer, size, error);
80*f6aab3d8Srobert   if (error.Fail())
81*f6aab3d8Srobert     return -pte_nomap;
82*f6aab3d8Srobert   return bytes_read;
83*f6aab3d8Srobert }
84*f6aab3d8Srobert 
85*f6aab3d8Srobert /// Set up the memory image callback for the given decoder.
SetupMemoryImage(pt_insn_decoder * decoder,Process & process)86*f6aab3d8Srobert static Error SetupMemoryImage(pt_insn_decoder *decoder, Process &process) {
87*f6aab3d8Srobert   pt_image *image = pt_insn_get_image(decoder);
88*f6aab3d8Srobert 
89*f6aab3d8Srobert   int status = pt_image_set_callback(image, ReadProcessMemory, &process);
90*f6aab3d8Srobert   if (IsLibiptError(status))
91*f6aab3d8Srobert     return make_error<IntelPTError>(status);
92*f6aab3d8Srobert   return Error::success();
93*f6aab3d8Srobert }
94*f6aab3d8Srobert 
95*f6aab3d8Srobert /// Create an instruction decoder for the given buffer and the given process.
96*f6aab3d8Srobert static Expected<PtInsnDecoderUP>
CreateInstructionDecoder(TraceIntelPT & trace_intel_pt,ArrayRef<uint8_t> buffer,Process & process)97*f6aab3d8Srobert CreateInstructionDecoder(TraceIntelPT &trace_intel_pt, ArrayRef<uint8_t> buffer,
98*f6aab3d8Srobert                          Process &process) {
99*f6aab3d8Srobert   Expected<pt_config> config = CreateBasicLibiptConfig(trace_intel_pt, buffer);
100*f6aab3d8Srobert   if (!config)
101*f6aab3d8Srobert     return config.takeError();
102*f6aab3d8Srobert 
103*f6aab3d8Srobert   pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&*config);
104*f6aab3d8Srobert   if (!decoder_ptr)
105*f6aab3d8Srobert     return make_error<IntelPTError>(-pte_nomem);
106*f6aab3d8Srobert 
107*f6aab3d8Srobert   PtInsnDecoderUP decoder_up(decoder_ptr, InsnDecoderDeleter);
108*f6aab3d8Srobert 
109*f6aab3d8Srobert   if (Error err = SetupMemoryImage(decoder_ptr, process))
110*f6aab3d8Srobert     return std::move(err);
111*f6aab3d8Srobert 
112*f6aab3d8Srobert   return decoder_up;
113*f6aab3d8Srobert }
114*f6aab3d8Srobert 
115*f6aab3d8Srobert /// Create a query decoder for the given buffer. The query decoder is the
116*f6aab3d8Srobert /// highest level decoder that operates directly on packets and doesn't perform
117*f6aab3d8Srobert /// actual instruction decoding. That's why it can be useful for inspecting a
118*f6aab3d8Srobert /// raw trace without pinning it to a particular process.
119*f6aab3d8Srobert static Expected<PtQueryDecoderUP>
CreateQueryDecoder(TraceIntelPT & trace_intel_pt,ArrayRef<uint8_t> buffer)120*f6aab3d8Srobert CreateQueryDecoder(TraceIntelPT &trace_intel_pt, ArrayRef<uint8_t> buffer) {
121*f6aab3d8Srobert   Expected<pt_config> config = CreateBasicLibiptConfig(trace_intel_pt, buffer);
122*f6aab3d8Srobert   if (!config)
123*f6aab3d8Srobert     return config.takeError();
124*f6aab3d8Srobert 
125*f6aab3d8Srobert   pt_query_decoder *decoder_ptr = pt_qry_alloc_decoder(&*config);
126*f6aab3d8Srobert   if (!decoder_ptr)
127*f6aab3d8Srobert     return make_error<IntelPTError>(-pte_nomem);
128*f6aab3d8Srobert 
129*f6aab3d8Srobert   return PtQueryDecoderUP(decoder_ptr, QueryDecoderDeleter);
130*f6aab3d8Srobert }
131*f6aab3d8Srobert 
132*f6aab3d8Srobert /// Class used to identify anomalies in traces, which should often indicate a
133*f6aab3d8Srobert /// fatal error in the trace.
134*f6aab3d8Srobert class PSBBlockAnomalyDetector {
135*f6aab3d8Srobert public:
PSBBlockAnomalyDetector(pt_insn_decoder & decoder,TraceIntelPT & trace_intel_pt,DecodedThread & decoded_thread)136*f6aab3d8Srobert   PSBBlockAnomalyDetector(pt_insn_decoder &decoder,
137*f6aab3d8Srobert                           TraceIntelPT &trace_intel_pt,
138*f6aab3d8Srobert                           DecodedThread &decoded_thread)
139*f6aab3d8Srobert       : m_decoder(decoder), m_decoded_thread(decoded_thread) {
140*f6aab3d8Srobert     m_infinite_decoding_loop_threshold =
141*f6aab3d8Srobert         trace_intel_pt.GetGlobalProperties()
142*f6aab3d8Srobert             .GetInfiniteDecodingLoopVerificationThreshold();
143*f6aab3d8Srobert     m_extremely_large_decoding_threshold =
144*f6aab3d8Srobert         trace_intel_pt.GetGlobalProperties()
145*f6aab3d8Srobert             .GetExtremelyLargeDecodingThreshold();
146*f6aab3d8Srobert     m_next_infinite_decoding_loop_threshold =
147*f6aab3d8Srobert         m_infinite_decoding_loop_threshold;
148*f6aab3d8Srobert   }
149*f6aab3d8Srobert 
150*f6aab3d8Srobert   /// \return
151*f6aab3d8Srobert   ///   An \a llvm::Error if an anomaly that includes the last instruction item
152*f6aab3d8Srobert   ///   in the trace, or \a llvm::Error::success otherwise.
DetectAnomaly()153*f6aab3d8Srobert   Error DetectAnomaly() {
154*f6aab3d8Srobert     RefreshPacketOffset();
155*f6aab3d8Srobert     uint64_t insn_added_since_last_packet_offset =
156*f6aab3d8Srobert         m_decoded_thread.GetTotalInstructionCount() -
157*f6aab3d8Srobert         m_insn_count_at_last_packet_offset;
158*f6aab3d8Srobert 
159*f6aab3d8Srobert     // We want to check if we might have fallen in an infinite loop. As this
160*f6aab3d8Srobert     // check is not a no-op, we want to do it when we have a strong suggestion
161*f6aab3d8Srobert     // that things went wrong. First, we check how many instructions we have
162*f6aab3d8Srobert     // decoded since we processed an Intel PT packet for the last time. This
163*f6aab3d8Srobert     // number should be low, because at some point we should see branches, jumps
164*f6aab3d8Srobert     // or interrupts that require a new packet to be processed. Once we reach
165*f6aab3d8Srobert     // certain threshold we start analyzing the trace.
166*f6aab3d8Srobert     //
167*f6aab3d8Srobert     // We use the number of decoded instructions since the last Intel PT packet
168*f6aab3d8Srobert     // as a proxy because, in fact, we don't expect a single packet to give,
169*f6aab3d8Srobert     // say, 100k instructions. That would mean that there are 100k sequential
170*f6aab3d8Srobert     // instructions without any single branch, which is highly unlikely, or that
171*f6aab3d8Srobert     // we found an infinite loop using direct jumps, e.g.
172*f6aab3d8Srobert     //
173*f6aab3d8Srobert     //   0x0A: nop or pause
174*f6aab3d8Srobert     //   0x0C: jump to 0x0A
175*f6aab3d8Srobert     //
176*f6aab3d8Srobert     // which is indeed code that is found in the kernel. I presume we reach
177*f6aab3d8Srobert     // this kind of code in the decoder because we don't handle self-modified
178*f6aab3d8Srobert     // code in post-mortem kernel traces.
179*f6aab3d8Srobert     //
180*f6aab3d8Srobert     // We are right now only signaling the anomaly as a trace error, but it
181*f6aab3d8Srobert     // would be more conservative to also discard all the trace items found in
182*f6aab3d8Srobert     // this PSB. I prefer not to do that for the time being to give more
183*f6aab3d8Srobert     // exposure to this kind of anomalies and help debugging. Discarding the
184*f6aab3d8Srobert     // trace items would just make investigation harded.
185*f6aab3d8Srobert     //
186*f6aab3d8Srobert     // Finally, if the user wants to see if a specific thread has an anomaly,
187*f6aab3d8Srobert     // it's enough to run the `thread trace dump info` command and look for the
188*f6aab3d8Srobert     // count of this kind of errors.
189*f6aab3d8Srobert 
190*f6aab3d8Srobert     if (insn_added_since_last_packet_offset >=
191*f6aab3d8Srobert         m_extremely_large_decoding_threshold) {
192*f6aab3d8Srobert       // In this case, we have decoded a massive amount of sequential
193*f6aab3d8Srobert       // instructions that don't loop. Honestly I wonder if this will ever
194*f6aab3d8Srobert       // happen, but better safe than sorry.
195*f6aab3d8Srobert       return createStringError(
196*f6aab3d8Srobert           inconvertibleErrorCode(),
197*f6aab3d8Srobert           "anomalous trace: possible infinite trace detected");
198*f6aab3d8Srobert     }
199*f6aab3d8Srobert     if (insn_added_since_last_packet_offset ==
200*f6aab3d8Srobert         m_next_infinite_decoding_loop_threshold) {
201*f6aab3d8Srobert       if (std::optional<uint64_t> loop_size = TryIdentifyInfiniteLoop()) {
202*f6aab3d8Srobert         return createStringError(
203*f6aab3d8Srobert             inconvertibleErrorCode(),
204*f6aab3d8Srobert             "anomalous trace: possible infinite loop detected of size %" PRIu64,
205*f6aab3d8Srobert             *loop_size);
206*f6aab3d8Srobert       }
207*f6aab3d8Srobert       m_next_infinite_decoding_loop_threshold *= 2;
208*f6aab3d8Srobert     }
209*f6aab3d8Srobert     return Error::success();
210*f6aab3d8Srobert   }
211*f6aab3d8Srobert 
212*f6aab3d8Srobert private:
TryIdentifyInfiniteLoop()213*f6aab3d8Srobert   std::optional<uint64_t> TryIdentifyInfiniteLoop() {
214*f6aab3d8Srobert     // The infinite decoding loops we'll encounter are due to sequential
215*f6aab3d8Srobert     // instructions that repeat themselves due to direct jumps, therefore in a
216*f6aab3d8Srobert     // cycle each individual address will only appear once. We use this
217*f6aab3d8Srobert     // information to detect cycles by finding the last 2 ocurrences of the last
218*f6aab3d8Srobert     // instruction added to the trace. Then we traverse the trace making sure
219*f6aab3d8Srobert     // that these two instructions where the ends of a repeating loop.
220*f6aab3d8Srobert 
221*f6aab3d8Srobert     // This is a utility that returns the most recent instruction index given a
222*f6aab3d8Srobert     // position in the trace. If the given position is an instruction, that
223*f6aab3d8Srobert     // position is returned. It skips non-instruction items.
224*f6aab3d8Srobert     auto most_recent_insn_index =
225*f6aab3d8Srobert         [&](uint64_t item_index) -> std::optional<uint64_t> {
226*f6aab3d8Srobert       while (true) {
227*f6aab3d8Srobert         if (m_decoded_thread.GetItemKindByIndex(item_index) ==
228*f6aab3d8Srobert             lldb::eTraceItemKindInstruction) {
229*f6aab3d8Srobert           return item_index;
230*f6aab3d8Srobert         }
231*f6aab3d8Srobert         if (item_index == 0)
232*f6aab3d8Srobert           return std::nullopt;
233*f6aab3d8Srobert         item_index--;
234*f6aab3d8Srobert       }
235*f6aab3d8Srobert       return std::nullopt;
236*f6aab3d8Srobert     };
237*f6aab3d8Srobert     // Similar to most_recent_insn_index but skips the starting position.
238*f6aab3d8Srobert     auto prev_insn_index = [&](uint64_t item_index) -> std::optional<uint64_t> {
239*f6aab3d8Srobert       if (item_index == 0)
240*f6aab3d8Srobert         return std::nullopt;
241*f6aab3d8Srobert       return most_recent_insn_index(item_index - 1);
242*f6aab3d8Srobert     };
243*f6aab3d8Srobert 
244*f6aab3d8Srobert     // We first find the most recent instruction.
245*f6aab3d8Srobert     std::optional<uint64_t> last_insn_index_opt =
246*f6aab3d8Srobert         *prev_insn_index(m_decoded_thread.GetItemsCount());
247*f6aab3d8Srobert     if (!last_insn_index_opt)
248*f6aab3d8Srobert       return std::nullopt;
249*f6aab3d8Srobert     uint64_t last_insn_index = *last_insn_index_opt;
250*f6aab3d8Srobert 
251*f6aab3d8Srobert     // We then find the most recent previous occurrence of that last
252*f6aab3d8Srobert     // instruction.
253*f6aab3d8Srobert     std::optional<uint64_t> last_insn_copy_index =
254*f6aab3d8Srobert         prev_insn_index(last_insn_index);
255*f6aab3d8Srobert     uint64_t loop_size = 1;
256*f6aab3d8Srobert     while (last_insn_copy_index &&
257*f6aab3d8Srobert            m_decoded_thread.GetInstructionLoadAddress(*last_insn_copy_index) !=
258*f6aab3d8Srobert                m_decoded_thread.GetInstructionLoadAddress(last_insn_index)) {
259*f6aab3d8Srobert       last_insn_copy_index = prev_insn_index(*last_insn_copy_index);
260*f6aab3d8Srobert       loop_size++;
261*f6aab3d8Srobert     }
262*f6aab3d8Srobert     if (!last_insn_copy_index)
263*f6aab3d8Srobert       return std::nullopt;
264*f6aab3d8Srobert 
265*f6aab3d8Srobert     // Now we check if the segment between these last positions of the last
266*f6aab3d8Srobert     // instruction address is in fact a repeating loop.
267*f6aab3d8Srobert     uint64_t loop_elements_visited = 1;
268*f6aab3d8Srobert     uint64_t insn_index_a = last_insn_index,
269*f6aab3d8Srobert              insn_index_b = *last_insn_copy_index;
270*f6aab3d8Srobert     while (loop_elements_visited < loop_size) {
271*f6aab3d8Srobert       if (std::optional<uint64_t> prev = prev_insn_index(insn_index_a))
272*f6aab3d8Srobert         insn_index_a = *prev;
273*f6aab3d8Srobert       else
274*f6aab3d8Srobert         return std::nullopt;
275*f6aab3d8Srobert       if (std::optional<uint64_t> prev = prev_insn_index(insn_index_b))
276*f6aab3d8Srobert         insn_index_b = *prev;
277*f6aab3d8Srobert       else
278*f6aab3d8Srobert         return std::nullopt;
279*f6aab3d8Srobert       if (m_decoded_thread.GetInstructionLoadAddress(insn_index_a) !=
280*f6aab3d8Srobert           m_decoded_thread.GetInstructionLoadAddress(insn_index_b))
281*f6aab3d8Srobert         return std::nullopt;
282*f6aab3d8Srobert       loop_elements_visited++;
283*f6aab3d8Srobert     }
284*f6aab3d8Srobert     return loop_size;
285*f6aab3d8Srobert   }
286*f6aab3d8Srobert 
287*f6aab3d8Srobert   // Refresh the internal counters if a new packet offset has been visited
RefreshPacketOffset()288*f6aab3d8Srobert   void RefreshPacketOffset() {
289*f6aab3d8Srobert     lldb::addr_t new_packet_offset;
290*f6aab3d8Srobert     if (!IsLibiptError(pt_insn_get_offset(&m_decoder, &new_packet_offset)) &&
291*f6aab3d8Srobert         new_packet_offset != m_last_packet_offset) {
292*f6aab3d8Srobert       m_last_packet_offset = new_packet_offset;
293*f6aab3d8Srobert       m_next_infinite_decoding_loop_threshold =
294*f6aab3d8Srobert           m_infinite_decoding_loop_threshold;
295*f6aab3d8Srobert       m_insn_count_at_last_packet_offset =
296*f6aab3d8Srobert           m_decoded_thread.GetTotalInstructionCount();
297*f6aab3d8Srobert     }
298*f6aab3d8Srobert   }
299*f6aab3d8Srobert 
300*f6aab3d8Srobert   pt_insn_decoder &m_decoder;
301*f6aab3d8Srobert   DecodedThread &m_decoded_thread;
302*f6aab3d8Srobert   lldb::addr_t m_last_packet_offset = LLDB_INVALID_ADDRESS;
303*f6aab3d8Srobert   uint64_t m_insn_count_at_last_packet_offset = 0;
304*f6aab3d8Srobert   uint64_t m_infinite_decoding_loop_threshold;
305*f6aab3d8Srobert   uint64_t m_next_infinite_decoding_loop_threshold;
306*f6aab3d8Srobert   uint64_t m_extremely_large_decoding_threshold;
307*f6aab3d8Srobert };
308*f6aab3d8Srobert 
309*f6aab3d8Srobert /// Class that decodes a raw buffer for a single PSB block using the low level
310*f6aab3d8Srobert /// libipt library. It assumes that kernel and user mode instructions are not
311*f6aab3d8Srobert /// mixed in the same PSB block.
312*f6aab3d8Srobert ///
313*f6aab3d8Srobert /// Throughout this code, the status of the decoder will be used to identify
314*f6aab3d8Srobert /// events needed to be processed or errors in the decoder. The values can be
315*f6aab3d8Srobert /// - negative: actual errors
316*f6aab3d8Srobert /// - positive or zero: not an error, but a list of bits signaling the status
317*f6aab3d8Srobert /// of the decoder, e.g. whether there are events that need to be decoded or
318*f6aab3d8Srobert /// not.
319*f6aab3d8Srobert class PSBBlockDecoder {
320*f6aab3d8Srobert public:
321*f6aab3d8Srobert   /// \param[in] decoder
322*f6aab3d8Srobert   ///     A decoder configured to start and end within the boundaries of the
323*f6aab3d8Srobert   ///     given \p psb_block.
324*f6aab3d8Srobert   ///
325*f6aab3d8Srobert   /// \param[in] psb_block
326*f6aab3d8Srobert   ///     The PSB block to decode.
327*f6aab3d8Srobert   ///
328*f6aab3d8Srobert   /// \param[in] next_block_ip
329*f6aab3d8Srobert   ///     The starting ip at the next PSB block of the same thread if available.
330*f6aab3d8Srobert   ///
331*f6aab3d8Srobert   /// \param[in] decoded_thread
332*f6aab3d8Srobert   ///     A \a DecodedThread object where the decoded instructions will be
333*f6aab3d8Srobert   ///     appended to. It might have already some instructions.
334*f6aab3d8Srobert   ///
335*f6aab3d8Srobert   /// \param[in] tsc_upper_bound
336*f6aab3d8Srobert   ///   Maximum allowed value of TSCs decoded from this PSB block.
337*f6aab3d8Srobert   ///   Any of this PSB's data occurring after this TSC will be excluded.
PSBBlockDecoder(PtInsnDecoderUP && decoder_up,const PSBBlock & psb_block,std::optional<lldb::addr_t> next_block_ip,DecodedThread & decoded_thread,TraceIntelPT & trace_intel_pt,std::optional<DecodedThread::TSC> tsc_upper_bound)338*f6aab3d8Srobert   PSBBlockDecoder(PtInsnDecoderUP &&decoder_up, const PSBBlock &psb_block,
339*f6aab3d8Srobert                   std::optional<lldb::addr_t> next_block_ip,
340*f6aab3d8Srobert                   DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
341*f6aab3d8Srobert                   std::optional<DecodedThread::TSC> tsc_upper_bound)
342*f6aab3d8Srobert       : m_decoder_up(std::move(decoder_up)), m_psb_block(psb_block),
343*f6aab3d8Srobert         m_next_block_ip(next_block_ip), m_decoded_thread(decoded_thread),
344*f6aab3d8Srobert         m_anomaly_detector(*m_decoder_up, trace_intel_pt, decoded_thread),
345*f6aab3d8Srobert         m_tsc_upper_bound(tsc_upper_bound) {}
346*f6aab3d8Srobert 
347*f6aab3d8Srobert   /// \param[in] trace_intel_pt
348*f6aab3d8Srobert   ///     The main Trace object that own the PSB block.
349*f6aab3d8Srobert   ///
350*f6aab3d8Srobert   /// \param[in] decoder
351*f6aab3d8Srobert   ///     A decoder configured to start and end within the boundaries of the
352*f6aab3d8Srobert   ///     given \p psb_block.
353*f6aab3d8Srobert   ///
354*f6aab3d8Srobert   /// \param[in] psb_block
355*f6aab3d8Srobert   ///     The PSB block to decode.
356*f6aab3d8Srobert   ///
357*f6aab3d8Srobert   /// \param[in] buffer
358*f6aab3d8Srobert   ///     The raw intel pt trace for this block.
359*f6aab3d8Srobert   ///
360*f6aab3d8Srobert   /// \param[in] process
361*f6aab3d8Srobert   ///     The process to decode. It provides the memory image to use for
362*f6aab3d8Srobert   ///     decoding.
363*f6aab3d8Srobert   ///
364*f6aab3d8Srobert   /// \param[in] next_block_ip
365*f6aab3d8Srobert   ///     The starting ip at the next PSB block of the same thread if available.
366*f6aab3d8Srobert   ///
367*f6aab3d8Srobert   /// \param[in] decoded_thread
368*f6aab3d8Srobert   ///     A \a DecodedThread object where the decoded instructions will be
369*f6aab3d8Srobert   ///     appended to. It might have already some instructions.
370*f6aab3d8Srobert   static Expected<PSBBlockDecoder>
Create(TraceIntelPT & trace_intel_pt,const PSBBlock & psb_block,ArrayRef<uint8_t> buffer,Process & process,std::optional<lldb::addr_t> next_block_ip,DecodedThread & decoded_thread,std::optional<DecodedThread::TSC> tsc_upper_bound)371*f6aab3d8Srobert   Create(TraceIntelPT &trace_intel_pt, const PSBBlock &psb_block,
372*f6aab3d8Srobert          ArrayRef<uint8_t> buffer, Process &process,
373*f6aab3d8Srobert          std::optional<lldb::addr_t> next_block_ip,
374*f6aab3d8Srobert          DecodedThread &decoded_thread,
375*f6aab3d8Srobert          std::optional<DecodedThread::TSC> tsc_upper_bound) {
376*f6aab3d8Srobert     Expected<PtInsnDecoderUP> decoder_up =
377*f6aab3d8Srobert         CreateInstructionDecoder(trace_intel_pt, buffer, process);
378*f6aab3d8Srobert     if (!decoder_up)
379*f6aab3d8Srobert       return decoder_up.takeError();
380*f6aab3d8Srobert 
381*f6aab3d8Srobert     return PSBBlockDecoder(std::move(*decoder_up), psb_block, next_block_ip,
382*f6aab3d8Srobert                            decoded_thread, trace_intel_pt, tsc_upper_bound);
383*f6aab3d8Srobert   }
384*f6aab3d8Srobert 
DecodePSBBlock()385*f6aab3d8Srobert   void DecodePSBBlock() {
386*f6aab3d8Srobert     int status = pt_insn_sync_forward(m_decoder_up.get());
387*f6aab3d8Srobert     assert(status >= 0 &&
388*f6aab3d8Srobert            "Synchronization shouldn't fail because this PSB was previously "
389*f6aab3d8Srobert            "decoded correctly.");
390*f6aab3d8Srobert 
391*f6aab3d8Srobert     // We emit a TSC before a sync event to more easily associate a timestamp to
392*f6aab3d8Srobert     // the sync event. If present, the current block's TSC would be the first
393*f6aab3d8Srobert     // TSC we'll see when processing events.
394*f6aab3d8Srobert     if (m_psb_block.tsc)
395*f6aab3d8Srobert       m_decoded_thread.NotifyTsc(*m_psb_block.tsc);
396*f6aab3d8Srobert 
397*f6aab3d8Srobert     m_decoded_thread.NotifySyncPoint(m_psb_block.psb_offset);
398*f6aab3d8Srobert 
399*f6aab3d8Srobert     DecodeInstructionsAndEvents(status);
400*f6aab3d8Srobert   }
401*f6aab3d8Srobert 
402*f6aab3d8Srobert private:
403*f6aab3d8Srobert   /// Append an instruction and return \b false if and only if a serious anomaly
404*f6aab3d8Srobert   /// has been detected.
AppendInstructionAndDetectAnomalies(const pt_insn & insn)405*f6aab3d8Srobert   bool AppendInstructionAndDetectAnomalies(const pt_insn &insn) {
406*f6aab3d8Srobert     m_decoded_thread.AppendInstruction(insn);
407*f6aab3d8Srobert 
408*f6aab3d8Srobert     if (Error err = m_anomaly_detector.DetectAnomaly()) {
409*f6aab3d8Srobert       m_decoded_thread.AppendCustomError(toString(std::move(err)),
410*f6aab3d8Srobert                                          /*fatal=*/true);
411*f6aab3d8Srobert       return false;
412*f6aab3d8Srobert     }
413*f6aab3d8Srobert     return true;
414*f6aab3d8Srobert   }
415*f6aab3d8Srobert   /// Decode all the instructions and events of the given PSB block. The
416*f6aab3d8Srobert   /// decoding loop might stop abruptly if an infinite decoding loop is
417*f6aab3d8Srobert   /// detected.
DecodeInstructionsAndEvents(int status)418*f6aab3d8Srobert   void DecodeInstructionsAndEvents(int status) {
419*f6aab3d8Srobert     pt_insn insn;
420*f6aab3d8Srobert 
421*f6aab3d8Srobert     while (true) {
422*f6aab3d8Srobert       status = ProcessPTEvents(status);
423*f6aab3d8Srobert 
424*f6aab3d8Srobert       if (IsLibiptError(status))
425*f6aab3d8Srobert         return;
426*f6aab3d8Srobert       else if (IsEndOfStream(status))
427*f6aab3d8Srobert         break;
428*f6aab3d8Srobert 
429*f6aab3d8Srobert       // The status returned by pt_insn_next will need to be processed
430*f6aab3d8Srobert       // by ProcessPTEvents in the next loop if it is not an error.
431*f6aab3d8Srobert       std::memset(&insn, 0, sizeof insn);
432*f6aab3d8Srobert       status = pt_insn_next(m_decoder_up.get(), &insn, sizeof(insn));
433*f6aab3d8Srobert 
434*f6aab3d8Srobert       if (IsLibiptError(status)) {
435*f6aab3d8Srobert         m_decoded_thread.AppendError(IntelPTError(status, insn.ip));
436*f6aab3d8Srobert         return;
437*f6aab3d8Srobert       } else if (IsEndOfStream(status)) {
438*f6aab3d8Srobert         break;
439*f6aab3d8Srobert       }
440*f6aab3d8Srobert 
441*f6aab3d8Srobert       if (!AppendInstructionAndDetectAnomalies(insn))
442*f6aab3d8Srobert         return;
443*f6aab3d8Srobert     }
444*f6aab3d8Srobert 
445*f6aab3d8Srobert     // We need to keep querying non-branching instructions until we hit the
446*f6aab3d8Srobert     // starting point of the next PSB. We won't see events at this point. This
447*f6aab3d8Srobert     // is based on
448*f6aab3d8Srobert     // https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#parallel-decode
449*f6aab3d8Srobert     if (m_next_block_ip && insn.ip != 0) {
450*f6aab3d8Srobert       while (insn.ip != *m_next_block_ip) {
451*f6aab3d8Srobert         if (!AppendInstructionAndDetectAnomalies(insn))
452*f6aab3d8Srobert           return;
453*f6aab3d8Srobert 
454*f6aab3d8Srobert         status = pt_insn_next(m_decoder_up.get(), &insn, sizeof(insn));
455*f6aab3d8Srobert 
456*f6aab3d8Srobert         if (IsLibiptError(status)) {
457*f6aab3d8Srobert           m_decoded_thread.AppendError(IntelPTError(status, insn.ip));
458*f6aab3d8Srobert           return;
459*f6aab3d8Srobert         }
460*f6aab3d8Srobert       }
461*f6aab3d8Srobert     }
462*f6aab3d8Srobert   }
463*f6aab3d8Srobert 
464*f6aab3d8Srobert   /// Process the TSC of a decoded PT event. Specifically, check if this TSC
465*f6aab3d8Srobert   /// is below the TSC upper bound for this PSB. If the TSC exceeds the upper
466*f6aab3d8Srobert   /// bound, return an error to abort decoding. Otherwise add the it to the
467*f6aab3d8Srobert   /// underlying DecodedThread and decoding should continue as expected.
468*f6aab3d8Srobert   ///
469*f6aab3d8Srobert   /// \param[in] tsc
470*f6aab3d8Srobert   ///   The TSC of the a decoded event.
ProcessPTEventTSC(DecodedThread::TSC tsc)471*f6aab3d8Srobert   Error ProcessPTEventTSC(DecodedThread::TSC tsc) {
472*f6aab3d8Srobert     if (m_tsc_upper_bound && tsc >= *m_tsc_upper_bound) {
473*f6aab3d8Srobert       // This event and all the remaining events of this PSB have a TSC
474*f6aab3d8Srobert       // outside the range of the "owning" ThreadContinuousExecution. For
475*f6aab3d8Srobert       // now we drop all of these events/instructions, future work can
476*f6aab3d8Srobert       // improve upon this by determining the "owning"
477*f6aab3d8Srobert       // ThreadContinuousExecution of the remaining PSB data.
478*f6aab3d8Srobert       std::string err_msg = formatv("decoding truncated: TSC {0} exceeds "
479*f6aab3d8Srobert                                     "maximum TSC value {1}, will skip decoding"
480*f6aab3d8Srobert                                     " the remaining data of the PSB",
481*f6aab3d8Srobert                                     tsc, *m_tsc_upper_bound)
482*f6aab3d8Srobert                                 .str();
483*f6aab3d8Srobert 
484*f6aab3d8Srobert       uint64_t offset;
485*f6aab3d8Srobert       int status = pt_insn_get_offset(m_decoder_up.get(), &offset);
486*f6aab3d8Srobert       if (!IsLibiptError(status)) {
487*f6aab3d8Srobert         err_msg = formatv("{2} (skipping {0} of {1} bytes)", offset,
488*f6aab3d8Srobert                           m_psb_block.size, err_msg)
489*f6aab3d8Srobert                       .str();
490*f6aab3d8Srobert       }
491*f6aab3d8Srobert       m_decoded_thread.AppendCustomError(err_msg);
492*f6aab3d8Srobert       return createStringError(inconvertibleErrorCode(), err_msg);
493*f6aab3d8Srobert     } else {
494*f6aab3d8Srobert       m_decoded_thread.NotifyTsc(tsc);
495*f6aab3d8Srobert       return Error::success();
496*f6aab3d8Srobert     }
497*f6aab3d8Srobert   }
498*f6aab3d8Srobert 
499*f6aab3d8Srobert   /// Before querying instructions, we need to query the events associated with
500*f6aab3d8Srobert   /// that instruction, e.g. timing and trace disablement events.
501*f6aab3d8Srobert   ///
502*f6aab3d8Srobert   /// \param[in] status
503*f6aab3d8Srobert   ///   The status gotten from the previous instruction decoding or PSB
504*f6aab3d8Srobert   ///   synchronization.
505*f6aab3d8Srobert   ///
506*f6aab3d8Srobert   /// \return
507*f6aab3d8Srobert   ///     The pte_status after decoding events.
ProcessPTEvents(int status)508*f6aab3d8Srobert   int ProcessPTEvents(int status) {
509*f6aab3d8Srobert     while (HasEvents(status)) {
510*f6aab3d8Srobert       pt_event event;
511*f6aab3d8Srobert       std::memset(&event, 0, sizeof event);
512*f6aab3d8Srobert       status = pt_insn_event(m_decoder_up.get(), &event, sizeof(event));
513*f6aab3d8Srobert 
514*f6aab3d8Srobert       if (IsLibiptError(status)) {
515*f6aab3d8Srobert         m_decoded_thread.AppendError(IntelPTError(status));
516*f6aab3d8Srobert         return status;
517*f6aab3d8Srobert       }
518*f6aab3d8Srobert 
519*f6aab3d8Srobert       if (event.has_tsc) {
520*f6aab3d8Srobert         if (Error err = ProcessPTEventTSC(event.tsc)) {
521*f6aab3d8Srobert           consumeError(std::move(err));
522*f6aab3d8Srobert           return -pte_internal;
523*f6aab3d8Srobert         }
524*f6aab3d8Srobert       }
525*f6aab3d8Srobert 
526*f6aab3d8Srobert       switch (event.type) {
527*f6aab3d8Srobert       case ptev_disabled:
528*f6aab3d8Srobert         // The CPU paused tracing the program, e.g. due to ip filtering.
529*f6aab3d8Srobert         m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledHW);
530*f6aab3d8Srobert         break;
531*f6aab3d8Srobert       case ptev_async_disabled:
532*f6aab3d8Srobert         // The kernel or user code paused tracing the program, e.g.
533*f6aab3d8Srobert         // a breakpoint or a ioctl invocation pausing the trace, or a
534*f6aab3d8Srobert         // context switch happened.
535*f6aab3d8Srobert         m_decoded_thread.AppendEvent(lldb::eTraceEventDisabledSW);
536*f6aab3d8Srobert         break;
537*f6aab3d8Srobert       case ptev_overflow:
538*f6aab3d8Srobert         // The CPU internal buffer had an overflow error and some instructions
539*f6aab3d8Srobert         // were lost. A OVF packet comes with an FUP packet (harcoded address)
540*f6aab3d8Srobert         // according to the documentation, so we'll continue seeing instructions
541*f6aab3d8Srobert         // after this event.
542*f6aab3d8Srobert         m_decoded_thread.AppendError(IntelPTError(-pte_overflow));
543*f6aab3d8Srobert         break;
544*f6aab3d8Srobert       default:
545*f6aab3d8Srobert         break;
546*f6aab3d8Srobert       }
547*f6aab3d8Srobert     }
548*f6aab3d8Srobert 
549*f6aab3d8Srobert     return status;
550*f6aab3d8Srobert   }
551*f6aab3d8Srobert 
552*f6aab3d8Srobert private:
553*f6aab3d8Srobert   PtInsnDecoderUP m_decoder_up;
554*f6aab3d8Srobert   PSBBlock m_psb_block;
555*f6aab3d8Srobert   std::optional<lldb::addr_t> m_next_block_ip;
556*f6aab3d8Srobert   DecodedThread &m_decoded_thread;
557*f6aab3d8Srobert   PSBBlockAnomalyDetector m_anomaly_detector;
558*f6aab3d8Srobert   std::optional<DecodedThread::TSC> m_tsc_upper_bound;
559*f6aab3d8Srobert };
560*f6aab3d8Srobert 
DecodeSingleTraceForThread(DecodedThread & decoded_thread,TraceIntelPT & trace_intel_pt,ArrayRef<uint8_t> buffer)561*f6aab3d8Srobert Error lldb_private::trace_intel_pt::DecodeSingleTraceForThread(
562*f6aab3d8Srobert     DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
563*f6aab3d8Srobert     ArrayRef<uint8_t> buffer) {
564*f6aab3d8Srobert   Expected<std::vector<PSBBlock>> blocks =
565*f6aab3d8Srobert       SplitTraceIntoPSBBlock(trace_intel_pt, buffer, /*expect_tscs=*/false);
566*f6aab3d8Srobert   if (!blocks)
567*f6aab3d8Srobert     return blocks.takeError();
568*f6aab3d8Srobert 
569*f6aab3d8Srobert   for (size_t i = 0; i < blocks->size(); i++) {
570*f6aab3d8Srobert     PSBBlock &block = blocks->at(i);
571*f6aab3d8Srobert 
572*f6aab3d8Srobert     Expected<PSBBlockDecoder> decoder = PSBBlockDecoder::Create(
573*f6aab3d8Srobert         trace_intel_pt, block, buffer.slice(block.psb_offset, block.size),
574*f6aab3d8Srobert         *decoded_thread.GetThread()->GetProcess(),
575*f6aab3d8Srobert         i + 1 < blocks->size() ? blocks->at(i + 1).starting_ip : None,
576*f6aab3d8Srobert         decoded_thread, std::nullopt);
577*f6aab3d8Srobert     if (!decoder)
578*f6aab3d8Srobert       return decoder.takeError();
579*f6aab3d8Srobert 
580*f6aab3d8Srobert     decoder->DecodePSBBlock();
581*f6aab3d8Srobert   }
582*f6aab3d8Srobert 
583*f6aab3d8Srobert   return Error::success();
584*f6aab3d8Srobert }
585*f6aab3d8Srobert 
DecodeSystemWideTraceForThread(DecodedThread & decoded_thread,TraceIntelPT & trace_intel_pt,const DenseMap<lldb::cpu_id_t,llvm::ArrayRef<uint8_t>> & buffers,const std::vector<IntelPTThreadContinousExecution> & executions)586*f6aab3d8Srobert Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
587*f6aab3d8Srobert     DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt,
588*f6aab3d8Srobert     const DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> &buffers,
589*f6aab3d8Srobert     const std::vector<IntelPTThreadContinousExecution> &executions) {
590*f6aab3d8Srobert   bool has_seen_psbs = false;
591*f6aab3d8Srobert   for (size_t i = 0; i < executions.size(); i++) {
592*f6aab3d8Srobert     const IntelPTThreadContinousExecution &execution = executions[i];
593*f6aab3d8Srobert 
594*f6aab3d8Srobert     auto variant = execution.thread_execution.variant;
595*f6aab3d8Srobert 
596*f6aab3d8Srobert     // We emit the first valid tsc
597*f6aab3d8Srobert     if (execution.psb_blocks.empty()) {
598*f6aab3d8Srobert       decoded_thread.NotifyTsc(execution.thread_execution.GetLowestKnownTSC());
599*f6aab3d8Srobert     } else {
600*f6aab3d8Srobert       assert(execution.psb_blocks.front().tsc &&
601*f6aab3d8Srobert              "per cpu decoding expects TSCs");
602*f6aab3d8Srobert       decoded_thread.NotifyTsc(
603*f6aab3d8Srobert           std::min(execution.thread_execution.GetLowestKnownTSC(),
604*f6aab3d8Srobert                    *execution.psb_blocks.front().tsc));
605*f6aab3d8Srobert     }
606*f6aab3d8Srobert 
607*f6aab3d8Srobert     // We then emit the CPU, which will be correctly associated with a tsc.
608*f6aab3d8Srobert     decoded_thread.NotifyCPU(execution.thread_execution.cpu_id);
609*f6aab3d8Srobert 
610*f6aab3d8Srobert     // If we haven't seen a PSB yet, then it's fine not to show errors
611*f6aab3d8Srobert     if (has_seen_psbs) {
612*f6aab3d8Srobert       if (execution.psb_blocks.empty()) {
613*f6aab3d8Srobert         decoded_thread.AppendCustomError(
614*f6aab3d8Srobert             formatv("Unable to find intel pt data a thread "
615*f6aab3d8Srobert                     "execution on cpu id = {0}",
616*f6aab3d8Srobert                     execution.thread_execution.cpu_id)
617*f6aab3d8Srobert                 .str());
618*f6aab3d8Srobert       }
619*f6aab3d8Srobert 
620*f6aab3d8Srobert       // A hinted start is a non-initial execution that doesn't have a switch
621*f6aab3d8Srobert       // in. An only end is an initial execution that doesn't have a switch in.
622*f6aab3d8Srobert       // Any of those cases represent a gap because we have seen a PSB before.
623*f6aab3d8Srobert       if (variant == ThreadContinuousExecution::Variant::HintedStart ||
624*f6aab3d8Srobert           variant == ThreadContinuousExecution::Variant::OnlyEnd) {
625*f6aab3d8Srobert         decoded_thread.AppendCustomError(
626*f6aab3d8Srobert             formatv("Unable to find the context switch in for a thread "
627*f6aab3d8Srobert                     "execution on cpu id = {0}",
628*f6aab3d8Srobert                     execution.thread_execution.cpu_id)
629*f6aab3d8Srobert                 .str());
630*f6aab3d8Srobert       }
631*f6aab3d8Srobert     }
632*f6aab3d8Srobert 
633*f6aab3d8Srobert     for (size_t j = 0; j < execution.psb_blocks.size(); j++) {
634*f6aab3d8Srobert       const PSBBlock &psb_block = execution.psb_blocks[j];
635*f6aab3d8Srobert 
636*f6aab3d8Srobert       Expected<PSBBlockDecoder> decoder = PSBBlockDecoder::Create(
637*f6aab3d8Srobert           trace_intel_pt, psb_block,
638*f6aab3d8Srobert           buffers.lookup(execution.thread_execution.cpu_id)
639*f6aab3d8Srobert               .slice(psb_block.psb_offset, psb_block.size),
640*f6aab3d8Srobert           *decoded_thread.GetThread()->GetProcess(),
641*f6aab3d8Srobert           j + 1 < execution.psb_blocks.size()
642*f6aab3d8Srobert               ? execution.psb_blocks[j + 1].starting_ip
643*f6aab3d8Srobert               : None,
644*f6aab3d8Srobert           decoded_thread, execution.thread_execution.GetEndTSC());
645*f6aab3d8Srobert       if (!decoder)
646*f6aab3d8Srobert         return decoder.takeError();
647*f6aab3d8Srobert 
648*f6aab3d8Srobert       has_seen_psbs = true;
649*f6aab3d8Srobert       decoder->DecodePSBBlock();
650*f6aab3d8Srobert     }
651*f6aab3d8Srobert 
652*f6aab3d8Srobert     // If we haven't seen a PSB yet, then it's fine not to show errors
653*f6aab3d8Srobert     if (has_seen_psbs) {
654*f6aab3d8Srobert       // A hinted end is a non-ending execution that doesn't have a switch out.
655*f6aab3d8Srobert       // An only start is an ending execution that doesn't have a switch out.
656*f6aab3d8Srobert       // Any of those cases represent a gap if we still have executions to
657*f6aab3d8Srobert       // process and we have seen a PSB before.
658*f6aab3d8Srobert       if (i + 1 != executions.size() &&
659*f6aab3d8Srobert           (variant == ThreadContinuousExecution::Variant::OnlyStart ||
660*f6aab3d8Srobert            variant == ThreadContinuousExecution::Variant::HintedEnd)) {
661*f6aab3d8Srobert         decoded_thread.AppendCustomError(
662*f6aab3d8Srobert             formatv("Unable to find the context switch out for a thread "
663*f6aab3d8Srobert                     "execution on cpu id = {0}",
664*f6aab3d8Srobert                     execution.thread_execution.cpu_id)
665*f6aab3d8Srobert                 .str());
666*f6aab3d8Srobert       }
667*f6aab3d8Srobert     }
668*f6aab3d8Srobert   }
669*f6aab3d8Srobert   return Error::success();
670*f6aab3d8Srobert }
671*f6aab3d8Srobert 
operator <(const IntelPTThreadContinousExecution & o) const672*f6aab3d8Srobert bool IntelPTThreadContinousExecution::operator<(
673*f6aab3d8Srobert     const IntelPTThreadContinousExecution &o) const {
674*f6aab3d8Srobert   // As the context switch might be incomplete, we look first for the first real
675*f6aab3d8Srobert   // PSB packet, which is a valid TSC. Otherwise, We query the thread execution
676*f6aab3d8Srobert   // itself for some tsc.
677*f6aab3d8Srobert   auto get_tsc = [](const IntelPTThreadContinousExecution &exec) {
678*f6aab3d8Srobert     return exec.psb_blocks.empty() ? exec.thread_execution.GetLowestKnownTSC()
679*f6aab3d8Srobert                                    : exec.psb_blocks.front().tsc;
680*f6aab3d8Srobert   };
681*f6aab3d8Srobert 
682*f6aab3d8Srobert   return get_tsc(*this) < get_tsc(o);
683*f6aab3d8Srobert }
684*f6aab3d8Srobert 
685*f6aab3d8Srobert Expected<std::vector<PSBBlock>>
SplitTraceIntoPSBBlock(TraceIntelPT & trace_intel_pt,llvm::ArrayRef<uint8_t> buffer,bool expect_tscs)686*f6aab3d8Srobert lldb_private::trace_intel_pt::SplitTraceIntoPSBBlock(
687*f6aab3d8Srobert     TraceIntelPT &trace_intel_pt, llvm::ArrayRef<uint8_t> buffer,
688*f6aab3d8Srobert     bool expect_tscs) {
689*f6aab3d8Srobert   // This follows
690*f6aab3d8Srobert   // https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#parallel-decode
691*f6aab3d8Srobert 
692*f6aab3d8Srobert   Expected<PtQueryDecoderUP> decoder_up =
693*f6aab3d8Srobert       CreateQueryDecoder(trace_intel_pt, buffer);
694*f6aab3d8Srobert   if (!decoder_up)
695*f6aab3d8Srobert     return decoder_up.takeError();
696*f6aab3d8Srobert 
697*f6aab3d8Srobert   pt_query_decoder *decoder = decoder_up.get().get();
698*f6aab3d8Srobert 
699*f6aab3d8Srobert   std::vector<PSBBlock> executions;
700*f6aab3d8Srobert 
701*f6aab3d8Srobert   while (true) {
702*f6aab3d8Srobert     uint64_t maybe_ip = LLDB_INVALID_ADDRESS;
703*f6aab3d8Srobert     int decoding_status = pt_qry_sync_forward(decoder, &maybe_ip);
704*f6aab3d8Srobert     if (IsLibiptError(decoding_status))
705*f6aab3d8Srobert       break;
706*f6aab3d8Srobert 
707*f6aab3d8Srobert     uint64_t psb_offset;
708*f6aab3d8Srobert     int offset_status = pt_qry_get_sync_offset(decoder, &psb_offset);
709*f6aab3d8Srobert     assert(offset_status >= 0 &&
710*f6aab3d8Srobert            "This can't fail because we were able to synchronize");
711*f6aab3d8Srobert 
712*f6aab3d8Srobert     std::optional<uint64_t> ip;
713*f6aab3d8Srobert     if (!(pts_ip_suppressed & decoding_status))
714*f6aab3d8Srobert       ip = maybe_ip;
715*f6aab3d8Srobert 
716*f6aab3d8Srobert     std::optional<uint64_t> tsc;
717*f6aab3d8Srobert     // Now we fetch the first TSC that comes after the PSB.
718*f6aab3d8Srobert     while (HasEvents(decoding_status)) {
719*f6aab3d8Srobert       pt_event event;
720*f6aab3d8Srobert       decoding_status = pt_qry_event(decoder, &event, sizeof(event));
721*f6aab3d8Srobert       if (IsLibiptError(decoding_status))
722*f6aab3d8Srobert         break;
723*f6aab3d8Srobert       if (event.has_tsc) {
724*f6aab3d8Srobert         tsc = event.tsc;
725*f6aab3d8Srobert         break;
726*f6aab3d8Srobert       }
727*f6aab3d8Srobert     }
728*f6aab3d8Srobert     if (IsLibiptError(decoding_status)) {
729*f6aab3d8Srobert       // We continue to the next PSB. This effectively merges this PSB with the
730*f6aab3d8Srobert       // previous one, and that should be fine because this PSB might be the
731*f6aab3d8Srobert       // direct continuation of the previous thread and it's better to show an
732*f6aab3d8Srobert       // error in the decoded thread than to hide it. If this is the first PSB,
733*f6aab3d8Srobert       // we are okay losing it. Besides that, an error at processing events
734*f6aab3d8Srobert       // means that we wouldn't be able to get any instruction out of it.
735*f6aab3d8Srobert       continue;
736*f6aab3d8Srobert     }
737*f6aab3d8Srobert 
738*f6aab3d8Srobert     if (expect_tscs && !tsc)
739*f6aab3d8Srobert       return createStringError(inconvertibleErrorCode(),
740*f6aab3d8Srobert                                "Found a PSB without TSC.");
741*f6aab3d8Srobert 
742*f6aab3d8Srobert     executions.push_back({
743*f6aab3d8Srobert         psb_offset,
744*f6aab3d8Srobert         tsc,
745*f6aab3d8Srobert         0,
746*f6aab3d8Srobert         ip,
747*f6aab3d8Srobert     });
748*f6aab3d8Srobert   }
749*f6aab3d8Srobert   if (!executions.empty()) {
750*f6aab3d8Srobert     // We now adjust the sizes of each block
751*f6aab3d8Srobert     executions.back().size = buffer.size() - executions.back().psb_offset;
752*f6aab3d8Srobert     for (int i = (int)executions.size() - 2; i >= 0; i--) {
753*f6aab3d8Srobert       executions[i].size =
754*f6aab3d8Srobert           executions[i + 1].psb_offset - executions[i].psb_offset;
755*f6aab3d8Srobert     }
756*f6aab3d8Srobert   }
757*f6aab3d8Srobert   return executions;
758*f6aab3d8Srobert }
759*f6aab3d8Srobert 
760*f6aab3d8Srobert Expected<std::optional<uint64_t>>
FindLowestTSCInTrace(TraceIntelPT & trace_intel_pt,ArrayRef<uint8_t> buffer)761*f6aab3d8Srobert lldb_private::trace_intel_pt::FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt,
762*f6aab3d8Srobert                                                    ArrayRef<uint8_t> buffer) {
763*f6aab3d8Srobert   Expected<PtQueryDecoderUP> decoder_up =
764*f6aab3d8Srobert       CreateQueryDecoder(trace_intel_pt, buffer);
765*f6aab3d8Srobert   if (!decoder_up)
766*f6aab3d8Srobert     return decoder_up.takeError();
767*f6aab3d8Srobert 
768*f6aab3d8Srobert   pt_query_decoder *decoder = decoder_up.get().get();
769*f6aab3d8Srobert   uint64_t ip = LLDB_INVALID_ADDRESS;
770*f6aab3d8Srobert   int status = pt_qry_sync_forward(decoder, &ip);
771*f6aab3d8Srobert   if (IsLibiptError(status))
772*f6aab3d8Srobert     return std::nullopt;
773*f6aab3d8Srobert 
774*f6aab3d8Srobert   while (HasEvents(status)) {
775*f6aab3d8Srobert     pt_event event;
776*f6aab3d8Srobert     status = pt_qry_event(decoder, &event, sizeof(event));
777*f6aab3d8Srobert     if (IsLibiptError(status))
778*f6aab3d8Srobert       return std::nullopt;
779*f6aab3d8Srobert     if (event.has_tsc)
780*f6aab3d8Srobert       return event.tsc;
781*f6aab3d8Srobert   }
782*f6aab3d8Srobert   return std::nullopt;
783*f6aab3d8Srobert }
784