1//===- bolt/tools/bat-dump/bat-dump.cpp - BAT dumper utility --------------===//
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#include "bolt/Profile/BoltAddressTranslation.h"
10#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/SmallString.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/ADT/Twine.h"
14#include "llvm/Object/Binary.h"
15#include "llvm/Object/ELFObjectFile.h"
16#include "llvm/Object/Error.h"
17#include "llvm/Object/ObjectFile.h"
18#include "llvm/Object/SymbolicFile.h"
19#include "llvm/Support/Casting.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Support/Errc.h"
22#include "llvm/Support/Error.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/ErrorOr.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/Program.h"
27#include "llvm/Support/raw_ostream.h"
28#include <assert.h>
29#include <cstdint>
30#include <map>
31#include <stdlib.h>
32#include <string>
33#include <system_error>
34#include <type_traits>
35#include <utility>
36
37using namespace llvm;
38using namespace bolt;
39
40namespace opts {
41
42static cl::OptionCategory BatDumpCategory("BAT dump options");
43
44static cl::OptionCategory *BatDumpCategories[] = {&BatDumpCategory};
45
46static cl::opt<std::string> InputFilename(cl::Positional,
47 cl::desc("<executable>"),
48 cl::Required,
49 cl::cat(BatDumpCategory));
50
51static cl::list<uint64_t> Translate("translate",
52 cl::desc("translate addresses using BAT"),
53 cl::value_desc("addr"),
54 cl::cat(BatDumpCategory));
55
56static cl::opt<bool> DumpAll("dump-all", cl::desc("dump all BAT tables"),
57 cl::cat(BatDumpCategory));
58
59} // namespace opts
60
61static StringRef ToolName;
62
63static void report_error(StringRef Message, std::error_code EC) {
64 assert(EC);
65 errs() << ToolName << ": '" << Message << "': " << EC.message() << ".\n";
66 exit(status: 1);
67}
68
69static void report_error(StringRef Message, Error E) {
70 assert(E);
71 errs() << ToolName << ": '" << Message << "': " << toString(E: std::move(E))
72 << ".\n";
73 exit(status: 1);
74}
75
76void dumpBATFor(llvm::object::ELFObjectFileBase *InputFile) {
77 BoltAddressTranslation BAT;
78 if (!BAT.enabledFor(InputFile)) {
79 errs() << "error: no BAT table found.\n";
80 exit(status: 1);
81 }
82
83 // Look for BAT section
84 bool Found = false;
85 StringRef SectionContents;
86 for (const llvm::object::SectionRef &Section : InputFile->sections()) {
87 Expected<StringRef> SectionNameOrErr = Section.getName();
88 if (Error E = SectionNameOrErr.takeError())
89 continue;
90
91 if (SectionNameOrErr.get() != BoltAddressTranslation::SECTION_NAME)
92 continue;
93
94 Found = true;
95 Expected<StringRef> ContentsOrErr = Section.getContents();
96 if (Error E = ContentsOrErr.takeError())
97 continue;
98 SectionContents = ContentsOrErr.get();
99 }
100
101 if (!Found) {
102 errs() << "BOLT-ERROR: failed to parse BOLT address translation "
103 "table. No BAT section found\n";
104 exit(status: 1);
105 }
106
107 if (std::error_code EC = BAT.parse(OS&: outs(), Buf: SectionContents)) {
108 errs() << "BOLT-ERROR: failed to parse BOLT address translation "
109 "table. Malformed BAT section\n";
110 exit(status: 1);
111 }
112
113 if (opts::DumpAll)
114 BAT.dump(OS&: outs());
115
116 if (!opts::Translate.empty()) {
117 // Build map of <Address, SymbolName> for InputFile
118 std::map<uint64_t, StringRef> FunctionsMap;
119 for (const llvm::object::ELFSymbolRef &Symbol : InputFile->symbols()) {
120 Expected<StringRef> NameOrError = Symbol.getName();
121 if (NameOrError.takeError())
122 continue;
123 if (cantFail(ValOrErr: Symbol.getType()) != llvm::object::SymbolRef::ST_Function)
124 continue;
125 const StringRef Name = *NameOrError;
126 const uint64_t Address = cantFail(ValOrErr: Symbol.getAddress());
127 FunctionsMap[Address] = Name;
128 }
129
130 outs() << "Translating addresses according to parsed BAT tables:\n";
131 for (uint64_t Address : opts::Translate) {
132 auto FI = FunctionsMap.upper_bound(x: Address);
133 if (FI == FunctionsMap.begin()) {
134 outs() << "No function symbol found for 0x" << Twine::utohexstr(Val: Address)
135 << "\n";
136 continue;
137 }
138 --FI;
139 outs() << "0x" << Twine::utohexstr(Val: Address) << " -> " << FI->second
140 << " + 0x"
141 << Twine::utohexstr(
142 Val: BAT.translate(FuncAddress: FI->first, Offset: Address - FI->first, IsBranchSrc: false))
143 << "\n";
144 }
145 }
146}
147
148int main(int argc, char **argv) {
149 cl::HideUnrelatedOptions(Categories: ArrayRef(opts::BatDumpCategories));
150 cl::ParseCommandLineOptions(argc, argv, Overview: "");
151
152 if (!sys::fs::exists(Path: opts::InputFilename))
153 report_error(Message: opts::InputFilename, EC: errc::no_such_file_or_directory);
154
155 ToolName = argv[0];
156 Expected<llvm::object::OwningBinary<llvm::object::Binary>> BinaryOrErr =
157 llvm::object::createBinary(Path: opts::InputFilename);
158 if (Error E = BinaryOrErr.takeError())
159 report_error(Message: opts::InputFilename, E: std::move(E));
160 llvm::object::Binary &Binary = *BinaryOrErr.get().getBinary();
161
162 if (auto *InputFile = dyn_cast<llvm::object::ELFObjectFileBase>(Val: &Binary))
163 dumpBATFor(InputFile);
164 else
165 report_error(Message: opts::InputFilename,
166 EC: llvm::object::object_error::invalid_file_type);
167
168 return EXIT_SUCCESS;
169}
170

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of bolt/tools/bat-dump/bat-dump.cpp