xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-xray/xray-fdr-dump.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- xray-fdr-dump.cpp: XRay FDR Trace Dump Tool ------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Implements the FDR trace dumping tool, using the libraries for handling FDR
100b57cec5SDimitry Andric // mode traces specifically.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric #include "xray-registry.h"
140b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
150b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
160b57cec5SDimitry Andric #include "llvm/XRay/BlockIndexer.h"
170b57cec5SDimitry Andric #include "llvm/XRay/BlockPrinter.h"
180b57cec5SDimitry Andric #include "llvm/XRay/BlockVerifier.h"
190b57cec5SDimitry Andric #include "llvm/XRay/FDRRecordConsumer.h"
200b57cec5SDimitry Andric #include "llvm/XRay/FDRRecordProducer.h"
210b57cec5SDimitry Andric #include "llvm/XRay/FDRRecords.h"
220b57cec5SDimitry Andric #include "llvm/XRay/FileHeaderReader.h"
230b57cec5SDimitry Andric #include "llvm/XRay/RecordPrinter.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric using namespace xray;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric static cl::SubCommand Dump("fdr-dump", "FDR Trace Dump");
290b57cec5SDimitry Andric static cl::opt<std::string> DumpInput(cl::Positional,
300b57cec5SDimitry Andric                                       cl::desc("<xray fdr mode log>"),
310b57cec5SDimitry Andric                                       cl::Required, cl::sub(Dump));
320b57cec5SDimitry Andric static cl::opt<bool> DumpVerify("verify",
330b57cec5SDimitry Andric                                 cl::desc("verify structure of the log"),
340b57cec5SDimitry Andric                                 cl::init(false), cl::sub(Dump));
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric static CommandRegistration Unused(&Dump, []() -> Error {
370b57cec5SDimitry Andric   // Open the file provided.
380b57cec5SDimitry Andric   auto FDOrErr = sys::fs::openNativeFileForRead(DumpInput);
390b57cec5SDimitry Andric   if (!FDOrErr)
400b57cec5SDimitry Andric     return FDOrErr.takeError();
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   uint64_t FileSize;
430b57cec5SDimitry Andric   if (auto EC = sys::fs::file_size(DumpInput, FileSize))
440b57cec5SDimitry Andric     return createStringError(EC, "Failed to get file size for '%s'.",
450b57cec5SDimitry Andric                              DumpInput.c_str());
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   std::error_code EC;
480b57cec5SDimitry Andric   sys::fs::mapped_file_region MappedFile(
490b57cec5SDimitry Andric       *FDOrErr, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0,
500b57cec5SDimitry Andric       EC);
510b57cec5SDimitry Andric   sys::fs::closeFile(*FDOrErr);
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   DataExtractor DE(StringRef(MappedFile.data(), MappedFile.size()), true, 8);
548bcb0991SDimitry Andric   uint64_t OffsetPtr = 0;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   auto FileHeaderOrError = readBinaryFormatHeader(DE, OffsetPtr);
570b57cec5SDimitry Andric   if (!FileHeaderOrError)
580b57cec5SDimitry Andric     return FileHeaderOrError.takeError();
590b57cec5SDimitry Andric   auto &H = FileHeaderOrError.get();
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   FileBasedRecordProducer P(H, DE, OffsetPtr);
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   RecordPrinter RP(outs(), "\n");
640b57cec5SDimitry Andric   if (!DumpVerify) {
650b57cec5SDimitry Andric     PipelineConsumer C({&RP});
660b57cec5SDimitry Andric     while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {
670b57cec5SDimitry Andric       auto R = P.produce();
680b57cec5SDimitry Andric       if (!R)
690b57cec5SDimitry Andric         return R.takeError();
700b57cec5SDimitry Andric       if (auto E = C.consume(std::move(R.get())))
710b57cec5SDimitry Andric         return E;
720b57cec5SDimitry Andric     }
730b57cec5SDimitry Andric     return Error::success();
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   BlockPrinter BP(outs(), RP);
770b57cec5SDimitry Andric   std::vector<std::unique_ptr<Record>> Records;
780b57cec5SDimitry Andric   LogBuilderConsumer C(Records);
790b57cec5SDimitry Andric   while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {
800b57cec5SDimitry Andric     auto R = P.produce();
810b57cec5SDimitry Andric     if (!R) {
820b57cec5SDimitry Andric       // Print records we've found so far.
830b57cec5SDimitry Andric       for (auto &Ptr : Records)
840b57cec5SDimitry Andric         if (auto E = Ptr->apply(RP))
850b57cec5SDimitry Andric           return joinErrors(std::move(E), R.takeError());
860b57cec5SDimitry Andric       return R.takeError();
870b57cec5SDimitry Andric     }
880b57cec5SDimitry Andric     if (auto E = C.consume(std::move(R.get())))
890b57cec5SDimitry Andric       return E;
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   // Once we have a trace, we then index the blocks.
930b57cec5SDimitry Andric   BlockIndexer::Index Index;
940b57cec5SDimitry Andric   BlockIndexer BI(Index);
950b57cec5SDimitry Andric   for (auto &Ptr : Records)
960b57cec5SDimitry Andric     if (auto E = Ptr->apply(BI))
970b57cec5SDimitry Andric       return E;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   if (auto E = BI.flush())
1000b57cec5SDimitry Andric     return E;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Then we validate while printing each block.
1030b57cec5SDimitry Andric   BlockVerifier BV;
104*5f757f3fSDimitry Andric   for (const auto &ProcessThreadBlocks : Index) {
1050b57cec5SDimitry Andric     auto &Blocks = ProcessThreadBlocks.second;
1060b57cec5SDimitry Andric     for (auto &B : Blocks) {
1070b57cec5SDimitry Andric       for (auto *R : B.Records) {
1080b57cec5SDimitry Andric         if (auto E = R->apply(BV))
1090b57cec5SDimitry Andric           return E;
1100b57cec5SDimitry Andric         if (auto E = R->apply(BP))
1110b57cec5SDimitry Andric           return E;
1120b57cec5SDimitry Andric       }
1130b57cec5SDimitry Andric       BV.reset();
1140b57cec5SDimitry Andric       BP.reset();
1150b57cec5SDimitry Andric     }
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric   outs().flush();
1180b57cec5SDimitry Andric   return Error::success();
1190b57cec5SDimitry Andric });
120