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::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 
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::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 
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::bad_message),
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::bad_message),
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::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 
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::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 
141 Error 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 
159 Error 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;
167   R.PID = E.getSigned(&OffsetPtr, 4);
168   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 
177 Error 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 
195 Error 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 
206 Error 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
255