1 //===- llvm-cxxmap.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // llvm-cxxmap computes a correspondence between old symbol names and new
10 // symbol names based on a symbol equivalence file.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/DenseSet.h"
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/InitLLVM.h"
19 #include "llvm/Support/LineIterator.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/SymbolRemappingReader.h"
22 #include "llvm/Support/WithColor.h"
23 #include "llvm/Support/raw_ostream.h"
27 cl::opt
<std::string
> OldSymbolFile(cl::Positional
, cl::Required
,
28 cl::desc("<symbol-file>"));
29 cl::opt
<std::string
> NewSymbolFile(cl::Positional
, cl::Required
,
30 cl::desc("<symbol-file>"));
31 cl::opt
<std::string
> RemappingFile("remapping-file", cl::Required
,
32 cl::desc("Remapping file"));
33 cl::alias
RemappingFileA("r", cl::aliasopt(RemappingFile
));
34 cl::opt
<std::string
> OutputFilename("output", cl::value_desc("output"),
35 cl::init("-"), cl::desc("Output file"));
36 cl::alias
OutputFilenameA("o", cl::aliasopt(OutputFilename
));
38 cl::opt
<bool> WarnAmbiguous(
40 cl::desc("Warn on equivalent symbols in the output symbol list"));
41 cl::opt
<bool> WarnIncomplete(
43 cl::desc("Warn on input symbols missing from output symbol list"));
45 static void warn(Twine Message
, Twine Whence
= "",
46 std::string Hint
= "") {
48 std::string WhenceStr
= Whence
.str();
49 if (!WhenceStr
.empty())
50 errs() << WhenceStr
<< ": ";
51 errs() << Message
<< "\n";
53 WithColor::note() << Hint
<< "\n";
56 static void exitWithError(Twine Message
, Twine Whence
= "",
57 std::string Hint
= "") {
59 std::string WhenceStr
= Whence
.str();
60 if (!WhenceStr
.empty())
61 errs() << WhenceStr
<< ": ";
62 errs() << Message
<< "\n";
64 WithColor::note() << Hint
<< "\n";
68 static void exitWithError(Error E
, StringRef Whence
= "") {
69 exitWithError(toString(std::move(E
)), Whence
);
72 static void exitWithErrorCode(std::error_code EC
, StringRef Whence
= "") {
73 exitWithError(EC
.message(), Whence
);
76 static void remapSymbols(MemoryBuffer
&OldSymbolFile
,
77 MemoryBuffer
&NewSymbolFile
,
78 MemoryBuffer
&RemappingFile
,
80 // Load the remapping file and prepare to canonicalize symbols.
81 SymbolRemappingReader Reader
;
82 if (Error E
= Reader
.read(RemappingFile
))
83 exitWithError(std::move(E
));
85 // Canonicalize the new symbols.
86 DenseMap
<SymbolRemappingReader::Key
, StringRef
> MappedNames
;
87 DenseSet
<StringRef
> UnparseableSymbols
;
88 for (line_iterator
LineIt(NewSymbolFile
, /*SkipBlanks=*/true, '#');
89 !LineIt
.is_at_eof(); ++LineIt
) {
90 StringRef Symbol
= *LineIt
;
92 auto K
= Reader
.insert(Symbol
);
94 UnparseableSymbols
.insert(Symbol
);
98 auto ItAndIsNew
= MappedNames
.insert({K
, Symbol
});
99 if (WarnAmbiguous
&& !ItAndIsNew
.second
&&
100 ItAndIsNew
.first
->second
!= Symbol
) {
101 warn("symbol " + Symbol
+ " is equivalent to earlier symbol " +
102 ItAndIsNew
.first
->second
,
103 NewSymbolFile
.getBufferIdentifier() + ":" +
104 Twine(LineIt
.line_number()),
105 "later symbol will not be the target of any remappings");
109 // Figure out which new symbol each old symbol is equivalent to.
110 for (line_iterator
LineIt(OldSymbolFile
, /*SkipBlanks=*/true, '#');
111 !LineIt
.is_at_eof(); ++LineIt
) {
112 StringRef Symbol
= *LineIt
;
114 auto K
= Reader
.lookup(Symbol
);
115 StringRef NewSymbol
= MappedNames
.lookup(K
);
117 if (NewSymbol
.empty()) {
118 if (WarnIncomplete
&& !UnparseableSymbols
.count(Symbol
)) {
119 warn("no new symbol matches old symbol " + Symbol
,
120 OldSymbolFile
.getBufferIdentifier() + ":" +
121 Twine(LineIt
.line_number()));
126 Out
<< Symbol
<< " " << NewSymbol
<< "\n";
130 int main(int argc
, const char *argv
[]) {
131 InitLLVM
X(argc
, argv
);
133 cl::ParseCommandLineOptions(argc
, argv
, "LLVM C++ mangled name remapper\n");
135 auto OldSymbolBufOrError
= MemoryBuffer::getFileOrSTDIN(OldSymbolFile
);
136 if (!OldSymbolBufOrError
)
137 exitWithErrorCode(OldSymbolBufOrError
.getError(), OldSymbolFile
);
139 auto NewSymbolBufOrError
= MemoryBuffer::getFileOrSTDIN(NewSymbolFile
);
140 if (!NewSymbolBufOrError
)
141 exitWithErrorCode(NewSymbolBufOrError
.getError(), NewSymbolFile
);
143 auto RemappingBufOrError
= MemoryBuffer::getFileOrSTDIN(RemappingFile
);
144 if (!RemappingBufOrError
)
145 exitWithErrorCode(RemappingBufOrError
.getError(), RemappingFile
);
148 raw_fd_ostream
OS(OutputFilename
.data(), EC
, sys::fs::F_Text
);
150 exitWithErrorCode(EC
, OutputFilename
);
152 remapSymbols(*OldSymbolBufOrError
.get(), *NewSymbolBufOrError
.get(),
153 *RemappingBufOrError
.get(), OS
);