[llvm-exegesis] [NFC] Fixing typo.
[llvm-complete.git] / lib / XRay / FDRRecordProducer.cpp
blob452bc6c55fb8627d0d0817754b5246d173d76c0d
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 //===----------------------------------------------------------------------===//
8 #include "llvm/XRay/FDRRecordProducer.h"
9 #include "llvm/Support/DataExtractor.h"
11 #include <cstdint>
13 namespace llvm {
14 namespace xray {
16 namespace {
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,
35 Expected<std::unique_ptr<Record>>
36 metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
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 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 make_unique<EndBufferRecord>();
51 case MetadataRecordKinds::NewCPUIdKind:
52 return make_unique<NewCPUIDRecord>();
53 case MetadataRecordKinds::TSCWrapKind:
54 return make_unique<TSCWrapRecord>();
55 case MetadataRecordKinds::WalltimeMarkerKind:
56 return make_unique<WallclockRecord>();
57 case MetadataRecordKinds::CustomEventMarkerKind:
58 if (Header.Version >= 5)
59 return make_unique<CustomEventRecordV5>();
60 return make_unique<CustomEventRecord>();
61 case MetadataRecordKinds::CallArgumentKind:
62 return make_unique<CallArgRecord>();
63 case MetadataRecordKinds::BufferExtentsKind:
64 return make_unique<BufferExtents>();
65 case MetadataRecordKinds::TypedEventMarkerKind:
66 return make_unique<TypedEventRecord>();
67 case MetadataRecordKinds::PidKind:
68 return make_unique<PIDRecord>();
69 case MetadataRecordKinds::EnumEndMarker:
70 llvm_unreachable("Invalid MetadataRecordKind");
72 llvm_unreachable("Unhandled MetadataRecordKinds enum value");
75 constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
76 return FirstByte & 0x01u;
79 } // namespace
81 Expected<std::unique_ptr<Record>>
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 %d.", OffsetPtr);
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();
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);
109 llvm_unreachable("Must always terminate with either an error or a record.");
112 Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
113 // First, we set up our result record.
114 std::unique_ptr<Record> R;
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(),
126 createStringError(
127 std::make_error_code(std::errc::executable_format_error),
128 "Failed to find the next BufferExtents record."));
130 R = std::move(BufferExtentsOrError.get());
131 assert(R != nullptr);
132 assert(isa<BufferExtents>(R.get()));
133 auto BE = dyn_cast<BufferExtents>(R.get());
134 CurrentBufferBytes = BE->size();
135 return std::move(R);
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:
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.
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 %d.", OffsetPtr);
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(),
163 createStringError(
164 std::make_error_code(std::errc::executable_format_error),
165 "Encountered an unsupported metadata record (%d) at offset %d.",
166 LoadedType, PreReadOffset));
167 R = std::move(MetadataRecordOrErr.get());
168 } else {
169 R = llvm::make_unique<FunctionRecord>();
171 RecordInitializer RI(E, OffsetPtr);
173 if (auto Err = R->apply(RI))
174 return std::move(Err);
176 // If we encountered a BufferExtents record, we should record the remaining
177 // bytes for the current buffer, to determine when we should start ignoring
178 // 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 %d (over-read by %d bytes); Record Type "
186 "= %s.",
187 OffsetPtr, (OffsetPtr - PreReadOffset) - CurrentBufferBytes,
188 Record::kindToString(R->getRecordType()).data());
190 CurrentBufferBytes -= OffsetPtr - PreReadOffset;
192 assert(R != nullptr);
193 return std::move(R);
196 } // namespace xray
197 } // namespace llvm