brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 0f4eed1 Raw
195 lines · cpp
1//===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//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-exception6//7//===----------------------------------------------------------------------===//8#include "llvm/XRay/FDRRecordProducer.h"9#include "llvm/Support/DataExtractor.h"10 11#include <cstdint>12 13using namespace llvm;14using namespace llvm::xray;15 16namespace {17 18// Keep this in sync with the values written in the XRay FDR mode runtime in19// compiler-rt.20enum MetadataRecordKinds : uint8_t {21  NewBufferKind,22  EndOfBufferKind,23  NewCPUIdKind,24  TSCWrapKind,25  WalltimeMarkerKind,26  CustomEventMarkerKind,27  CallArgumentKind,28  BufferExtentsKind,29  TypedEventMarkerKind,30  PidKind,31  // This is an end marker, used to identify the upper bound for this enum.32  EnumEndMarker,33};34} // namespace35 36static Expected<std::unique_ptr<Record>>37metadataRecordType(const XRayFileHeader &Header, uint8_t T) {38 39  if (T >= static_cast<uint8_t>(MetadataRecordKinds::EnumEndMarker))40    return createStringError(std::make_error_code(std::errc::invalid_argument),41                             "Invalid metadata record type: %d", T);42  switch (T) {43  case MetadataRecordKinds::NewBufferKind:44    return std::make_unique<NewBufferRecord>();45  case MetadataRecordKinds::EndOfBufferKind:46    if (Header.Version >= 2)47      return createStringError(48          std::make_error_code(std::errc::executable_format_error),49          "End of buffer records are no longer supported starting version "50          "2 of the log.");51    return std::make_unique<EndBufferRecord>();52  case MetadataRecordKinds::NewCPUIdKind:53    return std::make_unique<NewCPUIDRecord>();54  case MetadataRecordKinds::TSCWrapKind:55    return std::make_unique<TSCWrapRecord>();56  case MetadataRecordKinds::WalltimeMarkerKind:57    return std::make_unique<WallclockRecord>();58  case MetadataRecordKinds::CustomEventMarkerKind:59    if (Header.Version >= 5)60      return std::make_unique<CustomEventRecordV5>();61    return std::make_unique<CustomEventRecord>();62  case MetadataRecordKinds::CallArgumentKind:63    return std::make_unique<CallArgRecord>();64  case MetadataRecordKinds::BufferExtentsKind:65    return std::make_unique<BufferExtents>();66  case MetadataRecordKinds::TypedEventMarkerKind:67    return std::make_unique<TypedEventRecord>();68  case MetadataRecordKinds::PidKind:69    return std::make_unique<PIDRecord>();70  case MetadataRecordKinds::EnumEndMarker:71    llvm_unreachable("Invalid MetadataRecordKind");72  }73  llvm_unreachable("Unhandled MetadataRecordKinds enum value");74}75 76static constexpr bool isMetadataIntroducer(uint8_t FirstByte) {77  return FirstByte & 0x01u;78}79 80Expected<std::unique_ptr<Record>>81FileBasedRecordProducer::findNextBufferExtent() {82  // We seek one byte at a time until we find a suitable buffer extents metadata83  // record introducer.84  std::unique_ptr<Record> R;85  while (!R) {86    auto PreReadOffset = OffsetPtr;87    uint8_t FirstByte = E.getU8(&OffsetPtr);88    if (OffsetPtr == PreReadOffset)89      return createStringError(90          std::make_error_code(std::errc::executable_format_error),91          "Failed reading one byte from offset %" PRId64 ".", OffsetPtr);92 93    if (isMetadataIntroducer(FirstByte)) {94      auto LoadedType = FirstByte >> 1;95      if (LoadedType == MetadataRecordKinds::BufferExtentsKind) {96        auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);97        if (!MetadataRecordOrErr)98          return MetadataRecordOrErr.takeError();99 100        R = std::move(MetadataRecordOrErr.get());101        RecordInitializer RI(E, OffsetPtr);102        if (auto Err = R->apply(RI))103          return std::move(Err);104        return std::move(R);105      }106    }107  }108  llvm_unreachable("Must always terminate with either an error or a record.");109}110 111Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {112  // First, we set up our result record.113  std::unique_ptr<Record> R;114 115  // Before we do any further reading, we should check whether we're at the end116  // of the current buffer we're been consuming. In FDR logs version >= 3, we117  // rely on the buffer extents record to determine how many bytes we should be118  // considering as valid records.119  if (Header.Version >= 3 && CurrentBufferBytes == 0) {120    // Find the next buffer extents record.121    auto BufferExtentsOrError = findNextBufferExtent();122    if (!BufferExtentsOrError)123      return joinErrors(124          BufferExtentsOrError.takeError(),125          createStringError(126              std::make_error_code(std::errc::executable_format_error),127              "Failed to find the next BufferExtents record."));128 129    R = std::move(BufferExtentsOrError.get());130    assert(R != nullptr);131    assert(isa<BufferExtents>(R.get()));132    auto BE = cast<BufferExtents>(R.get());133    CurrentBufferBytes = BE->size();134    return std::move(R);135  }136 137  //138  // At the top level, we read one byte to determine the type of the record to139  // create. This byte will comprise of the following bits:140  //141  //   - offset 0: A '1' indicates a metadata record, a '0' indicates a function142  //     record.143  //   - offsets 1-7: For metadata records, this will indicate the kind of144  //     metadata record should be loaded.145  //146  // We read first byte, then create the appropriate type of record to consume147  // the rest of the bytes.148  auto PreReadOffset = OffsetPtr;149  uint8_t FirstByte = E.getU8(&OffsetPtr);150  if (OffsetPtr == PreReadOffset)151    return createStringError(152        std::make_error_code(std::errc::executable_format_error),153        "Failed reading one byte from offset %" PRId64 ".", OffsetPtr);154 155  // For metadata records, handle especially here.156  if (isMetadataIntroducer(FirstByte)) {157    auto LoadedType = FirstByte >> 1;158    auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);159    if (!MetadataRecordOrErr)160      return joinErrors(161          MetadataRecordOrErr.takeError(),162          createStringError(163              std::make_error_code(std::errc::executable_format_error),164              "Encountered an unsupported metadata record (%d) "165              "at offset %" PRId64 ".",166              LoadedType, PreReadOffset));167    R = std::move(MetadataRecordOrErr.get());168  } else {169    R = std::make_unique<FunctionRecord>();170  }171  RecordInitializer RI(E, OffsetPtr);172 173  if (auto Err = R->apply(RI))174    return std::move(Err);175 176  // If we encountered a BufferExtents record, we should record the remaining177  // bytes for the current buffer, to determine when we should start ignoring178  // potentially malformed data and looking for buffer extents records.179  if (auto BE = dyn_cast<BufferExtents>(R.get())) {180    CurrentBufferBytes = BE->size();181  } else if (Header.Version >= 3) {182    if (OffsetPtr - PreReadOffset > CurrentBufferBytes)183      return createStringError(184          std::make_error_code(std::errc::executable_format_error),185          "Buffer over-read at offset %" PRId64 " (over-read by %" PRId64186          " bytes); Record Type = %s.",187          OffsetPtr, (OffsetPtr - PreReadOffset) - CurrentBufferBytes,188          Record::kindToString(R->getRecordType()).data());189 190    CurrentBufferBytes -= OffsetPtr - PreReadOffset;191  }192  assert(R != nullptr);193  return std::move(R);194}195