1d6c18657SDean Michael Berris //===- Trace.cpp - XRay Trace Loading implementation. ---------------------===// 2d6c18657SDean Michael Berris // 3d6c18657SDean Michael Berris // The LLVM Compiler Infrastructure 4d6c18657SDean Michael Berris // 5d6c18657SDean Michael Berris // This file is distributed under the University of Illinois Open Source 6d6c18657SDean Michael Berris // License. See LICENSE.TXT for details. 7d6c18657SDean Michael Berris // 8d6c18657SDean Michael Berris //===----------------------------------------------------------------------===// 9d6c18657SDean Michael Berris // 10d6c18657SDean Michael Berris // XRay log reader implementation. 11d6c18657SDean Michael Berris // 12d6c18657SDean Michael Berris //===----------------------------------------------------------------------===// 13d6c18657SDean Michael Berris #include "llvm/XRay/Trace.h" 14d6c18657SDean Michael Berris #include "llvm/ADT/STLExtras.h" 15d6c18657SDean Michael Berris #include "llvm/Support/DataExtractor.h" 16d6c18657SDean Michael Berris #include "llvm/Support/Error.h" 17d6c18657SDean Michael Berris #include "llvm/Support/FileSystem.h" 18d6c18657SDean Michael Berris #include "llvm/XRay/YAMLXRayRecord.h" 19d6c18657SDean Michael Berris 20d6c18657SDean Michael Berris using namespace llvm; 21d6c18657SDean Michael Berris using namespace llvm::xray; 22d6c18657SDean Michael Berris using llvm::yaml::Input; 23d6c18657SDean Michael Berris 2449a49fe8SBenjamin Kramer namespace { 25d6c18657SDean Michael Berris using XRayRecordStorage = 26d6c18657SDean Michael Berris std::aligned_storage<sizeof(XRayRecord), alignof(XRayRecord)>::type; 27d6c18657SDean Michael Berris 28*a9d477a6SDean Michael Berris // This is the number of bytes in the "body" of a MetadataRecord in FDR Mode. 29*a9d477a6SDean Michael Berris // This already excludes the first byte, which indicates the type of metadata 30*a9d477a6SDean Michael Berris // record it is. 31*a9d477a6SDean Michael Berris constexpr auto kFDRMetadataBodySize = 15; 32*a9d477a6SDean Michael Berris 334f83c4d1SDean Michael Berris // Populates the FileHeader reference by reading the first 32 bytes of the file. 34*a9d477a6SDean Michael Berris Error readBinaryFormatHeader(DataExtractor &HeaderExtractor, 35*a9d477a6SDean Michael Berris uint32_t &OffsetPtr, XRayFileHeader &FileHeader) { 36d6c18657SDean Michael Berris // FIXME: Maybe deduce whether the data is little or big-endian using some 37d6c18657SDean Michael Berris // magic bytes in the beginning of the file? 38d6c18657SDean Michael Berris 39d6c18657SDean Michael Berris // First 32 bytes of the file will always be the header. We assume a certain 40d6c18657SDean Michael Berris // format here: 41d6c18657SDean Michael Berris // 42d6c18657SDean Michael Berris // (2) uint16 : version 43d6c18657SDean Michael Berris // (2) uint16 : type 44d6c18657SDean Michael Berris // (4) uint32 : bitfield 45d6c18657SDean Michael Berris // (8) uint64 : cycle frequency 46d6c18657SDean Michael Berris // (16) - : padding 47d6c18657SDean Michael Berris 48*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 49d6c18657SDean Michael Berris FileHeader.Version = HeaderExtractor.getU16(&OffsetPtr); 50*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 51*a9d477a6SDean Michael Berris return createStringError( 52*a9d477a6SDean Michael Berris std::make_error_code(std::errc::invalid_argument), 53*a9d477a6SDean Michael Berris "Failed reading version from file header at offset %d.", OffsetPtr); 54*a9d477a6SDean Michael Berris 55*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 56d6c18657SDean Michael Berris FileHeader.Type = HeaderExtractor.getU16(&OffsetPtr); 57*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 58*a9d477a6SDean Michael Berris return createStringError( 59*a9d477a6SDean Michael Berris std::make_error_code(std::errc::invalid_argument), 60*a9d477a6SDean Michael Berris "Failed reading file type from file header at offset %d.", OffsetPtr); 61*a9d477a6SDean Michael Berris 62*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 63d6c18657SDean Michael Berris uint32_t Bitfield = HeaderExtractor.getU32(&OffsetPtr); 64*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 65*a9d477a6SDean Michael Berris return createStringError( 66*a9d477a6SDean Michael Berris std::make_error_code(std::errc::invalid_argument), 67*a9d477a6SDean Michael Berris "Failed reading flag bits from file header at offset %d.", OffsetPtr); 68*a9d477a6SDean Michael Berris 69d6c18657SDean Michael Berris FileHeader.ConstantTSC = Bitfield & 1uL; 70d6c18657SDean Michael Berris FileHeader.NonstopTSC = Bitfield & 1uL << 1; 71*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 72d6c18657SDean Michael Berris FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr); 73*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 74*a9d477a6SDean Michael Berris return createStringError( 75*a9d477a6SDean Michael Berris std::make_error_code(std::errc::invalid_argument), 76*a9d477a6SDean Michael Berris "Failed reading cycle frequency from file header at offset %d.", 77*a9d477a6SDean Michael Berris OffsetPtr); 78*a9d477a6SDean Michael Berris 79*a9d477a6SDean Michael Berris std::memcpy(&FileHeader.FreeFormData, 80*a9d477a6SDean Michael Berris HeaderExtractor.getData().bytes_begin() + OffsetPtr, 16); 81*a9d477a6SDean Michael Berris 82*a9d477a6SDean Michael Berris // Manually advance the offset pointer 16 bytes, after getting a raw memcpy 83*a9d477a6SDean Michael Berris // from the underlying data. 84*a9d477a6SDean Michael Berris OffsetPtr += 16; 8510141261SDean Michael Berris if (FileHeader.Version != 1 && FileHeader.Version != 2 && 8610141261SDean Michael Berris FileHeader.Version != 3) 87*a9d477a6SDean Michael Berris return createStringError(std::make_error_code(std::errc::invalid_argument), 88*a9d477a6SDean Michael Berris "Unsupported XRay file version: %d at offset %d", 89*a9d477a6SDean Michael Berris FileHeader.Version, OffsetPtr); 904f83c4d1SDean Michael Berris return Error::success(); 914f83c4d1SDean Michael Berris } 924f83c4d1SDean Michael Berris 934f83c4d1SDean Michael Berris Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, 944f83c4d1SDean Michael Berris std::vector<XRayRecord> &Records) { 954f83c4d1SDean Michael Berris if (Data.size() < 32) 964f83c4d1SDean Michael Berris return make_error<StringError>( 974f83c4d1SDean Michael Berris "Not enough bytes for an XRay log.", 984f83c4d1SDean Michael Berris std::make_error_code(std::errc::invalid_argument)); 994f83c4d1SDean Michael Berris 1004f83c4d1SDean Michael Berris if (Data.size() - 32 == 0 || Data.size() % 32 != 0) 1014f83c4d1SDean Michael Berris return make_error<StringError>( 1024f83c4d1SDean Michael Berris "Invalid-sized XRay data.", 1034f83c4d1SDean Michael Berris std::make_error_code(std::errc::invalid_argument)); 1044f83c4d1SDean Michael Berris 105*a9d477a6SDean Michael Berris DataExtractor Reader(Data, true, 8); 106*a9d477a6SDean Michael Berris uint32_t OffsetPtr = 0; 107*a9d477a6SDean Michael Berris if (auto E = readBinaryFormatHeader(Reader, OffsetPtr, FileHeader)) 1084f83c4d1SDean Michael Berris return E; 109d6c18657SDean Michael Berris 110d6c18657SDean Michael Berris // Each record after the header will be 32 bytes, in the following format: 111d6c18657SDean Michael Berris // 112d6c18657SDean Michael Berris // (2) uint16 : record type 113d6c18657SDean Michael Berris // (1) uint8 : cpu id 114d6c18657SDean Michael Berris // (1) uint8 : type 115d6c18657SDean Michael Berris // (4) sint32 : function id 116d6c18657SDean Michael Berris // (8) uint64 : tsc 117d6c18657SDean Michael Berris // (4) uint32 : thread id 11810141261SDean Michael Berris // (4) uint32 : process id 11910141261SDean Michael Berris // (8) - : padding 120*a9d477a6SDean Michael Berris while (Reader.isValidOffset(OffsetPtr)) { 121*a9d477a6SDean Michael Berris if (!Reader.isValidOffsetForDataOfSize(OffsetPtr, 32)) 122*a9d477a6SDean Michael Berris return createStringError( 123*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 124*a9d477a6SDean Michael Berris "Not enough bytes to read a full record at offset %d.", OffsetPtr); 125*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 126*a9d477a6SDean Michael Berris auto RecordType = Reader.getU16(&OffsetPtr); 127*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 128*a9d477a6SDean Michael Berris return createStringError( 129*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 130*a9d477a6SDean Michael Berris "Failed reading record type at offset %d.", OffsetPtr); 131*a9d477a6SDean Michael Berris 132*a9d477a6SDean Michael Berris switch (RecordType) { 1330a465d7aSDean Michael Berris case 0: { // Normal records. 134d6c18657SDean Michael Berris Records.emplace_back(); 135d6c18657SDean Michael Berris auto &Record = Records.back(); 1360a465d7aSDean Michael Berris Record.RecordType = RecordType; 137*a9d477a6SDean Michael Berris 138*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 139*a9d477a6SDean Michael Berris Record.CPU = Reader.getU8(&OffsetPtr); 140*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 141*a9d477a6SDean Michael Berris return createStringError( 142*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 143*a9d477a6SDean Michael Berris "Failed reading CPU field at offset %d.", OffsetPtr); 144*a9d477a6SDean Michael Berris 145*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 146*a9d477a6SDean Michael Berris auto Type = Reader.getU8(&OffsetPtr); 147*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 148*a9d477a6SDean Michael Berris return createStringError( 149*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 150*a9d477a6SDean Michael Berris "Failed reading record type field at offset %d.", OffsetPtr); 151*a9d477a6SDean Michael Berris 152d6c18657SDean Michael Berris switch (Type) { 153d6c18657SDean Michael Berris case 0: 154d6c18657SDean Michael Berris Record.Type = RecordTypes::ENTER; 155d6c18657SDean Michael Berris break; 156d6c18657SDean Michael Berris case 1: 157d6c18657SDean Michael Berris Record.Type = RecordTypes::EXIT; 158d6c18657SDean Michael Berris break; 1590f84a7d3SDean Michael Berris case 2: 1600f84a7d3SDean Michael Berris Record.Type = RecordTypes::TAIL_EXIT; 1610f84a7d3SDean Michael Berris break; 1620a465d7aSDean Michael Berris case 3: 1630a465d7aSDean Michael Berris Record.Type = RecordTypes::ENTER_ARG; 1640a465d7aSDean Michael Berris break; 165d6c18657SDean Michael Berris default: 166*a9d477a6SDean Michael Berris return createStringError( 167*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 168*a9d477a6SDean Michael Berris "Unknown record type '%d' at offset %d.", Type, OffsetPtr); 169d6c18657SDean Michael Berris } 170*a9d477a6SDean Michael Berris 171*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 172*a9d477a6SDean Michael Berris Record.FuncId = Reader.getSigned(&OffsetPtr, sizeof(int32_t)); 173*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 174*a9d477a6SDean Michael Berris return createStringError( 175*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 176*a9d477a6SDean Michael Berris "Failed reading function id field at offset %d.", OffsetPtr); 177*a9d477a6SDean Michael Berris 178*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 179*a9d477a6SDean Michael Berris Record.TSC = Reader.getU64(&OffsetPtr); 180*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 181*a9d477a6SDean Michael Berris return createStringError( 182*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 183*a9d477a6SDean Michael Berris "Failed reading TSC field at offset %d.", OffsetPtr); 184*a9d477a6SDean Michael Berris 185*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 186*a9d477a6SDean Michael Berris Record.TId = Reader.getU32(&OffsetPtr); 187*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 188*a9d477a6SDean Michael Berris return createStringError( 189*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 190*a9d477a6SDean Michael Berris "Failed reading thread id field at offset %d.", OffsetPtr); 191*a9d477a6SDean Michael Berris 192*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 193*a9d477a6SDean Michael Berris Record.PId = Reader.getU32(&OffsetPtr); 194*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 195*a9d477a6SDean Michael Berris return createStringError( 196*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 197*a9d477a6SDean Michael Berris "Failed reading process id at offset %d.", OffsetPtr); 198*a9d477a6SDean Michael Berris 1990a465d7aSDean Michael Berris break; 2000a465d7aSDean Michael Berris } 2010a465d7aSDean Michael Berris case 1: { // Arg payload record. 2020a465d7aSDean Michael Berris auto &Record = Records.back(); 203*a9d477a6SDean Michael Berris 204*a9d477a6SDean Michael Berris // We skip the next two bytes of the record, because we don't need the 205*a9d477a6SDean Michael Berris // type and the CPU record for arg payloads. 2060a465d7aSDean Michael Berris OffsetPtr += 2; 207*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 208*a9d477a6SDean Michael Berris int32_t FuncId = Reader.getSigned(&OffsetPtr, sizeof(int32_t)); 209*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 210*a9d477a6SDean Michael Berris return createStringError( 211*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 212*a9d477a6SDean Michael Berris "Failed reading function id field at offset %d.", OffsetPtr); 213*a9d477a6SDean Michael Berris 214*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 215*a9d477a6SDean Michael Berris auto TId = Reader.getU32(&OffsetPtr); 216*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 217*a9d477a6SDean Michael Berris return createStringError( 218*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 219*a9d477a6SDean Michael Berris "Failed reading thread id field at offset %d.", OffsetPtr); 220*a9d477a6SDean Michael Berris 221*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 222*a9d477a6SDean Michael Berris auto PId = Reader.getU32(&OffsetPtr); 223*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 224*a9d477a6SDean Michael Berris return createStringError( 225*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 226*a9d477a6SDean Michael Berris "Failed reading process id field at offset %d.", OffsetPtr); 22710141261SDean Michael Berris 22810141261SDean Michael Berris // Make a check for versions above 3 for the Pid field 22910141261SDean Michael Berris if (Record.FuncId != FuncId || Record.TId != TId || 23010141261SDean Michael Berris (FileHeader.Version >= 3 ? Record.PId != PId : false)) 231*a9d477a6SDean Michael Berris return createStringError( 232*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 233*a9d477a6SDean Michael Berris "Corrupted log, found arg payload following non-matching " 234*a9d477a6SDean Michael Berris "function+thread record. Record for function %d != %d at offset " 235*a9d477a6SDean Michael Berris "%d", 236*a9d477a6SDean Michael Berris Record.FuncId, FuncId, OffsetPtr); 23710141261SDean Michael Berris 238*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 239*a9d477a6SDean Michael Berris auto Arg = Reader.getU64(&OffsetPtr); 240*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 241*a9d477a6SDean Michael Berris return createStringError( 242*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 243*a9d477a6SDean Michael Berris "Failed reading argument payload at offset %d.", OffsetPtr); 244*a9d477a6SDean Michael Berris 2450a465d7aSDean Michael Berris Record.CallArgs.push_back(Arg); 2460a465d7aSDean Michael Berris break; 2470a465d7aSDean Michael Berris } 2480a465d7aSDean Michael Berris default: 249*a9d477a6SDean Michael Berris return createStringError( 250*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 251*a9d477a6SDean Michael Berris "Unknown record type '%d' at offset %d.", RecordType, OffsetPtr); 2520a465d7aSDean Michael Berris } 253*a9d477a6SDean Michael Berris // Advance the offset pointer enough bytes to align to 32-byte records for 254*a9d477a6SDean Michael Berris // basic mode logs. 255*a9d477a6SDean Michael Berris OffsetPtr += 8; 256d6c18657SDean Michael Berris } 257d6c18657SDean Michael Berris return Error::success(); 258d6c18657SDean Michael Berris } 259d6c18657SDean Michael Berris 2604f83c4d1SDean Michael Berris /// When reading from a Flight Data Recorder mode log, metadata records are 2614f83c4d1SDean Michael Berris /// sparse compared to packed function records, so we must maintain state as we 2624f83c4d1SDean Michael Berris /// read through the sequence of entries. This allows the reader to denormalize 2634f83c4d1SDean Michael Berris /// the CPUId and Thread Id onto each Function Record and transform delta 2644f83c4d1SDean Michael Berris /// encoded TSC values into absolute encodings on each record. 2654f83c4d1SDean Michael Berris struct FDRState { 2664f83c4d1SDean Michael Berris uint16_t CPUId; 2674f83c4d1SDean Michael Berris uint16_t ThreadId; 26810141261SDean Michael Berris int32_t ProcessId; 2694f83c4d1SDean Michael Berris uint64_t BaseTSC; 270a7bbe448SDean Michael Berris 2714f83c4d1SDean Michael Berris /// Encode some of the state transitions for the FDR log reader as explicit 2724f83c4d1SDean Michael Berris /// checks. These are expectations for the next Record in the stream. 2734f83c4d1SDean Michael Berris enum class Token { 2744f83c4d1SDean Michael Berris NEW_BUFFER_RECORD_OR_EOF, 2754f83c4d1SDean Michael Berris WALLCLOCK_RECORD, 2764f83c4d1SDean Michael Berris NEW_CPU_ID_RECORD, 27760c24878SDean Michael Berris FUNCTION_SEQUENCE, 27860c24878SDean Michael Berris SCAN_TO_END_OF_THREAD_BUF, 279a7bbe448SDean Michael Berris CUSTOM_EVENT_DATA, 28010c873f1SMartin Pelikan CALL_ARGUMENT, 2816ec72625SDean Michael Berris BUFFER_EXTENTS, 28210141261SDean Michael Berris PID_RECORD, 2834f83c4d1SDean Michael Berris }; 2844f83c4d1SDean Michael Berris Token Expects; 285a7bbe448SDean Michael Berris 28660c24878SDean Michael Berris // Each threads buffer may have trailing garbage to scan over, so we track our 28760c24878SDean Michael Berris // progress. 28860c24878SDean Michael Berris uint64_t CurrentBufferSize; 28960c24878SDean Michael Berris uint64_t CurrentBufferConsumed; 2904f83c4d1SDean Michael Berris }; 291d6c18657SDean Michael Berris 29249a49fe8SBenjamin Kramer const char *fdrStateToTwine(const FDRState::Token &state) { 29360c24878SDean Michael Berris switch (state) { 29460c24878SDean Michael Berris case FDRState::Token::NEW_BUFFER_RECORD_OR_EOF: 29560c24878SDean Michael Berris return "NEW_BUFFER_RECORD_OR_EOF"; 29660c24878SDean Michael Berris case FDRState::Token::WALLCLOCK_RECORD: 29760c24878SDean Michael Berris return "WALLCLOCK_RECORD"; 29860c24878SDean Michael Berris case FDRState::Token::NEW_CPU_ID_RECORD: 29960c24878SDean Michael Berris return "NEW_CPU_ID_RECORD"; 30060c24878SDean Michael Berris case FDRState::Token::FUNCTION_SEQUENCE: 30160c24878SDean Michael Berris return "FUNCTION_SEQUENCE"; 30260c24878SDean Michael Berris case FDRState::Token::SCAN_TO_END_OF_THREAD_BUF: 30360c24878SDean Michael Berris return "SCAN_TO_END_OF_THREAD_BUF"; 304a7bbe448SDean Michael Berris case FDRState::Token::CUSTOM_EVENT_DATA: 305a7bbe448SDean Michael Berris return "CUSTOM_EVENT_DATA"; 30610c873f1SMartin Pelikan case FDRState::Token::CALL_ARGUMENT: 30710c873f1SMartin Pelikan return "CALL_ARGUMENT"; 3086ec72625SDean Michael Berris case FDRState::Token::BUFFER_EXTENTS: 3096ec72625SDean Michael Berris return "BUFFER_EXTENTS"; 31010141261SDean Michael Berris case FDRState::Token::PID_RECORD: 31110141261SDean Michael Berris return "PID_RECORD"; 31260c24878SDean Michael Berris } 31360c24878SDean Michael Berris return "UNKNOWN"; 31460c24878SDean Michael Berris } 31560c24878SDean Michael Berris 3164f83c4d1SDean Michael Berris /// State transition when a NewBufferRecord is encountered. 317*a9d477a6SDean Michael Berris Error processFDRNewBufferRecord(FDRState &State, DataExtractor &RecordExtractor, 318*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 31960c24878SDean Michael Berris if (State.Expects != FDRState::Token::NEW_BUFFER_RECORD_OR_EOF) 320*a9d477a6SDean Michael Berris return createStringError( 321*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 322*a9d477a6SDean Michael Berris "Malformed log: Read New Buffer record kind out of sequence; expected: " 323*a9d477a6SDean Michael Berris "%s at offset %d.", 324*a9d477a6SDean Michael Berris fdrStateToTwine(State.Expects), OffsetPtr); 325*a9d477a6SDean Michael Berris 326*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 3274f83c4d1SDean Michael Berris State.ThreadId = RecordExtractor.getU16(&OffsetPtr); 328*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 329*a9d477a6SDean Michael Berris return createStringError( 330*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 331*a9d477a6SDean Michael Berris "Failed reading the thread id at offset %d.", OffsetPtr); 3324f83c4d1SDean Michael Berris State.Expects = FDRState::Token::WALLCLOCK_RECORD; 333*a9d477a6SDean Michael Berris 334*a9d477a6SDean Michael Berris // Advance the offset pointer by enough bytes representing the remaining 335*a9d477a6SDean Michael Berris // padding in a metadata record. 336*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - 2; 337*a9d477a6SDean Michael Berris assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize); 3384f83c4d1SDean Michael Berris return Error::success(); 3394f83c4d1SDean Michael Berris } 3404f83c4d1SDean Michael Berris 3414f83c4d1SDean Michael Berris /// State transition when an EndOfBufferRecord is encountered. 342*a9d477a6SDean Michael Berris Error processFDREndOfBufferRecord(FDRState &State, uint32_t &OffsetPtr) { 34360c24878SDean Michael Berris if (State.Expects == FDRState::Token::NEW_BUFFER_RECORD_OR_EOF) 344*a9d477a6SDean Michael Berris return createStringError( 345*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 346*a9d477a6SDean Michael Berris "Malformed log: Received EOB message without current buffer; expected: " 347*a9d477a6SDean Michael Berris "%s at offset %d.", 348*a9d477a6SDean Michael Berris fdrStateToTwine(State.Expects), OffsetPtr); 349*a9d477a6SDean Michael Berris 35060c24878SDean Michael Berris State.Expects = FDRState::Token::SCAN_TO_END_OF_THREAD_BUF; 351*a9d477a6SDean Michael Berris 352*a9d477a6SDean Michael Berris // Advance the offset pointer by enough bytes representing the remaining 353*a9d477a6SDean Michael Berris // padding in a metadata record. 354*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize; 3554f83c4d1SDean Michael Berris return Error::success(); 3564f83c4d1SDean Michael Berris } 3574f83c4d1SDean Michael Berris 3584f83c4d1SDean Michael Berris /// State transition when a NewCPUIdRecord is encountered. 359*a9d477a6SDean Michael Berris Error processFDRNewCPUIdRecord(FDRState &State, DataExtractor &RecordExtractor, 360*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 3614f83c4d1SDean Michael Berris if (State.Expects != FDRState::Token::FUNCTION_SEQUENCE && 36260c24878SDean Michael Berris State.Expects != FDRState::Token::NEW_CPU_ID_RECORD) 3634f83c4d1SDean Michael Berris return make_error<StringError>( 3646ec72625SDean Michael Berris Twine("Malformed log. Read NewCPUId record kind out of sequence; " 3656ec72625SDean Michael Berris "expected: ") + 3666ec72625SDean Michael Berris fdrStateToTwine(State.Expects), 3674f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 368*a9d477a6SDean Michael Berris auto BeginOffset = OffsetPtr; 369*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 3704f83c4d1SDean Michael Berris State.CPUId = RecordExtractor.getU16(&OffsetPtr); 371*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 372*a9d477a6SDean Michael Berris return createStringError( 373*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 374*a9d477a6SDean Michael Berris "Failed reading the CPU field at offset %d.", OffsetPtr); 375*a9d477a6SDean Michael Berris 376*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 3774f83c4d1SDean Michael Berris State.BaseTSC = RecordExtractor.getU64(&OffsetPtr); 378*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 379*a9d477a6SDean Michael Berris return createStringError( 380*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 381*a9d477a6SDean Michael Berris "Failed reading the base TSC field at offset %d.", OffsetPtr); 382*a9d477a6SDean Michael Berris 3834f83c4d1SDean Michael Berris State.Expects = FDRState::Token::FUNCTION_SEQUENCE; 384*a9d477a6SDean Michael Berris 385*a9d477a6SDean Michael Berris // Advance the offset pointer by a few bytes, to account for the padding in 386*a9d477a6SDean Michael Berris // CPU ID metadata records that we've already advanced through. 387*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - (OffsetPtr - BeginOffset); 388*a9d477a6SDean Michael Berris assert(OffsetPtr - BeginOffset == kFDRMetadataBodySize); 3894f83c4d1SDean Michael Berris return Error::success(); 3904f83c4d1SDean Michael Berris } 3914f83c4d1SDean Michael Berris 3924f83c4d1SDean Michael Berris /// State transition when a TSCWrapRecord (overflow detection) is encountered. 393*a9d477a6SDean Michael Berris Error processFDRTSCWrapRecord(FDRState &State, DataExtractor &RecordExtractor, 394*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 39560c24878SDean Michael Berris if (State.Expects != FDRState::Token::FUNCTION_SEQUENCE) 3964f83c4d1SDean Michael Berris return make_error<StringError>( 3976ec72625SDean Michael Berris Twine("Malformed log. Read TSCWrap record kind out of sequence; " 3986ec72625SDean Michael Berris "expecting: ") + 3996ec72625SDean Michael Berris fdrStateToTwine(State.Expects), 4004f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 401*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 4024f83c4d1SDean Michael Berris State.BaseTSC = RecordExtractor.getU64(&OffsetPtr); 403*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 404*a9d477a6SDean Michael Berris return createStringError( 405*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 406*a9d477a6SDean Michael Berris "Failed reading the base TSC field at offset %d.", OffsetPtr); 407*a9d477a6SDean Michael Berris 408*a9d477a6SDean Michael Berris // Advance the offset pointer by a few more bytes, accounting for the padding 409*a9d477a6SDean Michael Berris // in the metadata record after reading the base TSC. 410*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - 8; 411*a9d477a6SDean Michael Berris assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize); 4124f83c4d1SDean Michael Berris return Error::success(); 4134f83c4d1SDean Michael Berris } 4144f83c4d1SDean Michael Berris 4154f83c4d1SDean Michael Berris /// State transition when a WallTimeMarkerRecord is encountered. 416*a9d477a6SDean Michael Berris Error processFDRWallTimeRecord(FDRState &State, DataExtractor &RecordExtractor, 417*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 41860c24878SDean Michael Berris if (State.Expects != FDRState::Token::WALLCLOCK_RECORD) 4194f83c4d1SDean Michael Berris return make_error<StringError>( 4206ec72625SDean Michael Berris Twine("Malformed log. Read Wallclock record kind out of sequence; " 4216ec72625SDean Michael Berris "expecting: ") + 4226ec72625SDean Michael Berris fdrStateToTwine(State.Expects), 4234f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 4246ec72625SDean Michael Berris 425*a9d477a6SDean Michael Berris // Read in the data from the walltime record. 426*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 427*a9d477a6SDean Michael Berris auto WallTime = RecordExtractor.getU64(&OffsetPtr); 428*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 429*a9d477a6SDean Michael Berris return createStringError( 430*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 431*a9d477a6SDean Michael Berris "Failed reading the walltime record at offset %d.", OffsetPtr); 432*a9d477a6SDean Michael Berris 4336ec72625SDean Michael Berris // TODO: Someday, reconcile the TSC ticks to wall clock time for presentation 4346ec72625SDean Michael Berris // purposes. For now, we're ignoring these records. 435*a9d477a6SDean Michael Berris (void)WallTime; 4364f83c4d1SDean Michael Berris State.Expects = FDRState::Token::NEW_CPU_ID_RECORD; 437*a9d477a6SDean Michael Berris 438*a9d477a6SDean Michael Berris // Advance the offset pointer by a few more bytes, accounting for the padding 439*a9d477a6SDean Michael Berris // in the metadata record after reading in the walltime data. 440*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - 8; 441*a9d477a6SDean Michael Berris assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize); 4424f83c4d1SDean Michael Berris return Error::success(); 4434f83c4d1SDean Michael Berris } 4444f83c4d1SDean Michael Berris 44510141261SDean Michael Berris /// State transition when a PidRecord is encountered. 446*a9d477a6SDean Michael Berris Error processFDRPidRecord(FDRState &State, DataExtractor &RecordExtractor, 447*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 44810141261SDean Michael Berris if (State.Expects != FDRState::Token::PID_RECORD) 44910141261SDean Michael Berris return make_error<StringError>( 45010141261SDean Michael Berris Twine("Malformed log. Read Pid record kind out of sequence; " 45110141261SDean Michael Berris "expected: ") + 45210141261SDean Michael Berris fdrStateToTwine(State.Expects), 45310141261SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 454*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 45510141261SDean Michael Berris State.ProcessId = RecordExtractor.getU32(&OffsetPtr); 456*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 457*a9d477a6SDean Michael Berris return createStringError( 458*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 459*a9d477a6SDean Michael Berris "Failed reading the process ID at offset %d.", OffsetPtr); 46010141261SDean Michael Berris State.Expects = FDRState::Token::NEW_CPU_ID_RECORD; 461*a9d477a6SDean Michael Berris 462*a9d477a6SDean Michael Berris // Advance the offset pointer by a few more bytes, accounting for the padding 463*a9d477a6SDean Michael Berris // in the metadata record after reading in the PID. 464*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - 4; 465*a9d477a6SDean Michael Berris assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize); 46610141261SDean Michael Berris return Error::success(); 46710141261SDean Michael Berris } 46810141261SDean Michael Berris 469a7bbe448SDean Michael Berris /// State transition when a CustomEventMarker is encountered. 470*a9d477a6SDean Michael Berris Error processCustomEventMarker(FDRState &State, DataExtractor &RecordExtractor, 471*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 472a7bbe448SDean Michael Berris // We can encounter a CustomEventMarker anywhere in the log, so we can handle 4733d0bc9efSKeith Wyss // it regardless of the expectation. However, we do set the expectation to 4743d0bc9efSKeith Wyss // read a set number of fixed bytes, as described in the metadata. 475*a9d477a6SDean Michael Berris auto BeginOffset = OffsetPtr; 476*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 477a7bbe448SDean Michael Berris uint32_t DataSize = RecordExtractor.getU32(&OffsetPtr); 478*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 479*a9d477a6SDean Michael Berris return createStringError( 480*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 481*a9d477a6SDean Michael Berris "Failed reading a custom event marker at offset %d.", OffsetPtr); 482*a9d477a6SDean Michael Berris 483*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 484a7bbe448SDean Michael Berris uint64_t TSC = RecordExtractor.getU64(&OffsetPtr); 485*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 486*a9d477a6SDean Michael Berris return createStringError( 487*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 488*a9d477a6SDean Michael Berris "Failed reading the TSC at offset %d.", OffsetPtr); 489a7bbe448SDean Michael Berris 4900a465d7aSDean Michael Berris // FIXME: Actually represent the record through the API. For now we only 4910a465d7aSDean Michael Berris // skip through the data. 492a7bbe448SDean Michael Berris (void)TSC; 493*a9d477a6SDean Michael Berris // Advance the offset ptr by the size of the data associated with the custom 494*a9d477a6SDean Michael Berris // event, as well as the padding associated with the remainder of the metadata 495*a9d477a6SDean Michael Berris // record. 496*a9d477a6SDean Michael Berris OffsetPtr += (kFDRMetadataBodySize - (OffsetPtr - BeginOffset)) + DataSize; 497*a9d477a6SDean Michael Berris if (!RecordExtractor.isValidOffset(OffsetPtr)) 498*a9d477a6SDean Michael Berris return createStringError( 499*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 500*a9d477a6SDean Michael Berris "Reading custom event data moves past addressable trace data (starting " 501*a9d477a6SDean Michael Berris "at offset %d, advancing to offset %d).", 502*a9d477a6SDean Michael Berris BeginOffset, OffsetPtr); 503a7bbe448SDean Michael Berris return Error::success(); 504a7bbe448SDean Michael Berris } 505a7bbe448SDean Michael Berris 5066ec72625SDean Michael Berris /// State transition when an BufferExtents record is encountered. 507*a9d477a6SDean Michael Berris Error processBufferExtents(FDRState &State, DataExtractor &RecordExtractor, 508*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 5096ec72625SDean Michael Berris if (State.Expects != FDRState::Token::BUFFER_EXTENTS) 5106ec72625SDean Michael Berris return make_error<StringError>( 5116ec72625SDean Michael Berris Twine("Malformed log. Buffer Extents unexpected; expected: ") + 5126ec72625SDean Michael Berris fdrStateToTwine(State.Expects), 5136ec72625SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 514*a9d477a6SDean Michael Berris 515*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 5166ec72625SDean Michael Berris State.CurrentBufferSize = RecordExtractor.getU64(&OffsetPtr); 517*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 518*a9d477a6SDean Michael Berris return createStringError( 519*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 520*a9d477a6SDean Michael Berris "Failed to read current buffer size at offset %d.", OffsetPtr); 521*a9d477a6SDean Michael Berris 5226ec72625SDean Michael Berris State.Expects = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF; 523*a9d477a6SDean Michael Berris 524*a9d477a6SDean Michael Berris // Advance the offset pointer by enough bytes accounting for the padding in a 525*a9d477a6SDean Michael Berris // metadata record, after we read in the buffer extents. 526*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - 8; 5276ec72625SDean Michael Berris return Error::success(); 5286ec72625SDean Michael Berris } 5296ec72625SDean Michael Berris 53010c873f1SMartin Pelikan /// State transition when a CallArgumentRecord is encountered. 531*a9d477a6SDean Michael Berris Error processFDRCallArgumentRecord(FDRState &State, 53210c873f1SMartin Pelikan DataExtractor &RecordExtractor, 533*a9d477a6SDean Michael Berris std::vector<XRayRecord> &Records, 534*a9d477a6SDean Michael Berris uint32_t &OffsetPtr) { 53510c873f1SMartin Pelikan auto &Enter = Records.back(); 536*a9d477a6SDean Michael Berris if (Enter.Type != RecordTypes::ENTER && Enter.Type != RecordTypes::ENTER_ARG) 53710c873f1SMartin Pelikan return make_error<StringError>( 53810c873f1SMartin Pelikan "CallArgument needs to be right after a function entry", 53910c873f1SMartin Pelikan std::make_error_code(std::errc::executable_format_error)); 540*a9d477a6SDean Michael Berris 541*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 542*a9d477a6SDean Michael Berris auto Arg = RecordExtractor.getU64(&OffsetPtr); 543*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 544*a9d477a6SDean Michael Berris return createStringError( 545*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 546*a9d477a6SDean Michael Berris "Failed to read argument record at offset %d.", OffsetPtr); 547*a9d477a6SDean Michael Berris 54810c873f1SMartin Pelikan Enter.Type = RecordTypes::ENTER_ARG; 549*a9d477a6SDean Michael Berris Enter.CallArgs.emplace_back(Arg); 550*a9d477a6SDean Michael Berris 551*a9d477a6SDean Michael Berris // Advance the offset pointer by enough bytes accounting for the padding in a 552*a9d477a6SDean Michael Berris // metadata record, after reading the payload. 553*a9d477a6SDean Michael Berris OffsetPtr += kFDRMetadataBodySize - 8; 55410c873f1SMartin Pelikan return Error::success(); 55510c873f1SMartin Pelikan } 55610c873f1SMartin Pelikan 5574f83c4d1SDean Michael Berris /// Advances the state machine for reading the FDR record type by reading one 558e96152a9SKeith Wyss /// Metadata Record and updating the State appropriately based on the kind of 5594f83c4d1SDean Michael Berris /// record encountered. The RecordKind is encoded in the first byte of the 5604f83c4d1SDean Michael Berris /// Record, which the caller should pass in because they have already read it 5614f83c4d1SDean Michael Berris /// to determine that this is a metadata record as opposed to a function record. 5626ec72625SDean Michael Berris /// 5636ec72625SDean Michael Berris /// Beginning with Version 2 of the FDR log, we do not depend on the size of the 5646ec72625SDean Michael Berris /// buffer, but rather use the extents to determine how far to read in the log 5656ec72625SDean Michael Berris /// for this particular buffer. 56610141261SDean Michael Berris /// 56710141261SDean Michael Berris /// In Version 3, FDR log now includes a pid metadata record after 56810141261SDean Michael Berris /// WallTimeMarker 569*a9d477a6SDean Michael Berris Error processFDRMetadataRecord(FDRState &State, DataExtractor &RecordExtractor, 570*a9d477a6SDean Michael Berris uint32_t &OffsetPtr, 5716ec72625SDean Michael Berris std::vector<XRayRecord> &Records, 572*a9d477a6SDean Michael Berris uint16_t Version, uint8_t FirstByte) { 573*a9d477a6SDean Michael Berris // The remaining 7 bits of the first byte are the RecordKind enum for each 574*a9d477a6SDean Michael Berris // Metadata Record. 575*a9d477a6SDean Michael Berris switch (FirstByte >> 1) { 5764f83c4d1SDean Michael Berris case 0: // NewBuffer 577*a9d477a6SDean Michael Berris if (auto E = processFDRNewBufferRecord(State, RecordExtractor, OffsetPtr)) 5784f83c4d1SDean Michael Berris return E; 5794f83c4d1SDean Michael Berris break; 5804f83c4d1SDean Michael Berris case 1: // EndOfBuffer 5816ec72625SDean Michael Berris if (Version >= 2) 5826ec72625SDean Michael Berris return make_error<StringError>( 5836ec72625SDean Michael Berris "Since Version 2 of FDR logging, we no longer support EOB records.", 5846ec72625SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 585*a9d477a6SDean Michael Berris if (auto E = processFDREndOfBufferRecord(State, OffsetPtr)) 5864f83c4d1SDean Michael Berris return E; 5874f83c4d1SDean Michael Berris break; 5884f83c4d1SDean Michael Berris case 2: // NewCPUId 589*a9d477a6SDean Michael Berris if (auto E = processFDRNewCPUIdRecord(State, RecordExtractor, OffsetPtr)) 5904f83c4d1SDean Michael Berris return E; 5914f83c4d1SDean Michael Berris break; 5924f83c4d1SDean Michael Berris case 3: // TSCWrap 593*a9d477a6SDean Michael Berris if (auto E = processFDRTSCWrapRecord(State, RecordExtractor, OffsetPtr)) 5944f83c4d1SDean Michael Berris return E; 5954f83c4d1SDean Michael Berris break; 5964f83c4d1SDean Michael Berris case 4: // WallTimeMarker 597*a9d477a6SDean Michael Berris if (auto E = processFDRWallTimeRecord(State, RecordExtractor, OffsetPtr)) 5984f83c4d1SDean Michael Berris return E; 59910141261SDean Michael Berris // In Version 3 and and above, a PidRecord is expected after WallTimeRecord 60010141261SDean Michael Berris if (Version >= 3) 60110141261SDean Michael Berris State.Expects = FDRState::Token::PID_RECORD; 6024f83c4d1SDean Michael Berris break; 603a7bbe448SDean Michael Berris case 5: // CustomEventMarker 604*a9d477a6SDean Michael Berris if (auto E = processCustomEventMarker(State, RecordExtractor, OffsetPtr)) 605a7bbe448SDean Michael Berris return E; 606a7bbe448SDean Michael Berris break; 60710c873f1SMartin Pelikan case 6: // CallArgument 608*a9d477a6SDean Michael Berris if (auto E = processFDRCallArgumentRecord(State, RecordExtractor, Records, 609*a9d477a6SDean Michael Berris OffsetPtr)) 61010c873f1SMartin Pelikan return E; 61110c873f1SMartin Pelikan break; 6126ec72625SDean Michael Berris case 7: // BufferExtents 613*a9d477a6SDean Michael Berris if (auto E = processBufferExtents(State, RecordExtractor, OffsetPtr)) 6146ec72625SDean Michael Berris return E; 6156ec72625SDean Michael Berris break; 61610141261SDean Michael Berris case 9: // Pid 617*a9d477a6SDean Michael Berris if (auto E = processFDRPidRecord(State, RecordExtractor, OffsetPtr)) 61810141261SDean Michael Berris return E; 61910141261SDean Michael Berris break; 6204f83c4d1SDean Michael Berris default: 621*a9d477a6SDean Michael Berris return createStringError( 622*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 623*a9d477a6SDean Michael Berris "Illegal metadata record type: '%d' at offset %d.", FirstByte >> 1, 624*a9d477a6SDean Michael Berris OffsetPtr); 6254f83c4d1SDean Michael Berris } 6264f83c4d1SDean Michael Berris return Error::success(); 6274f83c4d1SDean Michael Berris } 6284f83c4d1SDean Michael Berris 6294f83c4d1SDean Michael Berris /// Reads a function record from an FDR format log, appending a new XRayRecord 6304f83c4d1SDean Michael Berris /// to the vector being populated and updating the State with a new value 6314f83c4d1SDean Michael Berris /// reference value to interpret TSC deltas. 6324f83c4d1SDean Michael Berris /// 6334f83c4d1SDean Michael Berris /// The XRayRecord constructed includes information from the function record 6344f83c4d1SDean Michael Berris /// processed here as well as Thread ID and CPU ID formerly extracted into 6354f83c4d1SDean Michael Berris /// State. 636*a9d477a6SDean Michael Berris Error processFDRFunctionRecord(FDRState &State, DataExtractor &RecordExtractor, 637*a9d477a6SDean Michael Berris uint32_t &OffsetPtr, uint8_t FirstByte, 6384f83c4d1SDean Michael Berris std::vector<XRayRecord> &Records) { 6394f83c4d1SDean Michael Berris switch (State.Expects) { 6404f83c4d1SDean Michael Berris case FDRState::Token::NEW_BUFFER_RECORD_OR_EOF: 6414f83c4d1SDean Michael Berris return make_error<StringError>( 6424f83c4d1SDean Michael Berris "Malformed log. Received Function Record before new buffer setup.", 6434f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 6444f83c4d1SDean Michael Berris case FDRState::Token::WALLCLOCK_RECORD: 6454f83c4d1SDean Michael Berris return make_error<StringError>( 6464f83c4d1SDean Michael Berris "Malformed log. Received Function Record when expecting wallclock.", 6474f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 64810141261SDean Michael Berris case FDRState::Token::PID_RECORD: 64910141261SDean Michael Berris return make_error<StringError>( 65010141261SDean Michael Berris "Malformed log. Received Function Record when expecting pid.", 65110141261SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 6524f83c4d1SDean Michael Berris case FDRState::Token::NEW_CPU_ID_RECORD: 6534f83c4d1SDean Michael Berris return make_error<StringError>( 6544f83c4d1SDean Michael Berris "Malformed log. Received Function Record before first CPU record.", 6554f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 6564f83c4d1SDean Michael Berris default: 6574f83c4d1SDean Michael Berris Records.emplace_back(); 6584f83c4d1SDean Michael Berris auto &Record = Records.back(); 6594f83c4d1SDean Michael Berris Record.RecordType = 0; // Record is type NORMAL. 6604f83c4d1SDean Michael Berris // Strip off record type bit and use the next three bits. 661*a9d477a6SDean Michael Berris auto T = (FirstByte >> 1) & 0x07; 662*a9d477a6SDean Michael Berris switch (T) { 663*a9d477a6SDean Michael Berris case static_cast<decltype(T)>(RecordTypes::ENTER): 6644f83c4d1SDean Michael Berris Record.Type = RecordTypes::ENTER; 6654f83c4d1SDean Michael Berris break; 666*a9d477a6SDean Michael Berris case static_cast<decltype(T)>(RecordTypes::EXIT): 6674f83c4d1SDean Michael Berris Record.Type = RecordTypes::EXIT; 6684f83c4d1SDean Michael Berris break; 669*a9d477a6SDean Michael Berris case static_cast<decltype(T)>(RecordTypes::TAIL_EXIT): 6700f84a7d3SDean Michael Berris Record.Type = RecordTypes::TAIL_EXIT; 6710f84a7d3SDean Michael Berris break; 672*a9d477a6SDean Michael Berris case static_cast<decltype(T)>(RecordTypes::ENTER_ARG): 673*a9d477a6SDean Michael Berris Record.Type = RecordTypes::ENTER_ARG; 674*a9d477a6SDean Michael Berris State.Expects = FDRState::Token::CALL_ARGUMENT; 675*a9d477a6SDean Michael Berris break; 6764f83c4d1SDean Michael Berris default: 677*a9d477a6SDean Michael Berris return createStringError( 678*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 679*a9d477a6SDean Michael Berris "Illegal function record type '%d' at offset %d.", T, OffsetPtr); 6804f83c4d1SDean Michael Berris } 6814f83c4d1SDean Michael Berris Record.CPU = State.CPUId; 6824f83c4d1SDean Michael Berris Record.TId = State.ThreadId; 68310141261SDean Michael Berris Record.PId = State.ProcessId; 684*a9d477a6SDean Michael Berris 685*a9d477a6SDean Michael Berris // Back up one byte to re-read the first byte, which is important for 686*a9d477a6SDean Michael Berris // computing the function id for a record. 687*a9d477a6SDean Michael Berris --OffsetPtr; 688*a9d477a6SDean Michael Berris 6894f83c4d1SDean Michael Berris // Despite function Id being a signed int on XRayRecord, 6904f83c4d1SDean Michael Berris // when it is written to an FDR format, the top bits are truncated, 6914f83c4d1SDean Michael Berris // so it is effectively an unsigned value. When we shift off the 6924f83c4d1SDean Michael Berris // top four bits, we want the shift to be logical, so we read as 6934f83c4d1SDean Michael Berris // uint32_t. 694*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 6954f83c4d1SDean Michael Berris uint32_t FuncIdBitField = RecordExtractor.getU32(&OffsetPtr); 696*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 697*a9d477a6SDean Michael Berris return createStringError( 698*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 699*a9d477a6SDean Michael Berris "Failed reading truncated function id field at offset %d.", 700*a9d477a6SDean Michael Berris OffsetPtr); 701*a9d477a6SDean Michael Berris 7024f83c4d1SDean Michael Berris Record.FuncId = FuncIdBitField >> 4; 703*a9d477a6SDean Michael Berris 7044f83c4d1SDean Michael Berris // FunctionRecords have a 32 bit delta from the previous absolute TSC 7054f83c4d1SDean Michael Berris // or TSC delta. If this would overflow, we should read a TSCWrap record 7064f83c4d1SDean Michael Berris // with an absolute TSC reading. 707*a9d477a6SDean Michael Berris PreReadOffset = OffsetPtr; 708d78db156SMartin Pelikan uint64_t NewTSC = State.BaseTSC + RecordExtractor.getU32(&OffsetPtr); 709*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 710*a9d477a6SDean Michael Berris return createStringError( 711*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 712*a9d477a6SDean Michael Berris "Failed reading TSC delta at offset %d.", OffsetPtr); 713*a9d477a6SDean Michael Berris 714d78db156SMartin Pelikan State.BaseTSC = NewTSC; 715d78db156SMartin Pelikan Record.TSC = NewTSC; 7164f83c4d1SDean Michael Berris } 7174f83c4d1SDean Michael Berris return Error::success(); 7184f83c4d1SDean Michael Berris } 7194f83c4d1SDean Michael Berris 7204f83c4d1SDean Michael Berris /// Reads a log in FDR mode for version 1 of this binary format. FDR mode is 7214f83c4d1SDean Michael Berris /// defined as part of the compiler-rt project in xray_fdr_logging.h, and such 7224f83c4d1SDean Michael Berris /// a log consists of the familiar 32 bit XRayHeader, followed by sequences of 7234f83c4d1SDean Michael Berris /// of interspersed 16 byte Metadata Records and 8 byte Function Records. 7244f83c4d1SDean Michael Berris /// 7254f83c4d1SDean Michael Berris /// The following is an attempt to document the grammar of the format, which is 7264f83c4d1SDean Michael Berris /// parsed by this function for little-endian machines. Since the format makes 727d78db156SMartin Pelikan /// use of BitFields, when we support big-endian architectures, we will need to 72868168d17SSimon Pilgrim /// adjust not only the endianness parameter to llvm's RecordExtractor, but also 7294f83c4d1SDean Michael Berris /// the bit twiddling logic, which is consistent with the little-endian 7304f83c4d1SDean Michael Berris /// convention that BitFields within a struct will first be packed into the 7314f83c4d1SDean Michael Berris /// least significant bits the address they belong to. 7324f83c4d1SDean Michael Berris /// 7336ec72625SDean Michael Berris /// We expect a format complying with the grammar in the following pseudo-EBNF 7346ec72625SDean Michael Berris /// in Version 1 of the FDR log. 7354f83c4d1SDean Michael Berris /// 7364f83c4d1SDean Michael Berris /// FDRLog: XRayFileHeader ThreadBuffer* 7373d0bc9efSKeith Wyss /// XRayFileHeader: 32 bytes to identify the log as FDR with machine metadata. 7383d0bc9efSKeith Wyss /// Includes BufferSize 7393d0bc9efSKeith Wyss /// ThreadBuffer: NewBuffer WallClockTime NewCPUId FunctionSequence EOB 74060c24878SDean Michael Berris /// BufSize: 8 byte unsigned integer indicating how large the buffer is. 7414f83c4d1SDean Michael Berris /// NewBuffer: 16 byte metadata record with Thread Id. 7424f83c4d1SDean Michael Berris /// WallClockTime: 16 byte metadata record with human readable time. 74310141261SDean Michael Berris /// Pid: 16 byte metadata record with Pid 7444f83c4d1SDean Michael Berris /// NewCPUId: 16 byte metadata record with CPUId and a 64 bit TSC reading. 74560c24878SDean Michael Berris /// EOB: 16 byte record in a thread buffer plus mem garbage to fill BufSize. 7464f83c4d1SDean Michael Berris /// FunctionSequence: NewCPUId | TSCWrap | FunctionRecord 7474f83c4d1SDean Michael Berris /// TSCWrap: 16 byte metadata record with a full 64 bit TSC reading. 7484f83c4d1SDean Michael Berris /// FunctionRecord: 8 byte record with FunctionId, entry/exit, and TSC delta. 7496ec72625SDean Michael Berris /// 7506ec72625SDean Michael Berris /// In Version 2, we make the following changes: 7516ec72625SDean Michael Berris /// 7526ec72625SDean Michael Berris /// ThreadBuffer: BufferExtents NewBuffer WallClockTime NewCPUId 7536ec72625SDean Michael Berris /// FunctionSequence 7546ec72625SDean Michael Berris /// BufferExtents: 16 byte metdata record describing how many usable bytes are 7556ec72625SDean Michael Berris /// in the buffer. This is measured from the start of the buffer 7566ec72625SDean Michael Berris /// and must always be at least 48 (bytes). 75710141261SDean Michael Berris /// 75810141261SDean Michael Berris /// In Version 3, we make the following changes: 75910141261SDean Michael Berris /// 76010141261SDean Michael Berris /// ThreadBuffer: BufferExtents NewBuffer WallClockTime Pid NewCPUId 76110141261SDean Michael Berris /// FunctionSequence 7626ec72625SDean Michael Berris /// EOB: *deprecated* 7634f83c4d1SDean Michael Berris Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, 7644f83c4d1SDean Michael Berris std::vector<XRayRecord> &Records) { 7654f83c4d1SDean Michael Berris if (Data.size() < 32) 7664f83c4d1SDean Michael Berris return make_error<StringError>( 7674f83c4d1SDean Michael Berris "Not enough bytes for an XRay log.", 7684f83c4d1SDean Michael Berris std::make_error_code(std::errc::invalid_argument)); 7694f83c4d1SDean Michael Berris 770*a9d477a6SDean Michael Berris DataExtractor Reader(Data, true, 8); 771*a9d477a6SDean Michael Berris uint32_t OffsetPtr = 0; 7724f83c4d1SDean Michael Berris 773*a9d477a6SDean Michael Berris if (auto E = readBinaryFormatHeader(Reader, OffsetPtr, FileHeader)) 7744f83c4d1SDean Michael Berris return E; 7754f83c4d1SDean Michael Berris 77660c24878SDean Michael Berris uint64_t BufferSize = 0; 77760c24878SDean Michael Berris { 77860c24878SDean Michael Berris StringRef ExtraDataRef(FileHeader.FreeFormData, 16); 77960c24878SDean Michael Berris DataExtractor ExtraDataExtractor(ExtraDataRef, true, 8); 78060c24878SDean Michael Berris uint32_t ExtraDataOffset = 0; 78160c24878SDean Michael Berris BufferSize = ExtraDataExtractor.getU64(&ExtraDataOffset); 78260c24878SDean Michael Berris } 7836ec72625SDean Michael Berris 7846ec72625SDean Michael Berris FDRState::Token InitialExpectation; 7856ec72625SDean Michael Berris switch (FileHeader.Version) { 7866ec72625SDean Michael Berris case 1: 7876ec72625SDean Michael Berris InitialExpectation = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF; 7886ec72625SDean Michael Berris break; 7896ec72625SDean Michael Berris case 2: 79010141261SDean Michael Berris case 3: 7916ec72625SDean Michael Berris InitialExpectation = FDRState::Token::BUFFER_EXTENTS; 7926ec72625SDean Michael Berris break; 7936ec72625SDean Michael Berris default: 7946ec72625SDean Michael Berris return make_error<StringError>( 7956ec72625SDean Michael Berris Twine("Unsupported version '") + Twine(FileHeader.Version) + "'", 7966ec72625SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 7976ec72625SDean Michael Berris } 79810141261SDean Michael Berris FDRState State{0, 0, 0, 0, InitialExpectation, BufferSize, 0}; 7996ec72625SDean Michael Berris 8004f83c4d1SDean Michael Berris // RecordSize will tell the loop how far to seek ahead based on the record 8014f83c4d1SDean Michael Berris // type that we have just read. 802*a9d477a6SDean Michael Berris while (Reader.isValidOffset(OffsetPtr)) { 803*a9d477a6SDean Michael Berris auto BeginOffset = OffsetPtr; 80460c24878SDean Michael Berris if (State.Expects == FDRState::Token::SCAN_TO_END_OF_THREAD_BUF) { 805*a9d477a6SDean Michael Berris OffsetPtr += State.CurrentBufferSize - State.CurrentBufferConsumed; 80660c24878SDean Michael Berris State.CurrentBufferConsumed = 0; 80760c24878SDean Michael Berris State.Expects = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF; 80860c24878SDean Michael Berris continue; 80960c24878SDean Michael Berris } 810*a9d477a6SDean Michael Berris auto PreReadOffset = OffsetPtr; 811*a9d477a6SDean Michael Berris uint8_t BitField = Reader.getU8(&OffsetPtr); 812*a9d477a6SDean Michael Berris if (OffsetPtr == PreReadOffset) 813*a9d477a6SDean Michael Berris return createStringError( 814*a9d477a6SDean Michael Berris std::make_error_code(std::errc::executable_format_error), 815*a9d477a6SDean Michael Berris "Failed reading first byte of record at offset %d.", OffsetPtr); 8164f83c4d1SDean Michael Berris bool isMetadataRecord = BitField & 0x01uL; 8176ec72625SDean Michael Berris bool isBufferExtents = 8186ec72625SDean Michael Berris (BitField >> 1) == 7; // BufferExtents record kind == 7 8194f83c4d1SDean Michael Berris if (isMetadataRecord) { 820*a9d477a6SDean Michael Berris if (auto E = processFDRMetadataRecord(State, Reader, OffsetPtr, Records, 821*a9d477a6SDean Michael Berris FileHeader.Version, BitField)) 8224f83c4d1SDean Michael Berris return E; 8234f83c4d1SDean Michael Berris } else { // Process Function Record 824*a9d477a6SDean Michael Berris if (auto E = processFDRFunctionRecord(State, Reader, OffsetPtr, BitField, 8254f83c4d1SDean Michael Berris Records)) 8264f83c4d1SDean Michael Berris return E; 827d78db156SMartin Pelikan } 8286ec72625SDean Michael Berris 8296ec72625SDean Michael Berris // The BufferExtents record is technically not part of the buffer, so we 8306ec72625SDean Michael Berris // don't count the size of that record against the buffer's actual size. 8316ec72625SDean Michael Berris if (!isBufferExtents) 832*a9d477a6SDean Michael Berris State.CurrentBufferConsumed += OffsetPtr - BeginOffset; 833*a9d477a6SDean Michael Berris 8346ec72625SDean Michael Berris assert(State.CurrentBufferConsumed <= State.CurrentBufferSize); 835*a9d477a6SDean Michael Berris 83610141261SDean Michael Berris if ((FileHeader.Version == 2 || FileHeader.Version == 3) && 8376ec72625SDean Michael Berris State.CurrentBufferSize == State.CurrentBufferConsumed) { 8386ec72625SDean Michael Berris // In Version 2 of the log, we don't need to scan to the end of the thread 8396ec72625SDean Michael Berris // buffer if we've already consumed all the bytes we need to. 8406ec72625SDean Michael Berris State.Expects = FDRState::Token::BUFFER_EXTENTS; 8416ec72625SDean Michael Berris State.CurrentBufferSize = BufferSize; 8426ec72625SDean Michael Berris State.CurrentBufferConsumed = 0; 8436ec72625SDean Michael Berris } 8444f83c4d1SDean Michael Berris } 845d78db156SMartin Pelikan 846d78db156SMartin Pelikan // Having iterated over everything we've been given, we've either consumed 847d78db156SMartin Pelikan // everything and ended up in the end state, or were told to skip the rest. 848d78db156SMartin Pelikan bool Finished = State.Expects == FDRState::Token::SCAN_TO_END_OF_THREAD_BUF && 849d78db156SMartin Pelikan State.CurrentBufferSize == State.CurrentBufferConsumed; 8506ec72625SDean Michael Berris if ((State.Expects != FDRState::Token::NEW_BUFFER_RECORD_OR_EOF && 8516ec72625SDean Michael Berris State.Expects != FDRState::Token::BUFFER_EXTENTS) && 8526ec72625SDean Michael Berris !Finished) 8534f83c4d1SDean Michael Berris return make_error<StringError>( 85460c24878SDean Michael Berris Twine("Encountered EOF with unexpected state expectation ") + 85560c24878SDean Michael Berris fdrStateToTwine(State.Expects) + 85660c24878SDean Michael Berris ". Remaining expected bytes in thread buffer total " + 85760c24878SDean Michael Berris Twine(State.CurrentBufferSize - State.CurrentBufferConsumed), 8584f83c4d1SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 8594f83c4d1SDean Michael Berris 8604f83c4d1SDean Michael Berris return Error::success(); 8614f83c4d1SDean Michael Berris } 8624f83c4d1SDean Michael Berris 8634f83c4d1SDean Michael Berris Error loadYAMLLog(StringRef Data, XRayFileHeader &FileHeader, 8644f83c4d1SDean Michael Berris std::vector<XRayRecord> &Records) { 865d6c18657SDean Michael Berris YAMLXRayTrace Trace; 866d6c18657SDean Michael Berris Input In(Data); 867d6c18657SDean Michael Berris In >> Trace; 868d6c18657SDean Michael Berris if (In.error()) 869d6c18657SDean Michael Berris return make_error<StringError>("Failed loading YAML Data.", In.error()); 870d6c18657SDean Michael Berris 871d6c18657SDean Michael Berris FileHeader.Version = Trace.Header.Version; 872d6c18657SDean Michael Berris FileHeader.Type = Trace.Header.Type; 873d6c18657SDean Michael Berris FileHeader.ConstantTSC = Trace.Header.ConstantTSC; 874d6c18657SDean Michael Berris FileHeader.NonstopTSC = Trace.Header.NonstopTSC; 875d6c18657SDean Michael Berris FileHeader.CycleFrequency = Trace.Header.CycleFrequency; 876d6c18657SDean Michael Berris 877d6c18657SDean Michael Berris if (FileHeader.Version != 1) 878d6c18657SDean Michael Berris return make_error<StringError>( 879d6c18657SDean Michael Berris Twine("Unsupported XRay file version: ") + Twine(FileHeader.Version), 880d6c18657SDean Michael Berris std::make_error_code(std::errc::invalid_argument)); 881d6c18657SDean Michael Berris 882d6c18657SDean Michael Berris Records.clear(); 883d6c18657SDean Michael Berris std::transform(Trace.Records.begin(), Trace.Records.end(), 884d6c18657SDean Michael Berris std::back_inserter(Records), [&](const YAMLXRayRecord &R) { 8850a465d7aSDean Michael Berris return XRayRecord{R.RecordType, R.CPU, R.Type, R.FuncId, 88610141261SDean Michael Berris R.TSC, R.TId, R.PId, R.CallArgs}; 887d6c18657SDean Michael Berris }); 888d6c18657SDean Michael Berris return Error::success(); 889d6c18657SDean Michael Berris } 89049a49fe8SBenjamin Kramer } // namespace 891d6c18657SDean Michael Berris 892d6c18657SDean Michael Berris Expected<Trace> llvm::xray::loadTraceFile(StringRef Filename, bool Sort) { 893d6c18657SDean Michael Berris int Fd; 894d6c18657SDean Michael Berris if (auto EC = sys::fs::openFileForRead(Filename, Fd)) { 895d6c18657SDean Michael Berris return make_error<StringError>( 896d6c18657SDean Michael Berris Twine("Cannot read log from '") + Filename + "'", EC); 897d6c18657SDean Michael Berris } 898d6c18657SDean Michael Berris 899d6c18657SDean Michael Berris uint64_t FileSize; 900d6c18657SDean Michael Berris if (auto EC = sys::fs::file_size(Filename, FileSize)) { 901d6c18657SDean Michael Berris return make_error<StringError>( 902d6c18657SDean Michael Berris Twine("Cannot read log from '") + Filename + "'", EC); 903d6c18657SDean Michael Berris } 904d6c18657SDean Michael Berris if (FileSize < 4) { 905d6c18657SDean Michael Berris return make_error<StringError>( 906d6c18657SDean Michael Berris Twine("File '") + Filename + "' too small for XRay.", 90784da6615SHans Wennborg std::make_error_code(std::errc::executable_format_error)); 908d6c18657SDean Michael Berris } 909d6c18657SDean Michael Berris 910d78db156SMartin Pelikan // Map the opened file into memory and use a StringRef to access it later. 911d6c18657SDean Michael Berris std::error_code EC; 912d6c18657SDean Michael Berris sys::fs::mapped_file_region MappedFile( 913d6c18657SDean Michael Berris Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); 914d6c18657SDean Michael Berris if (EC) { 915d6c18657SDean Michael Berris return make_error<StringError>( 916d6c18657SDean Michael Berris Twine("Cannot read log from '") + Filename + "'", EC); 917d6c18657SDean Michael Berris } 918d78db156SMartin Pelikan auto Data = StringRef(MappedFile.data(), MappedFile.size()); 919d6c18657SDean Michael Berris 920d6c18657SDean Michael Berris // Attempt to detect the file type using file magic. We have a slight bias 921d6c18657SDean Michael Berris // towards the binary format, and we do this by making sure that the first 4 922d6c18657SDean Michael Berris // bytes of the binary file is some combination of the following byte 923d78db156SMartin Pelikan // patterns: (observe the code loading them assumes they're little endian) 924d6c18657SDean Michael Berris // 925d78db156SMartin Pelikan // 0x01 0x00 0x00 0x00 - version 1, "naive" format 926d78db156SMartin Pelikan // 0x01 0x00 0x01 0x00 - version 1, "flight data recorder" format 9276ec72625SDean Michael Berris // 0x02 0x00 0x01 0x00 - version 2, "flight data recorder" format 928d6c18657SDean Michael Berris // 929d78db156SMartin Pelikan // YAML files don't typically have those first four bytes as valid text so we 930d6c18657SDean Michael Berris // try loading assuming YAML if we don't find these bytes. 931d6c18657SDean Michael Berris // 932d6c18657SDean Michael Berris // Only if we can't load either the binary or the YAML format will we yield an 933d6c18657SDean Michael Berris // error. 934d6c18657SDean Michael Berris StringRef Magic(MappedFile.data(), 4); 935d6c18657SDean Michael Berris DataExtractor HeaderExtractor(Magic, true, 8); 936d6c18657SDean Michael Berris uint32_t OffsetPtr = 0; 937d6c18657SDean Michael Berris uint16_t Version = HeaderExtractor.getU16(&OffsetPtr); 938d6c18657SDean Michael Berris uint16_t Type = HeaderExtractor.getU16(&OffsetPtr); 939d6c18657SDean Michael Berris 9404f83c4d1SDean Michael Berris enum BinaryFormatType { NAIVE_FORMAT = 0, FLIGHT_DATA_RECORDER_FORMAT = 1 }; 9414f83c4d1SDean Michael Berris 942d6c18657SDean Michael Berris Trace T; 9436ec72625SDean Michael Berris switch (Type) { 9446ec72625SDean Michael Berris case NAIVE_FORMAT: 94510141261SDean Michael Berris if (Version == 1 || Version == 2 || Version == 3) { 9460f84a7d3SDean Michael Berris if (auto E = loadNaiveFormatLog(Data, T.FileHeader, T.Records)) 9474f83c4d1SDean Michael Berris return std::move(E); 9486ec72625SDean Michael Berris } else { 9496ec72625SDean Michael Berris return make_error<StringError>( 9506ec72625SDean Michael Berris Twine("Unsupported version for Basic/Naive Mode logging: ") + 9516ec72625SDean Michael Berris Twine(Version), 9526ec72625SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 9536ec72625SDean Michael Berris } 9546ec72625SDean Michael Berris break; 9556ec72625SDean Michael Berris case FLIGHT_DATA_RECORDER_FORMAT: 95610141261SDean Michael Berris if (Version == 1 || Version == 2 || Version == 3) { 957d78db156SMartin Pelikan if (auto E = loadFDRLog(Data, T.FileHeader, T.Records)) 958d6c18657SDean Michael Berris return std::move(E); 959d6c18657SDean Michael Berris } else { 9606ec72625SDean Michael Berris return make_error<StringError>( 9616ec72625SDean Michael Berris Twine("Unsupported version for FDR Mode logging: ") + Twine(Version), 9626ec72625SDean Michael Berris std::make_error_code(std::errc::executable_format_error)); 9636ec72625SDean Michael Berris } 9646ec72625SDean Michael Berris break; 9656ec72625SDean Michael Berris default: 966d78db156SMartin Pelikan if (auto E = loadYAMLLog(Data, T.FileHeader, T.Records)) 967d6c18657SDean Michael Berris return std::move(E); 968d6c18657SDean Michael Berris } 969d6c18657SDean Michael Berris 970d6c18657SDean Michael Berris if (Sort) 97128f3d5cbSMandeep Singh Grang std::stable_sort(T.Records.begin(), T.Records.end(), 972d6c18657SDean Michael Berris [&](const XRayRecord &L, const XRayRecord &R) { 973d6c18657SDean Michael Berris return L.TSC < R.TSC; 974d6c18657SDean Michael Berris }); 975d6c18657SDean Michael Berris 976d6c18657SDean Michael Berris return std::move(T); 977d6c18657SDean Michael Berris } 978