13164fcfdSRichard Smith //===- llvm-cxxmap.cpp ----------------------------------------------------===//
23164fcfdSRichard Smith //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63164fcfdSRichard Smith //
73164fcfdSRichard Smith //===----------------------------------------------------------------------===//
83164fcfdSRichard Smith //
93164fcfdSRichard Smith // llvm-cxxmap computes a correspondence between old symbol names and new
103164fcfdSRichard Smith // symbol names based on a symbol equivalence file.
113164fcfdSRichard Smith //
123164fcfdSRichard Smith //===----------------------------------------------------------------------===//
133164fcfdSRichard Smith
143164fcfdSRichard Smith #include "llvm/ADT/DenseMap.h"
15ba7a92c0SNico Weber #include "llvm/ADT/DenseSet.h"
163164fcfdSRichard Smith #include "llvm/ADT/StringRef.h"
176c8fe965SSimon Pilgrim #include "llvm/ProfileData/SymbolRemappingReader.h"
183164fcfdSRichard Smith #include "llvm/Support/CommandLine.h"
19ba7a92c0SNico Weber #include "llvm/Support/FileSystem.h"
203164fcfdSRichard Smith #include "llvm/Support/InitLLVM.h"
213164fcfdSRichard Smith #include "llvm/Support/LineIterator.h"
223164fcfdSRichard Smith #include "llvm/Support/MemoryBuffer.h"
233164fcfdSRichard Smith #include "llvm/Support/WithColor.h"
243164fcfdSRichard Smith #include "llvm/Support/raw_ostream.h"
253164fcfdSRichard Smith
263164fcfdSRichard Smith using namespace llvm;
273164fcfdSRichard Smith
28669275f8STimm Bäder cl::OptionCategory CXXMapCategory("CXX Map Options");
29669275f8STimm Bäder
303164fcfdSRichard Smith cl::opt<std::string> OldSymbolFile(cl::Positional, cl::Required,
31669275f8STimm Bäder cl::desc("<symbol-file>"),
32669275f8STimm Bäder cl::cat(CXXMapCategory));
333164fcfdSRichard Smith cl::opt<std::string> NewSymbolFile(cl::Positional, cl::Required,
34669275f8STimm Bäder cl::desc("<symbol-file>"),
35669275f8STimm Bäder cl::cat(CXXMapCategory));
363164fcfdSRichard Smith cl::opt<std::string> RemappingFile("remapping-file", cl::Required,
37669275f8STimm Bäder cl::desc("Remapping file"),
38669275f8STimm Bäder cl::cat(CXXMapCategory));
39669275f8STimm Bäder cl::alias RemappingFileA("r", cl::aliasopt(RemappingFile),
40669275f8STimm Bäder cl::cat(CXXMapCategory));
413164fcfdSRichard Smith cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
42669275f8STimm Bäder cl::init("-"), cl::desc("Output file"),
43669275f8STimm Bäder cl::cat(CXXMapCategory));
44669275f8STimm Bäder cl::alias OutputFilenameA("o", cl::aliasopt(OutputFilename),
45669275f8STimm Bäder cl::cat(CXXMapCategory));
463164fcfdSRichard Smith
473164fcfdSRichard Smith cl::opt<bool> WarnAmbiguous(
483164fcfdSRichard Smith "Wambiguous",
49669275f8STimm Bäder cl::desc("Warn on equivalent symbols in the output symbol list"),
50669275f8STimm Bäder cl::cat(CXXMapCategory));
513164fcfdSRichard Smith cl::opt<bool> WarnIncomplete(
523164fcfdSRichard Smith "Wincomplete",
53669275f8STimm Bäder cl::desc("Warn on input symbols missing from output symbol list"),
54669275f8STimm Bäder cl::cat(CXXMapCategory));
553164fcfdSRichard Smith
warn(Twine Message,Twine Whence="",std::string Hint="")563164fcfdSRichard Smith static void warn(Twine Message, Twine Whence = "",
573164fcfdSRichard Smith std::string Hint = "") {
583164fcfdSRichard Smith WithColor::warning();
593164fcfdSRichard Smith std::string WhenceStr = Whence.str();
603164fcfdSRichard Smith if (!WhenceStr.empty())
613164fcfdSRichard Smith errs() << WhenceStr << ": ";
623164fcfdSRichard Smith errs() << Message << "\n";
633164fcfdSRichard Smith if (!Hint.empty())
643164fcfdSRichard Smith WithColor::note() << Hint << "\n";
653164fcfdSRichard Smith }
663164fcfdSRichard Smith
exitWithError(Twine Message,Twine Whence="",std::string Hint="")673164fcfdSRichard Smith static void exitWithError(Twine Message, Twine Whence = "",
683164fcfdSRichard Smith std::string Hint = "") {
693164fcfdSRichard Smith WithColor::error();
703164fcfdSRichard Smith std::string WhenceStr = Whence.str();
713164fcfdSRichard Smith if (!WhenceStr.empty())
723164fcfdSRichard Smith errs() << WhenceStr << ": ";
733164fcfdSRichard Smith errs() << Message << "\n";
743164fcfdSRichard Smith if (!Hint.empty())
753164fcfdSRichard Smith WithColor::note() << Hint << "\n";
763164fcfdSRichard Smith ::exit(1);
773164fcfdSRichard Smith }
783164fcfdSRichard Smith
exitWithError(Error E,StringRef Whence="")793164fcfdSRichard Smith static void exitWithError(Error E, StringRef Whence = "") {
803164fcfdSRichard Smith exitWithError(toString(std::move(E)), Whence);
813164fcfdSRichard Smith }
823164fcfdSRichard Smith
exitWithErrorCode(std::error_code EC,StringRef Whence="")833164fcfdSRichard Smith static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
843164fcfdSRichard Smith exitWithError(EC.message(), Whence);
853164fcfdSRichard Smith }
863164fcfdSRichard Smith
remapSymbols(MemoryBuffer & OldSymbolFile,MemoryBuffer & NewSymbolFile,MemoryBuffer & RemappingFile,raw_ostream & Out)873164fcfdSRichard Smith static void remapSymbols(MemoryBuffer &OldSymbolFile,
883164fcfdSRichard Smith MemoryBuffer &NewSymbolFile,
893164fcfdSRichard Smith MemoryBuffer &RemappingFile,
903164fcfdSRichard Smith raw_ostream &Out) {
913164fcfdSRichard Smith // Load the remapping file and prepare to canonicalize symbols.
923164fcfdSRichard Smith SymbolRemappingReader Reader;
933164fcfdSRichard Smith if (Error E = Reader.read(RemappingFile))
943164fcfdSRichard Smith exitWithError(std::move(E));
953164fcfdSRichard Smith
963164fcfdSRichard Smith // Canonicalize the new symbols.
973164fcfdSRichard Smith DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
983164fcfdSRichard Smith DenseSet<StringRef> UnparseableSymbols;
993164fcfdSRichard Smith for (line_iterator LineIt(NewSymbolFile, /*SkipBlanks=*/true, '#');
1003164fcfdSRichard Smith !LineIt.is_at_eof(); ++LineIt) {
1013164fcfdSRichard Smith StringRef Symbol = *LineIt;
1023164fcfdSRichard Smith
1033164fcfdSRichard Smith auto K = Reader.insert(Symbol);
1043164fcfdSRichard Smith if (!K) {
1053164fcfdSRichard Smith UnparseableSymbols.insert(Symbol);
1063164fcfdSRichard Smith continue;
1073164fcfdSRichard Smith }
1083164fcfdSRichard Smith
1093164fcfdSRichard Smith auto ItAndIsNew = MappedNames.insert({K, Symbol});
1103164fcfdSRichard Smith if (WarnAmbiguous && !ItAndIsNew.second &&
1113164fcfdSRichard Smith ItAndIsNew.first->second != Symbol) {
1123164fcfdSRichard Smith warn("symbol " + Symbol + " is equivalent to earlier symbol " +
1133164fcfdSRichard Smith ItAndIsNew.first->second,
1143164fcfdSRichard Smith NewSymbolFile.getBufferIdentifier() + ":" +
1153164fcfdSRichard Smith Twine(LineIt.line_number()),
1163164fcfdSRichard Smith "later symbol will not be the target of any remappings");
1173164fcfdSRichard Smith }
1183164fcfdSRichard Smith }
1193164fcfdSRichard Smith
1203164fcfdSRichard Smith // Figure out which new symbol each old symbol is equivalent to.
1213164fcfdSRichard Smith for (line_iterator LineIt(OldSymbolFile, /*SkipBlanks=*/true, '#');
1223164fcfdSRichard Smith !LineIt.is_at_eof(); ++LineIt) {
1233164fcfdSRichard Smith StringRef Symbol = *LineIt;
1243164fcfdSRichard Smith
1253164fcfdSRichard Smith auto K = Reader.lookup(Symbol);
1263164fcfdSRichard Smith StringRef NewSymbol = MappedNames.lookup(K);
1273164fcfdSRichard Smith
1283164fcfdSRichard Smith if (NewSymbol.empty()) {
1293164fcfdSRichard Smith if (WarnIncomplete && !UnparseableSymbols.count(Symbol)) {
1303164fcfdSRichard Smith warn("no new symbol matches old symbol " + Symbol,
1313164fcfdSRichard Smith OldSymbolFile.getBufferIdentifier() + ":" +
1323164fcfdSRichard Smith Twine(LineIt.line_number()));
1333164fcfdSRichard Smith }
1343164fcfdSRichard Smith continue;
1353164fcfdSRichard Smith }
1363164fcfdSRichard Smith
1373164fcfdSRichard Smith Out << Symbol << " " << NewSymbol << "\n";
1383164fcfdSRichard Smith }
1393164fcfdSRichard Smith }
1403164fcfdSRichard Smith
main(int argc,const char * argv[])1413164fcfdSRichard Smith int main(int argc, const char *argv[]) {
1423164fcfdSRichard Smith InitLLVM X(argc, argv);
1433164fcfdSRichard Smith
144669275f8STimm Bäder cl::HideUnrelatedOptions({&CXXMapCategory, &getColorCategory()});
1453164fcfdSRichard Smith cl::ParseCommandLineOptions(argc, argv, "LLVM C++ mangled name remapper\n");
1463164fcfdSRichard Smith
147*e22ce615SSean Perry auto OldSymbolBufOrError =
148*e22ce615SSean Perry MemoryBuffer::getFileOrSTDIN(OldSymbolFile, /*IsText=*/true);
1493164fcfdSRichard Smith if (!OldSymbolBufOrError)
1503164fcfdSRichard Smith exitWithErrorCode(OldSymbolBufOrError.getError(), OldSymbolFile);
1513164fcfdSRichard Smith
152*e22ce615SSean Perry auto NewSymbolBufOrError =
153*e22ce615SSean Perry MemoryBuffer::getFileOrSTDIN(NewSymbolFile, /*IsText=*/true);
1543164fcfdSRichard Smith if (!NewSymbolBufOrError)
1553164fcfdSRichard Smith exitWithErrorCode(NewSymbolBufOrError.getError(), NewSymbolFile);
1563164fcfdSRichard Smith
157*e22ce615SSean Perry auto RemappingBufOrError =
158*e22ce615SSean Perry MemoryBuffer::getFileOrSTDIN(RemappingFile, /*IsText=*/true);
1593164fcfdSRichard Smith if (!RemappingBufOrError)
1603164fcfdSRichard Smith exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile);
1613164fcfdSRichard Smith
1623164fcfdSRichard Smith std::error_code EC;
16382b3e28eSAbhina Sreeskantharajan raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
1643164fcfdSRichard Smith if (EC)
1653164fcfdSRichard Smith exitWithErrorCode(EC, OutputFilename);
1663164fcfdSRichard Smith
1673164fcfdSRichard Smith remapSymbols(*OldSymbolBufOrError.get(), *NewSymbolBufOrError.get(),
1683164fcfdSRichard Smith *RemappingBufOrError.get(), OS);
1693164fcfdSRichard Smith }
170