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