1//===----------------------------------------------------------------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Plugins/PassPlugin.h"
10#include "llvm/ADT/DenseMap.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/Support/raw_ostream.h"
13
14#include <cstdint>
15
16using namespace llvm;
17
18Expected<PassPlugin> PassPlugin::load(StringRef Filename) {
19 std::string Error;
20 auto Library =
21 sys::DynamicLibrary::getPermanentLibrary(filename: Filename.str().c_str(), errMsg: &Error);
22 if (!Library.isValid())
23 return make_error<StringError>(Args: Twine("Could not load library '") +
24 Filename + "': " + Error,
25 Args: inconvertibleErrorCode());
26
27 PassPlugin P{Filename.str(), Library};
28
29 // llvmGetPassPluginInfo should be resolved to the definition from the plugin
30 // we are currently loading.
31 intptr_t getDetailsFn =
32 (intptr_t)Library.getAddressOfSymbol(symbolName: "llvmGetPassPluginInfo");
33
34 if (!getDetailsFn)
35 // If the symbol isn't found, this is probably a legacy plugin, which is an
36 // error
37 return make_error<StringError>(Args: Twine("Plugin entry point not found in '") +
38 Filename + "'. Is this a legacy plugin?",
39 Args: inconvertibleErrorCode());
40
41 P.Info = reinterpret_cast<decltype(llvmGetPassPluginInfo) *>(getDetailsFn)();
42
43 if (P.Info.APIVersion != LLVM_PLUGIN_API_VERSION)
44 return make_error<StringError>(
45 Args: Twine("Wrong API version on plugin '") + Filename + "'. Got version " +
46 Twine(P.Info.APIVersion) + ", supported version is " +
47 Twine(LLVM_PLUGIN_API_VERSION) + ".",
48 Args: inconvertibleErrorCode());
49
50 return P;
51}
52
53Error llvm::passPluginArguments(ArrayRef<PassPluginLibraryInfo> Infos,
54 ArrayRef<std::string> Args) {
55 DenseMap<StringRef, unsigned> Index;
56 for (auto [I, Info] : enumerate(First&: Infos))
57 if (!Index.try_emplace(Key: Info.PluginName, Args&: I).second)
58 return createStringError(S: "multiple pass plugins are named '" +
59 Twine(Info.PluginName) + "'");
60 // ParseArguments takes argv-style C strings. The argument is the suffix of
61 // Arg after the first comma, so it is NUL-terminated and needs no copy.
62 SmallVector<SmallVector<const char *, 0>, 0> PluginArgs(Infos.size());
63 for (const std::string &Arg : Args) {
64 auto [Name, Rest] = StringRef(Arg).split(Separator: ',');
65 // Rest is null without a comma and empty for an empty argument.
66 if (!Rest.data())
67 return createStringError(S: "expected <plugin>,<arg> in -plugin-arg=" + Arg);
68 auto It = Index.find(Val: Name);
69 if (It == Index.end())
70 return createStringError(S: "no pass plugin named '" + Name +
71 "' is loaded, in -plugin-arg=" + Arg);
72 PluginArgs[It->second].push_back(Elt: Rest.data());
73 }
74 for (auto [Info, PArgs] : zip_equal(t&: Infos, u&: PluginArgs)) {
75 if (PArgs.empty())
76 continue;
77 if (!Info.ParseArguments)
78 return createStringError(S: "pass plugin '" + Twine(Info.PluginName) +
79 "' does not accept arguments");
80 if (Error E = Info.ParseArguments(PArgs))
81 return E;
82 }
83 return Error::success();
84}
85