]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/XRay/FDRRecordProducer.cpp
Vendor import of llvm trunk r351319 (just before the release_80 branch
[FreeBSD/FreeBSD.git] / lib / XRay / FDRRecordProducer.cpp
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 //===----------------------------------------------------------------------===//
9 #include "llvm/XRay/FDRRecordProducer.h"
10 #include "llvm/Support/DataExtractor.h"
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
36 Expected<std::unique_ptr<Record>>
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
82 Expected<std::unique_ptr<Record>>
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
113 Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
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(),
127           createStringError(
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(),
164           createStringError(
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