Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/XRay/RecordInitializer.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/FDRRecords.h"
9
10
namespace llvm {
11
namespace xray {
12
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
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
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
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
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
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
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
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
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
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
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
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
433