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 PreReadOffset = OffsetPtr; 115 R.TSC = E.getU64(&OffsetPtr); 116 if (PreReadOffset == OffsetPtr) 117 return createStringError( 118 std::make_error_code(std::errc::invalid_argument), 119 "Cannot read a custom event TSC field at offset %d.", OffsetPtr); 120 121 // For version 4 onwards, of the FDR log, we want to also capture the CPU ID 122 // of the custom event. 123 if (Version >= 4) { 124 PreReadOffset = OffsetPtr; 125 R.CPU = E.getU16(&OffsetPtr); 126 if (PreReadOffset == OffsetPtr) 127 return createStringError( 128 std::make_error_code(std::errc::invalid_argument), 129 "Missing CPU field at offset %d", OffsetPtr); 130 } 131 132 assert(OffsetPtr > BeginOffset && 133 OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize); 134 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset); 135 136 // Next we read in a fixed chunk of data from the given offset. 137 if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size)) 138 return createStringError( 139 std::make_error_code(std::errc::bad_address), 140 "Cannot read %d bytes of custom event data from offset %d.", R.Size, 141 OffsetPtr); 142 143 std::vector<uint8_t> Buffer; 144 Buffer.resize(R.Size); 145 if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data()) 146 return createStringError( 147 std::make_error_code(std::errc::invalid_argument), 148 "Failed reading data into buffer of size %d at offset %d.", R.Size, 149 OffsetPtr); 150 R.Data.assign(Buffer.begin(), Buffer.end()); 151 return Error::success(); 152 } 153 154 Error RecordInitializer::visit(CallArgRecord &R) { 155 if (!E.isValidOffsetForDataOfSize(OffsetPtr, 156 MetadataRecord::kMetadataBodySize)) 157 return createStringError(std::make_error_code(std::errc::bad_address), 158 "Invalid offset for a call argument record (%d).", 159 OffsetPtr); 160 161 auto PreReadOffset = OffsetPtr; 162 R.Arg = E.getU64(&OffsetPtr); 163 if (PreReadOffset == OffsetPtr) 164 return createStringError(std::make_error_code(std::errc::invalid_argument), 165 "Cannot read a call arg record at offset %d.", 166 OffsetPtr); 167 168 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset); 169 return Error::success(); 170 } 171 172 Error RecordInitializer::visit(PIDRecord &R) { 173 if (!E.isValidOffsetForDataOfSize(OffsetPtr, 174 MetadataRecord::kMetadataBodySize)) 175 return createStringError(std::make_error_code(std::errc::bad_address), 176 "Invalid offset for a process ID record (%d).", 177 OffsetPtr); 178 179 auto PreReadOffset = OffsetPtr; 180 R.PID = E.getSigned(&OffsetPtr, 4); 181 if (PreReadOffset == OffsetPtr) 182 return createStringError(std::make_error_code(std::errc::invalid_argument), 183 "Cannot read a process ID record at offset %d.", 184 OffsetPtr); 185 186 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset); 187 return Error::success(); 188 } 189 190 Error RecordInitializer::visit(NewBufferRecord &R) { 191 if (!E.isValidOffsetForDataOfSize(OffsetPtr, 192 MetadataRecord::kMetadataBodySize)) 193 return createStringError(std::make_error_code(std::errc::bad_address), 194 "Invalid offset for a new buffer record (%d).", 195 OffsetPtr); 196 197 auto PreReadOffset = OffsetPtr; 198 R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t)); 199 if (PreReadOffset == OffsetPtr) 200 return createStringError(std::make_error_code(std::errc::invalid_argument), 201 "Cannot read a new buffer record at offset %d.", 202 OffsetPtr); 203 204 OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset); 205 return Error::success(); 206 } 207 208 Error RecordInitializer::visit(EndBufferRecord &R) { 209 if (!E.isValidOffsetForDataOfSize(OffsetPtr, 210 MetadataRecord::kMetadataBodySize)) 211 return createStringError(std::make_error_code(std::errc::bad_address), 212 "Invalid offset for an end-of-buffer record (%d).", 213 OffsetPtr); 214 215 OffsetPtr += MetadataRecord::kMetadataBodySize; 216 return Error::success(); 217 } 218 219 Error RecordInitializer::visit(FunctionRecord &R) { 220 // For function records, we need to retreat one byte back to read a full 221 // unsigned 32-bit value. The first four bytes will have the following 222 // layout: 223 // 224 // bit 0 : function record indicator (must be 0) 225 // bits 1..3 : function record type 226 // bits 4..32 : function id 227 // 228 if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize( 229 --OffsetPtr, FunctionRecord::kFunctionRecordSize)) 230 return createStringError(std::make_error_code(std::errc::bad_address), 231 "Invalid offset for a function record (%d).", 232 OffsetPtr); 233 234 auto BeginOffset = OffsetPtr; 235 auto PreReadOffset = BeginOffset; 236 uint32_t Buffer = E.getU32(&OffsetPtr); 237 if (PreReadOffset == OffsetPtr) 238 return createStringError(std::make_error_code(std::errc::bad_address), 239 "Cannot read function id field from offset %d.", 240 OffsetPtr); 241 unsigned FunctionType = (Buffer >> 1) & 0x07; 242 switch (FunctionType) { 243 case static_cast<unsigned>(RecordTypes::ENTER): 244 case static_cast<unsigned>(RecordTypes::ENTER_ARG): 245 case static_cast<unsigned>(RecordTypes::EXIT): 246 case static_cast<unsigned>(RecordTypes::TAIL_EXIT): 247 R.Kind = static_cast<RecordTypes>(FunctionType); 248 break; 249 default: 250 return createStringError(std::make_error_code(std::errc::invalid_argument), 251 "Unknown function record type '%d' at offset %d.", 252 FunctionType, BeginOffset); 253 } 254 255 R.FuncId = Buffer >> 4; 256 PreReadOffset = OffsetPtr; 257 R.Delta = E.getU32(&OffsetPtr); 258 if (OffsetPtr == PreReadOffset) 259 return createStringError(std::make_error_code(std::errc::invalid_argument), 260 "Failed reading TSC delta from offset %d.", 261 OffsetPtr); 262 assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset)); 263 return Error::success(); 264 } 265 266 } // namespace xray 267 } // namespace llvm 268