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