llvm.org GIT mirror llvm / 433938a
[XRay] Implement `llvm-xray extract`, start of the llvm-xray tool Usage: llvm-xray extract <object file> [-o <filename or '-'>] The tool gets the XRay instrumentation map from an object file and turns it into YAML. We first support ELF64 sleds on x86_64 binaries, with provision for supporting other supported platforms and formats later. This is the first of a many-part change to fully implement the `llvm-xray` tool. We also define a subcommand registration and dispatch mechanism to be used by other further subcommand implementations for llvm-xray. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285155 91177308-0d34-0410-b5e6-96231b3b80d8 Dean Michael Berris 3 years ago
19 changed file(s) with 494 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 ; RUN: not llvm-xray extract %S/Inputs/elf64-badentrysizes.bin 2>&1 | FileCheck %s
1 ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf64-badentrysizes.bin'.
2 ; CHECK-NEXT: Instrumentation map entries not evenly divisible by size of an XRay sled entry in ELF64.
0 ; RUN: not llvm-xray extract %S/Inputs/empty-file.bin 2>&1 | FileCheck %s
1
2 ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}empty-file.bin'.
3 ; CHECK-NEXT: The file was not recognized as a valid object file
0 ; This test makes sure we can extract the instrumentation map from an
1 ; XRay-instrumented object file.
2 ;
3 ; RUN: llvm-xray extract %S/Inputs/elf64-example.bin | FileCheck %s
4
5 ; CHECK: ---
6 ; CHECK-NEXT: - { id: 1, address: 0x000000000041C900, function: 0x000000000041C900, kind: function-enter,
7 ; CHECK-NEXT: always-instrument: true }
8 ; CHECK-NEXT: - { id: 1, address: 0x000000000041C912, function: 0x000000000041C900, kind: function-exit,
9 ; CHECK-NEXT: always-instrument: true }
10 ; CHECK-NEXT: - { id: 2, address: 0x000000000041C930, function: 0x000000000041C930, kind: function-enter,
11 ; CHECK-NEXT: always-instrument: true }
12 ; CHECK-NEXT: - { id: 2, address: 0x000000000041C946, function: 0x000000000041C930, kind: function-exit,
13 ; CHECK-NEXT: always-instrument: true }
14 ; CHECK-NEXT: ...
0 config.suffixes = ['.yaml', '.ll', '.txt']
0 ; RUN: not llvm-xray extract %S/Inputs/elf64-noinstr-map.bin 2>&1 | FileCheck %s
1
2 ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf64-noinstr-map.bin'.
3 ; CHECK-NEXT: Failed to find XRay instrumentation map.
0 ; RUN: not llvm-xray extract no-such-file 2>&1 | FileCheck %s
1
2 ; CHECK: llvm-xray: Cannot extract instrumentation map from 'no-such-file'.
3 ; CHECK-NEXT: No such file or directory
0 ; RUN: not llvm-xray extract %S/Inputs/elf32-noxray.bin 2>&1 | FileCheck %s
1 ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf32-noxray.bin'.
2 ; CHECK-NEXT: File format not supported (only does ELF little endian 64-bit).
0 set(LLVM_LINK_COMPONENTS
1 ${LLVM_TARGETS_TO_BUILD}
2 Support
3 Object)
4
5 set(LLVM_XRAY_TOOLS
6 xray-extract.cc
7 xray-registry.cc)
8
9 add_llvm_tool(llvm-xray llvm-xray.cc ${LLVM_XRAY_TOOLS})
0 //===- llvm-xray.cc - XRay Tool Main Program ------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the main entry point for the suite of XRay tools. All
10 // additional functionality are implemented as subcommands.
11 //
12 //===----------------------------------------------------------------------===//
13 //
14 // Basic usage:
15 //
16 // llvm-xray [options] [subcommand-specific options]
17 //
18 #include "xray-registry.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include
23
24 using namespace llvm;
25 using namespace llvm::xray;
26
27 int main(int argc, char *argv[]) {
28 cl::ParseCommandLineOptions(argc, argv,
29 "XRay Tools\n\n"
30 " This program consolidates multiple XRay trace "
31 "processing tools for convenient access.\n");
32 for (auto *SC : cl::getRegisteredSubcommands()) {
33 if (*SC)
34 if (auto C = dispatch(SC)) {
35 ExitOnError("llvm-xray: ")(C());
36 return 0;
37 }
38 }
39
40 cl::PrintHelpMessage(false, true);
41 }
0 //===- xray-extract.cc - XRay Instrumentation Map Extraction --------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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 #include
16 #include
17 #include
18
19 #include "xray-extract.h"
20
21 #include "xray-registry.h"
22 #include "xray-sleds.h"
23 #include "llvm/Object/ELF.h"
24 #include "llvm/Object/ObjectFile.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/DataExtractor.h"
27 #include "llvm/Support/ELF.h"
28 #include "llvm/Support/Error.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Format.h"
31 #include "llvm/Support/YAMLTraits.h"
32 #include "llvm/Support/raw_ostream.h"
33
34 using namespace llvm;
35 using namespace llvm::xray;
36 using namespace llvm::yaml;
37
38 // llvm-xray extract
39 // ----------------------------------------------------------------------------
40 static cl::SubCommand Extract("extract", "Extract instrumentation maps");
41 static cl::opt ExtractInput(cl::Positional,
42 cl::desc(""), cl::Required,
43 cl::sub(Extract));
44 static cl::opt
45 ExtractOutput("output", cl::value_desc("output file"), cl::init("-"),
46 cl::desc("output file; use '-' for stdout"),
47 cl::sub(Extract));
48 static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
49 cl::desc("Alias for -output"),
50 cl::sub(Extract));
51
52 struct YAMLXRaySledEntry {
53 int32_t FuncId;
54 Hex64 Address;
55 Hex64 Function;
56 SledEntry::FunctionKinds Kind;
57 bool AlwaysInstrument;
58 };
59
60 template <> struct ScalarEnumerationTraits {
61 static void enumeration(IO &IO, SledEntry::FunctionKinds &Kind) {
62 IO.enumCase(Kind, "function-enter", SledEntry::FunctionKinds::ENTRY);
63 IO.enumCase(Kind, "function-exit", SledEntry::FunctionKinds::EXIT);
64 IO.enumCase(Kind, "tail-exit", SledEntry::FunctionKinds::TAIL);
65 }
66 };
67
68 template <> struct MappingTraits {
69 static void mapping(IO &IO, YAMLXRaySledEntry &Entry) {
70 IO.mapRequired("id", Entry.FuncId);
71 IO.mapRequired("address", Entry.Address);
72 IO.mapRequired("function", Entry.Function);
73 IO.mapRequired("kind", Entry.Kind);
74 IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
75 }
76
77 static constexpr bool flow = true;
78 };
79
80 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLXRaySledEntry);
81
82 namespace {
83
84 llvm::Error LoadBinaryInstrELF(
85 StringRef Filename, std::deque &OutputSleds,
86 InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
87 InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
88 auto ObjectFile = object::ObjectFile::createObjectFile(Filename);
89
90 if (!ObjectFile)
91 return ObjectFile.takeError();
92
93 // FIXME: Maybe support other ELF formats. For now, 64-bit Little Endian only.
94 if (!ObjectFile->getBinary()->isELF())
95 return make_error(
96 "File format not supported (only does ELF).",
97 std::make_error_code(std::errc::not_supported));
98 if (ObjectFile->getBinary()->getArch() != Triple::x86_64)
99 return make_error(
100 "File format not supported (only does ELF little endian 64-bit).",
101 std::make_error_code(std::errc::not_supported));
102
103 // Find the section named "xray_instr_map".
104 StringRef Contents = "";
105 const auto &Sections = ObjectFile->getBinary()->sections();
106 auto I = find_if(Sections, [&](object::SectionRef Section) {
107 StringRef Name = "";
108 if (Section.getName(Name))
109 return false;
110 return Name == "xray_instr_map";
111 });
112 if (I == Sections.end())
113 return make_error(
114 "Failed to find XRay instrumentation map.",
115 std::make_error_code(std::errc::not_supported));
116 if (I->getContents(Contents))
117 return make_error(
118 "Failed to get contents of 'xray_instr_map' section.",
119 std::make_error_code(std::errc::executable_format_error));
120
121 // Copy the instrumentation map data into the Sleds data structure.
122 auto C = Contents.bytes_begin();
123 static constexpr size_t ELF64SledEntrySize = 32;
124
125 if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
126 return make_error(
127 "Instrumentation map entries not evenly divisible by size of an XRay "
128 "sled entry in ELF64.",
129 std::make_error_code(std::errc::executable_format_error));
130
131 int32_t FuncId = 1;
132 uint64_t CurFn = 0;
133 std::deque Sleds;
134 for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
135 DataExtractor Extractor(
136 StringRef(reinterpret_cast(C), ELF64SledEntrySize), true,
137 8);
138 Sleds.push_back({});
139 auto &Entry = Sleds.back();
140 uint32_t OffsetPtr = 0;
141 Entry.Address = Extractor.getU64(&OffsetPtr);
142 Entry.Function = Extractor.getU64(&OffsetPtr);
143 auto Kind = Extractor.getU8(&OffsetPtr);
144 switch (Kind) {
145 case 0: // ENTRY
146 Entry.Kind = SledEntry::FunctionKinds::ENTRY;
147 break;
148 case 1: // EXIT
149 Entry.Kind = SledEntry::FunctionKinds::EXIT;
150 break;
151 case 2: // TAIL
152 Entry.Kind = SledEntry::FunctionKinds::TAIL;
153 break;
154 default:
155 return make_error(
156 Twine("Encountered unknown sled type ") + "'" + Twine(int32_t{Kind}) +
157 "'.",
158 std::make_error_code(std::errc::protocol_error));
159 }
160 auto AlwaysInstrument = Extractor.getU8(&OffsetPtr);
161 Entry.AlwaysInstrument = AlwaysInstrument != 0;
162
163 // We replicate the function id generation scheme implemented in the runtime
164 // here. Ideally we should be able to break it out, or output this map from
165 // the runtime, but that's a design point we can discuss later on. For now,
166 // we replicate the logic and move on.
167 if (CurFn == 0) {
168 CurFn = Entry.Function;
169 InstrMap[FuncId] = Entry.Function;
170 FunctionIds[Entry.Function] = FuncId;
171 }
172 if (Entry.Function != CurFn) {
173 ++FuncId;
174 CurFn = Entry.Function;
175 InstrMap[FuncId] = Entry.Function;
176 FunctionIds[Entry.Function] = FuncId;
177 }
178 }
179 OutputSleds = std::move(Sleds);
180 return llvm::Error::success();
181 }
182
183 } // namespace
184
185 InstrumentationMapExtractor::InstrumentationMapExtractor(std::string Filename,
186 InputFormats Format,
187 Error &EC) {
188 ErrorAsOutParameter ErrAsOutputParam(&EC);
189 switch (Format) {
190 case InputFormats::ELF: {
191 EC = handleErrors(
192 LoadBinaryInstrELF(Filename, Sleds, FunctionAddresses, FunctionIds),
193 [](std::unique_ptr E) {
194 return joinErrors(
195 make_error(
196 Twine("Cannot extract instrumentation map from '") +
197 ExtractInput + "'.",
198 std::make_error_code(std::errc::protocol_error)),
199 std::move(E));
200 });
201 break;
202 }
203 default:
204 llvm_unreachable("Input format type not supported yet.");
205 break;
206 }
207 }
208
209 void InstrumentationMapExtractor::exportAsYAML(raw_ostream &OS) {
210 // First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
211 std::vector YAMLSleds;
212 YAMLSleds.reserve(Sleds.size());
213 for (const auto &Sled : Sleds) {
214 YAMLSleds.push_back({FunctionIds[Sled.Function], Sled.Address,
215 Sled.Function, Sled.Kind, Sled.AlwaysInstrument});
216 }
217 Output Out(OS);
218 Out << YAMLSleds;
219 }
220
221 static CommandRegistration Unused(&Extract, [] {
222 Error Err;
223 xray::InstrumentationMapExtractor Extractor(
224 ExtractInput, InstrumentationMapExtractor::InputFormats::ELF, Err);
225 if (Err)
226 return Err;
227
228 std::error_code EC;
229 raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text);
230 if (EC)
231 return make_error(
232 Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
233 Extractor.exportAsYAML(OS);
234 return Error::success();
235 });
0 //===- xray-extract.h - XRay Instrumentation Map Extraction ---------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Defines the interface for extracting the instrumentation map from an
10 // XRay-instrumented binary.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_TOOLS_XRAY_EXTRACT_H
15 #define LLVM_TOOLS_XRAY_EXTRACT_H
16
17 #include
18 #include
19 #include
20 #include
21
22 #include "xray-sleds.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/raw_ostream.h"
25
26 namespace llvm {
27 namespace xray {
28
29 class InstrumentationMapExtractor {
30 public:
31 typedef std::unordered_map FunctionAddressMap;
32 typedef std::unordered_map FunctionAddressReverseMap;
33
34 enum class InputFormats { ELF, YAML };
35
36 private:
37 std::deque Sleds;
38 FunctionAddressMap FunctionAddresses;
39 FunctionAddressReverseMap FunctionIds;
40
41 public:
42 /// Loads the instrumentation map from |Filename|. Updates |EC| in case there
43 /// were errors encountered opening the file. |Format| defines what the input
44 /// instrumentation map is in.
45 InstrumentationMapExtractor(std::string Filename, InputFormats Format,
46 Error &EC);
47
48 const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; }
49
50 /// Exports the loaded function address map as YAML through |OS|.
51 void exportAsYAML(raw_ostream &OS);
52 };
53
54 } // namespace xray
55 } // namespace llvm
56
57 #endif // LLVM_TOOLS_XRAY_EXTRACT_H
0 //===- xray-registry.cc - Implement a command registry. -------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implement a simple subcommand registry.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "xray-registry.h"
13
14 #include "llvm/Support/ManagedStatic.h"
15 #include
16
17 namespace llvm {
18 namespace xray {
19
20 using HandlerType = std::function;
21
22 ManagedStatic> Commands;
23
24 CommandRegistration::CommandRegistration(cl::SubCommand *SC,
25 HandlerType Command) {
26 assert(Commands->count(SC) == 0 &&
27 "Attempting to overwrite a command handler");
28 assert(Command && "Attempting to register an empty std::function");
29 (*Commands)[SC] = Command;
30 }
31
32 HandlerType dispatch(cl::SubCommand *SC) {
33 auto It = Commands->find(SC);
34 assert(It != Commands->end() &&
35 "Attempting to dispatch on un-registered SubCommand.");
36 return It->second;
37 }
38
39 } // namespace xray
40 } // namespace llvm
0 //===- xray-registry.h - Define registry mechanism for commands. ----------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implement a simple subcommand registry.
10 //
11 //===----------------------------------------------------------------------===//
12 #ifndef TOOLS_LLVM_XRAY_XRAY_REGISTRY_H
13 #define TOOLS_LLVM_XRAY_XRAY_REGISTRY_H
14
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/Error.h"
17
18 namespace llvm {
19 namespace xray {
20
21 // Use |CommandRegistration| as a global initialiser that registers a function
22 // and associates it with |SC|. This requires that a command has not been
23 // registered to a given |SC|.
24 //
25 // Usage:
26 //
27 // // At namespace scope.
28 // static CommandRegistration Unused(&MySubCommand, [] { ... });
29 //
30 struct CommandRegistration {
31 CommandRegistration(cl::SubCommand *SC, std::function Command);
32 };
33
34 // Requires that |SC| is not null and has an associated function to it.
35 std::function dispatch(cl::SubCommand *SC);
36
37 } // namespace xray
38 } // namespace llvm
39
40 #endif // TOOLS_LLVM_XRAY_XRAY_REGISTRY_H
0 //===- xray-sleds.h - XRay Sleds Data Structure ---------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Defines the structure used to represent XRay instrumentation map entries.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
14 #define LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
15
16 namespace llvm {
17 namespace xray {
18
19 struct SledEntry {
20 enum class FunctionKinds { ENTRY, EXIT, TAIL };
21
22 uint64_t Address;
23 uint64_t Function;
24 FunctionKinds Kind;
25 bool AlwaysInstrument;
26 };
27
28 } // namespace xray
29 } // namespace llvm
30
31 #endif // LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H