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