blob: 7f9fd4c9627c4d529b3e64a4e2f9d67de1d09f98 [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)
23 return createStringError(std::make_error_code(std::errc::bad_message),
24 "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(
42 std::make_error_code(std::errc::bad_message),
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::bad_message),
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
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)
68 return createStringError(std::make_error_code(std::errc::bad_message),
69 "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)
74 return createStringError(std::make_error_code(std::errc::bad_message),
75 "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)
91 return createStringError(std::make_error_code(std::errc::bad_message),
92 "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(
111 std::make_error_code(std::errc::bad_message),
112 "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(
118 std::make_error_code(std::errc::bad_message),
119 "Cannot read a custom event TSC field at offset %d.", OffsetPtr);
120
121 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
122
123 // Next we read in a fixed chunk of data from the given offset.
124 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
125 return createStringError(
126 std::make_error_code(std::errc::bad_address),
127 "Cannot read %d bytes of custom event data from offset %d.", R.Size,
128 OffsetPtr);
129
130 std::vector<uint8_t> Buffer;
131 Buffer.resize(R.Size);
132 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
133 return createStringError(
134 std::make_error_code(std::errc::bad_message),
135 "Failed reading data into buffer of size %d at offset %d.", R.Size,
136 OffsetPtr);
137 R.Data.assign(Buffer.begin(), Buffer.end());
138 return Error::success();
139}
140
141Error RecordInitializer::visit(CallArgRecord &R) {
142 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
143 MetadataRecord::kMetadataBodySize))
144 return createStringError(std::make_error_code(std::errc::bad_address),
145 "Invalid offset for a call argument record (%d).",
146 OffsetPtr);
147
148 auto PreReadOffset = OffsetPtr;
149 R.Arg = E.getU64(&OffsetPtr);
150 if (PreReadOffset == OffsetPtr)
151 return createStringError(std::make_error_code(std::errc::bad_message),
152 "Cannot read a call arg record at offset %d.",
153 OffsetPtr);
154
155 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
156 return Error::success();
157}
158
159Error RecordInitializer::visit(PIDRecord &R) {
160 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
161 MetadataRecord::kMetadataBodySize))
162 return createStringError(std::make_error_code(std::errc::bad_address),
163 "Invalid offset for a process ID record (%d).",
164 OffsetPtr);
165
166 auto PreReadOffset = OffsetPtr;
Dean Michael Berrisf135ac42018-08-31 20:02:55 +0000167 R.PID = E.getSigned(&OffsetPtr, 4);
Dean Michael Berrisa6c63432018-08-30 07:22:21 +0000168 if (PreReadOffset == OffsetPtr)
169 return createStringError(std::make_error_code(std::errc::bad_message),
170 "Cannot read a process ID record at offset %d.",
171 OffsetPtr);
172
173 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
174 return Error::success();
175}
176
177Error RecordInitializer::visit(NewBufferRecord &R) {
178 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
179 MetadataRecord::kMetadataBodySize))
180 return createStringError(std::make_error_code(std::errc::bad_address),
181 "Invalid offset for a new buffer record (%d).",
182 OffsetPtr);
183
184 auto PreReadOffset = OffsetPtr;
185 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
186 if (PreReadOffset == OffsetPtr)
187 return createStringError(std::make_error_code(std::errc::bad_message),
188 "Cannot read a new buffer record at offset %d.",
189 OffsetPtr);
190
191 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
192 return Error::success();
193}
194
195Error RecordInitializer::visit(EndBufferRecord &R) {
196 if (!E.isValidOffsetForDataOfSize(OffsetPtr,
197 MetadataRecord::kMetadataBodySize))
198 return createStringError(std::make_error_code(std::errc::bad_address),
199 "Invalid offset for an end-of-buffer record (%d).",
200 OffsetPtr);
201
202 OffsetPtr += MetadataRecord::kMetadataBodySize;
203 return Error::success();
204}
205
206Error RecordInitializer::visit(FunctionRecord &R) {
207 // For function records, we need to retreat one byte back to read a full
208 // unsigned 32-bit value. The first four bytes will have the following
209 // layout:
210 //
211 // bit 0 : function record indicator (must be 0)
212 // bits 1..3 : function record type
213 // bits 4..32 : function id
214 //
215 if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
216 --OffsetPtr, FunctionRecord::kFunctionRecordSize))
217 return createStringError(std::make_error_code(std::errc::bad_address),
218 "Invalid offset for a function record (%d).",
219 OffsetPtr);
220
221 auto BeginOffset = OffsetPtr;
222 auto PreReadOffset = BeginOffset;
223 uint32_t Buffer = E.getU32(&OffsetPtr);
224 if (PreReadOffset == OffsetPtr)
225 return createStringError(std::make_error_code(std::errc::bad_address),
226 "Cannot read function id field from offset %d.",
227 OffsetPtr);
228 unsigned FunctionType = (Buffer >> 1) & 0x07;
229 switch (FunctionType) {
230 case static_cast<unsigned>(RecordTypes::ENTER):
231 case static_cast<unsigned>(RecordTypes::ENTER_ARG):
232 case static_cast<unsigned>(RecordTypes::EXIT):
233 case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
234 R.Kind = static_cast<RecordTypes>(FunctionType);
235 break;
236 default:
237 return createStringError(std::make_error_code(std::errc::bad_message),
238 "Unknown function record type '%d' at offset %d.",
239 FunctionType, BeginOffset);
240 }
241
242 R.FuncId = Buffer >> 4;
243 PreReadOffset = OffsetPtr;
244 R.Delta = E.getU32(&OffsetPtr);
245 if (OffsetPtr == PreReadOffset)
246 return createStringError(std::make_error_code(std::errc::bad_message),
247 "Failed reading TSC delta from offset %d.",
248 OffsetPtr);
249 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
250 return Error::success();
251}
252
253} // namespace xray
254} // namespace llvm