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