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/FDRRecords.h"
9
10 namespace llvm {
11 namespace xray {
12
visit(BufferExtents & R)13 Error RecordInitializer::visit(BufferExtents &R) {
14 if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))
15 return createStringError(
16 std::make_error_code(std::errc::bad_address),
17 "Invalid offset for a buffer extent (%" PRId64 ").", OffsetPtr);
18
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 %" PRId64 ".",
24 OffsetPtr);
25
26 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
27 return Error::success();
28 }
29
visit(WallclockRecord & R)30 Error RecordInitializer::visit(WallclockRecord &R) {
31 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
32 MetadataRecord::kMetadataBodySize))
33 return createStringError(
34 std::make_error_code(std::errc::bad_address),
35 "Invalid offset for a wallclock record (%" PRId64 ").", OffsetPtr);
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 %" PRId64 ".",
43 OffsetPtr);
44
45 PreReadOffset = OffsetPtr;
46 R.Nanos = E.getU32(&OffsetPtr);
47 if (OffsetPtr == PreReadOffset)
48 return createStringError(
49 std::make_error_code(std::errc::invalid_argument),
50 "Cannot read wall clock 'nanos' field at offset %" PRId64 ".",
51 OffsetPtr);
52
53 // Align to metadata record size boundary.
54 assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
55 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
56 return Error::success();
57 }
58
visit(NewCPUIDRecord & R)59 Error RecordInitializer::visit(NewCPUIDRecord &R) {
60 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
61 MetadataRecord::kMetadataBodySize))
62 return createStringError(
63 std::make_error_code(std::errc::bad_address),
64 "Invalid offset for a new cpu id record (%" PRId64 ").", OffsetPtr);
65 auto BeginOffset = OffsetPtr;
66 auto PreReadOffset = OffsetPtr;
67 R.CPUId = E.getU16(&OffsetPtr);
68 if (OffsetPtr == PreReadOffset)
69 return createStringError(std::make_error_code(std::errc::invalid_argument),
70 "Cannot read CPU id at offset %" PRId64 ".",
71 OffsetPtr);
72
73 PreReadOffset = OffsetPtr;
74 R.TSC = E.getU64(&OffsetPtr);
75 if (OffsetPtr == PreReadOffset)
76 return createStringError(std::make_error_code(std::errc::invalid_argument),
77 "Cannot read CPU TSC at offset %" PRId64 ".",
78 OffsetPtr);
79
80 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
81 return Error::success();
82 }
83
visit(TSCWrapRecord & R)84 Error RecordInitializer::visit(TSCWrapRecord &R) {
85 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
86 MetadataRecord::kMetadataBodySize))
87 return createStringError(
88 std::make_error_code(std::errc::bad_address),
89 "Invalid offset for a new TSC wrap record (%" PRId64 ").", OffsetPtr);
90
91 auto PreReadOffset = OffsetPtr;
92 R.BaseTSC = E.getU64(&OffsetPtr);
93 if (PreReadOffset == OffsetPtr)
94 return createStringError(
95 std::make_error_code(std::errc::invalid_argument),
96 "Cannot read TSC wrap record at offset %" PRId64 ".", OffsetPtr);
97
98 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
99 return Error::success();
100 }
101
visit(CustomEventRecord & R)102 Error RecordInitializer::visit(CustomEventRecord &R) {
103 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
104 MetadataRecord::kMetadataBodySize))
105 return createStringError(
106 std::make_error_code(std::errc::bad_address),
107 "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);
108
109 auto BeginOffset = OffsetPtr;
110 auto PreReadOffset = OffsetPtr;
111 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
112 if (PreReadOffset == OffsetPtr)
113 return createStringError(
114 std::make_error_code(std::errc::invalid_argument),
115 "Cannot read a custom event record size field offset %" PRId64 ".",
116 OffsetPtr);
117
118 if (R.Size <= 0)
119 return createStringError(
120 std::make_error_code(std::errc::bad_address),
121 "Invalid size for custom event (size = %d) at offset %" PRId64 ".",
122 R.Size, OffsetPtr);
123
124 PreReadOffset = OffsetPtr;
125 R.TSC = E.getU64(&OffsetPtr);
126 if (PreReadOffset == OffsetPtr)
127 return createStringError(
128 std::make_error_code(std::errc::invalid_argument),
129 "Cannot read a custom event TSC field at offset %" PRId64 ".",
130 OffsetPtr);
131
132 // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
133 // of the custom event.
134 if (Version >= 4) {
135 PreReadOffset = OffsetPtr;
136 R.CPU = E.getU16(&OffsetPtr);
137 if (PreReadOffset == OffsetPtr)
138 return createStringError(
139 std::make_error_code(std::errc::invalid_argument),
140 "Missing CPU field at offset %" PRId64 ".", OffsetPtr);
141 }
142
143 assert(OffsetPtr > BeginOffset &&
144 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
145 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
146
147 // Next we read in a fixed chunk of data from the given offset.
148 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
149 return createStringError(
150 std::make_error_code(std::errc::bad_address),
151 "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
152 R.Size, OffsetPtr);
153
154 std::vector<uint8_t> Buffer;
155 Buffer.resize(R.Size);
156 PreReadOffset = OffsetPtr;
157 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
158 return createStringError(
159 std::make_error_code(std::errc::invalid_argument),
160 "Failed reading data into buffer of size %d at offset %" PRId64 ".",
161 R.Size, OffsetPtr);
162
163 assert(OffsetPtr >= PreReadOffset);
164 if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
165 return createStringError(
166 std::make_error_code(std::errc::invalid_argument),
167 "Failed reading enough bytes for the custom event payload -- read "
168 "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
169 OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
170
171 R.Data.assign(Buffer.begin(), Buffer.end());
172 return Error::success();
173 }
174
visit(CustomEventRecordV5 & R)175 Error RecordInitializer::visit(CustomEventRecordV5 &R) {
176 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
177 MetadataRecord::kMetadataBodySize))
178 return createStringError(
179 std::make_error_code(std::errc::bad_address),
180 "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);
181
182 auto BeginOffset = OffsetPtr;
183 auto PreReadOffset = OffsetPtr;
184
185 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
186 if (PreReadOffset == OffsetPtr)
187 return createStringError(
188 std::make_error_code(std::errc::invalid_argument),
189 "Cannot read a custom event record size field offset %" PRId64 ".",
190 OffsetPtr);
191
192 if (R.Size <= 0)
193 return createStringError(
194 std::make_error_code(std::errc::bad_address),
195 "Invalid size for custom event (size = %d) at offset %" PRId64 ".",
196 R.Size, OffsetPtr);
197
198 PreReadOffset = OffsetPtr;
199 R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
200 if (PreReadOffset == OffsetPtr)
201 return createStringError(
202 std::make_error_code(std::errc::invalid_argument),
203 "Cannot read a custom event record TSC delta field at offset "
204 "%" PRId64 ".",
205 OffsetPtr);
206
207 assert(OffsetPtr > BeginOffset &&
208 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
209 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
210
211 // Next we read in a fixed chunk of data from the given offset.
212 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
213 return createStringError(
214 std::make_error_code(std::errc::bad_address),
215 "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
216 R.Size, OffsetPtr);
217
218 std::vector<uint8_t> Buffer;
219 Buffer.resize(R.Size);
220 PreReadOffset = OffsetPtr;
221 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
222 return createStringError(
223 std::make_error_code(std::errc::invalid_argument),
224 "Failed reading data into buffer of size %d at offset %" PRId64 ".",
225 R.Size, OffsetPtr);
226
227 assert(OffsetPtr >= PreReadOffset);
228 if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
229 return createStringError(
230 std::make_error_code(std::errc::invalid_argument),
231 "Failed reading enough bytes for the custom event payload -- read "
232 "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
233 OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
234
235 R.Data.assign(Buffer.begin(), Buffer.end());
236 return Error::success();
237 }
238
visit(TypedEventRecord & R)239 Error RecordInitializer::visit(TypedEventRecord &R) {
240 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
241 MetadataRecord::kMetadataBodySize))
242 return createStringError(
243 std::make_error_code(std::errc::bad_address),
244 "Invalid offset for a typed event record (%" PRId64 ").", OffsetPtr);
245
246 auto BeginOffset = OffsetPtr;
247 auto PreReadOffset = OffsetPtr;
248
249 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
250 if (PreReadOffset == OffsetPtr)
251 return createStringError(
252 std::make_error_code(std::errc::invalid_argument),
253 "Cannot read a typed event record size field offset %" PRId64 ".",
254 OffsetPtr);
255
256 if (R.Size <= 0)
257 return createStringError(
258 std::make_error_code(std::errc::bad_address),
259 "Invalid size for typed event (size = %d) at offset %" PRId64 ".",
260 R.Size, OffsetPtr);
261
262 PreReadOffset = OffsetPtr;
263 R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
264 if (PreReadOffset == OffsetPtr)
265 return createStringError(
266 std::make_error_code(std::errc::invalid_argument),
267 "Cannot read a typed event record TSC delta field at offset "
268 "%" PRId64 ".",
269 OffsetPtr);
270
271 PreReadOffset = OffsetPtr;
272 R.EventType = E.getU16(&OffsetPtr);
273 if (PreReadOffset == OffsetPtr)
274 return createStringError(
275 std::make_error_code(std::errc::invalid_argument),
276 "Cannot read a typed event record type field at offset %" PRId64 ".",
277 OffsetPtr);
278
279 assert(OffsetPtr > BeginOffset &&
280 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
281 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
282
283 // Next we read in a fixed chunk of data from the given offset.
284 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
285 return createStringError(
286 std::make_error_code(std::errc::bad_address),
287 "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
288 R.Size, OffsetPtr);
289
290 std::vector<uint8_t> Buffer;
291 Buffer.resize(R.Size);
292 PreReadOffset = OffsetPtr;
293 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
294 return createStringError(
295 std::make_error_code(std::errc::invalid_argument),
296 "Failed reading data into buffer of size %d at offset %" PRId64 ".",
297 R.Size, OffsetPtr);
298
299 assert(OffsetPtr >= PreReadOffset);
300 if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
301 return createStringError(
302 std::make_error_code(std::errc::invalid_argument),
303 "Failed reading enough bytes for the typed event payload -- read "
304 "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
305 OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
306
307 R.Data.assign(Buffer.begin(), Buffer.end());
308 return Error::success();
309 }
310
visit(CallArgRecord & R)311 Error RecordInitializer::visit(CallArgRecord &R) {
312 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
313 MetadataRecord::kMetadataBodySize))
314 return createStringError(
315 std::make_error_code(std::errc::bad_address),
316 "Invalid offset for a call argument record (%" PRId64 ").",
317 OffsetPtr);
318
319 auto PreReadOffset = OffsetPtr;
320 R.Arg = E.getU64(&OffsetPtr);
321 if (PreReadOffset == OffsetPtr)
322 return createStringError(
323 std::make_error_code(std::errc::invalid_argument),
324 "Cannot read a call arg record at offset %" PRId64 ".", OffsetPtr);
325
326 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
327 return Error::success();
328 }
329
visit(PIDRecord & R)330 Error RecordInitializer::visit(PIDRecord &R) {
331 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
332 MetadataRecord::kMetadataBodySize))
333 return createStringError(
334 std::make_error_code(std::errc::bad_address),
335 "Invalid offset for a process ID record (%" PRId64 ").", OffsetPtr);
336
337 auto PreReadOffset = OffsetPtr;
338 R.PID = E.getSigned(&OffsetPtr, 4);
339 if (PreReadOffset == OffsetPtr)
340 return createStringError(
341 std::make_error_code(std::errc::invalid_argument),
342 "Cannot read a process ID record at offset %" PRId64 ".", OffsetPtr);
343
344 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
345 return Error::success();
346 }
347
visit(NewBufferRecord & R)348 Error RecordInitializer::visit(NewBufferRecord &R) {
349 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
350 MetadataRecord::kMetadataBodySize))
351 return createStringError(
352 std::make_error_code(std::errc::bad_address),
353 "Invalid offset for a new buffer record (%" PRId64 ").", OffsetPtr);
354
355 auto PreReadOffset = OffsetPtr;
356 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
357 if (PreReadOffset == OffsetPtr)
358 return createStringError(
359 std::make_error_code(std::errc::invalid_argument),
360 "Cannot read a new buffer record at offset %" PRId64 ".", OffsetPtr);
361
362 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
363 return Error::success();
364 }
365
visit(EndBufferRecord & R)366 Error RecordInitializer::visit(EndBufferRecord &R) {
367 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
368 MetadataRecord::kMetadataBodySize))
369 return createStringError(
370 std::make_error_code(std::errc::bad_address),
371 "Invalid offset for an end-of-buffer record (%" PRId64 ").",
372 OffsetPtr);
373
374 OffsetPtr += MetadataRecord::kMetadataBodySize;
375 return Error::success();
376 }
377
visit(FunctionRecord & R)378 Error RecordInitializer::visit(FunctionRecord &R) {
379 // For function records, we need to retreat one byte back to read a full
380 // unsigned 32-bit value. The first four bytes will have the following
381 // layout:
382 //
383 // bit 0 : function record indicator (must be 0)
384 // bits 1..3 : function record type
385 // bits 4..32 : function id
386 //
387 if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
388 --OffsetPtr, FunctionRecord::kFunctionRecordSize))
389 return createStringError(
390 std::make_error_code(std::errc::bad_address),
391 "Invalid offset for a function record (%" PRId64 ").", OffsetPtr);
392
393 auto BeginOffset = OffsetPtr;
394 auto PreReadOffset = BeginOffset;
395 uint32_t Buffer = E.getU32(&OffsetPtr);
396 if (PreReadOffset == OffsetPtr)
397 return createStringError(
398 std::make_error_code(std::errc::bad_address),
399 "Cannot read function id field from offset %" PRId64 ".", OffsetPtr);
400
401 // To get the function record type, we shift the buffer one to the right
402 // (truncating the function record indicator) then take the three bits
403 // (0b0111) to get the record type as an unsigned value.
404 unsigned FunctionType = (Buffer >> 1) & 0x07u;
405 switch (FunctionType) {
406 case static_cast<unsigned>(RecordTypes::ENTER):
407 case static_cast<unsigned>(RecordTypes::ENTER_ARG):
408 case static_cast<unsigned>(RecordTypes::EXIT):
409 case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
410 R.Kind = static_cast<RecordTypes>(FunctionType);
411 break;
412 default:
413 return createStringError(
414 std::make_error_code(std::errc::invalid_argument),
415 "Unknown function record type '%d' at offset %" PRId64 ".",
416 FunctionType, BeginOffset);
417 }
418
419 R.FuncId = Buffer >> 4;
420 PreReadOffset = OffsetPtr;
421 R.Delta = E.getU32(&OffsetPtr);
422 if (OffsetPtr == PreReadOffset)
423 return createStringError(
424 std::make_error_code(std::errc::invalid_argument),
425 "Failed reading TSC delta from offset %" PRId64 ".", OffsetPtr);
426 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
427 return Error::success();
428 }
429
430 } // namespace xray
431 } // namespace llvm
432