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