Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/XRay/FDRRecordProducer.cpp
35234 views
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"
10
11
#include <cstdint>
12
13
namespace llvm {
14
namespace xray {
15
16
namespace {
17
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,
33
};
34
35
Expected<std::unique_ptr<Record>>
36
metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
37
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 std::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 std::make_unique<EndBufferRecord>();
51
case MetadataRecordKinds::NewCPUIdKind:
52
return std::make_unique<NewCPUIDRecord>();
53
case MetadataRecordKinds::TSCWrapKind:
54
return std::make_unique<TSCWrapRecord>();
55
case MetadataRecordKinds::WalltimeMarkerKind:
56
return std::make_unique<WallclockRecord>();
57
case MetadataRecordKinds::CustomEventMarkerKind:
58
if (Header.Version >= 5)
59
return std::make_unique<CustomEventRecordV5>();
60
return std::make_unique<CustomEventRecord>();
61
case MetadataRecordKinds::CallArgumentKind:
62
return std::make_unique<CallArgRecord>();
63
case MetadataRecordKinds::BufferExtentsKind:
64
return std::make_unique<BufferExtents>();
65
case MetadataRecordKinds::TypedEventMarkerKind:
66
return std::make_unique<TypedEventRecord>();
67
case MetadataRecordKinds::PidKind:
68
return std::make_unique<PIDRecord>();
69
case MetadataRecordKinds::EnumEndMarker:
70
llvm_unreachable("Invalid MetadataRecordKind");
71
}
72
llvm_unreachable("Unhandled MetadataRecordKinds enum value");
73
}
74
75
constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
76
return FirstByte & 0x01u;
77
}
78
79
} // namespace
80
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 %" PRId64 ".", OffsetPtr);
93
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();
100
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);
106
}
107
}
108
}
109
llvm_unreachable("Must always terminate with either an error or a record.");
110
}
111
112
Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
113
// First, we set up our result record.
114
std::unique_ptr<Record> R;
115
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."));
129
130
R = std::move(BufferExtentsOrError.get());
131
assert(R != nullptr);
132
assert(isa<BufferExtents>(R.get()));
133
auto BE = cast<BufferExtents>(R.get());
134
CurrentBufferBytes = BE->size();
135
return std::move(R);
136
}
137
138
//
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:
141
//
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.
146
//
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 %" PRId64 ".", OffsetPtr);
155
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) "
166
"at offset %" PRId64 ".",
167
LoadedType, PreReadOffset));
168
R = std::move(MetadataRecordOrErr.get());
169
} else {
170
R = std::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 %" PRId64 " (over-read by %" PRId64
187
" bytes); Record Type = %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
199
200