17b73de9eSWalter Erquinigo //===-- IntelPTSingleBufferTrace.cpp --------------------------------------===//
27b73de9eSWalter Erquinigo //
37b73de9eSWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47b73de9eSWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
57b73de9eSWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67b73de9eSWalter Erquinigo //
77b73de9eSWalter Erquinigo //===----------------------------------------------------------------------===//
87b73de9eSWalter Erquinigo 
97b73de9eSWalter Erquinigo #include "IntelPTSingleBufferTrace.h"
107b73de9eSWalter Erquinigo 
117b73de9eSWalter Erquinigo #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
127b73de9eSWalter Erquinigo #include "lldb/Utility/Status.h"
137b73de9eSWalter Erquinigo #include "lldb/Utility/StreamString.h"
147b73de9eSWalter Erquinigo 
157b73de9eSWalter Erquinigo #include "llvm/Support/Host.h"
167b73de9eSWalter Erquinigo #include "llvm/Support/MemoryBuffer.h"
177b73de9eSWalter Erquinigo 
187b73de9eSWalter Erquinigo #include <sstream>
197b73de9eSWalter Erquinigo 
207b73de9eSWalter Erquinigo #include <linux/perf_event.h>
217b73de9eSWalter Erquinigo #include <sys/syscall.h>
227b73de9eSWalter Erquinigo #include <unistd.h>
237b73de9eSWalter Erquinigo 
247b73de9eSWalter Erquinigo using namespace lldb;
257b73de9eSWalter Erquinigo using namespace lldb_private;
267b73de9eSWalter Erquinigo using namespace process_linux;
277b73de9eSWalter Erquinigo using namespace llvm;
287b73de9eSWalter Erquinigo 
297b73de9eSWalter Erquinigo const char *kOSEventIntelPTTypeFile =
307b73de9eSWalter Erquinigo     "/sys/bus/event_source/devices/intel_pt/type";
317b73de9eSWalter Erquinigo 
327b73de9eSWalter Erquinigo const char *kPSBPeriodCapFile =
337b73de9eSWalter Erquinigo     "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc";
347b73de9eSWalter Erquinigo 
357b73de9eSWalter Erquinigo const char *kPSBPeriodValidValuesFile =
367b73de9eSWalter Erquinigo     "/sys/bus/event_source/devices/intel_pt/caps/psb_periods";
377b73de9eSWalter Erquinigo 
387b73de9eSWalter Erquinigo const char *kPSBPeriodBitOffsetFile =
397b73de9eSWalter Erquinigo     "/sys/bus/event_source/devices/intel_pt/format/psb_period";
407b73de9eSWalter Erquinigo 
417b73de9eSWalter Erquinigo const char *kTSCBitOffsetFile =
427b73de9eSWalter Erquinigo     "/sys/bus/event_source/devices/intel_pt/format/tsc";
437b73de9eSWalter Erquinigo 
447b73de9eSWalter Erquinigo enum IntelPTConfigFileType {
457b73de9eSWalter Erquinigo   Hex = 0,
467b73de9eSWalter Erquinigo   // 0 or 1
477b73de9eSWalter Erquinigo   ZeroOne,
487b73de9eSWalter Erquinigo   Decimal,
497b73de9eSWalter Erquinigo   // a bit index file always starts with the prefix config: following by an int,
507b73de9eSWalter Erquinigo   // which represents the offset of the perf_event_attr.config value where to
517b73de9eSWalter Erquinigo   // store a given configuration.
527b73de9eSWalter Erquinigo   BitOffset
537b73de9eSWalter Erquinigo };
547b73de9eSWalter Erquinigo 
ReadIntelPTConfigFile(const char * file,IntelPTConfigFileType type)557b73de9eSWalter Erquinigo static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
567b73de9eSWalter Erquinigo                                                 IntelPTConfigFileType type) {
577b73de9eSWalter Erquinigo   ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
587b73de9eSWalter Erquinigo       MemoryBuffer::getFileAsStream(file);
597b73de9eSWalter Erquinigo 
607b73de9eSWalter Erquinigo   if (!stream)
617b73de9eSWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
627b73de9eSWalter Erquinigo                              "Can't open the file '%s'", file);
637b73de9eSWalter Erquinigo 
647b73de9eSWalter Erquinigo   uint32_t value = 0;
657b73de9eSWalter Erquinigo   StringRef text_buffer = stream.get()->getBuffer();
667b73de9eSWalter Erquinigo 
677b73de9eSWalter Erquinigo   if (type == BitOffset) {
687b73de9eSWalter Erquinigo     const char *prefix = "config:";
697b73de9eSWalter Erquinigo     if (!text_buffer.startswith(prefix))
707b73de9eSWalter Erquinigo       return createStringError(inconvertibleErrorCode(),
717b73de9eSWalter Erquinigo                                "The file '%s' contents doesn't start with '%s'",
727b73de9eSWalter Erquinigo                                file, prefix);
737b73de9eSWalter Erquinigo     text_buffer = text_buffer.substr(strlen(prefix));
747b73de9eSWalter Erquinigo   }
757b73de9eSWalter Erquinigo 
767b73de9eSWalter Erquinigo   auto getRadix = [&]() {
777b73de9eSWalter Erquinigo     switch (type) {
787b73de9eSWalter Erquinigo     case Hex:
797b73de9eSWalter Erquinigo       return 16;
807b73de9eSWalter Erquinigo     case ZeroOne:
817b73de9eSWalter Erquinigo     case Decimal:
827b73de9eSWalter Erquinigo     case BitOffset:
837b73de9eSWalter Erquinigo       return 10;
847b73de9eSWalter Erquinigo     }
857b73de9eSWalter Erquinigo     llvm_unreachable("Fully covered switch above!");
867b73de9eSWalter Erquinigo   };
877b73de9eSWalter Erquinigo 
887b73de9eSWalter Erquinigo   auto createError = [&](const char *expected_value_message) {
897b73de9eSWalter Erquinigo     return createStringError(
907b73de9eSWalter Erquinigo         inconvertibleErrorCode(),
917b73de9eSWalter Erquinigo         "The file '%s' has an invalid value. It should be %s.", file,
927b73de9eSWalter Erquinigo         expected_value_message);
937b73de9eSWalter Erquinigo   };
947b73de9eSWalter Erquinigo 
957b73de9eSWalter Erquinigo   if (text_buffer.trim().consumeInteger(getRadix(), value) ||
967b73de9eSWalter Erquinigo       (type == ZeroOne && value != 0 && value != 1)) {
977b73de9eSWalter Erquinigo     switch (type) {
987b73de9eSWalter Erquinigo     case Hex:
997b73de9eSWalter Erquinigo       return createError("an unsigned hexadecimal int");
1007b73de9eSWalter Erquinigo     case ZeroOne:
1017b73de9eSWalter Erquinigo       return createError("0 or 1");
1027b73de9eSWalter Erquinigo     case Decimal:
1037b73de9eSWalter Erquinigo     case BitOffset:
1047b73de9eSWalter Erquinigo       return createError("an unsigned decimal int");
1057b73de9eSWalter Erquinigo     }
1067b73de9eSWalter Erquinigo   }
1077b73de9eSWalter Erquinigo   return value;
1087b73de9eSWalter Erquinigo }
1097b73de9eSWalter Erquinigo 
1107b73de9eSWalter Erquinigo /// Return the Linux perf event type for Intel PT.
GetIntelPTOSEventType()1117b73de9eSWalter Erquinigo Expected<uint32_t> process_linux::GetIntelPTOSEventType() {
1127b73de9eSWalter Erquinigo   return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile,
1137b73de9eSWalter Erquinigo                                IntelPTConfigFileType::Decimal);
1147b73de9eSWalter Erquinigo }
1157b73de9eSWalter Erquinigo 
CheckPsbPeriod(size_t psb_period)1167b73de9eSWalter Erquinigo static Error CheckPsbPeriod(size_t psb_period) {
1177b73de9eSWalter Erquinigo   Expected<uint32_t> cap =
1187b73de9eSWalter Erquinigo       ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne);
1197b73de9eSWalter Erquinigo   if (!cap)
1207b73de9eSWalter Erquinigo     return cap.takeError();
1217b73de9eSWalter Erquinigo   if (*cap == 0)
1227b73de9eSWalter Erquinigo     return createStringError(inconvertibleErrorCode(),
1237b73de9eSWalter Erquinigo                              "psb_period is unsupported in the system.");
1247b73de9eSWalter Erquinigo 
1257b73de9eSWalter Erquinigo   Expected<uint32_t> valid_values = ReadIntelPTConfigFile(
1267b73de9eSWalter Erquinigo       kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex);
1277b73de9eSWalter Erquinigo   if (!valid_values)
1287b73de9eSWalter Erquinigo     return valid_values.takeError();
1297b73de9eSWalter Erquinigo 
1307b73de9eSWalter Erquinigo   if (valid_values.get() & (1 << psb_period))
1317b73de9eSWalter Erquinigo     return Error::success();
1327b73de9eSWalter Erquinigo 
1337b73de9eSWalter Erquinigo   std::ostringstream error;
1347b73de9eSWalter Erquinigo   // 0 is always a valid value
1357b73de9eSWalter Erquinigo   error << "Invalid psb_period. Valid values are: 0";
1367b73de9eSWalter Erquinigo   uint32_t mask = valid_values.get();
1377b73de9eSWalter Erquinigo   while (mask) {
1387b73de9eSWalter Erquinigo     int index = __builtin_ctz(mask);
1397b73de9eSWalter Erquinigo     if (index > 0)
1407b73de9eSWalter Erquinigo       error << ", " << index;
1417b73de9eSWalter Erquinigo     // clear the lowest bit
1427b73de9eSWalter Erquinigo     mask &= mask - 1;
1437b73de9eSWalter Erquinigo   }
1447b73de9eSWalter Erquinigo   error << ".";
1457b73de9eSWalter Erquinigo   return createStringError(inconvertibleErrorCode(), error.str().c_str());
1467b73de9eSWalter Erquinigo }
1477b73de9eSWalter Erquinigo 
148909a2e3cSWalter Erquinigo #ifdef PERF_ATTR_SIZE_VER5
1497b73de9eSWalter Erquinigo static Expected<uint64_t>
GeneratePerfEventConfigValue(bool enable_tsc,Optional<uint64_t> psb_period)150b6bb9e7dSWalter Erquinigo GeneratePerfEventConfigValue(bool enable_tsc, Optional<uint64_t> psb_period) {
1517b73de9eSWalter Erquinigo   uint64_t config = 0;
1527b73de9eSWalter Erquinigo   // tsc is always supported
1537b73de9eSWalter Erquinigo   if (enable_tsc) {
1547b73de9eSWalter Erquinigo     if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
1557b73de9eSWalter Erquinigo             kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset))
1567b73de9eSWalter Erquinigo       config |= 1 << *offset;
1577b73de9eSWalter Erquinigo     else
1587b73de9eSWalter Erquinigo       return offset.takeError();
1597b73de9eSWalter Erquinigo   }
1607b73de9eSWalter Erquinigo   if (psb_period) {
1617b73de9eSWalter Erquinigo     if (Error error = CheckPsbPeriod(*psb_period))
1627b73de9eSWalter Erquinigo       return std::move(error);
1637b73de9eSWalter Erquinigo 
1647b73de9eSWalter Erquinigo     if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
1657b73de9eSWalter Erquinigo             kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset))
1667b73de9eSWalter Erquinigo       config |= *psb_period << *offset;
1677b73de9eSWalter Erquinigo     else
1687b73de9eSWalter Erquinigo       return offset.takeError();
1697b73de9eSWalter Erquinigo   }
1707b73de9eSWalter Erquinigo   return config;
1717b73de9eSWalter Erquinigo }
1727b73de9eSWalter Erquinigo 
1737b73de9eSWalter Erquinigo /// Create a \a perf_event_attr configured for
1747b73de9eSWalter Erquinigo /// an IntelPT event.
1757b73de9eSWalter Erquinigo ///
1767b73de9eSWalter Erquinigo /// \return
1777b73de9eSWalter Erquinigo ///   A \a perf_event_attr if successful,
1787b73de9eSWalter Erquinigo ///   or an \a llvm::Error otherwise.
1797b73de9eSWalter Erquinigo static Expected<perf_event_attr>
CreateIntelPTPerfEventConfiguration(bool enable_tsc,llvm::Optional<uint64_t> psb_period)1807b73de9eSWalter Erquinigo CreateIntelPTPerfEventConfiguration(bool enable_tsc,
181c4172c75SWalter Erquinigo                                     llvm::Optional<uint64_t> psb_period) {
1827b73de9eSWalter Erquinigo   perf_event_attr attr;
1837b73de9eSWalter Erquinigo   memset(&attr, 0, sizeof(attr));
1847b73de9eSWalter Erquinigo   attr.size = sizeof(attr);
1857b73de9eSWalter Erquinigo   attr.exclude_kernel = 1;
1867b73de9eSWalter Erquinigo   attr.exclude_hv = 1;
1877b73de9eSWalter Erquinigo   attr.exclude_idle = 1;
1887b73de9eSWalter Erquinigo 
1897b73de9eSWalter Erquinigo   if (Expected<uint64_t> config_value =
1907b73de9eSWalter Erquinigo           GeneratePerfEventConfigValue(enable_tsc, psb_period))
1917b73de9eSWalter Erquinigo     attr.config = *config_value;
1927b73de9eSWalter Erquinigo   else
1937b73de9eSWalter Erquinigo     return config_value.takeError();
1947b73de9eSWalter Erquinigo 
1957b73de9eSWalter Erquinigo   if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType())
1967b73de9eSWalter Erquinigo     attr.type = *intel_pt_type;
1977b73de9eSWalter Erquinigo   else
1987b73de9eSWalter Erquinigo     return intel_pt_type.takeError();
1997b73de9eSWalter Erquinigo 
2007b73de9eSWalter Erquinigo   return attr;
2017b73de9eSWalter Erquinigo }
202909a2e3cSWalter Erquinigo #endif
2037b73de9eSWalter Erquinigo 
GetIptTraceSize() const2046a5355e8SWalter Erquinigo size_t IntelPTSingleBufferTrace::GetIptTraceSize() const {
2057b73de9eSWalter Erquinigo   return m_perf_event.GetAuxBuffer().size();
2067b73de9eSWalter Erquinigo }
2077b73de9eSWalter Erquinigo 
Pause()208a7582059SWalter Erquinigo Error IntelPTSingleBufferTrace::Pause() {
209a7582059SWalter Erquinigo   return m_perf_event.DisableWithIoctl();
2101637545fSWalter Erquinigo }
211a7582059SWalter Erquinigo 
Resume()212a7582059SWalter Erquinigo Error IntelPTSingleBufferTrace::Resume() {
213a7582059SWalter Erquinigo   return m_perf_event.EnableWithIoctl();
2141637545fSWalter Erquinigo }
2151637545fSWalter Erquinigo 
GetIptTrace()2166a5355e8SWalter Erquinigo Expected<std::vector<uint8_t>> IntelPTSingleBufferTrace::GetIptTrace() {
2177b73de9eSWalter Erquinigo   // Disable the perf event to force a flush out of the CPU's internal buffer.
2187b73de9eSWalter Erquinigo   // Besides, we can guarantee that the CPU won't override any data as we are
2197b73de9eSWalter Erquinigo   // reading the buffer.
2207b73de9eSWalter Erquinigo   // The Intel documentation says:
2217b73de9eSWalter Erquinigo   //
2221637545fSWalter Erquinigo   // Packets are first buffered internally and then written out
2231637545fSWalter Erquinigo   // asynchronously. To collect packet output for postprocessing, a collector
2241637545fSWalter Erquinigo   // needs first to ensure that all packet data has been flushed from internal
2251637545fSWalter Erquinigo   // buffers. Software can ensure this by stopping packet generation by
2261637545fSWalter Erquinigo   // clearing IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
2277b73de9eSWalter Erquinigo   // Section 35.2.7.2).
2287b73de9eSWalter Erquinigo   //
2291637545fSWalter Erquinigo   // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as
2301637545fSWalter Erquinigo   // mentioned in the man page of perf_event_open.
231561a61fbSWalter Erquinigo   return m_perf_event.GetReadOnlyAuxBuffer();
2327b73de9eSWalter Erquinigo }
2337b73de9eSWalter Erquinigo 
Start(const TraceIntelPTStartRequest & request,Optional<lldb::tid_t> tid,Optional<cpu_id_t> cpu_id,bool disabled,Optional<int> cgroup_fd)234*d30fd5c3SGaurav Gaur Expected<IntelPTSingleBufferTrace> IntelPTSingleBufferTrace::Start(
235*d30fd5c3SGaurav Gaur     const TraceIntelPTStartRequest &request, Optional<lldb::tid_t> tid,
236*d30fd5c3SGaurav Gaur     Optional<cpu_id_t> cpu_id, bool disabled, Optional<int> cgroup_fd) {
237909a2e3cSWalter Erquinigo #ifndef PERF_ATTR_SIZE_VER5
238909a2e3cSWalter Erquinigo   return createStringError(inconvertibleErrorCode(),
239909a2e3cSWalter Erquinigo                            "Intel PT Linux perf event not supported");
240909a2e3cSWalter Erquinigo #else
2417b73de9eSWalter Erquinigo   Log *log = GetLog(POSIXLog::Trace);
2427b73de9eSWalter Erquinigo 
2436a5355e8SWalter Erquinigo   LLDB_LOG(log, "Will start tracing thread id {0} and cpu id {1}", tid, cpu_id);
2447b73de9eSWalter Erquinigo 
2456a5355e8SWalter Erquinigo   if (__builtin_popcount(request.ipt_trace_size) != 1 ||
2466a5355e8SWalter Erquinigo       request.ipt_trace_size < 4096) {
2477b73de9eSWalter Erquinigo     return createStringError(
2487b73de9eSWalter Erquinigo         inconvertibleErrorCode(),
2496a5355e8SWalter Erquinigo         "The intel pt trace size must be a power of 2 greater than or equal to "
2507b73de9eSWalter Erquinigo         "4096 (2^12) bytes. It was %" PRIu64 ".",
2516a5355e8SWalter Erquinigo         request.ipt_trace_size);
2527b73de9eSWalter Erquinigo   }
2537b73de9eSWalter Erquinigo   uint64_t page_size = getpagesize();
2545a92632dSWalter Erquinigo   uint64_t aux_buffer_numpages = static_cast<uint64_t>(llvm::PowerOf2Floor(
2556a5355e8SWalter Erquinigo       (request.ipt_trace_size + page_size - 1) / page_size));
2567b73de9eSWalter Erquinigo 
2577b73de9eSWalter Erquinigo   Expected<perf_event_attr> attr = CreateIntelPTPerfEventConfiguration(
2587b73de9eSWalter Erquinigo       request.enable_tsc, request.psb_period.map([](int value) {
2597b73de9eSWalter Erquinigo         return static_cast<uint64_t>(value);
2607b73de9eSWalter Erquinigo       }));
2617b73de9eSWalter Erquinigo   if (!attr)
2627b73de9eSWalter Erquinigo     return attr.takeError();
263a7582059SWalter Erquinigo   attr->disabled = disabled;
2647b73de9eSWalter Erquinigo 
2656a5355e8SWalter Erquinigo   LLDB_LOG(log, "Will create intel pt trace buffer of size {0}",
2666a5355e8SWalter Erquinigo            request.ipt_trace_size);
267*d30fd5c3SGaurav Gaur   unsigned long flags = 0;
268*d30fd5c3SGaurav Gaur   if (cgroup_fd) {
269*d30fd5c3SGaurav Gaur     tid = *cgroup_fd;
270*d30fd5c3SGaurav Gaur     flags |= PERF_FLAG_PID_CGROUP;
271*d30fd5c3SGaurav Gaur   }
2727b73de9eSWalter Erquinigo 
273*d30fd5c3SGaurav Gaur   if (Expected<PerfEvent> perf_event =
274*d30fd5c3SGaurav Gaur           PerfEvent::Init(*attr, tid, cpu_id, -1, flags)) {
2755a92632dSWalter Erquinigo     if (Error mmap_err = perf_event->MmapMetadataAndBuffers(
276fc5ef57cSWalter Erquinigo             /*num_data_pages=*/0, aux_buffer_numpages,
277fc5ef57cSWalter Erquinigo             /*data_buffer_write=*/true)) {
2787b73de9eSWalter Erquinigo       return std::move(mmap_err);
2797b73de9eSWalter Erquinigo     }
280a7582059SWalter Erquinigo     return IntelPTSingleBufferTrace(std::move(*perf_event));
2817b73de9eSWalter Erquinigo   } else {
2827b73de9eSWalter Erquinigo     return perf_event.takeError();
2837b73de9eSWalter Erquinigo   }
284909a2e3cSWalter Erquinigo #endif
2857b73de9eSWalter Erquinigo }
286a7582059SWalter Erquinigo 
GetPerfEvent() const287a7582059SWalter Erquinigo const PerfEvent &IntelPTSingleBufferTrace::GetPerfEvent() const {
288a7582059SWalter Erquinigo   return m_perf_event;
289a7582059SWalter Erquinigo }
290