LLVM  8.0.1
FDRRecordProducer.cpp
Go to the documentation of this file.
1 //===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
11 
12 #include <cstdint>
13 
14 namespace llvm {
15 namespace xray {
16 
17 namespace {
18 
19 // Keep this in sync with the values written in the XRay FDR mode runtime in
20 // compiler-rt.
21 enum MetadataRecordKinds : uint8_t {
22  NewBufferKind,
23  EndOfBufferKind,
24  NewCPUIdKind,
25  TSCWrapKind,
26  WalltimeMarkerKind,
27  CustomEventMarkerKind,
28  CallArgumentKind,
29  BufferExtentsKind,
30  TypedEventMarkerKind,
31  PidKind,
32  // This is an end marker, used to identify the upper bound for this enum.
33  EnumEndMarker,
34 };
35 
37 metadataRecordType(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 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 make_unique<EndBufferRecord>();
52  case MetadataRecordKinds::NewCPUIdKind:
53  return make_unique<NewCPUIDRecord>();
54  case MetadataRecordKinds::TSCWrapKind:
55  return make_unique<TSCWrapRecord>();
56  case MetadataRecordKinds::WalltimeMarkerKind:
57  return make_unique<WallclockRecord>();
58  case MetadataRecordKinds::CustomEventMarkerKind:
59  if (Header.Version >= 5)
60  return make_unique<CustomEventRecordV5>();
61  return make_unique<CustomEventRecord>();
62  case MetadataRecordKinds::CallArgumentKind:
63  return make_unique<CallArgRecord>();
64  case MetadataRecordKinds::BufferExtentsKind:
65  return make_unique<BufferExtents>();
66  case MetadataRecordKinds::TypedEventMarkerKind:
67  return make_unique<TypedEventRecord>();
68  case MetadataRecordKinds::PidKind:
69  return make_unique<PIDRecord>();
70  case MetadataRecordKinds::EnumEndMarker:
71  llvm_unreachable("Invalid MetadataRecordKind");
72  }
73  llvm_unreachable("Unhandled MetadataRecordKinds enum value");
74 }
75 
76 constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
77  return FirstByte & 0x01u;
78 }
79 
80 } // namespace
81 
83 FileBasedRecordProducer::findNextBufferExtent() {
84  // We seek one byte at a time until we find a suitable buffer extents metadata
85  // record introducer.
86  std::unique_ptr<Record> R;
87  while (!R) {
88  auto PreReadOffset = OffsetPtr;
89  uint8_t FirstByte = E.getU8(&OffsetPtr);
90  if (OffsetPtr == PreReadOffset)
91  return createStringError(
92  std::make_error_code(std::errc::executable_format_error),
93  "Failed reading one byte from offset %d.", OffsetPtr);
94 
95  if (isMetadataIntroducer(FirstByte)) {
96  auto LoadedType = FirstByte >> 1;
97  if (LoadedType == MetadataRecordKinds::BufferExtentsKind) {
98  auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
99  if (!MetadataRecordOrErr)
100  return MetadataRecordOrErr.takeError();
101 
102  R = std::move(MetadataRecordOrErr.get());
103  RecordInitializer RI(E, OffsetPtr);
104  if (auto Err = R->apply(RI))
105  return std::move(Err);
106  return std::move(R);
107  }
108  }
109  }
110  llvm_unreachable("Must always terminate with either an error or a record.");
111 }
112 
114  // First, we set up our result record.
115  std::unique_ptr<Record> R;
116 
117  // Before we do any further reading, we should check whether we're at the end
118  // of the current buffer we're been consuming. In FDR logs version >= 3, we
119  // rely on the buffer extents record to determine how many bytes we should be
120  // considering as valid records.
121  if (Header.Version >= 3 && CurrentBufferBytes == 0) {
122  // Find the next buffer extents record.
123  auto BufferExtentsOrError = findNextBufferExtent();
124  if (!BufferExtentsOrError)
125  return joinErrors(
126  BufferExtentsOrError.takeError(),
128  std::make_error_code(std::errc::executable_format_error),
129  "Failed to find the next BufferExtents record."));
130 
131  R = std::move(BufferExtentsOrError.get());
132  assert(R != nullptr);
133  assert(isa<BufferExtents>(R.get()));
134  auto BE = dyn_cast<BufferExtents>(R.get());
135  CurrentBufferBytes = BE->size();
136  return std::move(R);
137  }
138 
139  //
140  // At the top level, we read one byte to determine the type of the record to
141  // create. This byte will comprise of the following bits:
142  //
143  // - offset 0: A '1' indicates a metadata record, a '0' indicates a function
144  // record.
145  // - offsets 1-7: For metadata records, this will indicate the kind of
146  // metadata record should be loaded.
147  //
148  // We read first byte, then create the appropriate type of record to consume
149  // the rest of the bytes.
150  auto PreReadOffset = OffsetPtr;
151  uint8_t FirstByte = E.getU8(&OffsetPtr);
152  if (OffsetPtr == PreReadOffset)
153  return createStringError(
154  std::make_error_code(std::errc::executable_format_error),
155  "Failed reading one byte from offset %d.", OffsetPtr);
156 
157  // For metadata records, handle especially here.
158  if (isMetadataIntroducer(FirstByte)) {
159  auto LoadedType = FirstByte >> 1;
160  auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
161  if (!MetadataRecordOrErr)
162  return joinErrors(
163  MetadataRecordOrErr.takeError(),
165  std::make_error_code(std::errc::executable_format_error),
166  "Encountered an unsupported metadata record (%d) at offset %d.",
167  LoadedType, PreReadOffset));
168  R = std::move(MetadataRecordOrErr.get());
169  } else {
170  R = llvm::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 %d (over-read by %d bytes); Record Type "
187  "= %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
This class represents lattice values for constants.
Definition: AllocatorList.h:24
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: CachePruning.h:23
uint8_t getU8(uint32_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
#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:424
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:323
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:28
static StringRef kindToString(RecordKind K)
Definition: FDRRecords.cpp:32
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1164
uint16_t Version
Version of the XRay implementation that produced this file.
Definition: XRayRecord.h:30