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 PreReadOffset = OffsetPtr;
65   R.CPUId = E.getU16(&OffsetPtr);
66   if (OffsetPtr == PreReadOffset)
67     return createStringError(std::make_error_code(std::errc::bad_message),
68                              "Cannot read CPU id at offset %d.", OffsetPtr);
69 
70   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
71   return Error::success();
72 }
73 
74 Error RecordInitializer::visit(TSCWrapRecord &R) {
75   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
76                                     MetadataRecord::kMetadataBodySize))
77     return createStringError(std::make_error_code(std::errc::bad_address),
78                              "Invalid offset for a new TSC wrap record (%d).",
79                              OffsetPtr);
80 
81   auto PreReadOffset = OffsetPtr;
82   R.BaseTSC = E.getU64(&OffsetPtr);
83   if (PreReadOffset == OffsetPtr)
84     return createStringError(std::make_error_code(std::errc::bad_message),
85                              "Cannot read TSC wrap record at offset %d.",
86                              OffsetPtr);
87 
88   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
89   return Error::success();
90 }
91 
92 Error RecordInitializer::visit(CustomEventRecord &R) {
93   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
94                                     MetadataRecord::kMetadataBodySize))
95     return createStringError(std::make_error_code(std::errc::bad_address),
96                              "Invalid offset for a custom event record (%d).",
97                              OffsetPtr);
98 
99   auto BeginOffset = OffsetPtr;
100   auto PreReadOffset = OffsetPtr;
101   R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
102   if (PreReadOffset == OffsetPtr)
103     return createStringError(
104         std::make_error_code(std::errc::bad_message),
105         "Cannot read a custom event record size field offset %d.", OffsetPtr);
106 
107   PreReadOffset = OffsetPtr;
108   R.TSC = E.getU64(&OffsetPtr);
109   if (PreReadOffset == OffsetPtr)
110     return createStringError(
111         std::make_error_code(std::errc::bad_message),
112         "Cannot read a custom event TSC field at offset %d.", OffsetPtr);
113 
114   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
115 
116   // Next we read in a fixed chunk of data from the given offset.
117   if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
118     return createStringError(
119         std::make_error_code(std::errc::bad_address),
120         "Cannot read %d bytes of custom event data from offset %d.", R.Size,
121         OffsetPtr);
122 
123   std::vector<uint8_t> Buffer;
124   Buffer.resize(R.Size);
125   if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
126     return createStringError(
127         std::make_error_code(std::errc::bad_message),
128         "Failed reading data into buffer of size %d at offset %d.", R.Size,
129         OffsetPtr);
130   R.Data.assign(Buffer.begin(), Buffer.end());
131   return Error::success();
132 }
133 
134 Error RecordInitializer::visit(CallArgRecord &R) {
135   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
136                                     MetadataRecord::kMetadataBodySize))
137     return createStringError(std::make_error_code(std::errc::bad_address),
138                              "Invalid offset for a call argument record (%d).",
139                              OffsetPtr);
140 
141   auto PreReadOffset = OffsetPtr;
142   R.Arg = E.getU64(&OffsetPtr);
143   if (PreReadOffset == OffsetPtr)
144     return createStringError(std::make_error_code(std::errc::bad_message),
145                              "Cannot read a call arg record at offset %d.",
146                              OffsetPtr);
147 
148   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
149   return Error::success();
150 }
151 
152 Error RecordInitializer::visit(PIDRecord &R) {
153   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
154                                     MetadataRecord::kMetadataBodySize))
155     return createStringError(std::make_error_code(std::errc::bad_address),
156                              "Invalid offset for a process ID record (%d).",
157                              OffsetPtr);
158 
159   auto PreReadOffset = OffsetPtr;
160   R.PID = E.getSigned(&OffsetPtr, 4);
161   if (PreReadOffset == OffsetPtr)
162     return createStringError(std::make_error_code(std::errc::bad_message),
163                              "Cannot read a process ID record at offset %d.",
164                              OffsetPtr);
165 
166   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
167   return Error::success();
168 }
169 
170 Error RecordInitializer::visit(NewBufferRecord &R) {
171   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
172                                     MetadataRecord::kMetadataBodySize))
173     return createStringError(std::make_error_code(std::errc::bad_address),
174                              "Invalid offset for a new buffer record (%d).",
175                              OffsetPtr);
176 
177   auto PreReadOffset = OffsetPtr;
178   R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
179   if (PreReadOffset == OffsetPtr)
180     return createStringError(std::make_error_code(std::errc::bad_message),
181                              "Cannot read a new buffer record at offset %d.",
182                              OffsetPtr);
183 
184   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
185   return Error::success();
186 }
187 
188 Error RecordInitializer::visit(EndBufferRecord &R) {
189   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
190                                     MetadataRecord::kMetadataBodySize))
191     return createStringError(std::make_error_code(std::errc::bad_address),
192                              "Invalid offset for an end-of-buffer record (%d).",
193                              OffsetPtr);
194 
195   OffsetPtr += MetadataRecord::kMetadataBodySize;
196   return Error::success();
197 }
198 
199 Error RecordInitializer::visit(FunctionRecord &R) {
200   // For function records, we need to retreat one byte back to read a full
201   // unsigned 32-bit value. The first four bytes will have the following
202   // layout:
203   //
204   //   bit  0     : function record indicator (must be 0)
205   //   bits 1..3  : function record type
206   //   bits 4..32 : function id
207   //
208   if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
209                             --OffsetPtr, FunctionRecord::kFunctionRecordSize))
210     return createStringError(std::make_error_code(std::errc::bad_address),
211                              "Invalid offset for a function record (%d).",
212                              OffsetPtr);
213 
214   auto BeginOffset = OffsetPtr;
215   auto PreReadOffset = BeginOffset;
216   uint32_t Buffer = E.getU32(&OffsetPtr);
217   if (PreReadOffset == OffsetPtr)
218     return createStringError(std::make_error_code(std::errc::bad_address),
219                              "Cannot read function id field from offset %d.",
220                              OffsetPtr);
221   unsigned FunctionType = (Buffer >> 1) & 0x07;
222   switch (FunctionType) {
223   case static_cast<unsigned>(RecordTypes::ENTER):
224   case static_cast<unsigned>(RecordTypes::ENTER_ARG):
225   case static_cast<unsigned>(RecordTypes::EXIT):
226   case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
227     R.Kind = static_cast<RecordTypes>(FunctionType);
228     break;
229   default:
230     return createStringError(std::make_error_code(std::errc::bad_message),
231                              "Unknown function record type '%d' at offset %d.",
232                              FunctionType, BeginOffset);
233   }
234 
235   R.FuncId = Buffer >> 4;
236   PreReadOffset = OffsetPtr;
237   R.Delta = E.getU32(&OffsetPtr);
238   if (OffsetPtr == PreReadOffset)
239     return createStringError(std::make_error_code(std::errc::bad_message),
240                              "Failed reading TSC delta from offset %d.",
241                              OffsetPtr);
242   assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
243   return Error::success();
244 }
245 
246 } // namespace xray
247 } // namespace llvm
248