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