xref: /llvm-project/llvm/lib/XRay/RecordInitializer.cpp (revision f26a70a5e7b7b8715eadcb6dec3ff39a267fc666)
1a6c6343aSDean Michael Berris //===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
2a6c6343aSDean Michael Berris //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a6c6343aSDean Michael Berris //
7a6c6343aSDean Michael Berris //===----------------------------------------------------------------------===//
8a6c6343aSDean Michael Berris #include "llvm/XRay/FDRRecords.h"
9a6c6343aSDean Michael Berris 
10a6c6343aSDean Michael Berris namespace llvm {
11a6c6343aSDean Michael Berris namespace xray {
12a6c6343aSDean Michael Berris 
visit(BufferExtents & R)13a6c6343aSDean Michael Berris Error RecordInitializer::visit(BufferExtents &R) {
14a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))
15*f26a70a5SIgor Kudrin     return createStringError(
16*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
17*f26a70a5SIgor Kudrin         "Invalid offset for a buffer extent (%" PRId64 ").", OffsetPtr);
18a6c6343aSDean Michael Berris 
19a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
20a6c6343aSDean Michael Berris   R.Size = E.getU64(&OffsetPtr);
21a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
22f6095904SYi Kong     return createStringError(std::make_error_code(std::errc::invalid_argument),
23*f26a70a5SIgor Kudrin                              "Cannot read buffer extent at offset %" PRId64 ".",
24a6c6343aSDean Michael Berris                              OffsetPtr);
25a6c6343aSDean Michael Berris 
26a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
27a6c6343aSDean Michael Berris   return Error::success();
28a6c6343aSDean Michael Berris }
29a6c6343aSDean Michael Berris 
visit(WallclockRecord & R)30a6c6343aSDean Michael Berris Error RecordInitializer::visit(WallclockRecord &R) {
31a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
32a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
33*f26a70a5SIgor Kudrin     return createStringError(
34*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
35*f26a70a5SIgor Kudrin         "Invalid offset for a wallclock record (%" PRId64 ").", OffsetPtr);
36a6c6343aSDean Michael Berris   auto BeginOffset = OffsetPtr;
37a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
38a6c6343aSDean Michael Berris   R.Seconds = E.getU64(&OffsetPtr);
39a6c6343aSDean Michael Berris   if (OffsetPtr == PreReadOffset)
40a6c6343aSDean Michael Berris     return createStringError(
41f6095904SYi Kong         std::make_error_code(std::errc::invalid_argument),
42*f26a70a5SIgor Kudrin         "Cannot read wall clock 'seconds' field at offset %" PRId64 ".",
43*f26a70a5SIgor Kudrin         OffsetPtr);
44a6c6343aSDean Michael Berris 
45a6c6343aSDean Michael Berris   PreReadOffset = OffsetPtr;
46a6c6343aSDean Michael Berris   R.Nanos = E.getU32(&OffsetPtr);
47a6c6343aSDean Michael Berris   if (OffsetPtr == PreReadOffset)
48a6c6343aSDean Michael Berris     return createStringError(
49f6095904SYi Kong         std::make_error_code(std::errc::invalid_argument),
50*f26a70a5SIgor Kudrin         "Cannot read wall clock 'nanos' field at offset %" PRId64 ".",
51*f26a70a5SIgor Kudrin         OffsetPtr);
52a6c6343aSDean Michael Berris 
53a6c6343aSDean Michael Berris   // Align to metadata record size boundary.
54a6c6343aSDean Michael Berris   assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
55a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
56a6c6343aSDean Michael Berris   return Error::success();
57a6c6343aSDean Michael Berris }
58a6c6343aSDean Michael Berris 
visit(NewCPUIDRecord & R)59a6c6343aSDean Michael Berris Error RecordInitializer::visit(NewCPUIDRecord &R) {
60a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
61a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
62*f26a70a5SIgor Kudrin     return createStringError(
63*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
64*f26a70a5SIgor Kudrin         "Invalid offset for a new cpu id record (%" PRId64 ").", OffsetPtr);
65d2c50408SDean Michael Berris   auto BeginOffset = OffsetPtr;
66a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
67a6c6343aSDean Michael Berris   R.CPUId = E.getU16(&OffsetPtr);
68a6c6343aSDean Michael Berris   if (OffsetPtr == PreReadOffset)
69f6095904SYi Kong     return createStringError(std::make_error_code(std::errc::invalid_argument),
70*f26a70a5SIgor Kudrin                              "Cannot read CPU id at offset %" PRId64 ".",
71*f26a70a5SIgor Kudrin                              OffsetPtr);
72a6c6343aSDean Michael Berris 
73d2c50408SDean Michael Berris   PreReadOffset = OffsetPtr;
74d2c50408SDean Michael Berris   R.TSC = E.getU64(&OffsetPtr);
75d2c50408SDean Michael Berris   if (OffsetPtr == PreReadOffset)
76f6095904SYi Kong     return createStringError(std::make_error_code(std::errc::invalid_argument),
77*f26a70a5SIgor Kudrin                              "Cannot read CPU TSC at offset %" PRId64 ".",
78*f26a70a5SIgor Kudrin                              OffsetPtr);
79d2c50408SDean Michael Berris 
80d2c50408SDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
81a6c6343aSDean Michael Berris   return Error::success();
82a6c6343aSDean Michael Berris }
83a6c6343aSDean Michael Berris 
visit(TSCWrapRecord & R)84a6c6343aSDean Michael Berris Error RecordInitializer::visit(TSCWrapRecord &R) {
85a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
86a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
87*f26a70a5SIgor Kudrin     return createStringError(
88*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
89*f26a70a5SIgor Kudrin         "Invalid offset for a new TSC wrap record (%" PRId64 ").", OffsetPtr);
90a6c6343aSDean Michael Berris 
91a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
92a6c6343aSDean Michael Berris   R.BaseTSC = E.getU64(&OffsetPtr);
93a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
94*f26a70a5SIgor Kudrin     return createStringError(
95*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::invalid_argument),
96*f26a70a5SIgor Kudrin         "Cannot read TSC wrap record at offset %" PRId64 ".", OffsetPtr);
97a6c6343aSDean Michael Berris 
98a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
99a6c6343aSDean Michael Berris   return Error::success();
100a6c6343aSDean Michael Berris }
101a6c6343aSDean Michael Berris 
visit(CustomEventRecord & R)102a6c6343aSDean Michael Berris Error RecordInitializer::visit(CustomEventRecord &R) {
103a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
104a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
105*f26a70a5SIgor Kudrin     return createStringError(
106*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
107*f26a70a5SIgor Kudrin         "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);
108a6c6343aSDean Michael Berris 
109a6c6343aSDean Michael Berris   auto BeginOffset = OffsetPtr;
110a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
111a6c6343aSDean Michael Berris   R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
112a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
113a6c6343aSDean Michael Berris     return createStringError(
114f6095904SYi Kong         std::make_error_code(std::errc::invalid_argument),
115*f26a70a5SIgor Kudrin         "Cannot read a custom event record size field offset %" PRId64 ".",
116*f26a70a5SIgor Kudrin         OffsetPtr);
117a6c6343aSDean Michael Berris 
118da375a67SDean Michael Berris   if (R.Size <= 0)
119da375a67SDean Michael Berris     return createStringError(
120da375a67SDean Michael Berris         std::make_error_code(std::errc::bad_address),
121*f26a70a5SIgor Kudrin         "Invalid size for custom event (size = %d) at offset %" PRId64 ".",
122*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
123da375a67SDean Michael Berris 
124a6c6343aSDean Michael Berris   PreReadOffset = OffsetPtr;
125a6c6343aSDean Michael Berris   R.TSC = E.getU64(&OffsetPtr);
126a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
127a6c6343aSDean Michael Berris     return createStringError(
128f6095904SYi Kong         std::make_error_code(std::errc::invalid_argument),
129*f26a70a5SIgor Kudrin         "Cannot read a custom event TSC field at offset %" PRId64 ".",
130*f26a70a5SIgor Kudrin         OffsetPtr);
131a6c6343aSDean Michael Berris 
1326b67ff03SDean Michael Berris   // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
1336b67ff03SDean Michael Berris   // of the custom event.
1346b67ff03SDean Michael Berris   if (Version >= 4) {
1356b67ff03SDean Michael Berris     PreReadOffset = OffsetPtr;
1366b67ff03SDean Michael Berris     R.CPU = E.getU16(&OffsetPtr);
1376b67ff03SDean Michael Berris     if (PreReadOffset == OffsetPtr)
1386b67ff03SDean Michael Berris       return createStringError(
1396b67ff03SDean Michael Berris           std::make_error_code(std::errc::invalid_argument),
140*f26a70a5SIgor Kudrin           "Missing CPU field at offset %" PRId64 ".", OffsetPtr);
1416b67ff03SDean Michael Berris   }
1426b67ff03SDean Michael Berris 
1436b67ff03SDean Michael Berris   assert(OffsetPtr > BeginOffset &&
1446b67ff03SDean Michael Berris          OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
145a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
146a6c6343aSDean Michael Berris 
147a6c6343aSDean Michael Berris   // Next we read in a fixed chunk of data from the given offset.
148a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
149a6c6343aSDean Michael Berris     return createStringError(
150a6c6343aSDean Michael Berris         std::make_error_code(std::errc::bad_address),
151*f26a70a5SIgor Kudrin         "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
152*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
153a6c6343aSDean Michael Berris 
154a6c6343aSDean Michael Berris   std::vector<uint8_t> Buffer;
155a6c6343aSDean Michael Berris   Buffer.resize(R.Size);
156da375a67SDean Michael Berris   PreReadOffset = OffsetPtr;
157a6c6343aSDean Michael Berris   if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
158a6c6343aSDean Michael Berris     return createStringError(
159f6095904SYi Kong         std::make_error_code(std::errc::invalid_argument),
160*f26a70a5SIgor Kudrin         "Failed reading data into buffer of size %d at offset %" PRId64 ".",
161*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
162da375a67SDean Michael Berris 
163da375a67SDean Michael Berris   assert(OffsetPtr >= PreReadOffset);
164da375a67SDean Michael Berris   if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
165da375a67SDean Michael Berris     return createStringError(
166da375a67SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
167*f26a70a5SIgor Kudrin         "Failed reading enough bytes for the custom event payload -- read "
168*f26a70a5SIgor Kudrin         "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
169da375a67SDean Michael Berris         OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
170da375a67SDean Michael Berris 
171a6c6343aSDean Michael Berris   R.Data.assign(Buffer.begin(), Buffer.end());
172a6c6343aSDean Michael Berris   return Error::success();
173a6c6343aSDean Michael Berris }
174a6c6343aSDean Michael Berris 
visit(CustomEventRecordV5 & R)17559439dd0SDean Michael Berris Error RecordInitializer::visit(CustomEventRecordV5 &R) {
17659439dd0SDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
17759439dd0SDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
178*f26a70a5SIgor Kudrin     return createStringError(
179*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
180*f26a70a5SIgor Kudrin         "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);
18159439dd0SDean Michael Berris 
18259439dd0SDean Michael Berris   auto BeginOffset = OffsetPtr;
18359439dd0SDean Michael Berris   auto PreReadOffset = OffsetPtr;
18459439dd0SDean Michael Berris 
18559439dd0SDean Michael Berris   R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
18659439dd0SDean Michael Berris   if (PreReadOffset == OffsetPtr)
18759439dd0SDean Michael Berris     return createStringError(
18859439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
189*f26a70a5SIgor Kudrin         "Cannot read a custom event record size field offset %" PRId64 ".",
190*f26a70a5SIgor Kudrin         OffsetPtr);
19159439dd0SDean Michael Berris 
192da375a67SDean Michael Berris   if (R.Size <= 0)
193da375a67SDean Michael Berris     return createStringError(
194da375a67SDean Michael Berris         std::make_error_code(std::errc::bad_address),
195*f26a70a5SIgor Kudrin         "Invalid size for custom event (size = %d) at offset %" PRId64 ".",
196*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
197da375a67SDean Michael Berris 
19859439dd0SDean Michael Berris   PreReadOffset = OffsetPtr;
19959439dd0SDean Michael Berris   R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
20059439dd0SDean Michael Berris   if (PreReadOffset == OffsetPtr)
20159439dd0SDean Michael Berris     return createStringError(
20259439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
203*f26a70a5SIgor Kudrin         "Cannot read a custom event record TSC delta field at offset "
204*f26a70a5SIgor Kudrin         "%" PRId64 ".",
20559439dd0SDean Michael Berris         OffsetPtr);
20659439dd0SDean Michael Berris 
20759439dd0SDean Michael Berris   assert(OffsetPtr > BeginOffset &&
20859439dd0SDean Michael Berris          OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
20959439dd0SDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
21059439dd0SDean Michael Berris 
21159439dd0SDean Michael Berris   // Next we read in a fixed chunk of data from the given offset.
21259439dd0SDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
21359439dd0SDean Michael Berris     return createStringError(
21459439dd0SDean Michael Berris         std::make_error_code(std::errc::bad_address),
215*f26a70a5SIgor Kudrin         "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
216*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
21759439dd0SDean Michael Berris 
21859439dd0SDean Michael Berris   std::vector<uint8_t> Buffer;
21959439dd0SDean Michael Berris   Buffer.resize(R.Size);
220da375a67SDean Michael Berris   PreReadOffset = OffsetPtr;
22159439dd0SDean Michael Berris   if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
22259439dd0SDean Michael Berris     return createStringError(
22359439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
224*f26a70a5SIgor Kudrin         "Failed reading data into buffer of size %d at offset %" PRId64 ".",
225*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
226da375a67SDean Michael Berris 
227da375a67SDean Michael Berris   assert(OffsetPtr >= PreReadOffset);
228da375a67SDean Michael Berris   if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
229da375a67SDean Michael Berris     return createStringError(
230da375a67SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
231*f26a70a5SIgor Kudrin         "Failed reading enough bytes for the custom event payload -- read "
232*f26a70a5SIgor Kudrin         "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
233da375a67SDean Michael Berris         OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
234da375a67SDean Michael Berris 
23559439dd0SDean Michael Berris   R.Data.assign(Buffer.begin(), Buffer.end());
23659439dd0SDean Michael Berris   return Error::success();
23759439dd0SDean Michael Berris }
23859439dd0SDean Michael Berris 
visit(TypedEventRecord & R)23959439dd0SDean Michael Berris Error RecordInitializer::visit(TypedEventRecord &R) {
24059439dd0SDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
24159439dd0SDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
242*f26a70a5SIgor Kudrin     return createStringError(
243*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
244*f26a70a5SIgor Kudrin         "Invalid offset for a typed event record (%" PRId64 ").", OffsetPtr);
24559439dd0SDean Michael Berris 
24659439dd0SDean Michael Berris   auto BeginOffset = OffsetPtr;
24759439dd0SDean Michael Berris   auto PreReadOffset = OffsetPtr;
24859439dd0SDean Michael Berris 
24959439dd0SDean Michael Berris   R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
25059439dd0SDean Michael Berris   if (PreReadOffset == OffsetPtr)
25159439dd0SDean Michael Berris     return createStringError(
25259439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
253*f26a70a5SIgor Kudrin         "Cannot read a typed event record size field offset %" PRId64 ".",
254*f26a70a5SIgor Kudrin         OffsetPtr);
25559439dd0SDean Michael Berris 
256da375a67SDean Michael Berris   if (R.Size <= 0)
257da375a67SDean Michael Berris     return createStringError(
258da375a67SDean Michael Berris         std::make_error_code(std::errc::bad_address),
259*f26a70a5SIgor Kudrin         "Invalid size for typed event (size = %d) at offset %" PRId64 ".",
260*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
261da375a67SDean Michael Berris 
26259439dd0SDean Michael Berris   PreReadOffset = OffsetPtr;
26359439dd0SDean Michael Berris   R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
26459439dd0SDean Michael Berris   if (PreReadOffset == OffsetPtr)
26559439dd0SDean Michael Berris     return createStringError(
26659439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
267*f26a70a5SIgor Kudrin         "Cannot read a typed event record TSC delta field at offset "
268*f26a70a5SIgor Kudrin         "%" PRId64 ".",
26959439dd0SDean Michael Berris         OffsetPtr);
27059439dd0SDean Michael Berris 
27159439dd0SDean Michael Berris   PreReadOffset = OffsetPtr;
27259439dd0SDean Michael Berris   R.EventType = E.getU16(&OffsetPtr);
27359439dd0SDean Michael Berris   if (PreReadOffset == OffsetPtr)
27459439dd0SDean Michael Berris     return createStringError(
27559439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
276*f26a70a5SIgor Kudrin         "Cannot read a typed event record type field at offset %" PRId64 ".",
277*f26a70a5SIgor Kudrin         OffsetPtr);
27859439dd0SDean Michael Berris 
27959439dd0SDean Michael Berris   assert(OffsetPtr > BeginOffset &&
28059439dd0SDean Michael Berris          OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
28159439dd0SDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
28259439dd0SDean Michael Berris 
28359439dd0SDean Michael Berris   // Next we read in a fixed chunk of data from the given offset.
28459439dd0SDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
28559439dd0SDean Michael Berris     return createStringError(
28659439dd0SDean Michael Berris         std::make_error_code(std::errc::bad_address),
287*f26a70a5SIgor Kudrin         "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
288*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
28959439dd0SDean Michael Berris 
29059439dd0SDean Michael Berris   std::vector<uint8_t> Buffer;
29159439dd0SDean Michael Berris   Buffer.resize(R.Size);
292da375a67SDean Michael Berris   PreReadOffset = OffsetPtr;
29359439dd0SDean Michael Berris   if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
29459439dd0SDean Michael Berris     return createStringError(
29559439dd0SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
296*f26a70a5SIgor Kudrin         "Failed reading data into buffer of size %d at offset %" PRId64 ".",
297*f26a70a5SIgor Kudrin         R.Size, OffsetPtr);
298da375a67SDean Michael Berris 
299da375a67SDean Michael Berris   assert(OffsetPtr >= PreReadOffset);
300da375a67SDean Michael Berris   if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
301da375a67SDean Michael Berris     return createStringError(
302da375a67SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
303*f26a70a5SIgor Kudrin         "Failed reading enough bytes for the typed event payload -- read "
304*f26a70a5SIgor Kudrin         "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
305da375a67SDean Michael Berris         OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
306da375a67SDean Michael Berris 
30759439dd0SDean Michael Berris   R.Data.assign(Buffer.begin(), Buffer.end());
30859439dd0SDean Michael Berris   return Error::success();
30959439dd0SDean Michael Berris }
31059439dd0SDean Michael Berris 
visit(CallArgRecord & R)311a6c6343aSDean Michael Berris Error RecordInitializer::visit(CallArgRecord &R) {
312a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
313a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
314*f26a70a5SIgor Kudrin     return createStringError(
315*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
316*f26a70a5SIgor Kudrin         "Invalid offset for a call argument record (%" PRId64 ").",
317a6c6343aSDean Michael Berris         OffsetPtr);
318a6c6343aSDean Michael Berris 
319a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
320a6c6343aSDean Michael Berris   R.Arg = E.getU64(&OffsetPtr);
321a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
322*f26a70a5SIgor Kudrin     return createStringError(
323*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::invalid_argument),
324*f26a70a5SIgor Kudrin         "Cannot read a call arg record at offset %" PRId64 ".", OffsetPtr);
325a6c6343aSDean Michael Berris 
326a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
327a6c6343aSDean Michael Berris   return Error::success();
328a6c6343aSDean Michael Berris }
329a6c6343aSDean Michael Berris 
visit(PIDRecord & R)330a6c6343aSDean Michael Berris Error RecordInitializer::visit(PIDRecord &R) {
331a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
332a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
333*f26a70a5SIgor Kudrin     return createStringError(
334*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
335*f26a70a5SIgor Kudrin         "Invalid offset for a process ID record (%" PRId64 ").", OffsetPtr);
336a6c6343aSDean Michael Berris 
337a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
338f135ac4bSDean Michael Berris   R.PID = E.getSigned(&OffsetPtr, 4);
339a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
340*f26a70a5SIgor Kudrin     return createStringError(
341*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::invalid_argument),
342*f26a70a5SIgor Kudrin         "Cannot read a process ID record at offset %" PRId64 ".", OffsetPtr);
343a6c6343aSDean Michael Berris 
344a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
345a6c6343aSDean Michael Berris   return Error::success();
346a6c6343aSDean Michael Berris }
347a6c6343aSDean Michael Berris 
visit(NewBufferRecord & R)348a6c6343aSDean Michael Berris Error RecordInitializer::visit(NewBufferRecord &R) {
349a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
350a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
351*f26a70a5SIgor Kudrin     return createStringError(
352*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
353*f26a70a5SIgor Kudrin         "Invalid offset for a new buffer record (%" PRId64 ").", OffsetPtr);
354a6c6343aSDean Michael Berris 
355a6c6343aSDean Michael Berris   auto PreReadOffset = OffsetPtr;
356a6c6343aSDean Michael Berris   R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
357a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
358*f26a70a5SIgor Kudrin     return createStringError(
359*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::invalid_argument),
360*f26a70a5SIgor Kudrin         "Cannot read a new buffer record at offset %" PRId64 ".", OffsetPtr);
361a6c6343aSDean Michael Berris 
362a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
363a6c6343aSDean Michael Berris   return Error::success();
364a6c6343aSDean Michael Berris }
365a6c6343aSDean Michael Berris 
visit(EndBufferRecord & R)366a6c6343aSDean Michael Berris Error RecordInitializer::visit(EndBufferRecord &R) {
367a6c6343aSDean Michael Berris   if (!E.isValidOffsetForDataOfSize(OffsetPtr,
368a6c6343aSDean Michael Berris                                     MetadataRecord::kMetadataBodySize))
369*f26a70a5SIgor Kudrin     return createStringError(
370*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
371*f26a70a5SIgor Kudrin         "Invalid offset for an end-of-buffer record (%" PRId64 ").",
372a6c6343aSDean Michael Berris         OffsetPtr);
373a6c6343aSDean Michael Berris 
374a6c6343aSDean Michael Berris   OffsetPtr += MetadataRecord::kMetadataBodySize;
375a6c6343aSDean Michael Berris   return Error::success();
376a6c6343aSDean Michael Berris }
377a6c6343aSDean Michael Berris 
visit(FunctionRecord & R)378a6c6343aSDean Michael Berris Error RecordInitializer::visit(FunctionRecord &R) {
379a6c6343aSDean Michael Berris   // For function records, we need to retreat one byte back to read a full
380a6c6343aSDean Michael Berris   // unsigned 32-bit value. The first four bytes will have the following
381a6c6343aSDean Michael Berris   // layout:
382a6c6343aSDean Michael Berris   //
383a6c6343aSDean Michael Berris   //   bit  0     : function record indicator (must be 0)
384a6c6343aSDean Michael Berris   //   bits 1..3  : function record type
385a6c6343aSDean Michael Berris   //   bits 4..32 : function id
386a6c6343aSDean Michael Berris   //
387a6c6343aSDean Michael Berris   if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
388a6c6343aSDean Michael Berris                             --OffsetPtr, FunctionRecord::kFunctionRecordSize))
389*f26a70a5SIgor Kudrin     return createStringError(
390*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
391*f26a70a5SIgor Kudrin         "Invalid offset for a function record (%" PRId64 ").", OffsetPtr);
392a6c6343aSDean Michael Berris 
393a6c6343aSDean Michael Berris   auto BeginOffset = OffsetPtr;
394a6c6343aSDean Michael Berris   auto PreReadOffset = BeginOffset;
395a6c6343aSDean Michael Berris   uint32_t Buffer = E.getU32(&OffsetPtr);
396a6c6343aSDean Michael Berris   if (PreReadOffset == OffsetPtr)
397*f26a70a5SIgor Kudrin     return createStringError(
398*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::bad_address),
399*f26a70a5SIgor Kudrin         "Cannot read function id field from offset %" PRId64 ".", OffsetPtr);
400da375a67SDean Michael Berris 
401da375a67SDean Michael Berris   // To get the function record type, we shift the buffer one to the right
402da375a67SDean Michael Berris   // (truncating the function record indicator) then take the three bits
403da375a67SDean Michael Berris   // (0b0111) to get the record type as an unsigned value.
404da375a67SDean Michael Berris   unsigned FunctionType = (Buffer >> 1) & 0x07u;
405a6c6343aSDean Michael Berris   switch (FunctionType) {
406a6c6343aSDean Michael Berris   case static_cast<unsigned>(RecordTypes::ENTER):
407a6c6343aSDean Michael Berris   case static_cast<unsigned>(RecordTypes::ENTER_ARG):
408a6c6343aSDean Michael Berris   case static_cast<unsigned>(RecordTypes::EXIT):
409a6c6343aSDean Michael Berris   case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
410a6c6343aSDean Michael Berris     R.Kind = static_cast<RecordTypes>(FunctionType);
411a6c6343aSDean Michael Berris     break;
412a6c6343aSDean Michael Berris   default:
413*f26a70a5SIgor Kudrin     return createStringError(
414*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::invalid_argument),
415*f26a70a5SIgor Kudrin         "Unknown function record type '%d' at offset %" PRId64 ".",
416a6c6343aSDean Michael Berris         FunctionType, BeginOffset);
417a6c6343aSDean Michael Berris   }
418a6c6343aSDean Michael Berris 
419a6c6343aSDean Michael Berris   R.FuncId = Buffer >> 4;
420a6c6343aSDean Michael Berris   PreReadOffset = OffsetPtr;
421a6c6343aSDean Michael Berris   R.Delta = E.getU32(&OffsetPtr);
422a6c6343aSDean Michael Berris   if (OffsetPtr == PreReadOffset)
423*f26a70a5SIgor Kudrin     return createStringError(
424*f26a70a5SIgor Kudrin         std::make_error_code(std::errc::invalid_argument),
425*f26a70a5SIgor Kudrin         "Failed reading TSC delta from offset %" PRId64 ".", OffsetPtr);
426a6c6343aSDean Michael Berris   assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
427a6c6343aSDean Michael Berris   return Error::success();
428a6c6343aSDean Michael Berris }
429a6c6343aSDean Michael Berris 
430a6c6343aSDean Michael Berris } // namespace xray
431a6c6343aSDean Michael Berris } // namespace llvm
432