xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-xray/xray-extract.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- xray-extract.cpp: XRay Instrumentation Map Extraction --------------===//
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 // Implementation of the xray-extract.h interface.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric // FIXME: Support other XRay-instrumented binary formats other than ELF.
12*0b57cec5SDimitry Andric //
13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric #include "func-id-helper.h"
17*0b57cec5SDimitry Andric #include "xray-registry.h"
18*0b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/Error.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
22*0b57cec5SDimitry Andric #include "llvm/Support/Format.h"
23*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
24*0b57cec5SDimitry Andric #include "llvm/XRay/InstrumentationMap.h"
25*0b57cec5SDimitry Andric 
26*0b57cec5SDimitry Andric using namespace llvm;
27*0b57cec5SDimitry Andric using namespace llvm::xray;
28*0b57cec5SDimitry Andric using namespace llvm::yaml;
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric // llvm-xray extract
31*0b57cec5SDimitry Andric // ----------------------------------------------------------------------------
32*0b57cec5SDimitry Andric static cl::SubCommand Extract("extract", "Extract instrumentation maps");
33*0b57cec5SDimitry Andric static cl::opt<std::string> ExtractInput(cl::Positional,
34*0b57cec5SDimitry Andric                                          cl::desc("<input file>"), cl::Required,
35*0b57cec5SDimitry Andric                                          cl::sub(Extract));
36*0b57cec5SDimitry Andric static cl::opt<std::string>
37*0b57cec5SDimitry Andric     ExtractOutput("output", cl::value_desc("output file"), cl::init("-"),
38*0b57cec5SDimitry Andric                   cl::desc("output file; use '-' for stdout"),
39*0b57cec5SDimitry Andric                   cl::sub(Extract));
40*0b57cec5SDimitry Andric static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
41*0b57cec5SDimitry Andric                                 cl::desc("Alias for -output"),
42*0b57cec5SDimitry Andric                                 cl::sub(Extract));
43*0b57cec5SDimitry Andric static cl::opt<bool> ExtractSymbolize("symbolize", cl::value_desc("symbolize"),
44*0b57cec5SDimitry Andric                                       cl::init(false),
45*0b57cec5SDimitry Andric                                       cl::desc("symbolize functions"),
46*0b57cec5SDimitry Andric                                       cl::sub(Extract));
47*0b57cec5SDimitry Andric static cl::alias ExtractSymbolize2("s", cl::aliasopt(ExtractSymbolize),
48*0b57cec5SDimitry Andric                                    cl::desc("alias for -symbolize"),
49*0b57cec5SDimitry Andric                                    cl::sub(Extract));
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric namespace {
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS,
54*0b57cec5SDimitry Andric                   FuncIdConversionHelper &FH) {
55*0b57cec5SDimitry Andric   // First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
56*0b57cec5SDimitry Andric   std::vector<YAMLXRaySledEntry> YAMLSleds;
57*0b57cec5SDimitry Andric   auto Sleds = Map.sleds();
58*0b57cec5SDimitry Andric   YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end()));
59*0b57cec5SDimitry Andric   for (const auto &Sled : Sleds) {
60*0b57cec5SDimitry Andric     auto FuncId = Map.getFunctionId(Sled.Function);
61*0b57cec5SDimitry Andric     if (!FuncId)
62*0b57cec5SDimitry Andric       return;
63*0b57cec5SDimitry Andric     YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind,
64*0b57cec5SDimitry Andric                          Sled.AlwaysInstrument,
65*0b57cec5SDimitry Andric                          ExtractSymbolize ? FH.SymbolOrNumber(*FuncId) : ""});
66*0b57cec5SDimitry Andric   }
67*0b57cec5SDimitry Andric   Output Out(OS, nullptr, 0);
68*0b57cec5SDimitry Andric   Out << YAMLSleds;
69*0b57cec5SDimitry Andric }
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric } // namespace
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric static CommandRegistration Unused(&Extract, []() -> Error {
74*0b57cec5SDimitry Andric   auto InstrumentationMapOrError = loadInstrumentationMap(ExtractInput);
75*0b57cec5SDimitry Andric   if (!InstrumentationMapOrError)
76*0b57cec5SDimitry Andric     return joinErrors(make_error<StringError>(
77*0b57cec5SDimitry Andric                           Twine("Cannot extract instrumentation map from '") +
78*0b57cec5SDimitry Andric                               ExtractInput + "'.",
79*0b57cec5SDimitry Andric                           std::make_error_code(std::errc::invalid_argument)),
80*0b57cec5SDimitry Andric                       InstrumentationMapOrError.takeError());
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric   std::error_code EC;
83*0b57cec5SDimitry Andric   raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text);
84*0b57cec5SDimitry Andric   if (EC)
85*0b57cec5SDimitry Andric     return make_error<StringError>(
86*0b57cec5SDimitry Andric         Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
87*0b57cec5SDimitry Andric   const auto &FunctionAddresses =
88*0b57cec5SDimitry Andric       InstrumentationMapOrError->getFunctionAddresses();
89*0b57cec5SDimitry Andric   symbolize::LLVMSymbolizer Symbolizer;
90*0b57cec5SDimitry Andric   llvm::xray::FuncIdConversionHelper FuncIdHelper(ExtractInput, Symbolizer,
91*0b57cec5SDimitry Andric                                                   FunctionAddresses);
92*0b57cec5SDimitry Andric   exportAsYAML(*InstrumentationMapOrError, OS, FuncIdHelper);
93*0b57cec5SDimitry Andric   return Error::success();
94*0b57cec5SDimitry Andric });
95