blob: 78163031a8cc81b6ab73703f904c88ccddaf799e [file] [log] [blame]
Dean Michael Berrisa6c63432018-08-30 07:22:21 +00001//===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dean Michael Berrisa6c63432018-08-30 07:22:21 +00006//
7//===----------------------------------------------------------------------===//
8#include "llvm/XRay/FDRRecords.h"
9
10namespace llvm {
11namespace xray {
12
13Error 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).",
17 OffsetPtr);
18
19 auto PreReadOffset = OffsetPtr;
20 R.Size = E.getU64(&OffsetPtr);
21 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +000022 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000023 "Cannot read buffer extent at offset %d.",
24 OffsetPtr);
25
26 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
27 return Error::success();
28}
29
30Error 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).",
35 OffsetPtr);
36 auto BeginOffset = OffsetPtr;
37 auto PreReadOffset = OffsetPtr;
38 R.Seconds = E.getU64(&OffsetPtr);
39 if (OffsetPtr == PreReadOffset)
40 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +000041 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000042 "Cannot read wall clock 'seconds' field at offset %d.", OffsetPtr);
43
44 PreReadOffset = OffsetPtr;
45 R.Nanos = E.getU32(&OffsetPtr);
46 if (OffsetPtr == PreReadOffset)
47 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +000048 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000049 "Cannot read wall clock 'nanos' field at offset %d.", OffsetPtr);
50
51 // Align to metadata record size boundary.
52 assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
53 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
54 return Error::success();
55}
56
57Error 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).",
62 OffsetPtr);
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000063 auto BeginOffset = OffsetPtr;
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000064 auto PreReadOffset = OffsetPtr;
65 R.CPUId = E.getU16(&OffsetPtr);
66 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +000067 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000068 "Cannot read CPU id at offset %d.", OffsetPtr);
69
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000070 PreReadOffset = OffsetPtr;
71 R.TSC = E.getU64(&OffsetPtr);
72 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +000073 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000074 "Cannot read CPU TSC at offset %d.", OffsetPtr);
75
76 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000077 return Error::success();
78}
79
80Error 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).",
85 OffsetPtr);
86
87 auto PreReadOffset = OffsetPtr;
88 R.BaseTSC = E.getU64(&OffsetPtr);
89 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +000090 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000091 "Cannot read TSC wrap record at offset %d.",
92 OffsetPtr);
93
94 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
95 return Error::success();
96}
97
98Error 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).",
103 OffsetPtr);
104
105 auto BeginOffset = OffsetPtr;
106 auto PreReadOffset = OffsetPtr;
107 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
108 if (PreReadOffset == OffsetPtr)
109 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +0000110 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000111 "Cannot read a custom event record size field offset %d.", OffsetPtr);
112
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000113 if (R.Size <= 0)
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,
117 OffsetPtr);
118
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000119 PreReadOffset = OffsetPtr;
120 R.TSC = E.getU64(&OffsetPtr);
121 if (PreReadOffset == OffsetPtr)
122 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +0000123 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000124 "Cannot read a custom event TSC field at offset %d.", OffsetPtr);
125
Dean Michael Berris6b67ff02018-11-01 00:18:52 +0000126 // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
127 // of the custom event.
128 if (Version >= 4) {
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);
135 }
136
137 assert(OffsetPtr > BeginOffset &&
138 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000139 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
140
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,
146 OffsetPtr);
147
148 std::vector<uint8_t> Buffer;
149 Buffer.resize(R.Size);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000150 PreReadOffset = OffsetPtr;
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000151 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
152 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +0000153 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000154 "Failed reading data into buffer of size %d at offset %d.", R.Size,
155 OffsetPtr);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000156
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);
164
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000165 R.Data.assign(Buffer.begin(), Buffer.end());
166 return Error::success();
167}
168
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000169Error 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).",
174 OffsetPtr);
175
176 auto BeginOffset = OffsetPtr;
177 auto PreReadOffset = OffsetPtr;
178
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);
184
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000185 if (R.Size <= 0)
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,
189 OffsetPtr);
190
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000191 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.",
197 OffsetPtr);
198
199 assert(OffsetPtr > BeginOffset &&
200 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
201 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
202
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,
208 OffsetPtr);
209
210 std::vector<uint8_t> Buffer;
211 Buffer.resize(R.Size);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000212 PreReadOffset = OffsetPtr;
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000213 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,
217 OffsetPtr);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000218
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);
226
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000227 R.Data.assign(Buffer.begin(), Buffer.end());
228 return Error::success();
229}
230
231Error 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).",
236 OffsetPtr);
237
238 auto BeginOffset = OffsetPtr;
239 auto PreReadOffset = OffsetPtr;
240
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);
246
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000247 if (R.Size <= 0)
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,
251 OffsetPtr);
252
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000253 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.",
259 OffsetPtr);
260
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);
267
268 assert(OffsetPtr > BeginOffset &&
269 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
270 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
271
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,
277 OffsetPtr);
278
279 std::vector<uint8_t> Buffer;
280 Buffer.resize(R.Size);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000281 PreReadOffset = OffsetPtr;
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000282 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,
286 OffsetPtr);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000287
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);
295
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000296 R.Data.assign(Buffer.begin(), Buffer.end());
297 return Error::success();
298}
299
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000300Error 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).",
305 OffsetPtr);
306
307 auto PreReadOffset = OffsetPtr;
308 R.Arg = E.getU64(&OffsetPtr);
309 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000310 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000311 "Cannot read a call arg record at offset %d.",
312 OffsetPtr);
313
314 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
315 return Error::success();
316}
317
318Error 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).",
323 OffsetPtr);
324
325 auto PreReadOffset = OffsetPtr;
Dean Michael Berrisf135ac42018-08-31 20:02:55 +0000326 R.PID = E.getSigned(&OffsetPtr, 4);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000327 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000328 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000329 "Cannot read a process ID record at offset %d.",
330 OffsetPtr);
331
332 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
333 return Error::success();
334}
335
336Error 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).",
341 OffsetPtr);
342
343 auto PreReadOffset = OffsetPtr;
344 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
345 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000346 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000347 "Cannot read a new buffer record at offset %d.",
348 OffsetPtr);
349
350 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
351 return Error::success();
352}
353
354Error 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).",
359 OffsetPtr);
360
361 OffsetPtr += MetadataRecord::kMetadataBodySize;
362 return Error::success();
363}
364
365Error 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
368 // layout:
369 //
370 // bit 0 : function record indicator (must be 0)
371 // bits 1..3 : function record type
372 // bits 4..32 : function id
373 //
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).",
378 OffsetPtr);
379
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.",
386 OffsetPtr);
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000387
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;
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000392 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);
398 break;
399 default:
Yi Kongf6095902018-10-26 18:25:27 +0000400 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000401 "Unknown function record type '%d' at offset %d.",
402 FunctionType, BeginOffset);
403 }
404
405 R.FuncId = Buffer >> 4;
406 PreReadOffset = OffsetPtr;
407 R.Delta = E.getU32(&OffsetPtr);
408 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +0000409 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000410 "Failed reading TSC delta from offset %d.",
411 OffsetPtr);
412 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
413 return Error::success();
414}
415
416} // namespace xray
417} // namespace llvm