Ejemplo n.º 1
0
static std::string ProcessFailure(StringRef ProgPath, const char** Args,
                                  unsigned Timeout = 0,
                                  unsigned MemoryLimit = 0) {
  std::ostringstream OS;
  OS << "\nError running tool:\n ";
  for (const char **Arg = Args; *Arg; ++Arg)
    OS << " " << *Arg;
  OS << "\n";

  // Rerun the compiler, capturing any error messages to print them.
  SmallString<128> ErrorFilename;
  int ErrorFD;
  error_code EC = sys::fs::createTemporaryFile(
      "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename);
  if (EC) {
    errs() << "Error making unique filename: " << EC.message() << "\n";
    exit(1);
  }
  RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),
                        ErrorFilename.str(), Timeout, MemoryLimit);
  // FIXME: check return code ?

  // Print out the error messages generated by GCC if possible...
  std::ifstream ErrorFile(ErrorFilename.c_str());
  if (ErrorFile) {
    std::copy(std::istreambuf_iterator<char>(ErrorFile),
              std::istreambuf_iterator<char>(),
              std::ostreambuf_iterator<char>(OS));
    ErrorFile.close();
  }

  sys::fs::remove(ErrorFilename.c_str());
  return OS.str();
}
Ejemplo n.º 2
0
// Implement the 'x' operation. This function extracts files back to the file
// system.
static void doExtract(StringRef Name, object::Archive::child_iterator I) {
  // Retain the original mode.
  sys::fs::perms Mode = I->getAccessMode();
  SmallString<128> Storage = Name;

  int FD;
  failIfError(
      sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode),
      Storage.c_str());

  {
    raw_fd_ostream file(FD, false);

    // Get the data and its length
    StringRef Data = I->getBuffer();

    // Write the data.
    file.write(Data.data(), Data.size());
  }

  // If we're supposed to retain the original modification times, etc. do so
  // now.
  if (OriginalDates)
    failIfError(
        sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified()));

  if (close(FD))
    fail("Could not close the file");
}
Ejemplo n.º 3
0
bool LTOCodeGenerator::compileOptimizedToFile(const char **name,
                                              std::string &errMsg) {
  // make unique temp .o file to put generated object file
  SmallString<128> Filename;
  int FD;
  std::error_code EC =
      sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename);
  if (EC) {
    errMsg = EC.message();
    return false;
  }

  // generate object file
  tool_output_file objFile(Filename.c_str(), FD);

  bool genResult = compileOptimized(objFile.os(), errMsg);
  objFile.os().close();
  if (objFile.os().has_error()) {
    objFile.os().clear_error();
    sys::fs::remove(Twine(Filename));
    return false;
  }

  objFile.keep();
  if (!genResult) {
    sys::fs::remove(Twine(Filename));
    return false;
  }

  NativeObjectPath = Filename.c_str();
  *name = NativeObjectPath.c_str();
  return true;
}
Ejemplo n.º 4
0
std::unique_ptr<Module>
BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
                                         Module *M) {
  SmallString<128> Filename;
  int FD;
  std::error_code EC = sys::fs::createUniqueFile(
      OutputPrefix + "-extractblocks%%%%%%%", FD, Filename);
  if (EC) {
    outs() << "*** Basic Block extraction failed!\n";
    errs() << "Error creating temporary file: " << EC.message() << "\n";
    EmitProgressBitcode(M, "basicblockextractfail", true);
    return nullptr;
  }
  sys::RemoveFileOnSignal(Filename);

  tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD);
  for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
       I != E; ++I) {
    BasicBlock *BB = *I;
    // If the BB doesn't have a name, give it one so we have something to key
    // off of.
    if (!BB->hasName()) BB->setName("tmpbb");
    BlocksToNotExtractFile.os() << BB->getParent()->getName() << " "
                                << BB->getName() << "\n";
  }
  BlocksToNotExtractFile.os().close();
  if (BlocksToNotExtractFile.os().has_error()) {
    errs() << "Error writing list of blocks to not extract\n";
    EmitProgressBitcode(M, "basicblockextractfail", true);
    BlocksToNotExtractFile.os().clear_error();
    return nullptr;
  }
  BlocksToNotExtractFile.keep();

  std::string uniqueFN = "--extract-blocks-file=";
  uniqueFN += Filename.str();
  const char *ExtraArg = uniqueFN.c_str();

  std::vector<std::string> PI;
  PI.push_back("extract-blocks");
  std::unique_ptr<Module> Ret = runPassesOn(M, PI, false, 1, &ExtraArg);

  sys::fs::remove(Filename.c_str());

  if (!Ret) {
    outs() << "*** Basic Block extraction failed, please report a bug!\n";
    EmitProgressBitcode(M, "basicblockextractfail", true);
  }
  return Ret;
}
bool ReplacementHandling::serializeReplacements(
    const TUReplacementsMap &Replacements) {
  assert(!DestinationDir.empty() && "Destination directory not set");

  bool Errors = false;

  for (TUReplacementsMap::const_iterator I = Replacements.begin(),
                                         E = Replacements.end();
       I != E; ++I) {
    SmallString<128> ReplacementsFileName;
    SmallString<64> Error;
    bool Result = generateReplacementsFileName(DestinationDir,
                                               I->getValue().MainSourceFile,
                                               ReplacementsFileName, Error);
    if (!Result) {
      errs() << "Failed to generate replacements filename:" << Error << "\n";
      Errors = true;
      continue;
    }

    std::string ErrorInfo;
    raw_fd_ostream ReplacementsFile(ReplacementsFileName.c_str(), ErrorInfo,
                                    fs::F_None);
    if (!ErrorInfo.empty()) {
      errs() << "Error opening file: " << ErrorInfo << "\n";
      Errors = true;
      continue;
    }
    yaml::Output YAML(ReplacementsFile);
    YAML << const_cast<TranslationUnitReplacements &>(I->getValue());
  }
  return !Errors;
}
Ejemplo n.º 6
0
llvm::GlobalVariable *
MSRTTIBuilder::getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes) {
  SmallString<256> MangledName;
  {
    llvm::raw_svector_ostream Out(MangledName);
    Mangler.mangleCXXRTTIBaseClassArray(RD, Out);
  }

  // Forward-declare the base class array.
  // cl.exe pads the base class array with 1 (in 32 bit mode) or 4 (in 64 bit
  // mode) bytes of padding.  We provide a pointer sized amount of padding by
  // adding +1 to Classes.size().  The sections have pointer alignment and are
  // marked pick-any so it shouldn't matter.
  auto PtrType = getBaseClassDescriptorType(CGM)->getPointerTo();
  auto ArrayType = llvm::ArrayType::get(PtrType, Classes.size() + 1);
  auto BCA = new llvm::GlobalVariable(Module, ArrayType,
      /*Constant=*/true, Linkage, /*Initializer=*/0, MangledName.c_str());

  // Initialize the BaseClassArray.
  SmallVector<llvm::Constant *, 8> BaseClassArrayData;
  for (MSRTTIClass &Class : Classes)
    BaseClassArrayData.push_back(getBaseClassDescriptor(Class));
  BaseClassArrayData.push_back(llvm::ConstantPointerNull::get(PtrType));
  BCA->setInitializer(llvm::ConstantArray::get(ArrayType, BaseClassArrayData));
  return BCA;
}
Ejemplo n.º 7
0
// This method allows an ArchiveMember to be replaced with the data for a
// different file, presumably as an update to the member. It also makes sure
// the flags are reset correctly.
bool ArchiveMember::replaceWith(StringRef newFile, std::string* ErrMsg) {
  bool Exists;
  if (sys::fs::exists(newFile.str(), Exists) || !Exists) {
    if (ErrMsg)
      *ErrMsg = "Can not replace an archive member with a non-existent file";
    return true;
  }

  data = 0;
  path = newFile.str();

  // SVR4 symbol tables have an empty name
  if (path == ARFILE_SVR4_SYMTAB_NAME)
    flags |= SVR4SymbolTableFlag;
  else
    flags &= ~SVR4SymbolTableFlag;

  // BSD4.4 symbol tables have a special name
  if (path == ARFILE_BSD4_SYMTAB_NAME)
    flags |= BSD4SymbolTableFlag;
  else
    flags &= ~BSD4SymbolTableFlag;

  // String table name
  if (path == ARFILE_STRTAB_NAME)
    flags |= StringTableFlag;
  else
    flags &= ~StringTableFlag;

  // If it has a slash or its over 15 chars then its a long filename format
  if (path.length() > 15)
    flags |= HasLongFilenameFlag;
  else
    flags &= ~HasLongFilenameFlag;

  // Get the signature and status info
  const char* signature = (const char*) data;
  SmallString<4> magic;
  if (!signature) {
    sys::fs::get_magic(path, magic.capacity(), magic);
    signature = magic.c_str();

    sys::fs::file_status Status;
    error_code EC = sys::fs::status(path, Status);
    if (EC)
      return true;

    User = Status.getUser();
    Group = Status.getGroup();
    Mode = Status.permissions();
    ModTime = Status.getLastModificationTime();

    // FIXME: On posix this is a second stat.
    EC = sys::fs::file_size(path, Size);
    if (EC)
      return true;
  }

  return false;
}
Ejemplo n.º 8
0
/// Add a symbol which isn't defined just yet to a list to be resolved later.
void LTOModule::addPotentialUndefinedSymbol(ModuleSymbolTable::Symbol Sym,
                                            bool isFunc) {
  SmallString<64> name;
  {
    raw_svector_ostream OS(name);
    SymTab.printSymbolName(OS, Sym);
    name.c_str();
  }

  auto IterBool = _undefines.insert(std::make_pair(name, NameAndAttributes()));

  // we already have the symbol
  if (!IterBool.second)
    return;

  NameAndAttributes &info = IterBool.first->second;

  info.name = IterBool.first->first();

  const GlobalValue *decl = Sym.dyn_cast<GlobalValue *>();

  if (decl->hasExternalWeakLinkage())
    info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF;
  else
    info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;

  info.isFunction = isFunc;
  info.symbol = decl;
}
Ejemplo n.º 9
0
/// parseSymbols - Parse the symbols from the module and model-level ASM and add
/// them to either the defined or undefined lists.
bool LTOModule::parseSymbols(std::string &errMsg) {
  for (auto &Sym : IRFile->symbols()) {
    const GlobalValue *GV = IRFile->getSymbolGV(Sym.getRawDataRefImpl());
    uint32_t Flags = Sym.getFlags();
    if (Flags & object::BasicSymbolRef::SF_FormatSpecific)
      continue;

    bool IsUndefined = Flags & object::BasicSymbolRef::SF_Undefined;

    if (!GV) {
      SmallString<64> Buffer;
      {
        raw_svector_ostream OS(Buffer);
        Sym.printName(OS);
      }
      const char *Name = Buffer.c_str();

      if (IsUndefined)
        addAsmGlobalSymbolUndef(Name);
      else if (Flags & object::BasicSymbolRef::SF_Global)
        addAsmGlobalSymbol(Name, LTO_SYMBOL_SCOPE_DEFAULT);
      else
        addAsmGlobalSymbol(Name, LTO_SYMBOL_SCOPE_INTERNAL);
      continue;
    }

    auto *F = dyn_cast<Function>(GV);
    if (IsUndefined) {
      addPotentialUndefinedSymbol(Sym, F != nullptr);
      continue;
    }

    if (F) {
      addDefinedFunctionSymbol(Sym);
      continue;
    }

    if (isa<GlobalVariable>(GV)) {
      addDefinedDataSymbol(Sym);
      continue;
    }

    assert(isa<GlobalAlias>(GV));
    addDefinedDataSymbol(Sym);
  }

  // make symbols for all undefines
  for (StringMap<NameAndAttributes>::iterator u =_undefines.begin(),
         e = _undefines.end(); u != e; ++u) {
    // If this symbol also has a definition, then don't make an undefine because
    // it is a tentative definition.
    if (_defines.count(u->getKey())) continue;
    NameAndAttributes info = u->getValue();
    _symbols.push_back(info);
  }

  return false;
}
Ejemplo n.º 10
0
/// Launch each module's backend pipeline in a separate task in a thread pool.
static void thinLTOBackends(raw_fd_ostream *ApiFile,
                            const ModuleSummaryIndex &CombinedIndex) {
  unsigned TaskCount = 0;
  std::vector<ThinLTOTaskInfo> Tasks;
  Tasks.reserve(Modules.size());
  unsigned int MaxThreads = options::Parallelism
                                ? options::Parallelism
                                : thread::hardware_concurrency();

  // Create ThreadPool in nested scope so that threads will be joined
  // on destruction.
  {
    ThreadPool ThinLTOThreadPool(MaxThreads);
    for (claimed_file &F : Modules) {
      // Do all the gold callbacks in the main thread, since gold is not thread
      // safe by default.
      PluginInputFile InputFile(F.handle);
      const void *View = getSymbolsAndView(F);
      if (!View)
        continue;

      SmallString<128> Filename;
      if (!options::obj_path.empty())
        // Note that openOutputFile will append a unique ID for each task
        Filename = options::obj_path;
      else if (options::TheOutputType == options::OT_SAVE_TEMPS) {
        // Use the input file name so that we get a unique and identifiable
        // output file for each ThinLTO backend task.
        Filename = InputFile.file().name;
        Filename += ".thinlto.o";
      }
      bool TempOutFile = Filename.empty();

      SmallString<128> NewFilename;
      int FD = openOutputFile(Filename, TempOutFile, NewFilename,
                              // Only append the TaskID if we will use the
                              // non-unique obj_path.
                              !options::obj_path.empty() ? TaskCount : -1);
      TaskCount++;
      std::unique_ptr<raw_fd_ostream> OS =
          llvm::make_unique<raw_fd_ostream>(FD, true);

      // Enqueue the task
      ThinLTOThreadPool.async(thinLTOBackendTask, std::ref(F), View,
                              std::ref(InputFile.file()), ApiFile,
                              std::ref(CombinedIndex), OS.get(), TaskCount);

      // Record the information needed by the task or during its cleanup
      // to a ThinLTOTaskInfo instance. For information needed by the task
      // the unique_ptr ownership is transferred to the ThinLTOTaskInfo.
      Tasks.emplace_back(std::move(InputFile), std::move(OS),
                         NewFilename.c_str(), TempOutFile);
    }
  }

  for (auto &Task : Tasks)
    Task.cleanup();
}
Ejemplo n.º 11
0
void CodeGen::runSplitCodeGen(const SmallString<128> &BCFilename) {
  const std::string &TripleStr = M->getTargetTriple();
  Triple TheTriple(TripleStr);

  SubtargetFeatures Features = getFeatures(TheTriple);

  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
  CodeGenOpt::Level CGOptLevel = getCGOptLevel();

  SmallString<128> Filename;
  // Note that openOutputFile will append a unique ID for each task
  if (!options::obj_path.empty())
    Filename = options::obj_path;
  else if (options::TheOutputType == options::OT_SAVE_TEMPS)
    Filename = output_name + ".o";

  // Note that the default parallelism is 1 instead of the
  // hardware_concurrency, as there are behavioral differences between
  // parallelism levels (e.g. symbol ordering will be different, and some uses
  // of inline asm currently have issues with parallelism >1).
  unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1;

  std::vector<SmallString<128>> Filenames(MaxThreads);
  std::vector<SmallString<128>> BCFilenames(MaxThreads);
  bool TempOutFile = Filename.empty();
  {
    // Open a file descriptor for each backend task. This is done in a block
    // so that the output file descriptors are closed before gold opens them.
    std::list<llvm::raw_fd_ostream> OSs;
    std::vector<llvm::raw_pwrite_stream *> OSPtrs(MaxThreads);
    for (unsigned I = 0; I != MaxThreads; ++I) {
      int FD = openOutputFile(Filename, TempOutFile, Filenames[I],
                              // Only append ID if there are multiple tasks.
                              MaxThreads > 1 ? I : -1);
      OSs.emplace_back(FD, true);
      OSPtrs[I] = &OSs.back();
    }

    std::list<llvm::raw_fd_ostream> BCOSs;
    std::vector<llvm::raw_pwrite_stream *> BCOSPtrs;
    if (!BCFilename.empty() && MaxThreads > 1) {
      for (unsigned I = 0; I != MaxThreads; ++I) {
        int FD = openOutputFile(BCFilename, false, BCFilenames[I], I);
        BCOSs.emplace_back(FD, true);
        BCOSPtrs.push_back(&BCOSs.back());
      }
    }

    // Run backend tasks.
    splitCodeGen(std::move(M), OSPtrs, BCOSPtrs, options::mcpu, Features.getString(),
                 Options, RelocationModel, CodeModel::Default, CGOptLevel);
  }

  for (auto &Filename : Filenames)
    recordFile(Filename.c_str(), TempOutFile);
}
Ejemplo n.º 12
0
void LTOModule::addDefinedDataSymbol(const object::BasicSymbolRef &Sym) {
  SmallString<64> Buffer;
  {
    raw_svector_ostream OS(Buffer);
    Sym.printName(OS);
  }

  const GlobalValue *V = IRFile->getSymbolGV(Sym.getRawDataRefImpl());
  addDefinedDataSymbol(Buffer.c_str(), V);
}
Ejemplo n.º 13
0
void LTOModule::addDefinedFunctionSymbol(ModuleSymbolTable::Symbol Sym) {
  SmallString<64> Buffer;
  {
    raw_svector_ostream OS(Buffer);
    SymTab.printSymbolName(OS, Sym);
    Buffer.c_str();
  }

  const Function *F = cast<Function>(Sym.get<GlobalValue *>());
  addDefinedFunctionSymbol(Buffer, F);
}
Ejemplo n.º 14
0
void LTOModule::addDefinedDataSymbol(ModuleSymbolTable::Symbol Sym) {
  SmallString<64> Buffer;
  {
    raw_svector_ostream OS(Buffer);
    SymTab.printSymbolName(OS, Sym);
    Buffer.c_str();
  }

  const GlobalValue *V = Sym.get<GlobalValue *>();
  addDefinedDataSymbol(Buffer, V);
}
Ejemplo n.º 15
0
void LTOModule::addDefinedFunctionSymbol(const object::BasicSymbolRef &Sym) {
  SmallString<64> Buffer;
  {
    raw_svector_ostream OS(Buffer);
    Sym.printName(OS);
  }

  const Function *F =
      cast<Function>(IRFile->getSymbolGV(Sym.getRawDataRefImpl()));
  addDefinedFunctionSymbol(Buffer.c_str(), F);
}
Ejemplo n.º 16
0
TEST(TBDv2, WriteFile) {
  static const char tbd_v2_file3[] =
      "--- !tapi-tbd-v2\n"
      "archs:           [ i386, x86_64 ]\n"
      "platform:        macosx\n"
      "install-name:    '/usr/lib/libfoo.dylib'\n"
      "current-version: 1.2.3\n"
      "compatibility-version: 0\n"
      "swift-version:   5\n"
      "exports:         \n"
      "  - archs:           [ i386 ]\n"
      "    symbols:         [ _sym1 ]\n"
      "    weak-def-symbols: [ _sym2 ]\n"
      "    thread-local-symbols: [ _sym3 ]\n"
      "  - archs:           [ x86_64 ]\n"
      "    allowable-clients: [ clientA ]\n"
      "    re-exports:      [ '/usr/lib/libfoo.dylib' ]\n"
      "    symbols:         [ '_OBJC_EHTYPE_$_Class1' ]\n"
      "    objc-classes:    [ _Class1 ]\n"
      "    objc-ivars:      [ _Class1._ivar1 ]\n"
      "...\n";

  InterfaceFile File;
  File.setPath("libfoo.dylib");
  File.setInstallName("/usr/lib/libfoo.dylib");
  File.setFileType(FileType::TBD_V2);
  File.setArchitectures(AK_i386 | AK_x86_64);
  File.setPlatform(PlatformKind::macOS);
  File.setCurrentVersion(PackedVersion(1, 2, 3));
  File.setTwoLevelNamespace();
  File.setApplicationExtensionSafe();
  File.setSwiftABIVersion(5);
  File.setObjCConstraint(ObjCConstraintType::Retain_Release);
  File.addAllowableClient("clientA", AK_x86_64);
  File.addReexportedLibrary("/usr/lib/libfoo.dylib", AK_x86_64);
  File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", AK_i386);
  File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", AK_i386,
                 SymbolFlags::WeakDefined);
  File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", AK_i386,
                 SymbolFlags::ThreadLocalValue);
  File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", AK_x86_64);
  File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", AK_x86_64);
  File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1",
                 AK_x86_64);

  SmallString<4096> Buffer;
  raw_svector_ostream OS(Buffer);
  auto Result = TextAPIWriter::writeToStream(OS, File);
  EXPECT_FALSE(Result);
  EXPECT_STREQ(tbd_v2_file3, Buffer.c_str());
}
Ejemplo n.º 17
0
bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) {
  // make unique temp output file to put generated code
  SmallString<128> Filename;
  int FD;

  const char *Extension =
      (FileType == TargetMachine::CGFT_AssemblyFile ? "s" : "o");

  std::error_code EC =
      sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename);
  if (EC) {
    emitError(EC.message());
    return false;
  }

  // generate object file
  tool_output_file objFile(Filename.c_str(), FD);

  bool genResult = compileOptimized(&objFile.os());
  objFile.os().close();
  if (objFile.os().has_error()) {
    objFile.os().clear_error();
    sys::fs::remove(Twine(Filename));
    return false;
  }

  objFile.keep();
  if (!genResult) {
    sys::fs::remove(Twine(Filename));
    return false;
  }

  NativeObjectPath = Filename.c_str();
  *Name = NativeObjectPath.c_str();
  return true;
}
Ejemplo n.º 18
0
llvm::GlobalVariable *MSRTTIBuilder::getClassHierarchyDescriptor() {
  SmallString<256> MangledName;
  {
    llvm::raw_svector_ostream Out(MangledName);
    Mangler.mangleCXXRTTIClassHierarchyDescriptor(RD, Out);
  }

  // Check to see if we've already declared this ClassHierarchyDescriptor.
  if (auto CHD = Module.getNamedGlobal(MangledName))
    return CHD;

  // Serialize the class hierarchy and initialize the CHD Fields.
  SmallVector<MSRTTIClass, 8> Classes;
  serializeClassHierarchy(Classes, RD);
  Classes.front().initialize(/*Parent=*/0, /*Specifier=*/0);
  detectAmbiguousBases(Classes);
  int Flags = 0;
  for (auto Class : Classes) {
    if (Class.RD->getNumBases() > 1)
      Flags |= HasBranchingHierarchy;
    // Note: cl.exe does not calculate "HasAmbiguousBases" correctly.  We
    // believe the field isn't actually used.
    if (Class.Flags & MSRTTIClass::IsAmbiguous)
      Flags |= HasAmbiguousBases;
  }
  if ((Flags & HasBranchingHierarchy) && RD->getNumVBases() != 0)
    Flags |= HasVirtualBranchingHierarchy;
  // These gep indices are used to get the address of the first element of the
  // base class array.
  llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
                               llvm::ConstantInt::get(CGM.IntTy, 0)};

  // Forward-declare the class hierarchy descriptor
  auto Type = getClassHierarchyDescriptorType(CGM);
  auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
                                      /*Initializer=*/0, MangledName.c_str());

  // Initialize the base class ClassHierarchyDescriptor.
  llvm::Constant *Fields[] = {
    llvm::ConstantInt::get(CGM.IntTy, 0), // Unknown
    llvm::ConstantInt::get(CGM.IntTy, Flags),
    llvm::ConstantInt::get(CGM.IntTy, Classes.size()),
    llvm::ConstantExpr::getInBoundsGetElementPtr(
        getBaseClassArray(Classes),
        llvm::ArrayRef<llvm::Value *>(GEPIndices))};
  CHD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
  return CHD;
}
Ejemplo n.º 19
0
// Replace .. embedded in path for purposes of having
// a canonical path.
static std::string replaceDotDot(StringRef Path) {
  SmallString<128> Buffer;
  llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path),
    E = llvm::sys::path::end(Path);
  while (B != E) {
    if (B->compare(".") == 0) {
    }
    else if (B->compare("..") == 0)
      llvm::sys::path::remove_filename(Buffer);
    else
      llvm::sys::path::append(Buffer, *B);
    ++B;
  }
  if (Path.endswith("/") || Path.endswith("\\"))
    Buffer.append(1, Path.back());
  return Buffer.c_str();
}
Ejemplo n.º 20
0
std::string KleeHandler::getRunTimeLibraryPath(const char *argv0) {
  // allow specifying the path to the runtime library
  const char *env = getenv("KLEE_RUNTIME_LIBRARY_PATH");
  if (env)
    return std::string(env);

  // Take any function from the execution binary but not main (as not allowed by
  // C++ standard)
  void *MainExecAddr = (void *)(intptr_t)getRunTimeLibraryPath;
  SmallString<128> toolRoot(
      #if LLVM_VERSION_CODE >= LLVM_VERSION(3,4)
      llvm::sys::fs::getMainExecutable(argv0, MainExecAddr)
      #else
      llvm::sys::Path::GetMainExecutable(argv0, MainExecAddr).str()
      #endif
      );

  // Strip off executable so we have a directory path
  llvm::sys::path::remove_filename(toolRoot);

  SmallString<128> libDir;

  if ( strcmp(toolRoot.c_str(), KLEE_INSTALL_BIN_DIR ) == 0)
  {
    KLEE_DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() <<
                         "Using installed KLEE library runtime: ");
    libDir = KLEE_INSTALL_RUNTIME_DIR ;
  }
  else
  {
    KLEE_DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() <<
                         "Using build directory KLEE library runtime :");
    libDir = KLEE_DIR;
    llvm::sys::path::append(libDir,RUNTIME_CONFIGURATION);
    llvm::sys::path::append(libDir,"lib");
  }

  KLEE_DEBUG_WITH_TYPE("klee_runtime", llvm::dbgs() <<
                       libDir.c_str() << "\n");
  return libDir.str();
}
Ejemplo n.º 21
0
llvm::GlobalVariable *
MSRTTIBuilder::getBaseClassDescriptor(const MSRTTIClass &Class) {
  // Compute the fields for the BaseClassDescriptor.  They are computed up front
  // because they are mangled into the name of the object.
  uint32_t OffsetInVBTable = 0;
  int32_t VBPtrOffset = -1;
  if (Class.VirtualRoot) {
    auto &VTableContext = CGM.getMicrosoftVTableContext();
    OffsetInVBTable = VTableContext.getVBTableIndex(RD, Class.VirtualRoot) * 4;
    VBPtrOffset = Context.getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
  }

  SmallString<256> MangledName;
  {
    llvm::raw_svector_ostream Out(MangledName);
    Mangler.mangleCXXRTTIBaseClassDescriptor(Class.RD, Class.OffsetInVBase,
                                             VBPtrOffset, OffsetInVBTable,
                                             Class.Flags, Out);
  }

  // Check to see if we've already declared declared this object.
  if (auto BCD = Module.getNamedGlobal(MangledName))
    return BCD;

  // Forward-declare the base class descriptor.
  auto Type = getBaseClassDescriptorType(CGM);
  auto BCD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
                                      /*Initializer=*/0, MangledName.c_str());

  // Initialize the BaseClassDescriptor.
  llvm::Constant *Fields[] = {
    CGM.getMSTypeDescriptor(Context.getTypeDeclType(Class.RD)),
    llvm::ConstantInt::get(CGM.IntTy, Class.NumBases),
    llvm::ConstantInt::get(CGM.IntTy, Class.OffsetInVBase),
    llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
    llvm::ConstantInt::get(CGM.IntTy, OffsetInVBTable),
    llvm::ConstantInt::get(CGM.IntTy, Class.Flags),
    MSRTTIBuilder(CGM, Class.RD).getClassHierarchyDescriptor()};
  BCD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
  return BCD;
}
Ejemplo n.º 22
0
/// @brief Find program using shell lookup rules.
/// @param Program This is either an absolute path, relative path, or simple a
///        program name. Look in PATH for any programs that match. If no
///        extension is present, try all extensions in PATHEXT.
/// @return If ec == errc::success, The absolute path to the program. Otherwise
///         the return value is undefined.
static std::string FindProgram(const std::string &Program,
                               std::error_code &ec) {
  char PathName[MAX_PATH + 1];
  typedef SmallVector<StringRef, 12> pathext_t;
  pathext_t pathext;
  // Check for the program without an extension (in case it already has one).
  pathext.push_back("");
  SplitString(std::getenv("PATHEXT"), pathext, ";");

  for (pathext_t::iterator i = pathext.begin(), e = pathext.end(); i != e; ++i){
    SmallString<5> ext;
    for (std::size_t ii = 0, e = i->size(); ii != e; ++ii)
      ext.push_back(::tolower((*i)[ii]));
    LPCSTR Extension = NULL;
    if (ext.size() && ext[0] == '.')
      Extension = ext.c_str();
    DWORD length = ::SearchPathA(NULL,
                                 Program.c_str(),
                                 Extension,
                                 array_lengthof(PathName),
                                 PathName,
                                 NULL);
    if (length == 0)
      ec = windows_error(::GetLastError());
    else if (length > array_lengthof(PathName)) {
      // This may have been the file, return with error.
      ec = windows_error(ERROR_BUFFER_OVERFLOW);
      break;
    } else {
      // We found the path! Return it.
      ec = std::error_code();
      break;
    }
  }

  // Make sure PathName is valid.
  PathName[MAX_PATH] = 0;
  return PathName;
}
Ejemplo n.º 23
0
llvm::GlobalVariable *
MSRTTIBuilder::getCompleteObjectLocator(const VPtrInfo *Info) {
  SmallString<256> MangledName;
  {
    llvm::raw_svector_ostream Out(MangledName);
    Mangler.mangleCXXRTTICompleteObjectLocator(RD, Info->MangledPath, Out);
  }

  // Check to see if we've already computed this complete object locator.
  if (auto COL = Module.getNamedGlobal(MangledName))
    return COL;

  // Compute the fields of the complete object locator.
  int OffsetToTop = Info->FullOffsetInMDC.getQuantity();
  int VFPtrOffset = 0;
  // The offset includes the vtordisp if one exists.
  if (const CXXRecordDecl *VBase = Info->getVBaseWithVPtr())
    if (Context.getASTRecordLayout(RD)
      .getVBaseOffsetsMap()
      .find(VBase)
      ->second.hasVtorDisp())
      VFPtrOffset = Info->NonVirtualOffset.getQuantity() + 4;

  // Forward-declare the complete object locator.
  llvm::StructType *Type = getCompleteObjectLocatorType(CGM);
  auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
    /*Initializer=*/0, MangledName.c_str());

  // Initialize the CompleteObjectLocator.
  llvm::Constant *Fields[] = {
    llvm::ConstantInt::get(CGM.IntTy, 0), // IsDeltaEncoded
    llvm::ConstantInt::get(CGM.IntTy, OffsetToTop),
    llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset),
    CGM.getMSTypeDescriptor(Context.getTypeDeclType(RD)),
    getClassHierarchyDescriptor()};
  COL->setInitializer(llvm::ConstantStruct::get(Type, Fields));
  return COL;
}
Ejemplo n.º 24
0
void BuildSystemFrontendDelegate::commandStarted(Command* command) {
  // Don't report status if opted out by the command.
  if (!command->shouldShowStatus()) {
    return;
  }
  
  // Log the command.
  //
  // FIXME: Design the logging and status output APIs.
  SmallString<64> description;
  if (getFrontend().getInvocation().showVerboseStatus) {
    command->getVerboseDescription(description);
  } else {
    command->getShortDescription(description);

    // If the short description is empty, always show the verbose one.
    if (description.empty()) {
      command->getVerboseDescription(description);
    }
  }
  fprintf(stdout, "%s\n", description.c_str());
  fflush(stdout);
}
Ejemplo n.º 25
0
Logger::~Logger() {
  llvm::sys::ScopedLock L(LoggingMutex);

  static llvm::TimeRecord sBeginTR = llvm::TimeRecord::getCurrentTime();

  SmallString<64> LogMsg;
  llvm::raw_svector_ostream LogMsgOS(LogMsg);
  raw_ostream &OS = LogMsgOS;

  OS << '[' << int(CurrLevel) << ':' << Name << ':';

  // FIXME: Portability.
#if HAVE_PTHREAD_H && __APPLE__
  mach_port_t tid = pthread_mach_thread_np(pthread_self());
  OS << tid << ':';
#endif

  llvm::TimeRecord TR = llvm::TimeRecord::getCurrentTime();
  OS << llvm::format("%7.4f] ", TR.getWallTime() - sBeginTR.getWallTime());
  OS << Msg.str();

  llvm::errs() << LoggerName << ": " << LogMsg.str() << '\n';

#if __APPLE__
  // Use the Apple System Log facility.
  aslclient asl = asl_open(LoggerName.c_str(), "com.apple.console",
                           ASL_OPT_NO_DELAY);
  aslmsg msg = asl_new(ASL_TYPE_MSG);
  static const char *levstr[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
  asl_set(msg, ASL_KEY_LEVEL, levstr[int(CurrLevel)]);
  asl_set(msg, ASL_KEY_MSG, LogMsg.c_str());
  asl_send(asl, msg);
  asl_free(msg);
  asl_close(asl);
#endif
}
Ejemplo n.º 26
0
    // MCJIT will call this function before compiling any module
    // MCJIT takes ownership of both the MemoryBuffer object and the memory
    // to which it refers.
    virtual MemoryBuffer* getObject(const Module* M) {
        // Get the ModuleID
        const std::string ModuleID = M->getModuleIdentifier();

        // If we've flagged this as an IR file, cache it
        if (0 == ModuleID.compare(0, 3, "IR:")) {
            std::string IRFileName = ModuleID.substr(3);
            SmallString<128> IRCacheFile = CacheDir;
            sys::path::append(IRCacheFile, IRFileName);
            if (!sys::fs::exists(IRCacheFile.str())) {
                // This file isn't in our cache
                return NULL;
            }
            std::unique_ptr<MemoryBuffer> IRObjectBuffer;
            MemoryBuffer::getFile(IRCacheFile.c_str(), IRObjectBuffer, -1, false);
            // MCJIT will want to write into this buffer, and we don't want that
            // because the file has probably just been mmapped.  Instead we make
            // a copy.  The filed-based buffer will be released when it goes
            // out of scope.
            return MemoryBuffer::getMemBufferCopy(IRObjectBuffer->getBuffer());
        }

        return NULL;
    }
Ejemplo n.º 27
0
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
                        optional<size_t> Precision) {
  size_t Prec = Precision.value_or(getDefaultPrecision(Style));

  if (std::isnan(N)) {
    S << "nan";
    return;
  } else if (std::isinf(N)) {
    S << "INF";
    return;
  }

  char Letter;
  if (Style == FloatStyle::Exponent)
    Letter = 'e';
  else if (Style == FloatStyle::ExponentUpper)
    Letter = 'E';
  else
    Letter = 'f';

  SmallString<8> Spec;
  wpi::raw_svector_ostream Out(Spec);
  Out << "%." << Prec << Letter;

  if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
#ifdef _WIN32
// On MSVCRT and compatible, output of %e is incompatible to Posix
// by default. Number of exponent digits should be at least 2. "%+03d"
// FIXME: Implement our formatter to here or Support/Format.h!
#if defined(__MINGW32__)
    // FIXME: It should be generic to C++11.
    if (N == 0.0 && std::signbit(N)) {
      char NegativeZero[] = "-0.000000e+00";
      if (Style == FloatStyle::ExponentUpper)
        NegativeZero[strlen(NegativeZero) - 4] = 'E';
      S << NegativeZero;
      return;
    }
#else
    int fpcl = _fpclass(N);

    // negative zero
    if (fpcl == _FPCLASS_NZ) {
      char NegativeZero[] = "-0.000000e+00";
      if (Style == FloatStyle::ExponentUpper)
        NegativeZero[strlen(NegativeZero) - 4] = 'E';
      S << NegativeZero;
      return;
    }
#endif

    char buf[32];
    unsigned len;
    len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
    if (len <= sizeof(buf) - 2) {
      if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
          buf[len - 3] == '0') {
        int cs = buf[len - 4];
        if (cs == '+' || cs == '-') {
          int c1 = buf[len - 2];
          int c0 = buf[len - 1];
          if (isdigit(static_cast<unsigned char>(c1)) &&
              isdigit(static_cast<unsigned char>(c0))) {
            // Trim leading '0': "...e+012" -> "...e+12\0"
            buf[len - 3] = c1;
            buf[len - 2] = c0;
            buf[--len] = 0;
          }
        }
      }
      S << buf;
      return;
    }
