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