LLVM  10.0.0svn
FDRRecordProducer.cpp
Go to the documentation of this file.
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-exception
6 //
7 //===----------------------------------------------------------------------===//
10 
11 #include <cstdint>
12 
13 namespace llvm {
14 namespace xray {
15 
16 namespace {
17 
18 // Keep this in sync with the values written in the XRay FDR mode runtime in
19 // compiler-rt.
20 enum 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 
36 metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
37 
38  if (T >= static_cast<uint8_t>(MetadataRecordKinds::EnumEndMarker))
39  return createStringError(std::make_error_code(std::errc::invalid_argument),
40  "Invalid metadata record type: %d", T);
41  switch (T) {
42  case MetadataRecordKinds::NewBufferKind:
43  return std::make_unique<NewBufferRecord>();
44  case MetadataRecordKinds::EndOfBufferKind:
45  if (Header.Version >= 2)
46  return createStringError(
47  std::make_error_code(std::errc::executable_format_error),
48  "End of buffer records are no longer supported starting version "
49  "2 of the log.");
50  return std::make_unique<EndBufferRecord>();
51  case MetadataRecordKinds::NewCPUIdKind:
52  return std::make_unique<NewCPUIDRecord>();
53  case MetadataRecordKinds::TSCWrapKind:
54  return std::make_unique<TSCWrapRecord>();
55  case MetadataRecordKinds::WalltimeMarkerKind:
56  return std::make_unique<WallclockRecord>();
57  case MetadataRecordKinds::CustomEventMarkerKind:
58  if (Header.Version >= 5)
59  return std::make_unique<CustomEventRecordV5>();
60  return std::make_unique<CustomEventRecord>();
61  case MetadataRecordKinds::CallArgumentKind:
62  return std::make_unique<CallArgRecord>();
63  case MetadataRecordKinds::BufferExtentsKind:
64  return std::make_unique<BufferExtents>();
65  case MetadataRecordKinds::TypedEventMarkerKind:
66  return std::make_unique<TypedEventRecord>();
67  case MetadataRecordKinds::PidKind:
68  return std::make_unique<PIDRecord>();
69  case MetadataRecordKinds::EnumEndMarker:
70  llvm_unreachable("Invalid MetadataRecordKind");
71  }
72  llvm_unreachable("Unhandled MetadataRecordKinds enum value");
73 }
74 
75 constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
76  return FirstByte & 0x01u;
77 }
78 
79 } // namespace
80 
82 FileBasedRecordProducer::findNextBufferExtent() {
83  // We seek one byte at a time until we find a suitable buffer extents metadata
84  // record introducer.
85  std::unique_ptr<Record> R;
86  while (!R) {
87  auto PreReadOffset = OffsetPtr;
88  uint8_t FirstByte = E.getU8(&OffsetPtr);
89  if (OffsetPtr == PreReadOffset)
90  return createStringError(
91  std::make_error_code(std::errc::executable_format_error),
92  "Failed reading one byte from offset %" PRId64 ".", OffsetPtr);
93 
94  if (isMetadataIntroducer(FirstByte)) {
95  auto LoadedType = FirstByte >> 1;
96  if (LoadedType == MetadataRecordKinds::BufferExtentsKind) {
97  auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
98  if (!MetadataRecordOrErr)
99  return MetadataRecordOrErr.takeError();
100 
101  R = std::move(MetadataRecordOrErr.get());
102  RecordInitializer RI(E, OffsetPtr);
103  if (auto Err = R->apply(RI))
104  return std::move(Err);
105  return std::move(R);
106  }
107  }
108  }
109  llvm_unreachable("Must always terminate with either an error or a record.");
110 }
111 
113  // First, we set up our result record.
114  std::unique_ptr<Record> R;
115 
116  // Before we do any further reading, we should check whether we're at the end
117  // of the current buffer we're been consuming. In FDR logs version >= 3, we
118  // rely on the buffer extents record to determine how many bytes we should be
119  // considering as valid records.
120  if (Header.Version >= 3 && CurrentBufferBytes == 0) {
121  // Find the next buffer extents record.
122  auto BufferExtentsOrError = findNextBufferExtent();
123  if (!BufferExtentsOrError)
124  return joinErrors(
125  BufferExtentsOrError.takeError(),
127  std::make_error_code(std::errc::executable_format_error),
128  "Failed to find the next BufferExtents record."));
129 
130  R = std::move(BufferExtentsOrError.get());
131  assert(R != nullptr);
132  assert(isa<BufferExtents>(R.get()));
133  auto BE = cast<BufferExtents>(R.get());
134  CurrentBufferBytes = BE->size();
135  return std::move(R);
136  }
137 
138  //
139  // At the top level, we read one byte to determine the type of the record to
140  // create. This byte will comprise of the following bits:
141  //
142  // - offset 0: A '1' indicates a metadata record, a '0' indicates a function
143  // record.
144  // - offsets 1-7: For metadata records, this will indicate the kind of
145  // metadata record should be loaded.
146  //
147  // We read first byte, then create the appropriate type of record to consume
148  // the rest of the bytes.
149  auto PreReadOffset = OffsetPtr;
150  uint8_t FirstByte = E.getU8(&OffsetPtr);
151  if (OffsetPtr == PreReadOffset)
152  return createStringError(
153  std::make_error_code(std::errc::executable_format_error),
154  "Failed reading one byte from offset %" PRId64 ".", OffsetPtr);
155 
156  // For metadata records, handle especially here.
157  if (isMetadataIntroducer(FirstByte)) {
158  auto LoadedType = FirstByte >> 1;
159  auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
160  if (!MetadataRecordOrErr)
161  return joinErrors(
162  MetadataRecordOrErr.takeError(),
164  std::make_error_code(std::errc::executable_format_error),
165  "Encountered an unsupported metadata record (%d) "
166  "at offset %" PRId64 ".",
167  LoadedType, PreReadOffset));
168  R = std::move(MetadataRecordOrErr.get());
169  } else {
170  R = std::make_unique<FunctionRecord>();
171  }
172  RecordInitializer RI(E, OffsetPtr);
173 
174  if (auto Err = R->apply(RI))
175  return std::move(Err);
176 
177  // If we encountered a BufferExtents record, we should record the remaining
178  // bytes for the current buffer, to determine when we should start ignoring
179  // potentially malformed data and looking for buffer extents records.
180  if (auto BE = dyn_cast<BufferExtents>(R.get())) {
181  CurrentBufferBytes = BE->size();
182  } else if (Header.Version >= 3) {
183  if (OffsetPtr - PreReadOffset > CurrentBufferBytes)
184  return createStringError(
185  std::make_error_code(std::errc::executable_format_error),
186  "Buffer over-read at offset %" PRId64 " (over-read by %" PRId64
187  " bytes); Record Type = %s.",
188  OffsetPtr, (OffsetPtr - PreReadOffset) - CurrentBufferBytes,
189  Record::kindToString(R->getRecordType()).data());
190 
191  CurrentBufferBytes -= OffsetPtr - PreReadOffset;
192  }
193  assert(R != nullptr);
194  return std::move(R);
195 }
196 
197 } // namespace xray
198 } // namespace llvm
uint8_t getU8(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint8_t value from *offset_ptr.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Expected< std::unique_ptr< Record > > produce() override
This producer encapsulates the logic for loading a File-backed RecordProducer hidden behind a DataExt...
std::error_code make_error_code(BitcodeError E)
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:423
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
XRay traces all have a header providing some top-matter information useful to help tools determine ho...
Definition: XRayRecord.h:27
static StringRef kindToString(RecordKind K)
Definition: FDRRecords.cpp:31
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1197
uint16_t Version
Version of the XRay implementation that produced this file.
Definition: XRayRecord.h:29