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
25using namespace llvm;
26using namespace xray;
27
28static cl::SubCommand Dump("fdr-dump", "FDR Trace Dump");
29static cl::opt<std::string> DumpInput(cl::Positional,
30                                      cl::desc("<xray fdr mode log>"),
31                                      cl::Required, cl::sub(Dump));
32static cl::opt<bool> DumpVerify("verify",
33                                cl::desc("verify structure of the log"),
34                                cl::init(false), cl::sub(Dump));
35
36static 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