blob: 25b3ee8af219353a86901ec489a737e87f228417 [file] [log] [blame]
Dean Michael Berris146d57912018-08-31 08:04:56 +00001//===- 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
Dean Michael Berrisda375a62018-11-09 06:26:48 +000012#include <cstdint>
13
Dean Michael Berris146d57912018-08-31 08:04:56 +000014namespace llvm {
15namespace xray {
16
17namespace {
18
Dean Michael Berrisda375a62018-11-09 06:26:48 +000019// Keep this in sync with the values written in the XRay FDR mode runtime in
20// compiler-rt.
21enum 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
Dean Michael Berris146d57912018-08-31 08:04:56 +000036Expected<std::unique_ptr<Record>>
37metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000038
Dean Michael Berris146d57912018-08-31 08:04:56 +000039 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);
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000042 switch (T) {
43 case MetadataRecordKinds::NewBufferKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000044 return make_unique<NewBufferRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000045 case MetadataRecordKinds::EndOfBufferKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000046 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>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000052 case MetadataRecordKinds::NewCPUIdKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000053 return make_unique<NewCPUIDRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000054 case MetadataRecordKinds::TSCWrapKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000055 return make_unique<TSCWrapRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000056 case MetadataRecordKinds::WalltimeMarkerKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000057 return make_unique<WallclockRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000058 case MetadataRecordKinds::CustomEventMarkerKind:
Dean Michael Berris59439dd2018-11-07 04:37:42 +000059 if (Header.Version >= 5)
60 return make_unique<CustomEventRecordV5>();
Dean Michael Berris146d57912018-08-31 08:04:56 +000061 return make_unique<CustomEventRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000062 case MetadataRecordKinds::CallArgumentKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000063 return make_unique<CallArgRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000064 case MetadataRecordKinds::BufferExtentsKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000065 return make_unique<BufferExtents>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000066 case MetadataRecordKinds::TypedEventMarkerKind:
Dean Michael Berris59439dd2018-11-07 04:37:42 +000067 return make_unique<TypedEventRecord>();
Dean Michael Berrisfc774e22018-08-31 11:41:08 +000068 case MetadataRecordKinds::PidKind:
Dean Michael Berris146d57912018-08-31 08:04:56 +000069 return make_unique<PIDRecord>();
70 case MetadataRecordKinds::EnumEndMarker:
71 llvm_unreachable("Invalid MetadataRecordKind");
72 }
Simon Pilgrim95f41202018-08-31 09:24:09 +000073 llvm_unreachable("Unhandled MetadataRecordKinds enum value");
Dean Michael Berris146d57912018-08-31 08:04:56 +000074}
75
Dean Michael Berrisda375a62018-11-09 06:26:48 +000076constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
77 return FirstByte & 0x01u;
78}
79
Dean Michael Berris146d57912018-08-31 08:04:56 +000080} // namespace
81
Dean Michael Berrisda375a62018-11-09 06:26:48 +000082Expected<std::unique_ptr<Record>>
83FileBasedRecordProducer::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
Dean Michael Berris146d57912018-08-31 08:04:56 +0000113Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000114 // 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 //
Dean Michael Berris146d57912018-08-31 08:04:56 +0000140 // 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);
Dean Michael Berrise8c650a2018-11-01 22:57:50 +0000152 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
Dean Michael Berris146d57912018-08-31 08:04:56 +0000157 // For metadata records, handle especially here.
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000158 if (isMetadataIntroducer(FirstByte)) {
Dean Michael Berris146d57912018-08-31 08:04:56 +0000159 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
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000177 // 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 }
Dean Michael Berris146d57912018-08-31 08:04:56 +0000193 assert(R != nullptr);
194 return std::move(R);
195}
196
197} // namespace xray
198} // namespace llvm