blob: 2ebaa1cec26eb12223e50ca80e078f49274709b0 [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
154Error RecordInitializer::visit(CallArgRecord &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 call argument record (%d).",
159 OffsetPtr);
160
161 auto PreReadOffset = OffsetPtr;
162 R.Arg = E.getU64(&OffsetPtr);
163 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000164 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000165 "Cannot read a call arg record at offset %d.",
166 OffsetPtr);
167
168 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
169 return Error::success();
170}
171
172Error RecordInitializer::visit(PIDRecord &R) {
173 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
174 MetadataRecord::kMetadataBodySize))
175 return createStringError(std::make_error_code(std::errc::bad_address),
176 "Invalid offset for a process ID record (%d).",
177 OffsetPtr);
178
179 auto PreReadOffset = OffsetPtr;
Dean Michael Berrisf135ac42018-08-31 20:02:55 +0000180 R.PID = E.getSigned(&OffsetPtr, 4);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000181 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000182 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000183 "Cannot read a process ID record at offset %d.",
184 OffsetPtr);
185
186 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
187 return Error::success();
188}
189
190Error RecordInitializer::visit(NewBufferRecord &R) {
191 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
192 MetadataRecord::kMetadataBodySize))
193 return createStringError(std::make_error_code(std::errc::bad_address),
194 "Invalid offset for a new buffer record (%d).",
195 OffsetPtr);
196
197 auto PreReadOffset = OffsetPtr;
198 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
199 if (PreReadOffset == OffsetPtr)
Yi Kongf6095902018-10-26 18:25:27 +0000200 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000201 "Cannot read a new buffer record at offset %d.",
202 OffsetPtr);
203
204 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
205 return Error::success();
206}
207
208Error RecordInitializer::visit(EndBufferRecord &R) {
209 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
210 MetadataRecord::kMetadataBodySize))
211 return createStringError(std::make_error_code(std::errc::bad_address),
212 "Invalid offset for an end-of-buffer record (%d).",
213 OffsetPtr);
214
215 OffsetPtr += MetadataRecord::kMetadataBodySize;
216 return Error::success();
217}
218
219Error RecordInitializer::visit(FunctionRecord &R) {
220 // For function records, we need to retreat one byte back to read a full
221 // unsigned 32-bit value. The first four bytes will have the following
222 // layout:
223 //
224 // bit 0 : function record indicator (must be 0)
225 // bits 1..3 : function record type
226 // bits 4..32 : function id
227 //
228 if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
229 --OffsetPtr, FunctionRecord::kFunctionRecordSize))
230 return createStringError(std::make_error_code(std::errc::bad_address),
231 "Invalid offset for a function record (%d).",
232 OffsetPtr);
233
234 auto BeginOffset = OffsetPtr;
235 auto PreReadOffset = BeginOffset;
236 uint32_t Buffer = E.getU32(&OffsetPtr);
237 if (PreReadOffset == OffsetPtr)
238 return createStringError(std::make_error_code(std::errc::bad_address),
239 "Cannot read function id field from offset %d.",
240 OffsetPtr);
241 unsigned FunctionType = (Buffer >> 1) & 0x07;
242 switch (FunctionType) {
243 case static_cast<unsigned>(RecordTypes::ENTER):
244 case static_cast<unsigned>(RecordTypes::ENTER_ARG):
245 case static_cast<unsigned>(RecordTypes::EXIT):
246 case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
247 R.Kind = static_cast<RecordTypes>(FunctionType);
248 break;
249 default:
Yi Kongf6095902018-10-26 18:25:27 +0000250 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000251 "Unknown function record type '%d' at offset %d.",
252 FunctionType, BeginOffset);
253 }
254
255 R.FuncId = Buffer >> 4;
256 PreReadOffset = OffsetPtr;
257 R.Delta = E.getU32(&OffsetPtr);
258 if (OffsetPtr == PreReadOffset)
Yi Kongf6095902018-10-26 18:25:27 +0000259 return createStringError(std::make_error_code(std::errc::invalid_argument),
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000260 "Failed reading TSC delta from offset %d.",
261 OffsetPtr);
262 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
263 return Error::success();
264}
265
266} // namespace xray
267} // namespace llvm