1 //===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
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
7 //===----------------------------------------------------------------------===//
8 #include "llvm/XRay/FDRRecords.h"
13 Error RecordInitializer::visit(BufferExtents &R) {
14 if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))
15 return createStringError(std::make_error_code(std::errc::bad_address),
16 "Invalid offset for a buffer extent (%d).",
19 auto PreReadOffset = OffsetPtr;
20 R.Size = E.getU64(&OffsetPtr);
21 if (PreReadOffset == OffsetPtr)
22 return createStringError(std::make_error_code(std::errc::invalid_argument),
23 "Cannot read buffer extent at offset %d.",
26 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
27 return Error::success();
30 Error RecordInitializer::visit(WallclockRecord &R) {
31 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
32 MetadataRecord::kMetadataBodySize))
33 return createStringError(std::make_error_code(std::errc::bad_address),
34 "Invalid offset for a wallclock record (%d).",
36 auto BeginOffset = OffsetPtr;
37 auto PreReadOffset = OffsetPtr;
38 R.Seconds = E.getU64(&OffsetPtr);
39 if (OffsetPtr == PreReadOffset)
40 return createStringError(
41 std::make_error_code(std::errc::invalid_argument),
42 "Cannot read wall clock 'seconds' field at offset %d.", OffsetPtr);
44 PreReadOffset = OffsetPtr;
45 R.Nanos = E.getU32(&OffsetPtr);
46 if (OffsetPtr == PreReadOffset)
47 return createStringError(
48 std::make_error_code(std::errc::invalid_argument),
49 "Cannot read wall clock 'nanos' field at offset %d.", OffsetPtr);
51 // Align to metadata record size boundary.
52 assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
53 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
54 return Error::success();
57 Error RecordInitializer::visit(NewCPUIDRecord &R) {
58 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
59 MetadataRecord::kMetadataBodySize))
60 return createStringError(std::make_error_code(std::errc::bad_address),
61 "Invalid offset for a new cpu id record (%d).",
63 auto BeginOffset = OffsetPtr;
64 auto PreReadOffset = OffsetPtr;
65 R.CPUId = E.getU16(&OffsetPtr);
66 if (OffsetPtr == PreReadOffset)
67 return createStringError(std::make_error_code(std::errc::invalid_argument),
68 "Cannot read CPU id at offset %d.", OffsetPtr);
70 PreReadOffset = OffsetPtr;
71 R.TSC = E.getU64(&OffsetPtr);
72 if (OffsetPtr == PreReadOffset)
73 return createStringError(std::make_error_code(std::errc::invalid_argument),
74 "Cannot read CPU TSC at offset %d.", OffsetPtr);
76 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
77 return Error::success();
80 Error RecordInitializer::visit(TSCWrapRecord &R) {
81 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
82 MetadataRecord::kMetadataBodySize))
83 return createStringError(std::make_error_code(std::errc::bad_address),
84 "Invalid offset for a new TSC wrap record (%d).",
87 auto PreReadOffset = OffsetPtr;
88 R.BaseTSC = E.getU64(&OffsetPtr);
89 if (PreReadOffset == OffsetPtr)
90 return createStringError(std::make_error_code(std::errc::invalid_argument),
91 "Cannot read TSC wrap record at offset %d.",
94 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
95 return Error::success();
98 Error RecordInitializer::visit(CustomEventRecord &R) {
99 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
100 MetadataRecord::kMetadataBodySize))
101 return createStringError(std::make_error_code(std::errc::bad_address),
102 "Invalid offset for a custom event record (%d).",
105 auto BeginOffset = OffsetPtr;
106 auto PreReadOffset = OffsetPtr;
107 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
108 if (PreReadOffset == OffsetPtr)
109 return createStringError(
110 std::make_error_code(std::errc::invalid_argument),
111 "Cannot read a custom event record size field offset %d.", OffsetPtr);
114 return createStringError(
115 std::make_error_code(std::errc::bad_address),
116 "Invalid size for custom event (size = %d) at offset %d.", R.Size,
119 PreReadOffset = OffsetPtr;
120 R.TSC = E.getU64(&OffsetPtr);
121 if (PreReadOffset == OffsetPtr)
122 return createStringError(
123 std::make_error_code(std::errc::invalid_argument),
124 "Cannot read a custom event TSC field at offset %d.", OffsetPtr);
126 // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
127 // of the custom event.
129 PreReadOffset = OffsetPtr;
130 R.CPU = E.getU16(&OffsetPtr);
131 if (PreReadOffset == OffsetPtr)
132 return createStringError(
133 std::make_error_code(std::errc::invalid_argument),
134 "Missing CPU field at offset %d", OffsetPtr);
137 assert(OffsetPtr > BeginOffset &&
138 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
139 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
141 // Next we read in a fixed chunk of data from the given offset.
142 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
143 return createStringError(
144 std::make_error_code(std::errc::bad_address),
145 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
148 std::vector<uint8_t> Buffer;
149 Buffer.resize(R.Size);
150 PreReadOffset = OffsetPtr;
151 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
152 return createStringError(
153 std::make_error_code(std::errc::invalid_argument),
154 "Failed reading data into buffer of size %d at offset %d.", R.Size,
157 assert(OffsetPtr >= PreReadOffset);
158 if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
159 return createStringError(
160 std::make_error_code(std::errc::invalid_argument),
161 "Failed reading enough bytes for the custom event payload -- read %d "
162 "expecting %d bytes at offset %d.",
163 OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
165 R.Data.assign(Buffer.begin(), Buffer.end());
166 return Error::success();
169 Error RecordInitializer::visit(CustomEventRecordV5 &R) {
170 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
171 MetadataRecord::kMetadataBodySize))
172 return createStringError(std::make_error_code(std::errc::bad_address),
173 "Invalid offset for a custom event record (%d).",
176 auto BeginOffset = OffsetPtr;
177 auto PreReadOffset = OffsetPtr;
179 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
180 if (PreReadOffset == OffsetPtr)
181 return createStringError(
182 std::make_error_code(std::errc::invalid_argument),
183 "Cannot read a custom event record size field offset %d.", OffsetPtr);
186 return createStringError(
187 std::make_error_code(std::errc::bad_address),
188 "Invalid size for custom event (size = %d) at offset %d.", R.Size,
191 PreReadOffset = OffsetPtr;
192 R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
193 if (PreReadOffset == OffsetPtr)
194 return createStringError(
195 std::make_error_code(std::errc::invalid_argument),
196 "Cannot read a custom event record TSC delta field at offset %d.",
199 assert(OffsetPtr > BeginOffset &&
200 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
201 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
203 // Next we read in a fixed chunk of data from the given offset.
204 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
205 return createStringError(
206 std::make_error_code(std::errc::bad_address),
207 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
210 std::vector<uint8_t> Buffer;
211 Buffer.resize(R.Size);
212 PreReadOffset = OffsetPtr;
213 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
214 return createStringError(
215 std::make_error_code(std::errc::invalid_argument),
216 "Failed reading data into buffer of size %d at offset %d.", R.Size,
219 assert(OffsetPtr >= PreReadOffset);
220 if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
221 return createStringError(
222 std::make_error_code(std::errc::invalid_argument),
223 "Failed reading enough bytes for the custom event payload -- read %d "
224 "expecting %d bytes at offset %d.",
225 OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
227 R.Data.assign(Buffer.begin(), Buffer.end());
228 return Error::success();
231 Error RecordInitializer::visit(TypedEventRecord &R) {
232 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
233 MetadataRecord::kMetadataBodySize))
234 return createStringError(std::make_error_code(std::errc::bad_address),
235 "Invalid offset for a typed event record (%d).",
238 auto BeginOffset = OffsetPtr;
239 auto PreReadOffset = OffsetPtr;
241 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
242 if (PreReadOffset == OffsetPtr)
243 return createStringError(
244 std::make_error_code(std::errc::invalid_argument),
245 "Cannot read a typed event record size field offset %d.", OffsetPtr);
248 return createStringError(
249 std::make_error_code(std::errc::bad_address),
250 "Invalid size for typed event (size = %d) at offset %d.", R.Size,
253 PreReadOffset = OffsetPtr;
254 R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
255 if (PreReadOffset == OffsetPtr)
256 return createStringError(
257 std::make_error_code(std::errc::invalid_argument),
258 "Cannot read a typed event record TSC delta field at offset %d.",
261 PreReadOffset = OffsetPtr;
262 R.EventType = E.getU16(&OffsetPtr);
263 if (PreReadOffset == OffsetPtr)
264 return createStringError(
265 std::make_error_code(std::errc::invalid_argument),
266 "Cannot read a typed event record type field at offset %d.", OffsetPtr);
268 assert(OffsetPtr > BeginOffset &&
269 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
270 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
272 // Next we read in a fixed chunk of data from the given offset.
273 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
274 return createStringError(
275 std::make_error_code(std::errc::bad_address),
276 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
279 std::vector<uint8_t> Buffer;
280 Buffer.resize(R.Size);
281 PreReadOffset = OffsetPtr;
282 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
283 return createStringError(
284 std::make_error_code(std::errc::invalid_argument),
285 "Failed reading data into buffer of size %d at offset %d.", R.Size,
288 assert(OffsetPtr >= PreReadOffset);
289 if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
290 return createStringError(
291 std::make_error_code(std::errc::invalid_argument),
292 "Failed reading enough bytes for the typed event payload -- read %d "
293 "expecting %d bytes at offset %d.",
294 OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
296 R.Data.assign(Buffer.begin(), Buffer.end());
297 return Error::success();
300 Error RecordInitializer::visit(CallArgRecord &R) {
301 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
302 MetadataRecord::kMetadataBodySize))
303 return createStringError(std::make_error_code(std::errc::bad_address),
304 "Invalid offset for a call argument record (%d).",
307 auto PreReadOffset = OffsetPtr;
308 R.Arg = E.getU64(&OffsetPtr);
309 if (PreReadOffset == OffsetPtr)
310 return createStringError(std::make_error_code(std::errc::invalid_argument),
311 "Cannot read a call arg record at offset %d.",
314 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
315 return Error::success();
318 Error RecordInitializer::visit(PIDRecord &R) {
319 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
320 MetadataRecord::kMetadataBodySize))
321 return createStringError(std::make_error_code(std::errc::bad_address),
322 "Invalid offset for a process ID record (%d).",
325 auto PreReadOffset = OffsetPtr;
326 R.PID = E.getSigned(&OffsetPtr, 4);
327 if (PreReadOffset == OffsetPtr)
328 return createStringError(std::make_error_code(std::errc::invalid_argument),
329 "Cannot read a process ID record at offset %d.",
332 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
333 return Error::success();
336 Error RecordInitializer::visit(NewBufferRecord &R) {
337 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
338 MetadataRecord::kMetadataBodySize))
339 return createStringError(std::make_error_code(std::errc::bad_address),
340 "Invalid offset for a new buffer record (%d).",
343 auto PreReadOffset = OffsetPtr;
344 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
345 if (PreReadOffset == OffsetPtr)
346 return createStringError(std::make_error_code(std::errc::invalid_argument),
347 "Cannot read a new buffer record at offset %d.",
350 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
351 return Error::success();
354 Error RecordInitializer::visit(EndBufferRecord &R) {
355 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
356 MetadataRecord::kMetadataBodySize))
357 return createStringError(std::make_error_code(std::errc::bad_address),
358 "Invalid offset for an end-of-buffer record (%d).",
361 OffsetPtr += MetadataRecord::kMetadataBodySize;
362 return Error::success();
365 Error RecordInitializer::visit(FunctionRecord &R) {
366 // For function records, we need to retreat one byte back to read a full
367 // unsigned 32-bit value. The first four bytes will have the following
370 // bit 0 : function record indicator (must be 0)
371 // bits 1..3 : function record type
372 // bits 4..32 : function id
374 if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
375 --OffsetPtr, FunctionRecord::kFunctionRecordSize))
376 return createStringError(std::make_error_code(std::errc::bad_address),
377 "Invalid offset for a function record (%d).",
380 auto BeginOffset = OffsetPtr;
381 auto PreReadOffset = BeginOffset;
382 uint32_t Buffer = E.getU32(&OffsetPtr);
383 if (PreReadOffset == OffsetPtr)
384 return createStringError(std::make_error_code(std::errc::bad_address),
385 "Cannot read function id field from offset %d.",
388 // To get the function record type, we shift the buffer one to the right
389 // (truncating the function record indicator) then take the three bits
390 // (0b0111) to get the record type as an unsigned value.
391 unsigned FunctionType = (Buffer >> 1) & 0x07u;
392 switch (FunctionType) {
393 case static_cast<unsigned>(RecordTypes::ENTER):
394 case static_cast<unsigned>(RecordTypes::ENTER_ARG):
395 case static_cast<unsigned>(RecordTypes::EXIT):
396 case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
397 R.Kind = static_cast<RecordTypes>(FunctionType);
400 return createStringError(std::make_error_code(std::errc::invalid_argument),
401 "Unknown function record type '%d' at offset %d.",
402 FunctionType, BeginOffset);
405 R.FuncId = Buffer >> 4;
406 PreReadOffset = OffsetPtr;
407 R.Delta = E.getU32(&OffsetPtr);
408 if (OffsetPtr == PreReadOffset)
409 return createStringError(std::make_error_code(std::errc::invalid_argument),
410 "Failed reading TSC delta from offset %d.",
412 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
413 return Error::success();