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