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