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