Skip to content

Commit 953b489

Browse files
authored
Prepare CaGe to be extensible via plugins (tudasc#129)
* Prepare CaGe to be extensible via plugins * Move Plugin interface to dedicated interface include directory * add interface library for client tools to link against * Fix bug when creating unique pointer from loaded plugin
1 parent 3a31d27 commit 953b489

9 files changed

Lines changed: 116 additions & 39 deletions

File tree

tools/cage/include/cage/generator/CallGraphConsumer.h

Lines changed: 0 additions & 22 deletions
This file was deleted.

tools/cage/include/cage/generator/CallgraphGenerator.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* License: Part of the MetaCG project. Licensed under BSD 3 clause license. See LICENSE.txt file at
44
* https://github.com/tudasc/metacg/LICENSE.txt
55
*/
6-
#include "cage/generator/CallGraphConsumer.h"
6+
#include "../interface/CaGePlugin.h"
77

88
#include "io/MCGWriter.h"
99

@@ -18,13 +18,13 @@ class Generator {
1818
public:
1919
explicit Generator(PTAType ptaType) : ptaType(ptaType) {};
2020

21-
void addConsumer(std::unique_ptr<CallGraphConsumer> consumer) { consumers.push_back(std::move(consumer)); }
21+
void addPlugin(std::unique_ptr<Plugin> consumer) { plugins.push_back(std::move(consumer)); }
2222

2323
bool run(llvm::Module& M, llvm::ModuleAnalysisManager* MA);
2424

2525
private:
2626
PTAType ptaType;
27-
std::vector<std::unique_ptr<CallGraphConsumer>> consumers;
27+
std::vector<std::unique_ptr<Plugin>> plugins;
2828
};
2929

3030
} // namespace cage

tools/cage/include/cage/generator/FileExporter.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
#ifndef METACG_FILEEXPORTER_H
77
#define METACG_FILEEXPORTER_H
88

9-
#include "cage/generator/CallGraphConsumer.h"
9+
#include "cage/interface/CaGePlugin.h"
1010

1111
#include <string>
1212

