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 10 namespace llvm { 11 namespace xray { 12 13 Error 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 30 Error 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 59 Error 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 84 Error 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 102 Error 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 ID 133 // 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 175 Error 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 239 Error 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 311 Error 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 330 Error 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 348 Error 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 366 Error 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 378 Error RecordInitializer::visit(FunctionRecord &R) { 379 // For function records, we need to retreat one byte back to read a full 380 // unsigned 32-bit value. The first four bytes will have the following 381 // layout: 382 // 383 // bit 0 : function record indicator (must be 0) 384 // bits 1..3 : function record type 385 // bits 4..32 : function id 386 // 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 right 402 // (truncating the function record indicator) then take the three bits 403 // (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 430 } // namespace xray 431 } // namespace llvm 432