1 //===-- IntelPTCollector.cpp ------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "IntelPTCollector.h"
10 
11 #include "Perf.h"
12 
13 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
14 #include "lldb/Host/linux/Support.h"
15 #include "lldb/Utility/StreamString.h"
16 
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/MathExtras.h"
20 
21 #include <algorithm>
22 #include <cstddef>
23 #include <fstream>
24 #include <linux/perf_event.h>
25 #include <sstream>
26 #include <sys/ioctl.h>
27 #include <sys/syscall.h>
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace process_linux;
32 using namespace llvm;
33 
34 const char *kOSEventIntelPTTypeFile =
35     "/sys/bus/event_source/devices/intel_pt/type";
36 
37 const char *kPSBPeriodCapFile =
38     "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc";
39 
40 const char *kPSBPeriodValidValuesFile =
41     "/sys/bus/event_source/devices/intel_pt/caps/psb_periods";
42 
43 const char *kTSCBitOffsetFile =
44     "/sys/bus/event_source/devices/intel_pt/format/tsc";
45 
46 const char *kPSBPeriodBitOffsetFile =
47     "/sys/bus/event_source/devices/intel_pt/format/psb_period";
48 
49 enum IntelPTConfigFileType {
50   Hex = 0,
51   // 0 or 1
52   ZeroOne,
53   Decimal,
54   // a bit index file always starts with the prefix config: following by an int,
55   // which represents the offset of the perf_event_attr.config value where to
56   // store a given configuration.
57   BitOffset
58 };
59 
60 /// Get the content of /proc/cpuinfo that can be later used to decode traces.
61 static Expected<ArrayRef<uint8_t>> GetCPUInfo() {
62   static llvm::Optional<std::vector<uint8_t>> cpu_info;
63   if (!cpu_info) {
64     auto buffer_or_error = errorOrToExpected(getProcFile("cpuinfo"));
65     if (!buffer_or_error)
66       return buffer_or_error.takeError();
67     MemoryBuffer &buffer = **buffer_or_error;
68     cpu_info = std::vector<uint8_t>(
69         reinterpret_cast<const uint8_t *>(buffer.getBufferStart()),
70         reinterpret_cast<const uint8_t *>(buffer.getBufferEnd()));
71   }
72   return *cpu_info;
73 }
74 
75 static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
76                                                 IntelPTConfigFileType type) {
77   ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
78       MemoryBuffer::getFileAsStream(file);
79 
80   if (!stream)
81     return createStringError(inconvertibleErrorCode(),
82                              "Can't open the file '%s'", file);
83 
84   uint32_t value = 0;
85   StringRef text_buffer = stream.get()->getBuffer();
86 
87   if (type == BitOffset) {
88     const char *prefix = "config:";
89     if (!text_buffer.startswith(prefix))
90       return createStringError(inconvertibleErrorCode(),
91                                "The file '%s' contents doesn't start with '%s'",
92                                file, prefix);
93     text_buffer = text_buffer.substr(strlen(prefix));
94   }
95 
96   auto getRadix = [&]() {
97     switch (type) {
98     case Hex:
99       return 16;
100     case ZeroOne:
101     case Decimal:
102     case BitOffset:
103       return 10;
104     }
105     llvm_unreachable("Fully covered switch above!");
106   };
107 
108   auto createError = [&](const char *expected_value_message) {
109     return createStringError(
110         inconvertibleErrorCode(),
111         "The file '%s' has an invalid value. It should be %s.", file,
112         expected_value_message);
113   };
114 
115   if (text_buffer.trim().consumeInteger(getRadix(), value) ||
116       (type == ZeroOne && value != 0 && value != 1)) {
117     switch (type) {
118     case Hex:
119       return createError("an unsigned hexadecimal int");
120     case ZeroOne:
121       return createError("0 or 1");
122     case Decimal:
123     case BitOffset:
124       return createError("an unsigned decimal int");
125     }
126   }
127   return value;
128 }
129 
130 /// Return the Linux perf event type for Intel PT.
131 static Expected<uint32_t> GetOSEventType() {
132   return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile,
133                                IntelPTConfigFileType::Decimal);
134 }
135 
136 static Error CheckPsbPeriod(size_t psb_period) {
137   Expected<uint32_t> cap =
138       ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne);
139   if (!cap)
140     return cap.takeError();
141   if (*cap == 0)
142     return createStringError(inconvertibleErrorCode(),
143                              "psb_period is unsupported in the system.");
144 
145   Expected<uint32_t> valid_values = ReadIntelPTConfigFile(
146       kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex);
147   if (!valid_values)
148     return valid_values.takeError();
149 
150   if (valid_values.get() & (1 << psb_period))
151     return Error::success();
152 
153   std::ostringstream error;
154   // 0 is always a valid value
155   error << "Invalid psb_period. Valid values are: 0";
156   uint32_t mask = valid_values.get();
157   while (mask) {
158     int index = __builtin_ctz(mask);
159     if (index > 0)
160       error << ", " << index;
161     // clear the lowest bit
162     mask &= mask - 1;
163   }
164   error << ".";
165   return createStringError(inconvertibleErrorCode(), error.str().c_str());
166 }
167 
168 size_t IntelPTThreadTrace::GetTraceBufferSize() const {
169 #ifndef PERF_ATTR_SIZE_VER5
170   llvm_unreachable("Intel PT Linux perf event not supported");
171 #else
172   return m_perf_event.GetAuxBuffer().size();
173 #endif
174 }
175 
176 static Expected<uint64_t>
177 GeneratePerfEventConfigValue(bool enable_tsc, Optional<size_t> psb_period) {
178   uint64_t config = 0;
179   // tsc is always supported
180   if (enable_tsc) {
181     if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
182             kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset))
183       config |= 1 << *offset;
184     else
185       return offset.takeError();
186   }
187   if (psb_period) {
188     if (Error error = CheckPsbPeriod(*psb_period))
189       return std::move(error);
190 
191     if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
192             kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset))
193       config |= *psb_period << *offset;
194     else
195       return offset.takeError();
196   }
197   return config;
198 }
199 
200 llvm::Expected<perf_event_attr>
201 IntelPTThreadTrace::CreateIntelPTPerfEventConfiguration(
202     bool enable_tsc, Optional<size_t> psb_period) {
203   perf_event_attr attr;
204   memset(&attr, 0, sizeof(attr));
205   attr.size = sizeof(attr);
206   attr.exclude_kernel = 1;
207   attr.sample_type = PERF_SAMPLE_TIME;
208   attr.sample_id_all = 1;
209   attr.exclude_hv = 1;
210   attr.exclude_idle = 1;
211   attr.mmap = 1;
212 
213   if (Expected<uint64_t> config_value =
214           GeneratePerfEventConfigValue(enable_tsc, psb_period)) {
215     attr.config = *config_value;
216   } else {
217     return config_value.takeError();
218   }
219 
220   if (Expected<uint32_t> intel_pt_type = GetOSEventType()) {
221     attr.type = *intel_pt_type;
222   } else {
223     return intel_pt_type.takeError();
224   }
225 
226   return attr;
227 }
228 
229 llvm::Expected<IntelPTThreadTraceUP>
230 IntelPTThreadTrace::Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size,
231                            bool enable_tsc, Optional<size_t> psb_period) {
232 #ifndef PERF_ATTR_SIZE_VER5
233   llvm_unreachable("Intel PT Linux perf event not supported");
234 #else
235   Log *log = GetLog(POSIXLog::Ptrace);
236 
237   LLDB_LOG(log, "called thread id {0}", tid);
238 
239   if (__builtin_popcount(buffer_size) != 1 || buffer_size < 4096) {
240     return createStringError(
241         inconvertibleErrorCode(),
242         "The trace buffer size must be a power of 2 greater than or equal to "
243         "4096 (2^12) bytes. It was %" PRIu64 ".",
244         buffer_size);
245   }
246   uint64_t page_size = getpagesize();
247   uint64_t buffer_numpages = static_cast<uint64_t>(
248       llvm::PowerOf2Floor((buffer_size + page_size - 1) / page_size));
249 
250   Expected<perf_event_attr> attr =
251       IntelPTThreadTrace::CreateIntelPTPerfEventConfiguration(enable_tsc,
252                                                               psb_period);
253   if (!attr)
254     return attr.takeError();
255 
256   LLDB_LOG(log, "buffer size {0} ", buffer_size);
257 
258   if (Expected<PerfEvent> perf_event = PerfEvent::Init(*attr, tid)) {
259     if (Error mmap_err = perf_event->MmapMetadataAndBuffers(buffer_numpages,
260                                                             buffer_numpages)) {
261       return std::move(mmap_err);
262     }
263     return IntelPTThreadTraceUP(
264         new IntelPTThreadTrace(std::move(*perf_event), tid));
265   } else {
266     return perf_event.takeError();
267   }
268 #endif
269 }
270 
271 Expected<std::vector<uint8_t>>
272 IntelPTThreadTrace::GetIntelPTBuffer(size_t offset, size_t size) const {
273   std::vector<uint8_t> data(size, 0);
274   MutableArrayRef<uint8_t> buffer_ref(data);
275   Status error = ReadPerfTraceAux(buffer_ref, 0);
276   if (error.Fail())
277     return error.ToError();
278   return data;
279 }
280 
281 Status
282 IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
283                                      size_t offset) const {
284 #ifndef PERF_ATTR_SIZE_VER5
285   llvm_unreachable("perf event not supported");
286 #else
287   auto fd = m_perf_event.GetFd();
288   perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage();
289   // Disable the perf event to force a flush out of the CPU's internal buffer.
290   // Besides, we can guarantee that the CPU won't override any data as we are
291   // reading the buffer.
292   //
293   // The Intel documentation says:
294   //
295   // Packets are first buffered internally and then written out asynchronously.
296   // To collect packet output for postprocessing, a collector needs first to
297   // ensure that all packet data has been flushed from internal buffers.
298   // Software can ensure this by stopping packet generation by clearing
299   // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
300   // Section 35.2.7.2).
301   //
302   // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
303   // in the man page of perf_event_open.
304   ioctl(fd, PERF_EVENT_IOC_DISABLE);
305 
306   Log *log = GetLog(POSIXLog::Ptrace);
307   Status error;
308   uint64_t head = mmap_metadata.aux_head;
309 
310   LLDB_LOG(log, "Aux size -{0} , Head - {1}", mmap_metadata.aux_size, head);
311 
312   /**
313    * When configured as ring buffer, the aux buffer keeps wrapping around
314    * the buffer and its not possible to detect how many times the buffer
315    * wrapped. Initially the buffer is filled with zeros,as shown below
316    * so in order to get complete buffer we first copy firstpartsize, followed
317    * by any left over part from beginning to aux_head
318    *
319    * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
320    *                 aux_head->||<- firstpartsize  ->|
321    *
322    * */
323 
324   ReadCyclicBuffer(buffer, m_perf_event.GetAuxBuffer(),
325                    static_cast<size_t>(head), offset);
326   LLDB_LOG(log, "ReadCyclic Buffer Done");
327 
328   // Reenable tracing now we have read the buffer
329   ioctl(fd, PERF_EVENT_IOC_ENABLE);
330   return error;
331 #endif
332 }
333 
334 Status
335 IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
336                                       size_t offset) const {
337 #ifndef PERF_ATTR_SIZE_VER5
338   llvm_unreachable("perf event not supported");
339 #else
340   Log *log = GetLog(POSIXLog::Ptrace);
341   uint64_t bytes_remaining = buffer.size();
342   Status error;
343 
344   perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage();
345   uint64_t head = mmap_metadata.data_head;
346 
347   /*
348    * The data buffer and aux buffer have different implementations
349    * with respect to their definition of head pointer. In the case
350    * of Aux data buffer the head always wraps around the aux buffer
351    * and we don't need to care about it, whereas the data_head keeps
352    * increasing and needs to be wrapped by modulus operator
353    */
354 
355   LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
356 
357   auto data_buffer = m_perf_event.GetDataBuffer();
358 
359   if (head > data_buffer.size()) {
360     head = head % data_buffer.size();
361     LLDB_LOG(log, "Data size -{0} Head - {1}", mmap_metadata.data_size, head);
362 
363     ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset);
364     bytes_remaining -= buffer.size();
365   } else {
366     LLDB_LOG(log, "Head - {0}", head);
367     if (offset >= head) {
368       LLDB_LOG(log, "Invalid Offset ");
369       error.SetErrorString("invalid offset");
370       buffer = buffer.slice(buffer.size());
371       return error;
372     }
373 
374     auto data = data_buffer.slice(offset, (head - offset));
375     auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
376     bytes_remaining -= (remaining - buffer.begin());
377   }
378   buffer = buffer.drop_back(bytes_remaining);
379   return error;
380 #endif
381 }
382 
383 void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
384                                           llvm::ArrayRef<uint8_t> src,
385                                           size_t src_cyc_index, size_t offset) {
386 
387   Log *log = GetLog(POSIXLog::Ptrace);
388 
389   if (dst.empty() || src.empty()) {
390     dst = dst.drop_back(dst.size());
391     return;
392   }
393 
394   if (dst.data() == nullptr || src.data() == nullptr) {
395     dst = dst.drop_back(dst.size());
396     return;
397   }
398 
399   if (src_cyc_index > src.size()) {
400     dst = dst.drop_back(dst.size());
401     return;
402   }
403 
404   if (offset >= src.size()) {
405     LLDB_LOG(log, "Too Big offset ");
406     dst = dst.drop_back(dst.size());
407     return;
408   }
409 
410   llvm::SmallVector<ArrayRef<uint8_t>, 2> parts = {
411       src.slice(src_cyc_index), src.take_front(src_cyc_index)};
412 
413   if (offset > parts[0].size()) {
414     parts[1] = parts[1].slice(offset - parts[0].size());
415     parts[0] = parts[0].drop_back(parts[0].size());
416   } else if (offset == parts[0].size()) {
417     parts[0] = parts[0].drop_back(parts[0].size());
418   } else {
419     parts[0] = parts[0].slice(offset);
420   }
421   auto next = dst.begin();
422   auto bytes_left = dst.size();
423   for (auto part : parts) {
424     size_t chunk_size = std::min(part.size(), bytes_left);
425     next = std::copy_n(part.begin(), chunk_size, next);
426     bytes_left -= chunk_size;
427   }
428   dst = dst.drop_back(bytes_left);
429 }
430 
431 TraceThreadState IntelPTThreadTrace::GetState() const {
432   return {static_cast<int64_t>(m_tid),
433           {TraceBinaryData{"threadTraceBuffer",
434                            static_cast<int64_t>(GetTraceBufferSize())}}};
435 }
436 
437 /// IntelPTThreadTraceCollection
438 
439 bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const {
440   return m_thread_traces.count(tid);
441 }
442 
443 Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) {
444   auto it = m_thread_traces.find(tid);
445   if (it == m_thread_traces.end())
446     return createStringError(inconvertibleErrorCode(),
447                              "Thread %" PRIu64 " not currently traced", tid);
448   m_total_buffer_size -= it->second->GetTraceBufferSize();
449   m_thread_traces.erase(tid);
450   return Error::success();
451 }
452 
453 Error IntelPTThreadTraceCollection::TraceStart(
454     lldb::tid_t tid, const TraceIntelPTStartRequest &request) {
455   if (TracesThread(tid))
456     return createStringError(inconvertibleErrorCode(),
457                              "Thread %" PRIu64 " already traced", tid);
458 
459   Expected<IntelPTThreadTraceUP> trace_up = IntelPTThreadTrace::Create(
460       m_pid, tid, request.threadBufferSize, request.enableTsc,
461       request.psbPeriod.map([](int64_t period) { return (size_t)period; }));
462   if (!trace_up)
463     return trace_up.takeError();
464 
465   m_total_buffer_size += (*trace_up)->GetTraceBufferSize();
466   m_thread_traces.try_emplace(tid, std::move(*trace_up));
467   return Error::success();
468 }
469 
470 size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const {
471   return m_total_buffer_size;
472 }
473 
474 std::vector<TraceThreadState>
475 IntelPTThreadTraceCollection::GetThreadStates() const {
476   std::vector<TraceThreadState> states;
477   for (const auto &it : m_thread_traces)
478     states.push_back(it.second->GetState());
479   return states;
480 }
481 
482 Expected<const IntelPTThreadTrace &>
483 IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) const {
484   auto it = m_thread_traces.find(tid);
485   if (it == m_thread_traces.end())
486     return createStringError(inconvertibleErrorCode(),
487                              "Thread %" PRIu64 " not currently traced", tid);
488   return *it->second.get();
489 }
490 
491 void IntelPTThreadTraceCollection::Clear() {
492   m_thread_traces.clear();
493   m_total_buffer_size = 0;
494 }
495 
496 /// IntelPTProcessTrace
497 
498 bool IntelPTProcessTrace::TracesThread(lldb::tid_t tid) const {
499   return m_thread_traces.TracesThread(tid);
500 }
501 
502 Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) {
503   return m_thread_traces.TraceStop(tid);
504 }
505 
506 Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) {
507   if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize >
508       static_cast<size_t>(*m_tracing_params.processBufferSizeLimit))
509     return createStringError(
510         inconvertibleErrorCode(),
511         "Thread %" PRIu64 " can't be traced as the process trace size limit "
512         "has been reached. Consider retracing with a higher "
513         "limit.",
514         tid);
515 
516   return m_thread_traces.TraceStart(tid, m_tracing_params);
517 }
518 
519 const IntelPTThreadTraceCollection &
520 IntelPTProcessTrace::GetThreadTraces() const {
521   return m_thread_traces;
522 }
523 
524 /// IntelPTCollector
525 
526 IntelPTCollector::IntelPTCollector(lldb::pid_t pid)
527     : m_pid(pid), m_thread_traces(pid) {
528   if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
529           LoadPerfTscConversionParameters())
530     m_tsc_conversion =
531         std::make_unique<LinuxPerfZeroTscConversion>(*tsc_conversion);
532   else
533     LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), tsc_conversion.takeError(),
534                    "unable to load TSC to wall time conversion: {0}");
535 }
536 
537 Error IntelPTCollector::TraceStop(lldb::tid_t tid) {
538   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
539     return m_process_trace->TraceStop(tid);
540   return m_thread_traces.TraceStop(tid);
541 }
542 
543 Error IntelPTCollector::TraceStop(const TraceStopRequest &request) {
544   if (request.IsProcessTracing()) {
545     Clear();
546     return Error::success();
547   } else {
548     Error error = Error::success();
549     for (int64_t tid : *request.tids)
550       error = joinErrors(std::move(error),
551                          TraceStop(static_cast<lldb::tid_t>(tid)));
552     return error;
553   }
554 }
555 
556 Error IntelPTCollector::TraceStart(
557     const TraceIntelPTStartRequest &request,
558     const std::vector<lldb::tid_t> &process_threads) {
559   if (request.IsProcessTracing()) {
560     if (IsProcessTracingEnabled()) {
561       return createStringError(
562           inconvertibleErrorCode(),
563           "Process currently traced. Stop process tracing first");
564     }
565     m_process_trace = IntelPTProcessTrace(m_pid, request);
566 
567     Error error = Error::success();
568     for (lldb::tid_t tid : process_threads)
569       error = joinErrors(std::move(error), m_process_trace->TraceStart(tid));
570     return error;
571   } else {
572     Error error = Error::success();
573     for (int64_t tid : *request.tids)
574       error = joinErrors(std::move(error),
575                          m_thread_traces.TraceStart(tid, request));
576     return error;
577   }
578 }
579 
580 Error IntelPTCollector::OnThreadCreated(lldb::tid_t tid) {
581   if (!IsProcessTracingEnabled())
582     return Error::success();
583   return m_process_trace->TraceStart(tid);
584 }
585 
586 Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {
587   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
588     return m_process_trace->TraceStop(tid);
589   else if (m_thread_traces.TracesThread(tid))
590     return m_thread_traces.TraceStop(tid);
591   return Error::success();
592 }
593 
594 Expected<json::Value> IntelPTCollector::GetState() const {
595   Expected<ArrayRef<uint8_t>> cpu_info = GetCPUInfo();
596   if (!cpu_info)
597     return cpu_info.takeError();
598 
599   TraceGetStateResponse state;
600   state.processBinaryData.push_back(
601       {"cpuInfo", static_cast<int64_t>(cpu_info->size())});
602 
603   std::vector<TraceThreadState> thread_states =
604       m_thread_traces.GetThreadStates();
605   state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
606                              thread_states.end());
607 
608   if (IsProcessTracingEnabled()) {
609     thread_states = m_process_trace->GetThreadTraces().GetThreadStates();
610     state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
611                                thread_states.end());
612   }
613   return toJSON(state);
614 }
615 
616 Expected<const IntelPTThreadTrace &>
617 IntelPTCollector::GetTracedThread(lldb::tid_t tid) const {
618   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
619     return m_process_trace->GetThreadTraces().GetTracedThread(tid);
620   return m_thread_traces.GetTracedThread(tid);
621 }
622 
623 Expected<std::vector<uint8_t>>
624 IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
625   if (request.kind == "threadTraceBuffer") {
626     if (Expected<const IntelPTThreadTrace &> trace =
627             GetTracedThread(*request.tid))
628       return trace->GetIntelPTBuffer(request.offset, request.size);
629     else
630       return trace.takeError();
631   } else if (request.kind == "cpuInfo") {
632     return GetCPUInfo();
633   }
634   return createStringError(inconvertibleErrorCode(),
635                            "Unsuported trace binary data kind: %s",
636                            request.kind.c_str());
637 }
638 
639 void IntelPTCollector::ClearProcessTracing() { m_process_trace = None; }
640 
641 bool IntelPTCollector::IsSupported() {
642   Expected<uint32_t> intel_pt_type = GetOSEventType();
643   if (!intel_pt_type) {
644     llvm::consumeError(intel_pt_type.takeError());
645     return false;
646   }
647   return true;
648 }
649 
650 bool IntelPTCollector::IsProcessTracingEnabled() const {
651   return (bool)m_process_trace;
652 }
653 
654 void IntelPTCollector::Clear() {
655   ClearProcessTracing();
656   m_thread_traces.Clear();
657 }
658