1 //===- xray-fdr-dump.cpp: XRay FDR Trace Dump Tool ------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Implements the FDR trace dumping tool, using the libraries for handling FDR 10 // mode traces specifically. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "xray-registry.h" 14 #include "llvm/Support/CommandLine.h" 15 #include "llvm/Support/FileSystem.h" 16 #include "llvm/XRay/BlockIndexer.h" 17 #include "llvm/XRay/BlockPrinter.h" 18 #include "llvm/XRay/BlockVerifier.h" 19 #include "llvm/XRay/FDRRecordConsumer.h" 20 #include "llvm/XRay/FDRRecordProducer.h" 21 #include "llvm/XRay/FDRRecords.h" 22 #include "llvm/XRay/FileHeaderReader.h" 23 #include "llvm/XRay/RecordPrinter.h" 24 25 using namespace llvm; 26 using namespace xray; 27 28 static cl::SubCommand Dump("fdr-dump", "FDR Trace Dump"); 29 static cl::opt<std::string> DumpInput(cl::Positional, 30 cl::desc("<xray fdr mode log>"), 31 cl::Required, cl::sub(Dump)); 32 static cl::opt<bool> DumpVerify("verify", 33 cl::desc("verify structure of the log"), 34 cl::init(false), cl::sub(Dump)); 35 36 static CommandRegistration Unused(&Dump, []() -> Error { 37 // Open the file provided. 38 auto FDOrErr = sys::fs::openNativeFileForRead(DumpInput); 39 if (!FDOrErr) 40 return FDOrErr.takeError(); 41 42 uint64_t FileSize; 43 if (auto EC = sys::fs::file_size(DumpInput, FileSize)) 44 return createStringError(EC, "Failed to get file size for '%s'.", 45 DumpInput.c_str()); 46 47 std::error_code EC; 48 sys::fs::mapped_file_region MappedFile( 49 *FDOrErr, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, 50 EC); 51 sys::fs::closeFile(*FDOrErr); 52 53 DataExtractor DE(StringRef(MappedFile.data(), MappedFile.size()), true, 8); 54 uint64_t OffsetPtr = 0; 55 56 auto FileHeaderOrError = readBinaryFormatHeader(DE, OffsetPtr); 57 if (!FileHeaderOrError) 58 return FileHeaderOrError.takeError(); 59 auto &H = FileHeaderOrError.get(); 60 61 FileBasedRecordProducer P(H, DE, OffsetPtr); 62 63 RecordPrinter RP(outs(), "\n"); 64 if (!DumpVerify) { 65 PipelineConsumer C({&RP}); 66 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) { 67 auto R = P.produce(); 68 if (!R) 69 return R.takeError(); 70 if (auto E = C.consume(std::move(R.get()))) 71 return E; 72 } 73 return Error::success(); 74 } 75 76 BlockPrinter BP(outs(), RP); 77 std::vector<std::unique_ptr<Record>> Records; 78 LogBuilderConsumer C(Records); 79 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) { 80 auto R = P.produce(); 81 if (!R) { 82 // Print records we've found so far. 83 for (auto &Ptr : Records) 84 if (auto E = Ptr->apply(RP)) 85 return joinErrors(std::move(E), R.takeError()); 86 return R.takeError(); 87 } 88 if (auto E = C.consume(std::move(R.get()))) 89 return E; 90 } 91 92 // Once we have a trace, we then index the blocks. 93 BlockIndexer::Index Index; 94 BlockIndexer BI(Index); 95 for (auto &Ptr : Records) 96 if (auto E = Ptr->apply(BI)) 97 return E; 98 99 if (auto E = BI.flush()) 100 return E; 101 102 // Then we validate while printing each block. 103 BlockVerifier BV; 104 for (auto ProcessThreadBlocks : Index) { 105 auto &Blocks = ProcessThreadBlocks.second; 106 for (auto &B : Blocks) { 107 for (auto *R : B.Records) { 108 if (auto E = R->apply(BV)) 109 return E; 110 if (auto E = R->apply(BP)) 111 return E; 112 } 113 BV.reset(); 114 BP.reset(); 115 } 116 } 117 outs().flush(); 118 return Error::success(); 119 }); 120