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 
10 #include "TraceIntelPT.h"
11 
12 #include "lldb/Target/Process.h"
13 
14 using namespace lldb;
15 using namespace lldb_private;
16 using namespace lldb_private::trace_intel_pt;
17 using namespace llvm;
18 
19 // Simple struct used by the decoder to keep the state of the most
20 // recent TSC and a flag indicating whether TSCs are enabled, not enabled
21 // or we just don't yet.
22 struct TscInfo {
23   uint64_t tsc = 0;
24   LazyBool has_tsc = eLazyBoolCalculate;
25 
26   explicit operator bool() const { return has_tsc == eLazyBoolYes; }
27 };
28 
29 /// Class that decodes a raw buffer for a single thread using the low level
30 /// libipt library.
31 ///
32 /// Throughout this code, the status of the decoder will be used to identify
33 /// events needed to be processed or errors in the decoder. The values can be
34 /// - negative: actual errors
35 /// - positive or zero: not an error, but a list of bits signaling the status
36 /// of the decoder, e.g. whether there are events that need to be decoded or
37 /// not.
38 class LibiptDecoder {
39 public:
40   /// \param[in] decoder
41   ///     A well configured decoder. Using the current state of that decoder,
42   ///     decoding will start at its next valid PSB. It's not assumed that the
43   ///     decoder is already pointing at a valid PSB.
44   ///
45   /// \param[in] decoded_thread
46   ///     A \a DecodedThread object where the decoded instructions will be
47   ///     appended to. It might have already some instructions.
48   LibiptDecoder(pt_insn_decoder &decoder, DecodedThread &decoded_thread)
49       : m_decoder(decoder), m_decoded_thread(decoded_thread) {}
50 
51   /// Decode all the instructions until the end of the trace.
52   /// The decoding flow is based on
53   /// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop
54   /// but with some relaxation to allow for gaps in the trace.
55   void DecodeUntilEndOfTrace() {
56     int status = pte_ok;
57     while (!IsLibiptError(status = FindNextSynchronizationPoint())) {
58       // We have synchronized, so we can start decoding instructions and
59       // events.
60       // Multiple loops indicate gaps in the trace.
61       DecodeInstructionsAndEvents(status);
62     }
63   }
64 
65 private:
66   /// Invoke the low level function \a pt_insn_next and store the decoded
67   /// instruction in the given \a DecodedInstruction.
68   ///
69   /// \param[out] insn
70   ///   The instruction builder where the pt_insn information will be stored.
71   ///
72   /// \return
73   ///   The status returned by pt_insn_next.
74   int DecodeNextInstruction(DecodedInstruction &insn) {
75     return pt_insn_next(&m_decoder, &insn.pt_insn, sizeof(insn.pt_insn));
76   }
77 
78   /// Decode all the instructions and events until an error is found or the end
79   /// of the trace is reached.
80   ///
81   /// \param[in] status
82   ///   The status that was result of synchronizing to the most recent PSB.
83   void DecodeInstructionsAndEvents(int status) {
84     while (DecodedInstruction insn = ProcessPTEvents(status)) {
85       // The status returned by DecodeNextInstruction will need to be processed
86       // by ProcessPTEvents in the next loop if it is not an error.
87       if (IsLibiptError(status = DecodeNextInstruction(insn))) {
88         insn.libipt_error = status;
89         m_decoded_thread.Append(insn);
90         break;
91       }
92       m_decoded_thread.Append(insn);
93     }
94   }
95 
96   /// Move the decoder forward to the next synchronization point (i.e. next PSB
97   /// packet).
98   ///
99   /// Once the decoder is at that synchronization point, it can start decoding
100   /// instructions.
101   ///
102   /// If errors are found, they will be appended to the trace.
103   ///
104   /// \return
105   ///   The libipt decoder status after moving to the next PSB. Negative if
106   ///   no PSB was found.
107   int FindNextSynchronizationPoint() {
108     // Try to sync the decoder. If it fails, then get the decoder_offset and
109     // try to sync again from the next synchronization point. If the
110     // new_decoder_offset is same as decoder_offset then we can't move to the
111     // next synchronization point. Otherwise, keep resyncing until either end
112     // of trace stream (eos) is reached or pt_insn_sync_forward() passes.
113     int status = pt_insn_sync_forward(&m_decoder);
114 
115     if (!IsEndOfStream(status) && IsLibiptError(status)) {
116       uint64_t decoder_offset = 0;
117       int errcode_off = pt_insn_get_offset(&m_decoder, &decoder_offset);
118       if (!IsLibiptError(errcode_off)) { // we could get the offset
119         while (true) {
120           status = pt_insn_sync_forward(&m_decoder);
121           if (!IsLibiptError(status) || IsEndOfStream(status))
122             break;
123 
124           uint64_t new_decoder_offset = 0;
125           errcode_off = pt_insn_get_offset(&m_decoder, &new_decoder_offset);
126           if (IsLibiptError(errcode_off))
127             break; // We can't further synchronize.
128           else if (new_decoder_offset <= decoder_offset) {
129             // We tried resyncing the decoder and it didn't make any progress
130             // because the offset didn't change. We will not make any further
131             // progress. Hence, we stop in this situation.
132             break;
133           }
134           // We'll try again starting from a new offset.
135           decoder_offset = new_decoder_offset;
136         }
137       }
138     }
139 
140     // We make this call to record any synchronization errors.
141     if (IsLibiptError(status))
142       m_decoded_thread.Append(DecodedInstruction(status));
143 
144     return status;
145   }
146 
147   /// Before querying instructions, we need to query the events associated that
148   /// instruction e.g. timing events like ptev_tick, or paging events like
149   /// ptev_paging.
150   ///
151   /// If an error is found, it will be appended to the trace.
152   ///
153   /// \param[in] status
154   ///   The status gotten from the previous instruction decoding or PSB
155   ///   synchronization.
156   ///
157   /// \return
158   ///   A \a DecodedInstruction with event, tsc and error information.
159   DecodedInstruction ProcessPTEvents(int status) {
160     DecodedInstruction insn;
161     while (status & pts_event_pending) {
162       pt_event event;
163       status = pt_insn_event(&m_decoder, &event, sizeof(event));
164       if (IsLibiptError(status)) {
165         insn.libipt_error = status;
166         break;
167       }
168 
169       switch (event.type) {
170       case ptev_enabled:
171         // The kernel started or resumed tracing the program.
172         break;
173       case ptev_disabled:
174         // The CPU paused tracing the program, e.g. due to ip filtering.
175       case ptev_async_disabled:
176         // The kernel or user code paused tracing the program, e.g.
177         // a breakpoint or a ioctl invocation pausing the trace, or a
178         // context switch happened.
179 
180         if (m_decoded_thread.GetInstructionsCount() > 0) {
181           // A paused event before the first instruction can be safely
182           // discarded.
183           insn.events |= eTraceEventPaused;
184         }
185         break;
186       case ptev_overflow:
187         // The CPU internal buffer had an overflow error and some instructions
188         // were lost.
189         insn.libipt_error = -pte_overflow;
190         break;
191       default:
192         break;
193       }
194     }
195 
196     // We refresh the TSC that might have changed after processing the events.
197     // See
198     // https://github.com/intel/libipt/blob/master/doc/man/pt_evt_next.3.md
199     RefreshTscInfo();
200     if (m_tsc_info)
201       insn.tsc = m_tsc_info.tsc;
202     if (!insn)
203       m_decoded_thread.Append(insn);
204     return insn;
205   }
206 
207   /// Query the decoder for the most recent TSC timestamp and update
208   /// the inner tsc information accordingly.
209   void RefreshTscInfo() {
210     if (m_tsc_info.has_tsc == eLazyBoolNo)
211       return;
212 
213     uint64_t new_tsc;
214     int tsc_status;
215     if (IsLibiptError(tsc_status = pt_insn_time(&m_decoder, &new_tsc, nullptr,
216                                                 nullptr))) {
217       if (IsTscUnavailable(tsc_status)) {
218         // We now know that the trace doesn't support TSC, so we won't try
219         // again.
220         // See
221         // https://github.com/intel/libipt/blob/master/doc/man/pt_qry_time.3.md
222         m_tsc_info.has_tsc = eLazyBoolNo;
223       } else {
224         // We don't add TSC decoding errors in the decoded trace itself to
225         // prevent creating unnecessary gaps, but we can count how many of
226         // these errors happened. In this case we reuse the previous correct
227         // TSC we saw, as it's better than no TSC at all.
228         m_decoded_thread.RecordTscError(tsc_status);
229       }
230     } else {
231       m_tsc_info.tsc = new_tsc;
232       m_tsc_info.has_tsc = eLazyBoolYes;
233     }
234   }
235 
236 private:
237   pt_insn_decoder &m_decoder;
238   DecodedThread &m_decoded_thread;
239   TscInfo m_tsc_info;
240 };
241 
242 /// Callback used by libipt for reading the process memory.
243 ///
244 /// More information can be found in
245 /// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md
246 static int ReadProcessMemory(uint8_t *buffer, size_t size,
247                              const pt_asid * /* unused */, uint64_t pc,
248                              void *context) {
249   Process *process = static_cast<Process *>(context);
250 
251   Status error;
252   int bytes_read = process->ReadMemory(pc, buffer, size, error);
253   if (error.Fail())
254     return -pte_nomap;
255   return bytes_read;
256 }
257 
258 // RAII deleter for libipt's decoder
259 auto DecoderDeleter = [](pt_insn_decoder *decoder) {
260   pt_insn_free_decoder(decoder);
261 };
262 
263 using PtInsnDecoderUP =
264     std::unique_ptr<pt_insn_decoder, decltype(DecoderDeleter)>;
265 
266 static Expected<PtInsnDecoderUP>
267 CreateInstructionDecoder(DecodedThread &decoded_thread,
268                          TraceIntelPT &trace_intel_pt,
269                          ArrayRef<uint8_t> buffer) {
270   Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
271   if (!cpu_info)
272     return cpu_info.takeError();
273 
274   pt_config config;
275   pt_config_init(&config);
276   config.cpu = *cpu_info;
277   int status = pte_ok;
278 
279   if (IsLibiptError(status = pt_cpu_errata(&config.errata, &config.cpu)))
280     return make_error<IntelPTError>(status);
281 
282   // The libipt library does not modify the trace buffer, hence the
283   // following casts are safe.
284   config.begin = const_cast<uint8_t *>(buffer.data());
285   config.end = const_cast<uint8_t *>(buffer.data() + buffer.size());
286 
287   pt_insn_decoder *decoder_ptr = pt_insn_alloc_decoder(&config);
288   if (!decoder_ptr)
289     return make_error<IntelPTError>(-pte_nomem);
290   PtInsnDecoderUP decoder_up(decoder_ptr, DecoderDeleter);
291 
292   pt_image *image = pt_insn_get_image(decoder_ptr);
293   Process *process = decoded_thread.GetThread()->GetProcess().get();
294 
295   if (IsLibiptError(
296           status = pt_image_set_callback(image, ReadProcessMemory, process)))
297     return make_error<IntelPTError>(status);
298   return decoder_up;
299 }
300 
301 void lldb_private::trace_intel_pt::DecodeTrace(DecodedThread &decoded_thread,
302                                                TraceIntelPT &trace_intel_pt,
303                                                ArrayRef<uint8_t> buffer) {
304   Expected<PtInsnDecoderUP> decoder_up =
305       CreateInstructionDecoder(decoded_thread, trace_intel_pt, buffer);
306   if (!decoder_up)
307     return decoded_thread.SetAsFailed(decoder_up.takeError());
308 
309   LibiptDecoder libipt_decoder(*decoder_up.get(), decoded_thread);
310   libipt_decoder.DecodeUntilEndOfTrace();
311 }
312