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(
16 std::make_error_code(std::errc::bad_address
),
17 "Invalid offset for a buffer extent (%" PRId64
").", OffsetPtr
);
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
".",
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(
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
".",
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
".",
53 // Align to metadata record size boundary.
54 assert(OffsetPtr
- BeginOffset
<= MetadataRecord::kMetadataBodySize
);
55 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- BeginOffset
);
56 return Error::success();
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
".",
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
".",
80 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- BeginOffset
);
81 return Error::success();
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
);
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
);
98 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- PreReadOffset
);
99 return Error::success();
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
);
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
".",
119 return createStringError(
120 std::make_error_code(std::errc::bad_address
),
121 "Invalid size for custom event (size = %d) at offset %" PRId64
".",
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
".",
132 // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
133 // of the custom event.
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
);
143 assert(OffsetPtr
> BeginOffset
&&
144 OffsetPtr
- BeginOffset
<= MetadataRecord::kMetadataBodySize
);
145 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- BeginOffset
);
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
".",
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
".",
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
);
171 R
.Data
.assign(Buffer
.begin(), Buffer
.end());
172 return Error::success();
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
);
182 auto BeginOffset
= OffsetPtr
;
183 auto PreReadOffset
= OffsetPtr
;
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
".",
193 return createStringError(
194 std::make_error_code(std::errc::bad_address
),
195 "Invalid size for custom event (size = %d) at offset %" PRId64
".",
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 "
207 assert(OffsetPtr
> BeginOffset
&&
208 OffsetPtr
- BeginOffset
<= MetadataRecord::kMetadataBodySize
);
209 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- BeginOffset
);
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
".",
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
".",
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
);
235 R
.Data
.assign(Buffer
.begin(), Buffer
.end());
236 return Error::success();
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
);
246 auto BeginOffset
= OffsetPtr
;
247 auto PreReadOffset
= OffsetPtr
;
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
".",
257 return createStringError(
258 std::make_error_code(std::errc::bad_address
),
259 "Invalid size for typed event (size = %d) at offset %" PRId64
".",
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 "
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
".",
279 assert(OffsetPtr
> BeginOffset
&&
280 OffsetPtr
- BeginOffset
<= MetadataRecord::kMetadataBodySize
);
281 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- BeginOffset
);
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
".",
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
".",
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
);
307 R
.Data
.assign(Buffer
.begin(), Buffer
.end());
308 return Error::success();
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
").",
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
);
326 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- PreReadOffset
);
327 return Error::success();
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
);
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
);
344 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- PreReadOffset
);
345 return Error::success();
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
);
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
);
362 OffsetPtr
+= MetadataRecord::kMetadataBodySize
- (OffsetPtr
- PreReadOffset
);
363 return Error::success();
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
").",
374 OffsetPtr
+= MetadataRecord::kMetadataBodySize
;
375 return Error::success();
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
383 // bit 0 : function record indicator (must be 0)
384 // bits 1..3 : function record type
385 // bits 4..32 : function id
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
);
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
);
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
);
413 return createStringError(
414 std::make_error_code(std::errc::invalid_argument
),
415 "Unknown function record type '%d' at offset %" PRId64
".",
416 FunctionType
, BeginOffset
);
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();