LLVM 22.0.0git
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
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 in
19// 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} // namespace
35
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
81FileBasedRecordProducer::findNextBufferExtent() {
82 // We seek one byte at a time until we find a suitable buffer extents metadata
83 // 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
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 end
116 // of the current buffer we're been consuming. In FDR logs version >= 3, we
117 // rely on the buffer extents record to determine how many bytes we should be
118 // 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(),
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 to
139 // create. This byte will comprise of the following bits:
140 //
141 // - offset 0: A '1' indicates a metadata record, a '0' indicates a function
142 // record.
143 // - offsets 1-7: For metadata records, this will indicate the kind of
144 // metadata record should be loaded.
145 //
146 // We read first byte, then create the appropriate type of record to consume
147 // 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(),
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 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 %" PRId64 " (over-read by %" PRId64
186 " 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}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static constexpr bool isMetadataIntroducer(uint8_t FirstByte)
static Expected< std::unique_ptr< Record > > metadataRecordType(const XRayFileHeader &Header, uint8_t T)
#define T
Tagged union holding either a T or a Error.
Definition Error.h:485
Expected< std::unique_ptr< Record > > produce() override
This producer encapsulates the logic for loading a File-backed RecordProducer hidden behind a DataExt...
static LLVM_ABI StringRef kindToString(RecordKind K)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition Error.h:442
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
XRay traces all have a header providing some top-matter information useful to help tools determine ho...
Definition XRayRecord.h:26