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