blob: 35a3033f435a549f4ee50da14a45353ec4c32f03 [file] [log] [blame]
Dean Michael Berrisd6c18652017-01-11 06:39:09 +00001//===- Trace.cpp - XRay Trace Loading implementation. ---------------------===//
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +00002//
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//
10// XRay log reader implementation.
11//
12//===----------------------------------------------------------------------===//
Dean Michael Berrisd6c18652017-01-11 06:39:09 +000013#include "llvm/XRay/Trace.h"
14#include "llvm/ADT/STLExtras.h"
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +000015#include "llvm/Support/DataExtractor.h"
Dean Michael Berrisd6c18652017-01-11 06:39:09 +000016#include "llvm/Support/Error.h"
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +000017#include "llvm/Support/FileSystem.h"
Dean Michael Berrisd764c1b2018-08-22 07:37:55 +000018#include "llvm/XRay/FileHeaderReader.h"
Dean Michael Berrisd6c18652017-01-11 06:39:09 +000019#include "llvm/XRay/YAMLXRayRecord.h"
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +000020
21using namespace llvm;
22using namespace llvm::xray;
23using llvm::yaml::Input;
24
Benjamin Kramer49a49fe2017-08-20 13:03:48 +000025namespace {
Dean Michael Berrisd6c18652017-01-11 06:39:09 +000026using XRayRecordStorage =
27 std::aligned_storage<sizeof(XRayRecord), alignof(XRayRecord)>::type;
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +000028
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +000029// This is the number of bytes in the "body" of a MetadataRecord in FDR Mode.
30// This already excludes the first byte, which indicates the type of metadata
31// record it is.
32constexpr auto kFDRMetadataBodySize = 15;
33
Dean Michael Berris5b7548c2018-08-31 17:06:28 +000034Error loadNaiveFormatLog(StringRef Data, bool IsLittleEndian,
35 XRayFileHeader &FileHeader,
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +000036 std::vector<XRayRecord> &Records) {
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +000037 if (Data.size() < 32)
38 return make_error<StringError>(
39 "Not enough bytes for an XRay log.",
40 std::make_error_code(std::errc::invalid_argument));
41
42 if (Data.size() - 32 == 0 || Data.size() % 32 != 0)
43 return make_error<StringError>(
44 "Invalid-sized XRay data.",
45 std::make_error_code(std::errc::invalid_argument));
46
Dean Michael Berris5b7548c2018-08-31 17:06:28 +000047 DataExtractor Reader(Data, IsLittleEndian, 8);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +000048 uint32_t OffsetPtr = 0;
Dean Michael Berrisd764c1b2018-08-22 07:37:55 +000049 auto FileHeaderOrError = readBinaryFormatHeader(Reader, OffsetPtr);
50 if (!FileHeaderOrError)
51 return FileHeaderOrError.takeError();
52 FileHeader = std::move(FileHeaderOrError.get());
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +000053
54 // Each record after the header will be 32 bytes, in the following format:
55 //
56 // (2) uint16 : record type
57 // (1) uint8 : cpu id
58 // (1) uint8 : type
59 // (4) sint32 : function id
60 // (8) uint64 : tsc
61 // (4) uint32 : thread id
Dean Michael Berris10141262018-07-13 05:38:22 +000062 // (4) uint32 : process id
63 // (8) - : padding
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +000064 while (Reader.isValidOffset(OffsetPtr)) {
65 if (!Reader.isValidOffsetForDataOfSize(OffsetPtr, 32))
66 return createStringError(
67 std::make_error_code(std::errc::executable_format_error),
68 "Not enough bytes to read a full record at offset %d.", OffsetPtr);
69 auto PreReadOffset = OffsetPtr;
70 auto RecordType = Reader.getU16(&OffsetPtr);
71 if (OffsetPtr == PreReadOffset)
72 return createStringError(
73 std::make_error_code(std::errc::executable_format_error),
74 "Failed reading record type at offset %d.", OffsetPtr);
75
76 switch (RecordType) {
Dean Michael Berris0a465d72017-10-05 05:18:17 +000077 case 0: { // Normal records.
78 Records.emplace_back();
79 auto &Record = Records.back();
80 Record.RecordType = RecordType;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +000081
82 PreReadOffset = OffsetPtr;
83 Record.CPU = Reader.getU8(&OffsetPtr);
84 if (OffsetPtr == PreReadOffset)
85 return createStringError(
86 std::make_error_code(std::errc::executable_format_error),
87 "Failed reading CPU field at offset %d.", OffsetPtr);
88
89 PreReadOffset = OffsetPtr;
90 auto Type = Reader.getU8(&OffsetPtr);
91 if (OffsetPtr == PreReadOffset)
92 return createStringError(
93 std::make_error_code(std::errc::executable_format_error),
94 "Failed reading record type field at offset %d.", OffsetPtr);
95
Dean Michael Berris0a465d72017-10-05 05:18:17 +000096 switch (Type) {
97 case 0:
98 Record.Type = RecordTypes::ENTER;
99 break;
100 case 1:
101 Record.Type = RecordTypes::EXIT;
102 break;
103 case 2:
104 Record.Type = RecordTypes::TAIL_EXIT;
105 break;
106 case 3:
107 Record.Type = RecordTypes::ENTER_ARG;
108 break;
109 default:
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000110 return createStringError(
111 std::make_error_code(std::errc::executable_format_error),
112 "Unknown record type '%d' at offset %d.", Type, OffsetPtr);
Dean Michael Berris0a465d72017-10-05 05:18:17 +0000113 }
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000114
115 PreReadOffset = OffsetPtr;
116 Record.FuncId = Reader.getSigned(&OffsetPtr, sizeof(int32_t));
117 if (OffsetPtr == PreReadOffset)
118 return createStringError(
119 std::make_error_code(std::errc::executable_format_error),
120 "Failed reading function id field at offset %d.", OffsetPtr);
121
122 PreReadOffset = OffsetPtr;
123 Record.TSC = Reader.getU64(&OffsetPtr);
124 if (OffsetPtr == PreReadOffset)
125 return createStringError(
126 std::make_error_code(std::errc::executable_format_error),
127 "Failed reading TSC field at offset %d.", OffsetPtr);
128
129 PreReadOffset = OffsetPtr;
130 Record.TId = Reader.getU32(&OffsetPtr);
131 if (OffsetPtr == PreReadOffset)
132 return createStringError(
133 std::make_error_code(std::errc::executable_format_error),
134 "Failed reading thread id field at offset %d.", OffsetPtr);
135
136 PreReadOffset = OffsetPtr;
137 Record.PId = Reader.getU32(&OffsetPtr);
138 if (OffsetPtr == PreReadOffset)
139 return createStringError(
140 std::make_error_code(std::errc::executable_format_error),
141 "Failed reading process id at offset %d.", OffsetPtr);
142
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000143 break;
Dean Michael Berris0a465d72017-10-05 05:18:17 +0000144 }
145 case 1: { // Arg payload record.
146 auto &Record = Records.back();
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000147
148 // We skip the next two bytes of the record, because we don't need the
149 // type and the CPU record for arg payloads.
Dean Michael Berris0a465d72017-10-05 05:18:17 +0000150 OffsetPtr += 2;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000151 PreReadOffset = OffsetPtr;
152 int32_t FuncId = Reader.getSigned(&OffsetPtr, sizeof(int32_t));
153 if (OffsetPtr == PreReadOffset)
154 return createStringError(
155 std::make_error_code(std::errc::executable_format_error),
156 "Failed reading function id field at offset %d.", OffsetPtr);
157
158 PreReadOffset = OffsetPtr;
159 auto TId = Reader.getU32(&OffsetPtr);
160 if (OffsetPtr == PreReadOffset)
161 return createStringError(
162 std::make_error_code(std::errc::executable_format_error),
163 "Failed reading thread id field at offset %d.", OffsetPtr);
164
165 PreReadOffset = OffsetPtr;
166 auto PId = Reader.getU32(&OffsetPtr);
167 if (OffsetPtr == PreReadOffset)
168 return createStringError(
169 std::make_error_code(std::errc::executable_format_error),
170 "Failed reading process id field at offset %d.", OffsetPtr);
Dean Michael Berris10141262018-07-13 05:38:22 +0000171
172 // Make a check for versions above 3 for the Pid field
173 if (Record.FuncId != FuncId || Record.TId != TId ||
174 (FileHeader.Version >= 3 ? Record.PId != PId : false))
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000175 return createStringError(
176 std::make_error_code(std::errc::executable_format_error),
177 "Corrupted log, found arg payload following non-matching "
178 "function+thread record. Record for function %d != %d at offset "
179 "%d",
180 Record.FuncId, FuncId, OffsetPtr);
Dean Michael Berris10141262018-07-13 05:38:22 +0000181
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000182 PreReadOffset = OffsetPtr;
183 auto Arg = Reader.getU64(&OffsetPtr);
184 if (OffsetPtr == PreReadOffset)
185 return createStringError(
186 std::make_error_code(std::errc::executable_format_error),
187 "Failed reading argument payload at offset %d.", OffsetPtr);
188
Dean Michael Berris0a465d72017-10-05 05:18:17 +0000189 Record.CallArgs.push_back(Arg);
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000190 break;
Dean Michael Berris0a465d72017-10-05 05:18:17 +0000191 }
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000192 default:
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000193 return createStringError(
194 std::make_error_code(std::errc::executable_format_error),
195 "Unknown record type '%d' at offset %d.", RecordType, OffsetPtr);
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000196 }
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000197 // Advance the offset pointer enough bytes to align to 32-byte records for
198 // basic mode logs.
199 OffsetPtr += 8;
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000200 }
201 return Error::success();
202}
203
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000204/// When reading from a Flight Data Recorder mode log, metadata records are
205/// sparse compared to packed function records, so we must maintain state as we
206/// read through the sequence of entries. This allows the reader to denormalize
207/// the CPUId and Thread Id onto each Function Record and transform delta
208/// encoded TSC values into absolute encodings on each record.
209struct FDRState {
210 uint16_t CPUId;
211 uint16_t ThreadId;
Dean Michael Berris10141262018-07-13 05:38:22 +0000212 int32_t ProcessId;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000213 uint64_t BaseTSC;
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000214
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000215 /// Encode some of the state transitions for the FDR log reader as explicit
216 /// checks. These are expectations for the next Record in the stream.
217 enum class Token {
218 NEW_BUFFER_RECORD_OR_EOF,
219 WALLCLOCK_RECORD,
220 NEW_CPU_ID_RECORD,
Dean Michael Berris60c24872017-03-29 06:10:12 +0000221 FUNCTION_SEQUENCE,
222 SCAN_TO_END_OF_THREAD_BUF,
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000223 CUSTOM_EVENT_DATA,
Martin Pelikan10c873f2017-09-27 04:48:03 +0000224 CALL_ARGUMENT,
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000225 BUFFER_EXTENTS,
Dean Michael Berris10141262018-07-13 05:38:22 +0000226 PID_RECORD,
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000227 };
228 Token Expects;
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000229
Dean Michael Berris60c24872017-03-29 06:10:12 +0000230 // Each threads buffer may have trailing garbage to scan over, so we track our
231 // progress.
232 uint64_t CurrentBufferSize;
233 uint64_t CurrentBufferConsumed;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000234};
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000235
Benjamin Kramer49a49fe2017-08-20 13:03:48 +0000236const char *fdrStateToTwine(const FDRState::Token &state) {
Dean Michael Berris60c24872017-03-29 06:10:12 +0000237 switch (state) {
238 case FDRState::Token::NEW_BUFFER_RECORD_OR_EOF:
239 return "NEW_BUFFER_RECORD_OR_EOF";
240 case FDRState::Token::WALLCLOCK_RECORD:
241 return "WALLCLOCK_RECORD";
242 case FDRState::Token::NEW_CPU_ID_RECORD:
243 return "NEW_CPU_ID_RECORD";
244 case FDRState::Token::FUNCTION_SEQUENCE:
245 return "FUNCTION_SEQUENCE";
246 case FDRState::Token::SCAN_TO_END_OF_THREAD_BUF:
247 return "SCAN_TO_END_OF_THREAD_BUF";
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000248 case FDRState::Token::CUSTOM_EVENT_DATA:
249 return "CUSTOM_EVENT_DATA";
Martin Pelikan10c873f2017-09-27 04:48:03 +0000250 case FDRState::Token::CALL_ARGUMENT:
251 return "CALL_ARGUMENT";
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000252 case FDRState::Token::BUFFER_EXTENTS:
253 return "BUFFER_EXTENTS";
Dean Michael Berris10141262018-07-13 05:38:22 +0000254 case FDRState::Token::PID_RECORD:
255 return "PID_RECORD";
Dean Michael Berris60c24872017-03-29 06:10:12 +0000256 }
257 return "UNKNOWN";
258}
259
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000260/// State transition when a NewBufferRecord is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000261Error processFDRNewBufferRecord(FDRState &State, DataExtractor &RecordExtractor,
262 uint32_t &OffsetPtr) {
Dean Michael Berris60c24872017-03-29 06:10:12 +0000263 if (State.Expects != FDRState::Token::NEW_BUFFER_RECORD_OR_EOF)
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000264 return createStringError(
265 std::make_error_code(std::errc::executable_format_error),
266 "Malformed log: Read New Buffer record kind out of sequence; expected: "
267 "%s at offset %d.",
268 fdrStateToTwine(State.Expects), OffsetPtr);
269
270 auto PreReadOffset = OffsetPtr;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000271 State.ThreadId = RecordExtractor.getU16(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000272 if (OffsetPtr == PreReadOffset)
273 return createStringError(
274 std::make_error_code(std::errc::executable_format_error),
275 "Failed reading the thread id at offset %d.", OffsetPtr);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000276 State.Expects = FDRState::Token::WALLCLOCK_RECORD;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000277
278 // Advance the offset pointer by enough bytes representing the remaining
279 // padding in a metadata record.
280 OffsetPtr += kFDRMetadataBodySize - 2;
281 assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000282 return Error::success();
283}
284
285/// State transition when an EndOfBufferRecord is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000286Error processFDREndOfBufferRecord(FDRState &State, uint32_t &OffsetPtr) {
Dean Michael Berris60c24872017-03-29 06:10:12 +0000287 if (State.Expects == FDRState::Token::NEW_BUFFER_RECORD_OR_EOF)
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000288 return createStringError(
289 std::make_error_code(std::errc::executable_format_error),
290 "Malformed log: Received EOB message without current buffer; expected: "
291 "%s at offset %d.",
292 fdrStateToTwine(State.Expects), OffsetPtr);
293
Dean Michael Berris60c24872017-03-29 06:10:12 +0000294 State.Expects = FDRState::Token::SCAN_TO_END_OF_THREAD_BUF;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000295
296 // Advance the offset pointer by enough bytes representing the remaining
297 // padding in a metadata record.
298 OffsetPtr += kFDRMetadataBodySize;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000299 return Error::success();
300}
301
302/// State transition when a NewCPUIdRecord is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000303Error processFDRNewCPUIdRecord(FDRState &State, DataExtractor &RecordExtractor,
304 uint32_t &OffsetPtr) {
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000305 if (State.Expects != FDRState::Token::FUNCTION_SEQUENCE &&
Dean Michael Berris60c24872017-03-29 06:10:12 +0000306 State.Expects != FDRState::Token::NEW_CPU_ID_RECORD)
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000307 return make_error<StringError>(
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000308 Twine("Malformed log. Read NewCPUId record kind out of sequence; "
309 "expected: ") +
310 fdrStateToTwine(State.Expects),
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000311 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000312 auto BeginOffset = OffsetPtr;
313 auto PreReadOffset = OffsetPtr;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000314 State.CPUId = RecordExtractor.getU16(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000315 if (OffsetPtr == PreReadOffset)
316 return createStringError(
317 std::make_error_code(std::errc::executable_format_error),
318 "Failed reading the CPU field at offset %d.", OffsetPtr);
319
320 PreReadOffset = OffsetPtr;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000321 State.BaseTSC = RecordExtractor.getU64(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000322 if (OffsetPtr == PreReadOffset)
323 return createStringError(
324 std::make_error_code(std::errc::executable_format_error),
325 "Failed reading the base TSC field at offset %d.", OffsetPtr);
326
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000327 State.Expects = FDRState::Token::FUNCTION_SEQUENCE;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000328
329 // Advance the offset pointer by a few bytes, to account for the padding in
330 // CPU ID metadata records that we've already advanced through.
331 OffsetPtr += kFDRMetadataBodySize - (OffsetPtr - BeginOffset);
332 assert(OffsetPtr - BeginOffset == kFDRMetadataBodySize);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000333 return Error::success();
334}
335
336/// State transition when a TSCWrapRecord (overflow detection) is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000337Error processFDRTSCWrapRecord(FDRState &State, DataExtractor &RecordExtractor,
338 uint32_t &OffsetPtr) {
Dean Michael Berris60c24872017-03-29 06:10:12 +0000339 if (State.Expects != FDRState::Token::FUNCTION_SEQUENCE)
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000340 return make_error<StringError>(
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000341 Twine("Malformed log. Read TSCWrap record kind out of sequence; "
342 "expecting: ") +
343 fdrStateToTwine(State.Expects),
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000344 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000345 auto PreReadOffset = OffsetPtr;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000346 State.BaseTSC = RecordExtractor.getU64(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000347 if (OffsetPtr == PreReadOffset)
348 return createStringError(
349 std::make_error_code(std::errc::executable_format_error),
350 "Failed reading the base TSC field at offset %d.", OffsetPtr);
351
352 // Advance the offset pointer by a few more bytes, accounting for the padding
353 // in the metadata record after reading the base TSC.
354 OffsetPtr += kFDRMetadataBodySize - 8;
355 assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000356 return Error::success();
357}
358
359/// State transition when a WallTimeMarkerRecord is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000360Error processFDRWallTimeRecord(FDRState &State, DataExtractor &RecordExtractor,
361 uint32_t &OffsetPtr) {
Dean Michael Berris60c24872017-03-29 06:10:12 +0000362 if (State.Expects != FDRState::Token::WALLCLOCK_RECORD)
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000363 return make_error<StringError>(
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000364 Twine("Malformed log. Read Wallclock record kind out of sequence; "
365 "expecting: ") +
366 fdrStateToTwine(State.Expects),
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000367 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000368
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000369 // Read in the data from the walltime record.
370 auto PreReadOffset = OffsetPtr;
371 auto WallTime = RecordExtractor.getU64(&OffsetPtr);
372 if (OffsetPtr == PreReadOffset)
373 return createStringError(
374 std::make_error_code(std::errc::executable_format_error),
375 "Failed reading the walltime record at offset %d.", OffsetPtr);
376
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000377 // TODO: Someday, reconcile the TSC ticks to wall clock time for presentation
378 // purposes. For now, we're ignoring these records.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000379 (void)WallTime;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000380 State.Expects = FDRState::Token::NEW_CPU_ID_RECORD;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000381
382 // Advance the offset pointer by a few more bytes, accounting for the padding
383 // in the metadata record after reading in the walltime data.
384 OffsetPtr += kFDRMetadataBodySize - 8;
385 assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000386 return Error::success();
387}
388
Dean Michael Berris10141262018-07-13 05:38:22 +0000389/// State transition when a PidRecord is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000390Error processFDRPidRecord(FDRState &State, DataExtractor &RecordExtractor,
391 uint32_t &OffsetPtr) {
Dean Michael Berris10141262018-07-13 05:38:22 +0000392 if (State.Expects != FDRState::Token::PID_RECORD)
393 return make_error<StringError>(
394 Twine("Malformed log. Read Pid record kind out of sequence; "
395 "expected: ") +
396 fdrStateToTwine(State.Expects),
397 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000398 auto PreReadOffset = OffsetPtr;
Dean Michael Berris10141262018-07-13 05:38:22 +0000399 State.ProcessId = RecordExtractor.getU32(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000400 if (OffsetPtr == PreReadOffset)
401 return createStringError(
402 std::make_error_code(std::errc::executable_format_error),
403 "Failed reading the process ID at offset %d.", OffsetPtr);
Dean Michael Berris10141262018-07-13 05:38:22 +0000404 State.Expects = FDRState::Token::NEW_CPU_ID_RECORD;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000405
406 // Advance the offset pointer by a few more bytes, accounting for the padding
407 // in the metadata record after reading in the PID.
408 OffsetPtr += kFDRMetadataBodySize - 4;
409 assert(OffsetPtr - PreReadOffset == kFDRMetadataBodySize);
Dean Michael Berris10141262018-07-13 05:38:22 +0000410 return Error::success();
411}
412
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000413/// State transition when a CustomEventMarker is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000414Error processCustomEventMarker(FDRState &State, DataExtractor &RecordExtractor,
415 uint32_t &OffsetPtr) {
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000416 // We can encounter a CustomEventMarker anywhere in the log, so we can handle
Keith Wyss3d0bc9e2017-08-02 21:47:27 +0000417 // it regardless of the expectation. However, we do set the expectation to
418 // read a set number of fixed bytes, as described in the metadata.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000419 auto BeginOffset = OffsetPtr;
420 auto PreReadOffset = OffsetPtr;
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000421 uint32_t DataSize = RecordExtractor.getU32(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000422 if (OffsetPtr == PreReadOffset)
423 return createStringError(
424 std::make_error_code(std::errc::executable_format_error),
425 "Failed reading a custom event marker at offset %d.", OffsetPtr);
426
427 PreReadOffset = OffsetPtr;
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000428 uint64_t TSC = RecordExtractor.getU64(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000429 if (OffsetPtr == PreReadOffset)
430 return createStringError(
431 std::make_error_code(std::errc::executable_format_error),
432 "Failed reading the TSC at offset %d.", OffsetPtr);
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000433
Dean Michael Berris0a465d72017-10-05 05:18:17 +0000434 // FIXME: Actually represent the record through the API. For now we only
435 // skip through the data.
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000436 (void)TSC;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000437 // Advance the offset ptr by the size of the data associated with the custom
438 // event, as well as the padding associated with the remainder of the metadata
439 // record.
440 OffsetPtr += (kFDRMetadataBodySize - (OffsetPtr - BeginOffset)) + DataSize;
441 if (!RecordExtractor.isValidOffset(OffsetPtr))
442 return createStringError(
443 std::make_error_code(std::errc::executable_format_error),
444 "Reading custom event data moves past addressable trace data (starting "
445 "at offset %d, advancing to offset %d).",
446 BeginOffset, OffsetPtr);
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000447 return Error::success();
448}
449
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000450/// State transition when an BufferExtents record is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000451Error processBufferExtents(FDRState &State, DataExtractor &RecordExtractor,
452 uint32_t &OffsetPtr) {
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000453 if (State.Expects != FDRState::Token::BUFFER_EXTENTS)
454 return make_error<StringError>(
455 Twine("Malformed log. Buffer Extents unexpected; expected: ") +
456 fdrStateToTwine(State.Expects),
457 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000458
459 auto PreReadOffset = OffsetPtr;
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000460 State.CurrentBufferSize = RecordExtractor.getU64(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000461 if (OffsetPtr == PreReadOffset)
462 return createStringError(
463 std::make_error_code(std::errc::executable_format_error),
464 "Failed to read current buffer size at offset %d.", OffsetPtr);
465
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000466 State.Expects = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000467
468 // Advance the offset pointer by enough bytes accounting for the padding in a
469 // metadata record, after we read in the buffer extents.
470 OffsetPtr += kFDRMetadataBodySize - 8;
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000471 return Error::success();
472}
473
Martin Pelikan10c873f2017-09-27 04:48:03 +0000474/// State transition when a CallArgumentRecord is encountered.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000475Error processFDRCallArgumentRecord(FDRState &State,
Martin Pelikan10c873f2017-09-27 04:48:03 +0000476 DataExtractor &RecordExtractor,
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000477 std::vector<XRayRecord> &Records,
478 uint32_t &OffsetPtr) {
Martin Pelikan10c873f2017-09-27 04:48:03 +0000479 auto &Enter = Records.back();
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000480 if (Enter.Type != RecordTypes::ENTER && Enter.Type != RecordTypes::ENTER_ARG)
Martin Pelikan10c873f2017-09-27 04:48:03 +0000481 return make_error<StringError>(
482 "CallArgument needs to be right after a function entry",
483 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000484
485 auto PreReadOffset = OffsetPtr;
486 auto Arg = RecordExtractor.getU64(&OffsetPtr);
487 if (OffsetPtr == PreReadOffset)
488 return createStringError(
489 std::make_error_code(std::errc::executable_format_error),
490 "Failed to read argument record at offset %d.", OffsetPtr);
491
Martin Pelikan10c873f2017-09-27 04:48:03 +0000492 Enter.Type = RecordTypes::ENTER_ARG;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000493 Enter.CallArgs.emplace_back(Arg);
494
495 // Advance the offset pointer by enough bytes accounting for the padding in a
496 // metadata record, after reading the payload.
497 OffsetPtr += kFDRMetadataBodySize - 8;
Martin Pelikan10c873f2017-09-27 04:48:03 +0000498 return Error::success();
499}
500
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000501/// Advances the state machine for reading the FDR record type by reading one
Keith Wysse96152a2017-04-06 03:32:01 +0000502/// Metadata Record and updating the State appropriately based on the kind of
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000503/// record encountered. The RecordKind is encoded in the first byte of the
504/// Record, which the caller should pass in because they have already read it
505/// to determine that this is a metadata record as opposed to a function record.
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000506///
507/// Beginning with Version 2 of the FDR log, we do not depend on the size of the
508/// buffer, but rather use the extents to determine how far to read in the log
509/// for this particular buffer.
Dean Michael Berris10141262018-07-13 05:38:22 +0000510///
511/// In Version 3, FDR log now includes a pid metadata record after
512/// WallTimeMarker
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000513Error processFDRMetadataRecord(FDRState &State, DataExtractor &RecordExtractor,
514 uint32_t &OffsetPtr,
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000515 std::vector<XRayRecord> &Records,
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000516 uint16_t Version, uint8_t FirstByte) {
517 // The remaining 7 bits of the first byte are the RecordKind enum for each
518 // Metadata Record.
519 switch (FirstByte >> 1) {
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000520 case 0: // NewBuffer
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000521 if (auto E = processFDRNewBufferRecord(State, RecordExtractor, OffsetPtr))
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000522 return E;
523 break;
524 case 1: // EndOfBuffer
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000525 if (Version >= 2)
526 return make_error<StringError>(
527 "Since Version 2 of FDR logging, we no longer support EOB records.",
528 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000529 if (auto E = processFDREndOfBufferRecord(State, OffsetPtr))
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000530 return E;
531 break;
532 case 2: // NewCPUId
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000533 if (auto E = processFDRNewCPUIdRecord(State, RecordExtractor, OffsetPtr))
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000534 return E;
535 break;
536 case 3: // TSCWrap
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000537 if (auto E = processFDRTSCWrapRecord(State, RecordExtractor, OffsetPtr))
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000538 return E;
539 break;
540 case 4: // WallTimeMarker
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000541 if (auto E = processFDRWallTimeRecord(State, RecordExtractor, OffsetPtr))
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000542 return E;
Dean Michael Berris10141262018-07-13 05:38:22 +0000543 // In Version 3 and and above, a PidRecord is expected after WallTimeRecord
544 if (Version >= 3)
545 State.Expects = FDRState::Token::PID_RECORD;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000546 break;
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000547 case 5: // CustomEventMarker
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000548 if (auto E = processCustomEventMarker(State, RecordExtractor, OffsetPtr))
Dean Michael Berrisa7bbe442017-05-12 01:06:41 +0000549 return E;
550 break;
Martin Pelikan10c873f2017-09-27 04:48:03 +0000551 case 6: // CallArgument
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000552 if (auto E = processFDRCallArgumentRecord(State, RecordExtractor, Records,
553 OffsetPtr))
Martin Pelikan10c873f2017-09-27 04:48:03 +0000554 return E;
555 break;
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000556 case 7: // BufferExtents
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000557 if (auto E = processBufferExtents(State, RecordExtractor, OffsetPtr))
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000558 return E;
559 break;
Dean Michael Berris10141262018-07-13 05:38:22 +0000560 case 9: // Pid
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000561 if (auto E = processFDRPidRecord(State, RecordExtractor, OffsetPtr))
Dean Michael Berris10141262018-07-13 05:38:22 +0000562 return E;
563 break;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000564 default:
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000565 return createStringError(
566 std::make_error_code(std::errc::executable_format_error),
567 "Illegal metadata record type: '%d' at offset %d.", FirstByte >> 1,
568 OffsetPtr);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000569 }
570 return Error::success();
571}
572
573/// Reads a function record from an FDR format log, appending a new XRayRecord
574/// to the vector being populated and updating the State with a new value
575/// reference value to interpret TSC deltas.
576///
577/// The XRayRecord constructed includes information from the function record
578/// processed here as well as Thread ID and CPU ID formerly extracted into
579/// State.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000580Error processFDRFunctionRecord(FDRState &State, DataExtractor &RecordExtractor,
581 uint32_t &OffsetPtr, uint8_t FirstByte,
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000582 std::vector<XRayRecord> &Records) {
583 switch (State.Expects) {
584 case FDRState::Token::NEW_BUFFER_RECORD_OR_EOF:
585 return make_error<StringError>(
586 "Malformed log. Received Function Record before new buffer setup.",
587 std::make_error_code(std::errc::executable_format_error));
588 case FDRState::Token::WALLCLOCK_RECORD:
589 return make_error<StringError>(
590 "Malformed log. Received Function Record when expecting wallclock.",
591 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berris10141262018-07-13 05:38:22 +0000592 case FDRState::Token::PID_RECORD:
593 return make_error<StringError>(
594 "Malformed log. Received Function Record when expecting pid.",
595 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000596 case FDRState::Token::NEW_CPU_ID_RECORD:
597 return make_error<StringError>(
598 "Malformed log. Received Function Record before first CPU record.",
599 std::make_error_code(std::errc::executable_format_error));
600 default:
601 Records.emplace_back();
602 auto &Record = Records.back();
603 Record.RecordType = 0; // Record is type NORMAL.
604 // Strip off record type bit and use the next three bits.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000605 auto T = (FirstByte >> 1) & 0x07;
606 switch (T) {
607 case static_cast<decltype(T)>(RecordTypes::ENTER):
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000608 Record.Type = RecordTypes::ENTER;
609 break;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000610 case static_cast<decltype(T)>(RecordTypes::EXIT):
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000611 Record.Type = RecordTypes::EXIT;
612 break;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000613 case static_cast<decltype(T)>(RecordTypes::TAIL_EXIT):
Dean Michael Berris0f84a7d2017-09-18 06:08:46 +0000614 Record.Type = RecordTypes::TAIL_EXIT;
615 break;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000616 case static_cast<decltype(T)>(RecordTypes::ENTER_ARG):
617 Record.Type = RecordTypes::ENTER_ARG;
618 State.Expects = FDRState::Token::CALL_ARGUMENT;
619 break;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000620 default:
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000621 return createStringError(
622 std::make_error_code(std::errc::executable_format_error),
623 "Illegal function record type '%d' at offset %d.", T, OffsetPtr);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000624 }
625 Record.CPU = State.CPUId;
626 Record.TId = State.ThreadId;
Dean Michael Berris10141262018-07-13 05:38:22 +0000627 Record.PId = State.ProcessId;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000628
629 // Back up one byte to re-read the first byte, which is important for
630 // computing the function id for a record.
631 --OffsetPtr;
632
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000633 // Despite function Id being a signed int on XRayRecord,
634 // when it is written to an FDR format, the top bits are truncated,
635 // so it is effectively an unsigned value. When we shift off the
636 // top four bits, we want the shift to be logical, so we read as
637 // uint32_t.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000638 auto PreReadOffset = OffsetPtr;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000639 uint32_t FuncIdBitField = RecordExtractor.getU32(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000640 if (OffsetPtr == PreReadOffset)
641 return createStringError(
642 std::make_error_code(std::errc::executable_format_error),
643 "Failed reading truncated function id field at offset %d.",
644 OffsetPtr);
645
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000646 Record.FuncId = FuncIdBitField >> 4;
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000647
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000648 // FunctionRecords have a 32 bit delta from the previous absolute TSC
649 // or TSC delta. If this would overflow, we should read a TSCWrap record
650 // with an absolute TSC reading.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000651 PreReadOffset = OffsetPtr;
Martin Pelikand78db152017-09-15 04:22:16 +0000652 uint64_t NewTSC = State.BaseTSC + RecordExtractor.getU32(&OffsetPtr);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000653 if (OffsetPtr == PreReadOffset)
654 return createStringError(
655 std::make_error_code(std::errc::executable_format_error),
656 "Failed reading TSC delta at offset %d.", OffsetPtr);
657
Martin Pelikand78db152017-09-15 04:22:16 +0000658 State.BaseTSC = NewTSC;
659 Record.TSC = NewTSC;
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000660 }
661 return Error::success();
662}
663
664/// Reads a log in FDR mode for version 1 of this binary format. FDR mode is
665/// defined as part of the compiler-rt project in xray_fdr_logging.h, and such
666/// a log consists of the familiar 32 bit XRayHeader, followed by sequences of
667/// of interspersed 16 byte Metadata Records and 8 byte Function Records.
668///
669/// The following is an attempt to document the grammar of the format, which is
670/// parsed by this function for little-endian machines. Since the format makes
Martin Pelikand78db152017-09-15 04:22:16 +0000671/// use of BitFields, when we support big-endian architectures, we will need to
Simon Pilgrim68168d12017-03-30 12:59:53 +0000672/// adjust not only the endianness parameter to llvm's RecordExtractor, but also
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000673/// the bit twiddling logic, which is consistent with the little-endian
674/// convention that BitFields within a struct will first be packed into the
675/// least significant bits the address they belong to.
676///
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000677/// We expect a format complying with the grammar in the following pseudo-EBNF
678/// in Version 1 of the FDR log.
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000679///
680/// FDRLog: XRayFileHeader ThreadBuffer*
Keith Wyss3d0bc9e2017-08-02 21:47:27 +0000681/// XRayFileHeader: 32 bytes to identify the log as FDR with machine metadata.
682/// Includes BufferSize
683/// ThreadBuffer: NewBuffer WallClockTime NewCPUId FunctionSequence EOB
Dean Michael Berris60c24872017-03-29 06:10:12 +0000684/// BufSize: 8 byte unsigned integer indicating how large the buffer is.
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000685/// NewBuffer: 16 byte metadata record with Thread Id.
686/// WallClockTime: 16 byte metadata record with human readable time.
Dean Michael Berris10141262018-07-13 05:38:22 +0000687/// Pid: 16 byte metadata record with Pid
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000688/// NewCPUId: 16 byte metadata record with CPUId and a 64 bit TSC reading.
Dean Michael Berris60c24872017-03-29 06:10:12 +0000689/// EOB: 16 byte record in a thread buffer plus mem garbage to fill BufSize.
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000690/// FunctionSequence: NewCPUId | TSCWrap | FunctionRecord
691/// TSCWrap: 16 byte metadata record with a full 64 bit TSC reading.
692/// FunctionRecord: 8 byte record with FunctionId, entry/exit, and TSC delta.
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000693///
694/// In Version 2, we make the following changes:
695///
696/// ThreadBuffer: BufferExtents NewBuffer WallClockTime NewCPUId
697/// FunctionSequence
698/// BufferExtents: 16 byte metdata record describing how many usable bytes are
699/// in the buffer. This is measured from the start of the buffer
700/// and must always be at least 48 (bytes).
Dean Michael Berris10141262018-07-13 05:38:22 +0000701///
702/// In Version 3, we make the following changes:
703///
704/// ThreadBuffer: BufferExtents NewBuffer WallClockTime Pid NewCPUId
705/// FunctionSequence
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000706/// EOB: *deprecated*
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000707Error loadFDRLog(StringRef Data, bool IsLittleEndian,
708 XRayFileHeader &FileHeader, std::vector<XRayRecord> &Records) {
Dean Michael Berrisd764c1b2018-08-22 07:37:55 +0000709
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000710 if (Data.size() < 32)
711 return make_error<StringError>(
712 "Not enough bytes for an XRay log.",
713 std::make_error_code(std::errc::invalid_argument));
714
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000715 DataExtractor Reader(Data, IsLittleEndian, 8);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000716 uint32_t OffsetPtr = 0;
Dean Michael Berrisd764c1b2018-08-22 07:37:55 +0000717 auto FileHeaderOrError = readBinaryFormatHeader(Reader, OffsetPtr);
718 if (!FileHeaderOrError)
719 return FileHeaderOrError.takeError();
720 FileHeader = std::move(FileHeaderOrError.get());
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000721
Dean Michael Berris60c24872017-03-29 06:10:12 +0000722 uint64_t BufferSize = 0;
723 {
724 StringRef ExtraDataRef(FileHeader.FreeFormData, 16);
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000725 DataExtractor ExtraDataExtractor(ExtraDataRef, IsLittleEndian, 8);
Dean Michael Berris60c24872017-03-29 06:10:12 +0000726 uint32_t ExtraDataOffset = 0;
727 BufferSize = ExtraDataExtractor.getU64(&ExtraDataOffset);
728 }
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000729
730 FDRState::Token InitialExpectation;
731 switch (FileHeader.Version) {
732 case 1:
733 InitialExpectation = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF;
734 break;
735 case 2:
Dean Michael Berris10141262018-07-13 05:38:22 +0000736 case 3:
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000737 InitialExpectation = FDRState::Token::BUFFER_EXTENTS;
738 break;
739 default:
740 return make_error<StringError>(
741 Twine("Unsupported version '") + Twine(FileHeader.Version) + "'",
742 std::make_error_code(std::errc::executable_format_error));
743 }
Dean Michael Berris10141262018-07-13 05:38:22 +0000744 FDRState State{0, 0, 0, 0, InitialExpectation, BufferSize, 0};
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000745
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000746 // RecordSize will tell the loop how far to seek ahead based on the record
747 // type that we have just read.
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000748 while (Reader.isValidOffset(OffsetPtr)) {
749 auto BeginOffset = OffsetPtr;
Dean Michael Berris60c24872017-03-29 06:10:12 +0000750 if (State.Expects == FDRState::Token::SCAN_TO_END_OF_THREAD_BUF) {
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000751 OffsetPtr += State.CurrentBufferSize - State.CurrentBufferConsumed;
Dean Michael Berris60c24872017-03-29 06:10:12 +0000752 State.CurrentBufferConsumed = 0;
753 State.Expects = FDRState::Token::NEW_BUFFER_RECORD_OR_EOF;
754 continue;
755 }
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000756 auto PreReadOffset = OffsetPtr;
757 uint8_t BitField = Reader.getU8(&OffsetPtr);
758 if (OffsetPtr == PreReadOffset)
759 return createStringError(
760 std::make_error_code(std::errc::executable_format_error),
761 "Failed reading first byte of record at offset %d.", OffsetPtr);
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000762 bool isMetadataRecord = BitField & 0x01uL;
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000763 bool isBufferExtents =
764 (BitField >> 1) == 7; // BufferExtents record kind == 7
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000765 if (isMetadataRecord) {
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000766 if (auto E = processFDRMetadataRecord(State, Reader, OffsetPtr, Records,
767 FileHeader.Version, BitField))
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000768 return E;
769 } else { // Process Function Record
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000770 if (auto E = processFDRFunctionRecord(State, Reader, OffsetPtr, BitField,
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000771 Records))
772 return E;
773 }
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000774
775 // The BufferExtents record is technically not part of the buffer, so we
776 // don't count the size of that record against the buffer's actual size.
777 if (!isBufferExtents)
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000778 State.CurrentBufferConsumed += OffsetPtr - BeginOffset;
779
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000780 assert(State.CurrentBufferConsumed <= State.CurrentBufferSize);
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000781
Dean Michael Berris10141262018-07-13 05:38:22 +0000782 if ((FileHeader.Version == 2 || FileHeader.Version == 3) &&
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000783 State.CurrentBufferSize == State.CurrentBufferConsumed) {
784 // In Version 2 of the log, we don't need to scan to the end of the thread
785 // buffer if we've already consumed all the bytes we need to.
786 State.Expects = FDRState::Token::BUFFER_EXTENTS;
787 State.CurrentBufferSize = BufferSize;
788 State.CurrentBufferConsumed = 0;
789 }
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000790 }
Martin Pelikand78db152017-09-15 04:22:16 +0000791
792 // Having iterated over everything we've been given, we've either consumed
793 // everything and ended up in the end state, or were told to skip the rest.
794 bool Finished = State.Expects == FDRState::Token::SCAN_TO_END_OF_THREAD_BUF &&
Dean Michael Berris0f84a7d2017-09-18 06:08:46 +0000795 State.CurrentBufferSize == State.CurrentBufferConsumed;
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000796 if ((State.Expects != FDRState::Token::NEW_BUFFER_RECORD_OR_EOF &&
797 State.Expects != FDRState::Token::BUFFER_EXTENTS) &&
798 !Finished)
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000799 return make_error<StringError>(
Dean Michael Berris60c24872017-03-29 06:10:12 +0000800 Twine("Encountered EOF with unexpected state expectation ") +
801 fdrStateToTwine(State.Expects) +
802 ". Remaining expected bytes in thread buffer total " +
803 Twine(State.CurrentBufferSize - State.CurrentBufferConsumed),
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000804 std::make_error_code(std::errc::executable_format_error));
805
806 return Error::success();
807}
808
809Error loadYAMLLog(StringRef Data, XRayFileHeader &FileHeader,
810 std::vector<XRayRecord> &Records) {
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000811 YAMLXRayTrace Trace;
812 Input In(Data);
813 In >> Trace;
814 if (In.error())
815 return make_error<StringError>("Failed loading YAML Data.", In.error());
816
817 FileHeader.Version = Trace.Header.Version;
818 FileHeader.Type = Trace.Header.Type;
819 FileHeader.ConstantTSC = Trace.Header.ConstantTSC;
820 FileHeader.NonstopTSC = Trace.Header.NonstopTSC;
821 FileHeader.CycleFrequency = Trace.Header.CycleFrequency;
822
823 if (FileHeader.Version != 1)
824 return make_error<StringError>(
825 Twine("Unsupported XRay file version: ") + Twine(FileHeader.Version),
826 std::make_error_code(std::errc::invalid_argument));
827
828 Records.clear();
829 std::transform(Trace.Records.begin(), Trace.Records.end(),
830 std::back_inserter(Records), [&](const YAMLXRayRecord &R) {
Dean Michael Berris10141262018-07-13 05:38:22 +0000831 return XRayRecord{R.RecordType, R.CPU, R.Type, R.FuncId,
832 R.TSC, R.TId, R.PId, R.CallArgs};
Dean Michael Berrisf8f909f2017-01-10 02:38:11 +0000833 });
834 return Error::success();
835}
Benjamin Kramer49a49fe2017-08-20 13:03:48 +0000836} // namespace
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000837
838Expected<Trace> llvm::xray::loadTraceFile(StringRef Filename, bool Sort) {
839 int Fd;
840 if (auto EC = sys::fs::openFileForRead(Filename, Fd)) {
841 return make_error<StringError>(
842 Twine("Cannot read log from '") + Filename + "'", EC);
843 }
844
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000845 uint64_t FileSize;
846 if (auto EC = sys::fs::file_size(Filename, FileSize)) {
847 return make_error<StringError>(
848 Twine("Cannot read log from '") + Filename + "'", EC);
849 }
850 if (FileSize < 4) {
851 return make_error<StringError>(
852 Twine("File '") + Filename + "' too small for XRay.",
Hans Wennborg84da6612017-01-12 18:33:14 +0000853 std::make_error_code(std::errc::executable_format_error));
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000854 }
855
Martin Pelikand78db152017-09-15 04:22:16 +0000856 // Map the opened file into memory and use a StringRef to access it later.
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000857 std::error_code EC;
858 sys::fs::mapped_file_region MappedFile(
859 Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
860 if (EC) {
861 return make_error<StringError>(
862 Twine("Cannot read log from '") + Filename + "'", EC);
863 }
Martin Pelikand78db152017-09-15 04:22:16 +0000864 auto Data = StringRef(MappedFile.data(), MappedFile.size());
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000865
866 // TODO: Lift the endianness and implementation selection here.
867 DataExtractor LittleEndianDE(Data, true, 8);
868 auto TraceOrError = loadTrace(LittleEndianDE, Sort);
869 if (!TraceOrError) {
870 DataExtractor BigEndianDE(Data, false, 8);
871 TraceOrError = loadTrace(BigEndianDE, Sort);
872 }
873 return TraceOrError;
Dean Michael Berrisf81b0802018-08-24 10:30:37 +0000874}
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000875
Dean Michael Berrisf81b0802018-08-24 10:30:37 +0000876Expected<Trace> llvm::xray::loadTrace(const DataExtractor &DE, bool Sort) {
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000877 // Attempt to detect the file type using file magic. We have a slight bias
878 // towards the binary format, and we do this by making sure that the first 4
879 // bytes of the binary file is some combination of the following byte
Martin Pelikand78db152017-09-15 04:22:16 +0000880 // patterns: (observe the code loading them assumes they're little endian)
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000881 //
Martin Pelikand78db152017-09-15 04:22:16 +0000882 // 0x01 0x00 0x00 0x00 - version 1, "naive" format
883 // 0x01 0x00 0x01 0x00 - version 1, "flight data recorder" format
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000884 // 0x02 0x00 0x01 0x00 - version 2, "flight data recorder" format
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000885 //
Martin Pelikand78db152017-09-15 04:22:16 +0000886 // YAML files don't typically have those first four bytes as valid text so we
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000887 // try loading assuming YAML if we don't find these bytes.
888 //
889 // Only if we can't load either the binary or the YAML format will we yield an
890 // error.
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000891 DataExtractor HeaderExtractor(DE.getData(), DE.isLittleEndian(), 8);
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000892 uint32_t OffsetPtr = 0;
893 uint16_t Version = HeaderExtractor.getU16(&OffsetPtr);
894 uint16_t Type = HeaderExtractor.getU16(&OffsetPtr);
895
Dean Michael Berris4f83c4d2017-02-17 01:47:16 +0000896 enum BinaryFormatType { NAIVE_FORMAT = 0, FLIGHT_DATA_RECORDER_FORMAT = 1 };
897
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000898 Trace T;
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000899 switch (Type) {
900 case NAIVE_FORMAT:
Dean Michael Berris10141262018-07-13 05:38:22 +0000901 if (Version == 1 || Version == 2 || Version == 3) {
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000902 if (auto E = loadNaiveFormatLog(DE.getData(), DE.isLittleEndian(),
903 T.FileHeader, T.Records))
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000904 return std::move(E);
905 } else {
906 return make_error<StringError>(
907 Twine("Unsupported version for Basic/Naive Mode logging: ") +
908 Twine(Version),
909 std::make_error_code(std::errc::executable_format_error));
910 }
911 break;
912 case FLIGHT_DATA_RECORDER_FORMAT:
Dean Michael Berris10141262018-07-13 05:38:22 +0000913 if (Version == 1 || Version == 2 || Version == 3) {
Dean Michael Berris5b7548c2018-08-31 17:06:28 +0000914 if (auto E = loadFDRLog(DE.getData(), DE.isLittleEndian(), T.FileHeader,
915 T.Records))
Dean Michael Berris6ec72622017-11-21 07:16:57 +0000916 return std::move(E);
917 } else {
918 return make_error<StringError>(
919 Twine("Unsupported version for FDR Mode logging: ") + Twine(Version),
920 std::make_error_code(std::errc::executable_format_error));
921 }
922 break;
923 default:
Dean Michael Berrisf81b0802018-08-24 10:30:37 +0000924 if (auto E = loadYAMLLog(DE.getData(), T.FileHeader, T.Records))
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000925 return std::move(E);
926 }
927
928 if (Sort)
Mandeep Singh Grang28f3d5c2017-11-14 18:11:08 +0000929 std::stable_sort(T.Records.begin(), T.Records.end(),
Dean Michael Berrisa9d477a2018-08-07 04:42:39 +0000930 [&](const XRayRecord &L, const XRayRecord &R) {
931 return L.TSC < R.TSC;
932 });
Dean Michael Berrisd6c18652017-01-11 06:39:09 +0000933
934 return std::move(T);
935}