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