xref: /llvm-project/llvm/lib/XRay/RecordInitializer.cpp (revision 6b67ff03002f39adf773f456aa4fd79bb22f3a04)
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 
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 
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 
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 
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 
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   PreReadOffset = OffsetPtr;
115   R.TSC = E.getU64(&OffsetPtr);
116   if (PreReadOffset == OffsetPtr)
117     return createStringError(
118         std::make_error_code(std::errc::invalid_argument),
119         "Cannot read a custom event TSC field at offset %d.", OffsetPtr);
120 
121   // 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);
134   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(
147         std::make_error_code(std::errc::invalid_argument),
148         "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 
154 Error 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)
164     return createStringError(std::make_error_code(std::errc::invalid_argument),
165                              "Cannot read a call arg record at offset %d.",
166                              OffsetPtr);
167 
168   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
169   return Error::success();
170 }
171 
172 Error 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;
180   R.PID = E.getSigned(&OffsetPtr, 4);
181   if (PreReadOffset == OffsetPtr)
182     return createStringError(std::make_error_code(std::errc::invalid_argument),
183                              "Cannot read a process ID record at offset %d.",
184                              OffsetPtr);
185 
186   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
187   return Error::success();
188 }
189 
190 Error 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)
200     return createStringError(std::make_error_code(std::errc::invalid_argument),
201                              "Cannot read a new buffer record at offset %d.",
202                              OffsetPtr);
203 
204   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
205   return Error::success();
206 }
207 
208 Error 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 
219 Error 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:
250     return createStringError(std::make_error_code(std::errc::invalid_argument),
251                              "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)
259     return createStringError(std::make_error_code(std::errc::invalid_argument),
260                              "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
268