RecordInitializer.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. //===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/XRay/FDRRecords.h"
  9. namespace llvm {
  10. namespace xray {
  11. Error RecordInitializer::visit(BufferExtents &R) {
  12. if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))
  13. return createStringError(
  14. std::make_error_code(std::errc::bad_address),
  15. "Invalid offset for a buffer extent (%" PRId64 ").", OffsetPtr);
  16. auto PreReadOffset = OffsetPtr;
  17. R.Size = E.getU64(&OffsetPtr);
  18. if (PreReadOffset == OffsetPtr)
  19. return createStringError(std::make_error_code(std::errc::invalid_argument),
  20. "Cannot read buffer extent at offset %" PRId64 ".",
  21. OffsetPtr);
  22. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
  23. return Error::success();
  24. }
  25. Error RecordInitializer::visit(WallclockRecord &R) {
  26. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  27. MetadataRecord::kMetadataBodySize))
  28. return createStringError(
  29. std::make_error_code(std::errc::bad_address),
  30. "Invalid offset for a wallclock record (%" PRId64 ").", OffsetPtr);
  31. auto BeginOffset = OffsetPtr;
  32. auto PreReadOffset = OffsetPtr;
  33. R.Seconds = E.getU64(&OffsetPtr);
  34. if (OffsetPtr == PreReadOffset)
  35. return createStringError(
  36. std::make_error_code(std::errc::invalid_argument),
  37. "Cannot read wall clock 'seconds' field at offset %" PRId64 ".",
  38. OffsetPtr);
  39. PreReadOffset = OffsetPtr;
  40. R.Nanos = E.getU32(&OffsetPtr);
  41. if (OffsetPtr == PreReadOffset)
  42. return createStringError(
  43. std::make_error_code(std::errc::invalid_argument),
  44. "Cannot read wall clock 'nanos' field at offset %" PRId64 ".",
  45. OffsetPtr);
  46. // Align to metadata record size boundary.
  47. assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
  48. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
  49. return Error::success();
  50. }
  51. Error RecordInitializer::visit(NewCPUIDRecord &R) {
  52. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  53. MetadataRecord::kMetadataBodySize))
  54. return createStringError(
  55. std::make_error_code(std::errc::bad_address),
  56. "Invalid offset for a new cpu id record (%" PRId64 ").", OffsetPtr);
  57. auto BeginOffset = OffsetPtr;
  58. auto PreReadOffset = OffsetPtr;
  59. R.CPUId = E.getU16(&OffsetPtr);
  60. if (OffsetPtr == PreReadOffset)
  61. return createStringError(std::make_error_code(std::errc::invalid_argument),
  62. "Cannot read CPU id at offset %" PRId64 ".",
  63. OffsetPtr);
  64. PreReadOffset = OffsetPtr;
  65. R.TSC = E.getU64(&OffsetPtr);
  66. if (OffsetPtr == PreReadOffset)
  67. return createStringError(std::make_error_code(std::errc::invalid_argument),
  68. "Cannot read CPU TSC at offset %" PRId64 ".",
  69. OffsetPtr);
  70. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
  71. return Error::success();
  72. }
  73. Error RecordInitializer::visit(TSCWrapRecord &R) {
  74. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  75. MetadataRecord::kMetadataBodySize))
  76. return createStringError(
  77. std::make_error_code(std::errc::bad_address),
  78. "Invalid offset for a new TSC wrap record (%" PRId64 ").", OffsetPtr);
  79. auto PreReadOffset = OffsetPtr;
  80. R.BaseTSC = E.getU64(&OffsetPtr);
  81. if (PreReadOffset == OffsetPtr)
  82. return createStringError(
  83. std::make_error_code(std::errc::invalid_argument),
  84. "Cannot read TSC wrap record at offset %" PRId64 ".", OffsetPtr);
  85. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
  86. return Error::success();
  87. }
  88. Error RecordInitializer::visit(CustomEventRecord &R) {
  89. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  90. MetadataRecord::kMetadataBodySize))
  91. return createStringError(
  92. std::make_error_code(std::errc::bad_address),
  93. "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);
  94. auto BeginOffset = OffsetPtr;
  95. auto PreReadOffset = OffsetPtr;
  96. R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
  97. if (PreReadOffset == OffsetPtr)
  98. return createStringError(
  99. std::make_error_code(std::errc::invalid_argument),
  100. "Cannot read a custom event record size field offset %" PRId64 ".",
  101. OffsetPtr);
  102. if (R.Size <= 0)
  103. return createStringError(
  104. std::make_error_code(std::errc::bad_address),
  105. "Invalid size for custom event (size = %d) at offset %" PRId64 ".",
  106. R.Size, OffsetPtr);
  107. PreReadOffset = OffsetPtr;
  108. R.TSC = E.getU64(&OffsetPtr);
  109. if (PreReadOffset == OffsetPtr)
  110. return createStringError(
  111. std::make_error_code(std::errc::invalid_argument),
  112. "Cannot read a custom event TSC field at offset %" PRId64 ".",
  113. OffsetPtr);
  114. // For version 4 onwards, of the FDR log, we want to also capture the CPU ID
  115. // of the custom event.
  116. if (Version >= 4) {
  117. PreReadOffset = OffsetPtr;
  118. R.CPU = E.getU16(&OffsetPtr);
  119. if (PreReadOffset == OffsetPtr)
  120. return createStringError(
  121. std::make_error_code(std::errc::invalid_argument),
  122. "Missing CPU field at offset %" PRId64 ".", OffsetPtr);
  123. }
  124. assert(OffsetPtr > BeginOffset &&
  125. OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
  126. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
  127. // Next we read in a fixed chunk of data from the given offset.
  128. if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
  129. return createStringError(
  130. std::make_error_code(std::errc::bad_address),
  131. "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
  132. R.Size, OffsetPtr);
  133. std::vector<uint8_t> Buffer;
  134. Buffer.resize(R.Size);
  135. PreReadOffset = OffsetPtr;
  136. if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
  137. return createStringError(
  138. std::make_error_code(std::errc::invalid_argument),
  139. "Failed reading data into buffer of size %d at offset %" PRId64 ".",
  140. R.Size, OffsetPtr);
  141. assert(OffsetPtr >= PreReadOffset);
  142. if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
  143. return createStringError(
  144. std::make_error_code(std::errc::invalid_argument),
  145. "Failed reading enough bytes for the custom event payload -- read "
  146. "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
  147. OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
  148. R.Data.assign(Buffer.begin(), Buffer.end());
  149. return Error::success();
  150. }
  151. Error RecordInitializer::visit(CustomEventRecordV5 &R) {
  152. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  153. MetadataRecord::kMetadataBodySize))
  154. return createStringError(
  155. std::make_error_code(std::errc::bad_address),
  156. "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);
  157. auto BeginOffset = OffsetPtr;
  158. auto PreReadOffset = OffsetPtr;
  159. R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
  160. if (PreReadOffset == OffsetPtr)
  161. return createStringError(
  162. std::make_error_code(std::errc::invalid_argument),
  163. "Cannot read a custom event record size field offset %" PRId64 ".",
  164. OffsetPtr);
  165. if (R.Size <= 0)
  166. return createStringError(
  167. std::make_error_code(std::errc::bad_address),
  168. "Invalid size for custom event (size = %d) at offset %" PRId64 ".",
  169. R.Size, OffsetPtr);
  170. PreReadOffset = OffsetPtr;
  171. R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
  172. if (PreReadOffset == OffsetPtr)
  173. return createStringError(
  174. std::make_error_code(std::errc::invalid_argument),
  175. "Cannot read a custom event record TSC delta field at offset "
  176. "%" PRId64 ".",
  177. OffsetPtr);
  178. assert(OffsetPtr > BeginOffset &&
  179. OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
  180. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
  181. // Next we read in a fixed chunk of data from the given offset.
  182. if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
  183. return createStringError(
  184. std::make_error_code(std::errc::bad_address),
  185. "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
  186. R.Size, OffsetPtr);
  187. std::vector<uint8_t> Buffer;
  188. Buffer.resize(R.Size);
  189. PreReadOffset = OffsetPtr;
  190. if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
  191. return createStringError(
  192. std::make_error_code(std::errc::invalid_argument),
  193. "Failed reading data into buffer of size %d at offset %" PRId64 ".",
  194. R.Size, OffsetPtr);
  195. assert(OffsetPtr >= PreReadOffset);
  196. if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
  197. return createStringError(
  198. std::make_error_code(std::errc::invalid_argument),
  199. "Failed reading enough bytes for the custom event payload -- read "
  200. "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
  201. OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
  202. R.Data.assign(Buffer.begin(), Buffer.end());
  203. return Error::success();
  204. }
  205. Error RecordInitializer::visit(TypedEventRecord &R) {
  206. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  207. MetadataRecord::kMetadataBodySize))
  208. return createStringError(
  209. std::make_error_code(std::errc::bad_address),
  210. "Invalid offset for a typed event record (%" PRId64 ").", OffsetPtr);
  211. auto BeginOffset = OffsetPtr;
  212. auto PreReadOffset = OffsetPtr;
  213. R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));
  214. if (PreReadOffset == OffsetPtr)
  215. return createStringError(
  216. std::make_error_code(std::errc::invalid_argument),
  217. "Cannot read a typed event record size field offset %" PRId64 ".",
  218. OffsetPtr);
  219. if (R.Size <= 0)
  220. return createStringError(
  221. std::make_error_code(std::errc::bad_address),
  222. "Invalid size for typed event (size = %d) at offset %" PRId64 ".",
  223. R.Size, OffsetPtr);
  224. PreReadOffset = OffsetPtr;
  225. R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
  226. if (PreReadOffset == OffsetPtr)
  227. return createStringError(
  228. std::make_error_code(std::errc::invalid_argument),
  229. "Cannot read a typed event record TSC delta field at offset "
  230. "%" PRId64 ".",
  231. OffsetPtr);
  232. PreReadOffset = OffsetPtr;
  233. R.EventType = E.getU16(&OffsetPtr);
  234. if (PreReadOffset == OffsetPtr)
  235. return createStringError(
  236. std::make_error_code(std::errc::invalid_argument),
  237. "Cannot read a typed event record type field at offset %" PRId64 ".",
  238. OffsetPtr);
  239. assert(OffsetPtr > BeginOffset &&
  240. OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);
  241. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);
  242. // Next we read in a fixed chunk of data from the given offset.
  243. if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))
  244. return createStringError(
  245. std::make_error_code(std::errc::bad_address),
  246. "Cannot read %d bytes of custom event data from offset %" PRId64 ".",
  247. R.Size, OffsetPtr);
  248. std::vector<uint8_t> Buffer;
  249. Buffer.resize(R.Size);
  250. PreReadOffset = OffsetPtr;
  251. if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
  252. return createStringError(
  253. std::make_error_code(std::errc::invalid_argument),
  254. "Failed reading data into buffer of size %d at offset %" PRId64 ".",
  255. R.Size, OffsetPtr);
  256. assert(OffsetPtr >= PreReadOffset);
  257. if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
  258. return createStringError(
  259. std::make_error_code(std::errc::invalid_argument),
  260. "Failed reading enough bytes for the typed event payload -- read "
  261. "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",
  262. OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
  263. R.Data.assign(Buffer.begin(), Buffer.end());
  264. return Error::success();
  265. }
  266. Error RecordInitializer::visit(CallArgRecord &R) {
  267. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  268. MetadataRecord::kMetadataBodySize))
  269. return createStringError(
  270. std::make_error_code(std::errc::bad_address),
  271. "Invalid offset for a call argument record (%" PRId64 ").",
  272. OffsetPtr);
  273. auto PreReadOffset = OffsetPtr;
  274. R.Arg = E.getU64(&OffsetPtr);
  275. if (PreReadOffset == OffsetPtr)
  276. return createStringError(
  277. std::make_error_code(std::errc::invalid_argument),
  278. "Cannot read a call arg record at offset %" PRId64 ".", OffsetPtr);
  279. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
  280. return Error::success();
  281. }
  282. Error RecordInitializer::visit(PIDRecord &R) {
  283. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  284. MetadataRecord::kMetadataBodySize))
  285. return createStringError(
  286. std::make_error_code(std::errc::bad_address),
  287. "Invalid offset for a process ID record (%" PRId64 ").", OffsetPtr);
  288. auto PreReadOffset = OffsetPtr;
  289. R.PID = E.getSigned(&OffsetPtr, 4);
  290. if (PreReadOffset == OffsetPtr)
  291. return createStringError(
  292. std::make_error_code(std::errc::invalid_argument),
  293. "Cannot read a process ID record at offset %" PRId64 ".", OffsetPtr);
  294. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
  295. return Error::success();
  296. }
  297. Error RecordInitializer::visit(NewBufferRecord &R) {
  298. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  299. MetadataRecord::kMetadataBodySize))
  300. return createStringError(
  301. std::make_error_code(std::errc::bad_address),
  302. "Invalid offset for a new buffer record (%" PRId64 ").", OffsetPtr);
  303. auto PreReadOffset = OffsetPtr;
  304. R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));
  305. if (PreReadOffset == OffsetPtr)
  306. return createStringError(
  307. std::make_error_code(std::errc::invalid_argument),
  308. "Cannot read a new buffer record at offset %" PRId64 ".", OffsetPtr);
  309. OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);
  310. return Error::success();
  311. }
  312. Error RecordInitializer::visit(EndBufferRecord &R) {
  313. if (!E.isValidOffsetForDataOfSize(OffsetPtr,
  314. MetadataRecord::kMetadataBodySize))
  315. return createStringError(
  316. std::make_error_code(std::errc::bad_address),
  317. "Invalid offset for an end-of-buffer record (%" PRId64 ").",
  318. OffsetPtr);
  319. OffsetPtr += MetadataRecord::kMetadataBodySize;
  320. return Error::success();
  321. }
  322. Error RecordInitializer::visit(FunctionRecord &R) {
  323. // For function records, we need to retreat one byte back to read a full
  324. // unsigned 32-bit value. The first four bytes will have the following
  325. // layout:
  326. //
  327. // bit 0 : function record indicator (must be 0)
  328. // bits 1..3 : function record type
  329. // bits 4..32 : function id
  330. //
  331. if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(
  332. --OffsetPtr, FunctionRecord::kFunctionRecordSize))
  333. return createStringError(
  334. std::make_error_code(std::errc::bad_address),
  335. "Invalid offset for a function record (%" PRId64 ").", OffsetPtr);
  336. auto BeginOffset = OffsetPtr;
  337. auto PreReadOffset = BeginOffset;
  338. uint32_t Buffer = E.getU32(&OffsetPtr);
  339. if (PreReadOffset == OffsetPtr)
  340. return createStringError(
  341. std::make_error_code(std::errc::bad_address),
  342. "Cannot read function id field from offset %" PRId64 ".", OffsetPtr);
  343. // To get the function record type, we shift the buffer one to the right
  344. // (truncating the function record indicator) then take the three bits
  345. // (0b0111) to get the record type as an unsigned value.
  346. unsigned FunctionType = (Buffer >> 1) & 0x07u;
  347. switch (FunctionType) {
  348. case static_cast<unsigned>(RecordTypes::ENTER):
  349. case static_cast<unsigned>(RecordTypes::ENTER_ARG):
  350. case static_cast<unsigned>(RecordTypes::EXIT):
  351. case static_cast<unsigned>(RecordTypes::TAIL_EXIT):
  352. R.Kind = static_cast<RecordTypes>(FunctionType);
  353. break;
  354. default:
  355. return createStringError(
  356. std::make_error_code(std::errc::invalid_argument),
  357. "Unknown function record type '%d' at offset %" PRId64 ".",
  358. FunctionType, BeginOffset);
  359. }
  360. R.FuncId = Buffer >> 4;
  361. PreReadOffset = OffsetPtr;
  362. R.Delta = E.getU32(&OffsetPtr);
  363. if (OffsetPtr == PreReadOffset)
  364. return createStringError(
  365. std::make_error_code(std::errc::invalid_argument),
  366. "Failed reading TSC delta from offset %" PRId64 ".", OffsetPtr);
  367. assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));
  368. return Error::success();
  369. }
  370. } // namespace xray
  371. } // namespace llvm