blob: cc9dd4609498c28e47c8a174d0bae0c249b3226e [file] [log] [blame]
Dean Michael Berrisa6c63432018-08-30 07:22:21 +00001//===- 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
11namespace llvm {
12namespace xray {
13
14Error 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)
Yi Kongf6095902018-10-26 18:25:27 +000023 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000024 "Cannot read buffer extent at offset %d.",
25 OffsetPtr);
26
27 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
28 return Error::success();
29}
30
31Error 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(
Yi Kongf6095902018-10-26 18:25:27 +000042 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000043 "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(
Yi Kongf6095902018-10-26 18:25:27 +000049 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000050 "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
58Error 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);
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000064 auto BeginOffset = OffsetPtr;
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000065 auto PreReadOffset = OffsetPtr;
66 R.CPUId = E.getU16(&OffsetPtr);
67 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +000068 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000069 "Cannot read CPU id at offset %d.", OffsetPtr);
70
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000071 PreReadOffset = OffsetPtr;
72 R.TSC = E.getU64(&OffsetPtr);
73 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +000074 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000075 "Cannot read CPU TSC at offset %d.", OffsetPtr);
76
77 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000078 return Error::success();
79}
80
81Error 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)
Yi Kongf6095902018-10-26 18:25:27 +000091 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +000092 "Cannot read TSC wrap record at offset %d.",
93 OffsetPtr);
94
95 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
96 return Error::success();
97}
98
99Error 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(
Yi Kongf6095902018-10-26 18:25:27 +0000111 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000112 "Cannot read a custom event record size field offset %d.", OffsetPtr);
113
114 PreReadOffset = OffsetPtr;
115 R.TSC = E.getU64(&OffsetPtr);
116 if (PreReadOffset == OffsetPtr)
117 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +0000118 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000119 "Cannot read a custom event TSC field at offset %d.", OffsetPtr);
120
Dean Michael Berris6b67ff02018-11-01 00:18:52 +0000121 // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
122 // of the custom event.
123 if (Version >= 4) {
124 PreReadOffset = OffsetPtr;
125 R.CPU = E.getU16(&OffsetPtr);
126 if (PreReadOffset == OffsetPtr)
127 return createStringError(
128 std::make_error_code(std::errc::invalid_argument),
129 "Missing CPU field at offset %d", OffsetPtr);
130 }
131
132 assert(OffsetPtr > BeginOffset &&
133 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000134 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
135
136 // Next we read in a fixed chunk of data from the given offset.
137 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
138 return createStringError(
139 std::make_error_code(std::errc::bad_address),
140 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
141 OffsetPtr);
142
143 std::vector<uint8_t> Buffer;
144 Buffer.resize(R.Size);
145 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
146 return createStringError(
Yi Kongf6095902018-10-26 18:25:27 +0000147 std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000148 "Failed reading data into buffer of size %d at offset %d.", R.Size,
149 OffsetPtr);
150 R.Data.assign(Buffer.begin(), Buffer.end());
151 return Error::success();
152}
153
Dean Michael Berris59439dd2018-11-07 04:37:42 +0000154Error RecordInitializer::visit(CustomEventRecordV5 &R) {
155 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
156 MetadataRecord::kMetadataBodySize))
157 return createStringError(std::make_error_code(std::errc::bad_address),
158 "Invalid offset for a custom event record (%d).",
159 OffsetPtr);
160
161 auto BeginOffset = OffsetPtr;
162 auto PreReadOffset = OffsetPtr;
163
164 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
165 if (PreReadOffset == OffsetPtr)
166 return createStringError(
167 std::make_error_code(std::errc::invalid_argument),
168 "Cannot read a custom event record size field offset %d.", OffsetPtr);
169
170 PreReadOffset = OffsetPtr;
171 R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
172 if (PreReadOffset == OffsetPtr)
173 return createStringError(
174 std::make_error_code(std::errc::invalid_argument),
175 "Cannot read a custom event record TSC delta field at offset %d.",
176 OffsetPtr);
177
178 assert(OffsetPtr > BeginOffset &&
179 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
180 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
181
182 // Next we read in a fixed chunk of data from the given offset.
183 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
184 return createStringError(
185 std::make_error_code(std::errc::bad_address),
186 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
187 OffsetPtr);
188
189 std::vector<uint8_t> Buffer;
190 Buffer.resize(R.Size);
191 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
192 return createStringError(
193 std::make_error_code(std::errc::invalid_argument),
194 "Failed reading data into buffer of size %d at offset %d.", R.Size,
195 OffsetPtr);
196 R.Data.assign(Buffer.begin(), Buffer.end());
197 return Error::success();
198}
199
200Error RecordInitializer::visit(TypedEventRecord &R) {
201 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
202 MetadataRecord::kMetadataBodySize))
203 return createStringError(std::make_error_code(std::errc::bad_address),
204 "Invalid offset for a typed event record (%d).",
205 OffsetPtr);
206
207 auto BeginOffset = OffsetPtr;
208 auto PreReadOffset = OffsetPtr;
209
210 R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
211 if (PreReadOffset == OffsetPtr)
212 return createStringError(
213 std::make_error_code(std::errc::invalid_argument),
214 "Cannot read a typed event record size field offset %d.", OffsetPtr);
215
216 PreReadOffset = OffsetPtr;
217 R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
218 if (PreReadOffset == OffsetPtr)
219 return createStringError(
220 std::make_error_code(std::errc::invalid_argument),
221 "Cannot read a typed event record TSC delta field at offset %d.",
222 OffsetPtr);
223
224 PreReadOffset = OffsetPtr;
225 R.EventType = E.getU16(&OffsetPtr);
226 if (PreReadOffset == OffsetPtr)
227 return createStringError(
228 std::make_error_code(std::errc::invalid_argument),
229 "Cannot read a typed event record type field at offset %d.", OffsetPtr);
230
231 assert(OffsetPtr > BeginOffset &&
232 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
233 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
234
235 // Next we read in a fixed chunk of data from the given offset.
236 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
237 return createStringError(
238 std::make_error_code(std::errc::bad_address),
239 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
240 OffsetPtr);
241
242 std::vector<uint8_t> Buffer;
243 Buffer.resize(R.Size);
244 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
245 return createStringError(
246 std::make_error_code(std::errc::invalid_argument),
247 "Failed reading data into buffer of size %d at offset %d.", R.Size,
248 OffsetPtr);
249 R.Data.assign(Buffer.begin(), Buffer.end());
250 return Error::success();
251}
252
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000253Error RecordInitializer::visit(CallArgRecord &R) {
254 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
255 MetadataRecord::kMetadataBodySize))
256 return createStringError(std::make_error_code(std::errc::bad_address),
257 "Invalid offset for a call argument record (%d).",
258 OffsetPtr);
259
260 auto PreReadOffset = OffsetPtr;
261 R.Arg = E.getU64(&OffsetPtr);
262 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000263 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000264 "Cannot read a call arg record at offset %d.",
265 OffsetPtr);
266
267 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
268 return Error::success();
269}
270
271Error RecordInitializer::visit(PIDRecord &R) {
272 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
273 MetadataRecord::kMetadataBodySize))
274 return createStringError(std::make_error_code(std::errc::bad_address),
275 "Invalid offset for a process ID record (%d).",
276 OffsetPtr);
277
278 auto PreReadOffset = OffsetPtr;
Dean Michael Berrisf135ac42018-08-31 20:02:55 +0000279 R.PID = E.getSigned(&OffsetPtr, 4);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000280 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000281 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000282 "Cannot read a process ID record at offset %d.",
283 OffsetPtr);
284
285 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
286 return Error::success();
287}
288
289Error RecordInitializer::visit(NewBufferRecord &R) {
290 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
291 MetadataRecord::kMetadataBodySize))
292 return createStringError(std::make_error_code(std::errc::bad_address),
293 "Invalid offset for a new buffer record (%d).",
294 OffsetPtr);
295
296 auto PreReadOffset = OffsetPtr;
297 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
298 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000299 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000300 "Cannot read a new buffer record at offset %d.",
301 OffsetPtr);
302
303 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
304 return Error::success();
305}
306
307Error RecordInitializer::visit(EndBufferRecord &R) {
308 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
309 MetadataRecord::kMetadataBodySize))
310 return createStringError(std::make_error_code(std::errc::bad_address),
311 "Invalid offset for an end-of-buffer record (%d).",
312 OffsetPtr);
313
314 OffsetPtr += MetadataRecord::kMetadataBodySize;
315 return Error::success();
316}
317
318Error RecordInitializer::visit(FunctionRecord &R) {
319 // For function records, we need to retreat one byte back to read a full
320 // unsigned 32-bit value. The first four bytes will have the following
321 // layout:
322 //
323 // bit 0 : function record indicator (must be 0)
324 // bits 1..3 : function record type
325 // bits 4..32 : function id
326 //
327 if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
328 --OffsetPtr, FunctionRecord::kFunctionRecordSize))
329 return createStringError(std::make_error_code(std::errc::bad_address),
330 "Invalid offset for a function record (%d).",
331 OffsetPtr);
332
333 auto BeginOffset = OffsetPtr;
334 auto PreReadOffset = BeginOffset;
335 uint32_t Buffer = E.getU32(&OffsetPtr);
336 if (PreReadOffset == OffsetPtr)
337 return createStringError(std::make_error_code(std::errc::bad_address),
338 "Cannot read function id field from offset %d.",
339 OffsetPtr);
340 unsigned FunctionType = (Buffer >> 1) & 0x07;
341 switch (FunctionType) {
342 case static_cast<unsigned>(RecordTypes::ENTER):
343 case static_cast<unsigned>(RecordTypes::ENTER_ARG):
344 case static_cast<unsigned>(RecordTypes::EXIT):
345 case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
346 R.Kind = static_cast<RecordTypes>(FunctionType);
347 break;
348 default:
Yi Kongf6095902018-10-26 18:25:27 +0000349 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000350 "Unknown function record type '%d' at offset %d.",
351 FunctionType, BeginOffset);
352 }
353
354 R.FuncId = Buffer >> 4;
355 PreReadOffset = OffsetPtr;
356 R.Delta = E.getU32(&OffsetPtr);
357 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +0000358 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000359 "Failed reading TSC delta from offset %d.",
360 OffsetPtr);
361 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
362 return Error::success();
363}
364
365} // namespace xray
366} // namespace llvm