554 lines · cpp
1//===- SymbolRewriter.cpp - Symbol Rewriter -------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// SymbolRewriter is a LLVM pass which can rewrite symbols transparently within10// existing code. It is implemented as a compiler pass and is configured via a11// YAML configuration file.12//13// The YAML configuration file format is as follows:14//15// RewriteMapFile := RewriteDescriptors16// RewriteDescriptors := RewriteDescriptor | RewriteDescriptors17// RewriteDescriptor := RewriteDescriptorType ':' '{' RewriteDescriptorFields '}'18// RewriteDescriptorFields := RewriteDescriptorField | RewriteDescriptorFields19// RewriteDescriptorField := FieldIdentifier ':' FieldValue ','20// RewriteDescriptorType := Identifier21// FieldIdentifier := Identifier22// FieldValue := Identifier23// Identifier := [0-9a-zA-Z]+24//25// Currently, the following descriptor types are supported:26//27// - function: (function rewriting)28// + Source (original name of the function)29// + Target (explicit transformation)30// + Transform (pattern transformation)31// + Naked (boolean, whether the function is undecorated)32// - global variable: (external linkage global variable rewriting)33// + Source (original name of externally visible variable)34// + Target (explicit transformation)35// + Transform (pattern transformation)36// - global alias: (global alias rewriting)37// + Source (original name of the aliased name)38// + Target (explicit transformation)39// + Transform (pattern transformation)40//41// Note that source and exactly one of [Target, Transform] must be provided42//43// New rewrite descriptors can be created. Addding a new rewrite descriptor44// involves:45//46// a) extended the rewrite descriptor kind enumeration47// (<anonymous>::RewriteDescriptor::RewriteDescriptorType)48// b) implementing the new descriptor49// (c.f. <anonymous>::ExplicitRewriteFunctionDescriptor)50// c) extending the rewrite map parser51// (<anonymous>::RewriteMapParser::parseEntry)52//53// Specify to rewrite the symbols using the `-rewrite-symbols` option, and54// specify the map file to use for the rewriting via the `-rewrite-map-file`55// option.56//57//===----------------------------------------------------------------------===//58 59#include "llvm/Transforms/Utils/SymbolRewriter.h"60#include "llvm/ADT/SmallString.h"61#include "llvm/ADT/StringRef.h"62#include "llvm/ADT/ilist.h"63#include "llvm/ADT/iterator_range.h"64#include "llvm/IR/Comdat.h"65#include "llvm/IR/Function.h"66#include "llvm/IR/GlobalAlias.h"67#include "llvm/IR/GlobalObject.h"68#include "llvm/IR/GlobalVariable.h"69#include "llvm/IR/Module.h"70#include "llvm/IR/Value.h"71#include "llvm/Support/Casting.h"72#include "llvm/Support/CommandLine.h"73#include "llvm/Support/ErrorHandling.h"74#include "llvm/Support/ErrorOr.h"75#include "llvm/Support/MemoryBuffer.h"76#include "llvm/Support/Regex.h"77#include "llvm/Support/SourceMgr.h"78#include "llvm/Support/YAMLParser.h"79#include <memory>80#include <string>81#include <vector>82 83using namespace llvm;84using namespace SymbolRewriter;85 86#define DEBUG_TYPE "symbol-rewriter"87 88static cl::list<std::string> RewriteMapFiles("rewrite-map-file",89 cl::desc("Symbol Rewrite Map"),90 cl::value_desc("filename"),91 cl::Hidden);92 93static void rewriteComdat(Module &M, GlobalObject *GO,94 const std::string &Source,95 const std::string &Target) {96 if (Comdat *CD = GO->getComdat()) {97 auto &Comdats = M.getComdatSymbolTable();98 99 Comdat *C = M.getOrInsertComdat(Target);100 C->setSelectionKind(CD->getSelectionKind());101 GO->setComdat(C);102 103 Comdats.erase(Comdats.find(Source));104 }105}106 107namespace {108 109template <RewriteDescriptor::Type DT, typename ValueType,110 ValueType *(Module::*Get)(StringRef) const>111class ExplicitRewriteDescriptor : public RewriteDescriptor {112public:113 const std::string Source;114 const std::string Target;115 116 ExplicitRewriteDescriptor(StringRef S, StringRef T, const bool Naked)117 : RewriteDescriptor(DT),118 Source(std::string(Naked ? StringRef("\01" + S.str()) : S)),119 Target(std::string(T)) {}120 121 bool performOnModule(Module &M) override;122 123 static bool classof(const RewriteDescriptor *RD) {124 return RD->getType() == DT;125 }126};127 128} // end anonymous namespace129 130template <RewriteDescriptor::Type DT, typename ValueType,131 ValueType *(Module::*Get)(StringRef) const>132bool ExplicitRewriteDescriptor<DT, ValueType, Get>::performOnModule(Module &M) {133 bool Changed = false;134 if (ValueType *S = (M.*Get)(Source)) {135 if (GlobalObject *GO = dyn_cast<GlobalObject>(S))136 rewriteComdat(M, GO, Source, Target);137 138 if (Value *T = (M.*Get)(Target))139 S->setValueName(T->getValueName());140 else141 S->setName(Target);142 143 Changed = true;144 }145 return Changed;146}147 148namespace {149 150template <RewriteDescriptor::Type DT, typename ValueType,151 ValueType *(Module::*Get)(StringRef) const,152 iterator_range<typename iplist<ValueType>::iterator>153 (Module::*Iterator)()>154class PatternRewriteDescriptor : public RewriteDescriptor {155public:156 const std::string Pattern;157 const std::string Transform;158 159 PatternRewriteDescriptor(StringRef P, StringRef T)160 : RewriteDescriptor(DT), Pattern(std::string(P)),161 Transform(std::string(T)) {}162 163 bool performOnModule(Module &M) override;164 165 static bool classof(const RewriteDescriptor *RD) {166 return RD->getType() == DT;167 }168};169 170} // end anonymous namespace171 172template <RewriteDescriptor::Type DT, typename ValueType,173 ValueType *(Module::*Get)(StringRef) const,174 iterator_range<typename iplist<ValueType>::iterator>175 (Module::*Iterator)()>176bool PatternRewriteDescriptor<DT, ValueType, Get, Iterator>::177performOnModule(Module &M) {178 bool Changed = false;179 for (auto &C : (M.*Iterator)()) {180 std::string Error;181 182 std::string Name = Regex(Pattern).sub(Transform, C.getName(), &Error);183 if (!Error.empty())184 report_fatal_error(Twine("unable to transforn ") + C.getName() + " in " +185 M.getModuleIdentifier() + ": " + Error);186 187 if (C.getName() == Name)188 continue;189 190 if (GlobalObject *GO = dyn_cast<GlobalObject>(&C))191 rewriteComdat(M, GO, std::string(C.getName()), Name);192 193 if (Value *V = (M.*Get)(Name))194 C.setValueName(V->getValueName());195 else196 C.setName(Name);197 198 Changed = true;199 }200 return Changed;201}202 203namespace {204 205/// Represents a rewrite for an explicitly named (function) symbol. Both the206/// source function name and target function name of the transformation are207/// explicitly spelt out.208using ExplicitRewriteFunctionDescriptor =209 ExplicitRewriteDescriptor<RewriteDescriptor::Type::Function, Function,210 &Module::getFunction>;211 212/// Represents a rewrite for an explicitly named (global variable) symbol. Both213/// the source variable name and target variable name are spelt out. This214/// applies only to module level variables.215using ExplicitRewriteGlobalVariableDescriptor =216 ExplicitRewriteDescriptor<RewriteDescriptor::Type::GlobalVariable,217 GlobalVariable, &Module::getGlobalVariable>;218 219/// Represents a rewrite for an explicitly named global alias. Both the source220/// and target name are explicitly spelt out.221using ExplicitRewriteNamedAliasDescriptor =222 ExplicitRewriteDescriptor<RewriteDescriptor::Type::NamedAlias, GlobalAlias,223 &Module::getNamedAlias>;224 225/// Represents a rewrite for a regular expression based pattern for functions.226/// A pattern for the function name is provided and a transformation for that227/// pattern to determine the target function name create the rewrite rule.228using PatternRewriteFunctionDescriptor =229 PatternRewriteDescriptor<RewriteDescriptor::Type::Function, Function,230 &Module::getFunction, &Module::functions>;231 232/// Represents a rewrite for a global variable based upon a matching pattern.233/// Each global variable matching the provided pattern will be transformed as234/// described in the transformation pattern for the target. Applies only to235/// module level variables.236using PatternRewriteGlobalVariableDescriptor =237 PatternRewriteDescriptor<RewriteDescriptor::Type::GlobalVariable,238 GlobalVariable, &Module::getGlobalVariable,239 &Module::globals>;240 241/// PatternRewriteNamedAliasDescriptor - represents a rewrite for global242/// aliases which match a given pattern. The provided transformation will be243/// applied to each of the matching names.244using PatternRewriteNamedAliasDescriptor =245 PatternRewriteDescriptor<RewriteDescriptor::Type::NamedAlias, GlobalAlias,246 &Module::getNamedAlias, &Module::aliases>;247 248} // end anonymous namespace249 250bool RewriteMapParser::parse(const std::string &MapFile,251 RewriteDescriptorList *DL) {252 ErrorOr<std::unique_ptr<MemoryBuffer>> Mapping =253 MemoryBuffer::getFile(MapFile);254 255 if (!Mapping)256 report_fatal_error(Twine("unable to read rewrite map '") + MapFile +257 "': " + Mapping.getError().message());258 259 if (!parse(*Mapping, DL))260 report_fatal_error(Twine("unable to parse rewrite map '") + MapFile + "'");261 262 return true;263}264 265bool RewriteMapParser::parse(std::unique_ptr<MemoryBuffer> &MapFile,266 RewriteDescriptorList *DL) {267 SourceMgr SM;268 yaml::Stream YS(MapFile->getBuffer(), SM);269 270 for (auto &Document : YS) {271 yaml::MappingNode *DescriptorList;272 273 // ignore empty documents274 if (isa<yaml::NullNode>(Document.getRoot()))275 continue;276 277 DescriptorList = dyn_cast<yaml::MappingNode>(Document.getRoot());278 if (!DescriptorList) {279 YS.printError(Document.getRoot(), "DescriptorList node must be a map");280 return false;281 }282 283 for (auto &Descriptor : *DescriptorList)284 if (!parseEntry(YS, Descriptor, DL))285 return false;286 }287 288 return true;289}290 291bool RewriteMapParser::parseEntry(yaml::Stream &YS, yaml::KeyValueNode &Entry,292 RewriteDescriptorList *DL) {293 yaml::ScalarNode *Key;294 yaml::MappingNode *Value;295 SmallString<32> KeyStorage;296 StringRef RewriteType;297 298 Key = dyn_cast<yaml::ScalarNode>(Entry.getKey());299 if (!Key) {300 YS.printError(Entry.getKey(), "rewrite type must be a scalar");301 return false;302 }303 304 Value = dyn_cast<yaml::MappingNode>(Entry.getValue());305 if (!Value) {306 YS.printError(Entry.getValue(), "rewrite descriptor must be a map");307 return false;308 }309 310 RewriteType = Key->getValue(KeyStorage);311 if (RewriteType == "function")312 return parseRewriteFunctionDescriptor(YS, Key, Value, DL);313 else if (RewriteType == "global variable")314 return parseRewriteGlobalVariableDescriptor(YS, Key, Value, DL);315 else if (RewriteType == "global alias")316 return parseRewriteGlobalAliasDescriptor(YS, Key, Value, DL);317 318 YS.printError(Entry.getKey(), "unknown rewrite type");319 return false;320}321 322bool RewriteMapParser::323parseRewriteFunctionDescriptor(yaml::Stream &YS, yaml::ScalarNode *K,324 yaml::MappingNode *Descriptor,325 RewriteDescriptorList *DL) {326 bool Naked = false;327 std::string Source;328 std::string Target;329 std::string Transform;330 331 for (auto &Field : *Descriptor) {332 yaml::ScalarNode *Key;333 yaml::ScalarNode *Value;334 SmallString<32> KeyStorage;335 SmallString<32> ValueStorage;336 StringRef KeyValue;337 338 Key = dyn_cast<yaml::ScalarNode>(Field.getKey());339 if (!Key) {340 YS.printError(Field.getKey(), "descriptor key must be a scalar");341 return false;342 }343 344 Value = dyn_cast<yaml::ScalarNode>(Field.getValue());345 if (!Value) {346 YS.printError(Field.getValue(), "descriptor value must be a scalar");347 return false;348 }349 350 KeyValue = Key->getValue(KeyStorage);351 if (KeyValue == "source") {352 Source = std::string(Value->getValue(ValueStorage));353 } else if (KeyValue == "target") {354 Target = std::string(Value->getValue(ValueStorage));355 } else if (KeyValue == "transform") {356 Transform = std::string(Value->getValue(ValueStorage));357 } else if (KeyValue == "naked") {358 std::string Undecorated;359 360 Undecorated = std::string(Value->getValue(ValueStorage));361 Naked = StringRef(Undecorated).lower() == "true" || Undecorated == "1";362 } else {363 YS.printError(Field.getKey(), "unknown key for function");364 return false;365 }366 }367 368 if (Transform.empty() == Target.empty()) {369 YS.printError(Descriptor,370 "exactly one of transform or target must be specified");371 return false;372 }373 374 // TODO see if there is a more elegant solution to selecting the rewrite375 // descriptor type376 if (!Target.empty()) {377 DL->push_back(std::make_unique<ExplicitRewriteFunctionDescriptor>(378 Source, Target, Naked));379 return true;380 }381 382 {383 std::string Error;384 if (!Regex(Source).isValid(Error)) {385 YS.printError(Descriptor, "invalid Source regex: " + Error);386 return false;387 }388 }389 390 DL->push_back(391 std::make_unique<PatternRewriteFunctionDescriptor>(Source, Transform));392 393 return true;394}395 396bool RewriteMapParser::397parseRewriteGlobalVariableDescriptor(yaml::Stream &YS, yaml::ScalarNode *K,398 yaml::MappingNode *Descriptor,399 RewriteDescriptorList *DL) {400 std::string Source;401 std::string Target;402 std::string Transform;403 404 for (auto &Field : *Descriptor) {405 yaml::ScalarNode *Key;406 yaml::ScalarNode *Value;407 SmallString<32> KeyStorage;408 SmallString<32> ValueStorage;409 StringRef KeyValue;410 411 Key = dyn_cast<yaml::ScalarNode>(Field.getKey());412 if (!Key) {413 YS.printError(Field.getKey(), "descriptor Key must be a scalar");414 return false;415 }416 417 Value = dyn_cast<yaml::ScalarNode>(Field.getValue());418 if (!Value) {419 YS.printError(Field.getValue(), "descriptor value must be a scalar");420 return false;421 }422 423 KeyValue = Key->getValue(KeyStorage);424 if (KeyValue == "source") {425 Source = std::string(Value->getValue(ValueStorage));426 } else if (KeyValue == "target") {427 Target = std::string(Value->getValue(ValueStorage));428 } else if (KeyValue == "transform") {429 Transform = std::string(Value->getValue(ValueStorage));430 } else {431 YS.printError(Field.getKey(), "unknown Key for Global Variable");432 return false;433 }434 }435 436 if (Transform.empty() == Target.empty()) {437 YS.printError(Descriptor,438 "exactly one of transform or target must be specified");439 return false;440 }441 442 if (!Target.empty()) {443 DL->push_back(std::make_unique<ExplicitRewriteGlobalVariableDescriptor>(444 Source, Target,445 /*Naked*/ false));446 return true;447 }448 449 {450 std::string Error;451 if (!Regex(Source).isValid(Error)) {452 YS.printError(Descriptor, "invalid Source regex: " + Error);453 return false;454 }455 }456 457 DL->push_back(std::make_unique<PatternRewriteGlobalVariableDescriptor>(458 Source, Transform));459 460 return true;461}462 463bool RewriteMapParser::464parseRewriteGlobalAliasDescriptor(yaml::Stream &YS, yaml::ScalarNode *K,465 yaml::MappingNode *Descriptor,466 RewriteDescriptorList *DL) {467 std::string Source;468 std::string Target;469 std::string Transform;470 471 for (auto &Field : *Descriptor) {472 yaml::ScalarNode *Key;473 yaml::ScalarNode *Value;474 SmallString<32> KeyStorage;475 SmallString<32> ValueStorage;476 StringRef KeyValue;477 478 Key = dyn_cast<yaml::ScalarNode>(Field.getKey());479 if (!Key) {480 YS.printError(Field.getKey(), "descriptor key must be a scalar");481 return false;482 }483 484 Value = dyn_cast<yaml::ScalarNode>(Field.getValue());485 if (!Value) {486 YS.printError(Field.getValue(), "descriptor value must be a scalar");487 return false;488 }489 490 KeyValue = Key->getValue(KeyStorage);491 if (KeyValue == "source") {492 Source = std::string(Value->getValue(ValueStorage));493 } else if (KeyValue == "target") {494 Target = std::string(Value->getValue(ValueStorage));495 } else if (KeyValue == "transform") {496 Transform = std::string(Value->getValue(ValueStorage));497 } else {498 YS.printError(Field.getKey(), "unknown key for Global Alias");499 return false;500 }501 }502 503 if (Transform.empty() == Target.empty()) {504 YS.printError(Descriptor,505 "exactly one of transform or target must be specified");506 return false;507 }508 509 if (!Target.empty()) {510 DL->push_back(std::make_unique<ExplicitRewriteNamedAliasDescriptor>(511 Source, Target,512 /*Naked*/ false));513 return true;514 }515 516 {517 std::string Error;518 if (!Regex(Source).isValid(Error)) {519 YS.printError(Descriptor, "invalid Source regex: " + Error);520 return false;521 }522 }523 524 DL->push_back(525 std::make_unique<PatternRewriteNamedAliasDescriptor>(Source, Transform));526 527 return true;528}529 530PreservedAnalyses RewriteSymbolPass::run(Module &M, ModuleAnalysisManager &AM) {531 if (!runImpl(M))532 return PreservedAnalyses::all();533 534 return PreservedAnalyses::none();535}536 537bool RewriteSymbolPass::runImpl(Module &M) {538 bool Changed;539 540 Changed = false;541 for (auto &Descriptor : Descriptors)542 Changed |= Descriptor->performOnModule(M);543 544 return Changed;545}546 547void RewriteSymbolPass::loadAndParseMapFiles() {548 const std::vector<std::string> MapFiles(RewriteMapFiles);549 SymbolRewriter::RewriteMapParser Parser;550 551 for (const auto &MapFile : MapFiles)552 Parser.parse(MapFile, &Descriptors);553}554