1313
namespace cage {
1414

15-
class FileExporter : public CallGraphConsumer {
15+
class FileExporter : public Plugin {
1616
public:
17-
FileExporter(std::string outfile) : outfile(outfile) {}
18-
void consumeCallGraph(metacg::Callgraph&) override;
17+
FileExporter(const std::string& outfile) : outfile(outfile) {}
18+
void consumeCallGraph(const metacg::Callgraph&) override;
1919

2020
private:
2121
std::string outfile;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* File: CallGraphConsumer.h
3+
* License: Part of the MetaCG project. Licensed under BSD 3 clause license. See LICENSE.txt file at
4+
* https://github.com/tudasc/metacg/LICENSE.txt
5+
*/
6+
#ifndef METACG_CAGEPLUGIN_H
7+
#define METACG_CAGEPLUGIN_H
8+
9+
#include <string> //can not predeclare std::string
10+
11+
namespace metacg {
12+
class Callgraph;
13+
class Metadata;
14+
}
15+
16+
namespace llvm {
17+
class Module;
18+
}
19+
20+
namespace cage {
21+
22+
struct Plugin {
23+
virtual ~Plugin() = default;
24+
/**
25+
* Overwrite if you need to modify the graph, e.g. adding nodes, edges or metadata, based on the LLVM Module
26+
* This will be called before any consumers can consume the graph
27+
* For multiple plugins, invocations of this function are executed in the order the plugins were registered
28+
* @param m the full LLVM::Module as available to the pass
29+
* @param cg the metacg callgraph to be modified
30+
* @return void
31+
*/
32+
virtual void augmentCallGraph(const llvm::Module& m, metacg::Callgraph& cg) {}
33+
34+
/**
35+
* Overwrite this if you only need to read from the graph, e.g. converting to different formats, or graph analysis
36+
* @param cg the metacg callgraph to be read from
37+
*/
38+
virtual void consumeCallGraph(const metacg::Callgraph& cg){};
39+
40+
/**
41+
* Overwrite this if you want your Plugin to be listed with a name in the debug logs
42+
* @return the logging name of your plugin
43+
*/
44+
[[nodiscard]] virtual std::string getPluginName() const { return "unnamed Plugin"; }
45+
};
46+
47+
} // namespace cage
48+
49+
50+
51+
#endif // METACG_CAGEPLUGIN_H

tools/cage/src/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
include(AddLLVM)
22

3-
add_llvm_pass_plugin(cage-plugin Plugin.cpp)
3+
add_llvm_pass_plugin(cage-plugin CaGe.cpp)
44
target_include_directories(cage-plugin PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/tools/cage/include>)
55
target_link_libraries(cage-plugin PRIVATE cage)
66

7+
add_library(cage-plugin-interface INTERFACE)
8+
target_include_directories(
9+
cage-plugin-interface INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/tools/cage/include/cage/interface>
10+
)
11+
target_link_libraries(cage-plugin-interface INTERFACE metacg::metacg)
12+
713
add_subdirectory(generator)
Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
* License: Part of the MetaCG project. Licensed under BSD 3 clause license. See LICENSE.txt file at
44
* https://github.com/tudasc/metacg/LICENSE.txt
55
*/
6-
#include "cage/Plugin.h"
6+
#include "cage/CaGe.h"
7+
#include "cage/interface/CaGePlugin.h"
78

8-
#include "llvm/IR/LegacyPassManager.h"
99
#include "llvm/Passes/PassBuilder.h"
1010
#include "llvm/Passes/PassPlugin.h"
11+
#include "llvm/Support/DynamicLibrary.h"
1112

1213
#include "cage/generator/CallgraphGenerator.h"
1314
#include "cage/generator/FileExporter.h"
@@ -30,7 +31,32 @@ static opt<cage::PTAType> pta(
3031

3132
static opt<std::string> cgout("cg-file", desc("Output file for the generated call graph"), cat(cageOpts), init(""));
3233

34+
static list<std::string> pluginPaths("plugin-paths", desc("option list"), cat(cageOpts), CommaSeparated);
35+
3336
namespace cage {
37+
38+
Plugin* loadPlugin(const std::string& pluginPath) {
39+
metacg::MCGLogger::instance().getConsole()->debug("Loading plugin");
40+
std::string err;
41+
auto lib = sys::DynamicLibrary::getPermanentLibrary(pluginPath.c_str(), &err);
42+
if (!lib.isValid()) {
43+
metacg::MCGLogger::instance().getErrConsole()->error("cannot locate the library at {}!", pluginPath);
44+
metacg::MCGLogger::instance().getErrConsole()->error("Reason: {}", err);
45+
return nullptr;
46+
}
47+
metacg::MCGLogger::instance().getConsole()->trace("Getting collection object from plugin {}", pluginPath);
48+
void* sym = lib.getAddressOfSymbol("getPlugin");
49+
if (!sym) {
50+
metacg::MCGLogger::instance().getErrConsole()->error(
51+
"Could not load collectors from plugin, no Function \"getPlugin()\"!");
52+
return nullptr;
53+
}
54+
auto getPlugin = reinterpret_cast<Plugin* (*)()>(sym);
55+
Plugin* loadedPlugin = getPlugin();
56+
metacg::MCGLogger::logInfo("Successfully loaded Plugin: {}", loadedPlugin->getPluginName());
57+
return loadedPlugin;
58+
}
59+
3460
PreservedAnalyses CaGe::run(Module& M, ModuleAnalysisManager& MA) {
3561
if (cageVerbose) {
3662
outs() << "Running CaGe in verbose mode\n";
@@ -40,8 +66,7 @@ PreservedAnalyses CaGe::run(Module& M, ModuleAnalysisManager& MA) {
4066
std::string outfile = cgout.getValue();
4167
if (outfile.empty()) {
4268
// If empty, check environment variable
43-
const auto* cgNameEnv = std::getenv("CAGE_CG");
44-
if (cgNameEnv) {
69+
if (const auto* cgNameEnv = std::getenv("CAGE_CG")) {
4570
outfile = cgNameEnv;
4671
} else {
4772
// Default output file
@@ -50,7 +75,15 @@ PreservedAnalyses CaGe::run(Module& M, ModuleAnalysisManager& MA) {
5075
}
5176

5277
Generator gen(pta);
53-
gen.addConsumer(std::make_unique<FileExporter>(outfile));
78+
gen.addPlugin(std::make_unique<FileExporter>(outfile));
79+
80+
// Load external plugins
81+
for (const auto& pluginPath : pluginPaths) {
82+
SPDLOG_INFO("Loading external plugin from: {}", pluginPath);
83+
if (auto p = std::unique_ptr<Plugin>(loadPlugin(pluginPath))) {
84+
gen.addPlugin(std::move(p));
85+
}
86+
}
5487

5588
if (!gen.run(M, &MA))
5689
return PreservedAnalyses::all();
@@ -84,6 +117,7 @@ llvm::PassPluginLibraryInfo getPluginInfo() {
84117
if (Name == "CaGe") {
85118
outs() << "Registering CaGe to run as pipeline described\n";
86119
MPM.addPass(cage::CaGe());
120+
87121
return true;
88122
} else {
89123
outs() << "Did not register CaGe\n";

tools/cage/src/generator/CallGraphGenerator.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ struct CallBaseVisitor : public llvm::InstVisitor<CallBaseVisitor> {
138138
}
139139
origin = functionInfoMap[F]->getFilename().str();
140140
}
141+
141142
return mcg->getOrInsertNode(nameToUse.str(), std::move(origin), false, hasBody);
142143
}
143144

@@ -166,9 +167,16 @@ bool Generator::run(Module& M, ModuleAnalysisManager* MA) {
166167
// Take resulting metacg call graph
167168
auto mcg = cbv.takeResult();
168169

169-
// Run registered consumers
170-
for (auto& consumer : consumers) {
171-
consumer->consumeCallGraph(*mcg);
170+
// Run registered plugin's augmentation
171+
for (auto& plugin : plugins) {
172+
metacg::MCGLogger::instance().debug("Running {} augment",plugin->getPluginName());
173+
plugin->augmentCallGraph(M,*mcg);
174+
}
175+
176+
// Run registered plugins consumption
177+
for (auto& plugin : plugins) {
178+
metacg::MCGLogger::instance().debug("Running {} consume", plugin->getPluginName());
179+
plugin->consumeCallGraph(*mcg);
172180
}
173181
}
174182
return false;

tools/cage/src/generator/FileExporter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace cage {
1515

16-
void FileExporter::consumeCallGraph(metacg::Callgraph& graph) {
16+
void FileExporter::consumeCallGraph(const metacg::Callgraph& graph) {
1717
metacg::io::JsonSink jsSink;
1818
metacg::io::VersionFourMCGWriter mcgw({{4, 0}, {"CaGe", 0, 1, MetaCG_GIT_SHA}}, true, true);
1919
mcgw.write(&graph, jsSink);

0 commit comments

Comments
 (0)