#endif
  }

  if (Style == FloatStyle::Percent)
    N *= 100.0;

  char Buf[32];
  format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
  S << Buf;
  if (Style == FloatStyle::Percent)
    S << '%';
}
Ejemplo n.º 28
0
static void
performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
                      std::vector<NewArchiveIterator> &NewMembers) {
  SmallString<128> TmpArchive;
  failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a",
                                        TmpArchiveFD, TmpArchive));

  TemporaryOutput = TmpArchive.c_str();
  tool_output_file Output(TemporaryOutput, TmpArchiveFD);
  raw_fd_ostream &Out = Output.os();
  Out << "!<arch>\n";

  std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs;

  std::vector<std::unique_ptr<MemoryBuffer>> Buffers;
  std::vector<MemoryBufferRef> Members;

  for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) {
    NewArchiveIterator &Member = NewMembers[I];
    MemoryBufferRef MemberRef;

    if (Member.isNewMember()) {
      StringRef Filename = Member.getNew();
      int FD = Member.getFD();
      const sys::fs::file_status &Status = Member.getStatus();
      ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
          MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false);
      failIfError(MemberBufferOrErr.getError(), Filename);
      Buffers.push_back(std::move(MemberBufferOrErr.get()));
      MemberRef = Buffers.back()->getMemBufferRef();
    } else {
      object::Archive::child_iterator OldMember = Member.getOld();
      ErrorOr<MemoryBufferRef> MemberBufferOrErr =
          OldMember->getMemoryBufferRef();
      failIfError(MemberBufferOrErr.getError());
      MemberRef = MemberBufferOrErr.get();
    }
    Members.push_back(MemberRef);
  }

  if (Symtab) {
    writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs);
  }

  std::vector<unsigned> StringMapIndexes;
  writeStringTable(Out, NewMembers, StringMapIndexes);

  std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI =
      MemberOffsetRefs.begin();

  unsigned MemberNum = 0;
  unsigned LongNameMemberNum = 0;
  for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(),
                                                 E = NewMembers.end();
       I != E; ++I, ++MemberNum) {

    unsigned Pos = Out.tell();
    while (MemberRefsI != MemberOffsetRefs.end() &&
           MemberRefsI->second == MemberNum) {
      Out.seek(MemberRefsI->first);
      print32BE(Out, Pos);
      ++MemberRefsI;
    }
    Out.seek(Pos);

    MemoryBufferRef File = Members[MemberNum];
    if (I->isNewMember()) {
      StringRef FileName = I->getNew();
      const sys::fs::file_status &Status = I->getStatus();

      StringRef Name = sys::path::filename(FileName);
      if (Name.size() < 16)
        printMemberHeader(Out, Name, Status.getLastModificationTime(),
                          Status.getUser(), Status.getGroup(),
                          Status.permissions(), Status.getSize());
      else
        printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++],
                          Status.getLastModificationTime(), Status.getUser(),
                          Status.getGroup(), Status.permissions(),
                          Status.getSize());
    } else {
      object::Archive::child_iterator OldMember = I->getOld();
      StringRef Name = I->getName();

      if (Name.size() < 16)
        printMemberHeader(Out, Name, OldMember->getLastModified(),
                          OldMember->getUID(), OldMember->getGID(),
                          OldMember->getAccessMode(), OldMember->getSize());
      else
        printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++],
                          OldMember->getLastModified(), OldMember->getUID(),
                          OldMember->getGID(), OldMember->getAccessMode(),
                          OldMember->getSize());
    }

    Out << File.getBuffer();

    if (Out.tell() % 2)
      Out << '\n';
  }

  Output.keep();
  Out.close();
  sys::fs::rename(TemporaryOutput, ArchiveName);
  TemporaryOutput = nullptr;
}
Ejemplo n.º 29
0
static void codegen(std::unique_ptr<Module> M) {
  const std::string &TripleStr = M->getTargetTriple();
  Triple TheTriple(TripleStr);

  std::string ErrMsg;
  const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
  if (!TheTarget)
    message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());

  if (unsigned NumOpts = options::extra.size())
    cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);

  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(TheTriple);
  for (const std::string &A : MAttrs)
    Features.AddFeature(A);

  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
  CodeGenOpt::Level CGOptLevel;
  switch (options::OptLevel) {
  case 0:
    CGOptLevel = CodeGenOpt::None;
    break;
  case 1:
    CGOptLevel = CodeGenOpt::Less;
    break;
  case 2:
    CGOptLevel = CodeGenOpt::Default;
    break;
  case 3:
    CGOptLevel = CodeGenOpt::Aggressive;
    break;
  }
  std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
      TripleStr, options::mcpu, Features.getString(), Options, RelocationModel,
      CodeModel::Default, CGOptLevel));

  runLTOPasses(*M, *TM);

  if (options::TheOutputType == options::OT_SAVE_TEMPS)
    saveBCFile(output_name + ".opt.bc", *M);

  SmallString<128> Filename;
  if (!options::obj_path.empty())
    Filename = options::obj_path;
  else if (options::TheOutputType == options::OT_SAVE_TEMPS)
    Filename = output_name + ".o";

  std::vector<SmallString<128>> Filenames(options::Parallelism);
  bool TempOutFile = Filename.empty();
  {
    // Open a file descriptor for each backend thread. This is done in a block
    // so that the output file descriptors are closed before gold opens them.
    std::list<llvm::raw_fd_ostream> OSs;
    std::vector<llvm::raw_pwrite_stream *> OSPtrs(options::Parallelism);
    for (unsigned I = 0; I != options::Parallelism; ++I) {
      int FD;
      if (TempOutFile) {
        std::error_code EC =
            sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filenames[I]);
        if (EC)
          message(LDPL_FATAL, "Could not create temporary file: %s",
                  EC.message().c_str());
      } else {
        Filenames[I] = Filename;
        if (options::Parallelism != 1)
          Filenames[I] += utostr(I);
        std::error_code EC =
            sys::fs::openFileForWrite(Filenames[I], FD, sys::fs::F_None);
        if (EC)
          message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
      }
      OSs.emplace_back(FD, true);
      OSPtrs[I] = &OSs.back();
    }

    // Run backend threads.
    splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(),
                 Options, RelocationModel, CodeModel::Default, CGOptLevel);
  }

  for (auto &Filename : Filenames) {
    if (add_input_file(Filename.c_str()) != LDPS_OK)
      message(LDPL_FATAL,
              "Unable to add .o file to the link. File left behind in: %s",
              Filename.c_str());
    if (TempOutFile)
      Cleanup.push_back(Filename.c_str());
  }
}
Ejemplo n.º 30
0
/// Called by gold to see whether this file is one that our plugin can handle.
/// We'll try to open it and register all the symbols with add_symbol if
/// possible.
static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
                                        int *claimed) {
  LLVMContext Context;
  MemoryBufferRef BufferRef;
  std::unique_ptr<MemoryBuffer> Buffer;
  if (get_view) {
    const void *view;
    if (get_view(file->handle, &view) != LDPS_OK) {
      message(LDPL_ERROR, "Failed to get a view of %s", file->name);
      return LDPS_ERR;
    }
    BufferRef =
        MemoryBufferRef(StringRef((const char *)view, file->filesize), "");
  } else {
    int64_t offset = 0;
    // Gold has found what might be IR part-way inside of a file, such as
    // an .a archive.
    if (file->offset) {
      offset = file->offset;
    }
    ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
        MemoryBuffer::getOpenFileSlice(file->fd, file->name, file->filesize,
                                       offset);
    if (std::error_code EC = BufferOrErr.getError()) {
      message(LDPL_ERROR, EC.message().c_str());
      return LDPS_ERR;
    }
    Buffer = std::move(BufferOrErr.get());
    BufferRef = Buffer->getMemBufferRef();
  }

  Context.setDiagnosticHandler(diagnosticHandler);
  ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
      object::IRObjectFile::create(BufferRef, Context);
  std::error_code EC = ObjOrErr.getError();
  if (EC == object::object_error::invalid_file_type ||
      EC == object::object_error::bitcode_section_not_found)
    return LDPS_OK;

  *claimed = 1;

  if (EC) {
    message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s",
            EC.message().c_str());
    return LDPS_ERR;
  }
  std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr);

  Modules.resize(Modules.size() + 1);
  claimed_file &cf = Modules.back();

  cf.handle = file->handle;

  // If we are doing ThinLTO compilation, don't need to process the symbols.
  // Later we simply build a combined index file after all files are claimed.
  if (options::thinlto) return LDPS_OK;

  for (auto &Sym : Obj->symbols()) {
    uint32_t Symflags = Sym.getFlags();
    if (shouldSkip(Symflags))
      continue;

    cf.syms.push_back(ld_plugin_symbol());
    ld_plugin_symbol &sym = cf.syms.back();
    sym.version = nullptr;

    SmallString<64> Name;
    {
      raw_svector_ostream OS(Name);
      Sym.printName(OS);
    }
    sym.name = strdup(Name.c_str());

    const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());

    sym.visibility = LDPV_DEFAULT;
    if (GV) {
      switch (GV->getVisibility()) {
      case GlobalValue::DefaultVisibility:
        sym.visibility = LDPV_DEFAULT;
        break;
      case GlobalValue::HiddenVisibility:
        sym.visibility = LDPV_HIDDEN;
        break;
      case GlobalValue::ProtectedVisibility:
        sym.visibility = LDPV_PROTECTED;
        break;
      }
    }

    if (Symflags & object::BasicSymbolRef::SF_Undefined) {
      sym.def = LDPK_UNDEF;
      if (GV && GV->hasExternalWeakLinkage())
        sym.def = LDPK_WEAKUNDEF;
    } else {
      sym.def = LDPK_DEF;
      if (GV) {
        assert(!GV->hasExternalWeakLinkage() &&
               !GV->hasAvailableExternallyLinkage() && "Not a declaration!");
        if (GV->hasCommonLinkage())
          sym.def = LDPK_COMMON;
        else if (GV->isWeakForLinker())
          sym.def = LDPK_WEAKDEF;
      }
    }

    sym.size = 0;
    sym.comdat_key = nullptr;
    if (GV) {
      const GlobalObject *Base = getBaseObject(*GV);
      if (!Base)
        message(LDPL_FATAL, "Unable to determine comdat of alias!");
      const Comdat *C = Base->getComdat();
      if (C)
        sym.comdat_key = strdup(C->getName().str().c_str());
      else if (Base->hasWeakLinkage() || Base->hasLinkOnceLinkage())
        sym.comdat_key = strdup(sym.name);
    }

    sym.resolution = LDPR_UNKNOWN;
  }

  if (!cf.syms.empty()) {
    if (add_symbols(cf.handle, cf.syms.size(), cf.syms.data()) != LDPS_OK) {
      message(LDPL_ERROR, "Unable to add symbols!");
      return LDPS_ERR;
    }
  }

  return LDPS_OK;
}