brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.7 KiB · 6319fd5 Raw
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