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