Skip to content

Commit

Permalink
Copy, patch and monitor external binary plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
joern274 committed Jan 25, 2025
1 parent 3317129 commit 3691e9e
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 231 deletions.
1 change: 1 addition & 0 deletions cmake/detect_dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ endif()
# #### patchelf
# ###############################
message(STATUS "using patchelf from deps")
add_subdirectory(deps/patchelf)
add_library(patchelf::patchelf INTERFACE IMPORTED)
set_target_properties(patchelf::patchelf PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/deps/patchelf"
Expand Down
26 changes: 21 additions & 5 deletions deps/patchelf/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
# minimum required cmake version
cmake_minimum_required(VERSION 3.0)

set(PATCHELF_SRC patchelf.cc)
set(PATCHELF_HDR elf.h patchelf.h)
set(PATCHELF_DIR patchelf)
set(PATCHELF_SRC ${PATCHELF_DIR}/patchelf.cc)
set(PATCHELF_HDR ${PATCHELF_DIR}/elf.h ${PATCHELF_DIR}/patchelf.h)

add_library (patchelf::patchelf SHARED ${PATCHELF_SRC})
add_library (patchelf SHARED ${PATCHELF_SRC})

target_include_directories(patchelf::patchelf PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_include_directories(patchelf PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/patchelf>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")

install(TARGETS patchelf
LIBRARY DESTINATION ${LIBRARY_INSTALL_DIRECTORY}
PERMISSIONS
OWNER_READ
OWNER_WRITE
OWNER_EXECUTE
GROUP_READ
GROUP_EXECUTE
WORLD_READ
WORLD_EXECUTE
)

set_target_properties(patchelf PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/deps/patchelf"
)
File renamed without changes.
214 changes: 27 additions & 187 deletions deps/patchelf/patchelf.cc → deps/patchelf/patchelf/patchelf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ static bool clobberOldSections = true;
static std::vector<std::string> fileNames;
static std::string outputFileName;
static bool alwaysWrite = false;
static std::string oldRPath;
static std::vector<std::string> neededLibraries;
#ifdef DEFAULT_PAGESIZE
static int forcedPageSize = DEFAULT_PAGESIZE;
#else
Expand Down Expand Up @@ -1645,7 +1647,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,

switch (op) {
case rpPrint: {
printf("%s\n", rpath ? rpath : "");
oldRPath = std::string(rpath ? rpath : "");
return;
}
case rpRemove: {
Expand Down Expand Up @@ -1968,6 +1970,7 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
template<ElfFileParams>
void ElfFile<ElfFileParamNames>::printNeededLibs() const
{
neededLibraries.clear();
const auto shdrDynamic = findSectionHeader(".dynamic");
const auto shdrDynStr = findSectionHeader(".dynstr");
const char *strTab = (const char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
Expand All @@ -1977,7 +1980,7 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() const
for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_NEEDED) {
const char *name = strTab + rdi(dyn->d_un.d_val);
printf("%s\n", name);
neededLibraries.push_back(name);
}
}
}
Expand Down Expand Up @@ -2569,196 +2572,33 @@ static void showHelp(const std::string & progName)
FILENAME...\n", progName.c_str());
}


static int mainWrapped(int argc, char * * argv)
std::string patchelf::get_rpath(const std::string& filename)
{
if (argc <= 1) {
showHelp(argv[0]);
return 1;
}

if (getenv("PATCHELF_DEBUG") != nullptr)
debugMode = true;

int i;
for (i = 1; i < argc; ++i) {
std::string arg(argv[i]);
if (arg == "--set-interpreter" || arg == "--interpreter") {
if (++i == argc) error("missing argument");
newInterpreter = resolveArgument(argv[i]);
}
else if (arg == "--page-size") {
if (++i == argc) error("missing argument");
forcedPageSize = atoi(argv[i]);
if (forcedPageSize <= 0) error("invalid argument to --page-size");
}
else if (arg == "--print-interpreter") {
printInterpreter = true;
}
else if (arg == "--print-os-abi") {
printOsAbi = true;
}
else if (arg == "--set-os-abi") {
if (++i == argc) error("missing argument");
setOsAbi = true;
newOsAbi = resolveArgument(argv[i]);
}
else if (arg == "--print-soname") {
printSoname = true;
}
else if (arg == "--set-soname") {
if (++i == argc) error("missing argument");
setSoname = true;
newSoname = resolveArgument(argv[i]);
}
else if (arg == "--remove-rpath") {
removeRPath = true;
}
else if (arg == "--shrink-rpath") {
shrinkRPath = true;
}
else if (arg == "--allowed-rpath-prefixes") {
if (++i == argc) error("missing argument");
allowedRpathPrefixes = splitColonDelimitedString(argv[i]);
}
else if (arg == "--set-rpath") {
if (++i == argc) error("missing argument");
setRPath = true;
newRPath = resolveArgument(argv[i]);
}
else if (arg == "--add-rpath") {
if (++i == argc) error("missing argument");
addRPath = true;
newRPath = resolveArgument(argv[i]);
}
else if (arg == "--print-rpath") {
printRPath = true;
}
else if (arg == "--force-rpath") {
/* Generally we prefer to emit DT_RUNPATH instead of
DT_RPATH, as the latter is obsolete. However, there is
a slight semantic difference: DT_RUNPATH is "scoped",
it only affects the executable or library in question,
not its recursive imports. So maybe you really want to
force the use of DT_RPATH. That's what this option
does. Without it, DT_RPATH (if encountered) is
converted to DT_RUNPATH, and if neither is present, a
DT_RUNPATH is added. With it, DT_RPATH isn't converted
to DT_RUNPATH, and if neither is present, a DT_RPATH is
added. */
forceRPath = true;
}
else if (arg == "--print-needed") {
printNeeded = true;
}
else if (arg == "--no-sort") {
noSort = true;
}
else if (arg == "--add-needed") {
if (++i == argc) error("missing argument");
neededLibsToAdd.insert(resolveArgument(argv[i]));
}
else if (arg == "--remove-needed") {
if (++i == argc) error("missing argument");
neededLibsToRemove.insert(resolveArgument(argv[i]));
}
else if (arg == "--replace-needed") {
if (i+2 >= argc) error("missing argument(s)");
neededLibsToReplace[ argv[i+1] ] = argv[i+2];
i += 2;
}
else if (arg == "--clear-symbol-version") {
if (++i == argc) error("missing argument");
symbolsToClearVersion.insert(resolveArgument(argv[i]));
}
else if (arg == "--print-execstack") {
printExecstack = true;
}
else if (arg == "--clear-execstack") {
clearExecstack = true;
}
else if (arg == "--set-execstack") {
setExecstack = true;
}
else if (arg == "--output") {
if (++i == argc) error("missing argument");
outputFileName = resolveArgument(argv[i]);
alwaysWrite = true;
}
else if (arg == "--debug") {
debugMode = true;
}
else if (arg == "--no-default-lib") {
noDefaultLib = true;
}
else if (arg == "--add-debug-tag") {
addDebugTag = true;
}
else if (arg == "--rename-dynamic-symbols") {
renameDynamicSymbols = true;
if (++i == argc) error("missing argument");

const char* fname = argv[i];
std::ifstream infile(fname);
if (!infile) error(fmt("Cannot open map file ", fname));

std::string line, from, to;
size_t lineCount = 1;
while (std::getline(infile, line))
{
std::istringstream iss(line);
if (!(iss >> from))
break;
if (!(iss >> to))
error(fmt(fname, ":", lineCount, ": Map file line is missing the second element"));
if (symbolsToRenameKeys.count(from))
error(fmt(fname, ":", lineCount, ": Name '", from, "' appears twice in the map file"));
if (from.find('@') != std::string_view::npos || to.find('@') != std::string_view::npos)
error(fmt(fname, ":", lineCount, ": Name pair contains version tag: ", from, " ", to));
lineCount++;
symbolsToRename[*symbolsToRenameKeys.insert(from).first] = to;
}
}
else if (arg == "--no-clobber-old-sections") {
clobberOldSections = false;
}
else if (arg == "--help" || arg == "-h" ) {
showHelp(argv[0]);
return 0;
}
else if (arg == "--version") {
printf(PACKAGE_STRING "\n");
return 0;
}
else {
fileNames.push_back(arg);
}
}

if (fileNames.empty()) error("missing filename");

if (!outputFileName.empty() && fileNames.size() != 1)
error("--output option only allowed with single input file");

if (setRPath && addRPath)
error("--set-rpath option not allowed with --add-rpath");

fileNames.push_back(filename);
printRPath = true;
patchElf();
return oldRPath;
}

return 0;
void patchelf::set_rpath(const std::string& filename, const std::string& rp)
{
fileNames.push_back(filename);
setRPath = true;
newRPath = rp;
patchElf();
}

int main(int argc, char * * argv)
std::vector<std::string> patchelf::get_needed_libraries(const std::string& filename)
{
#ifdef __OpenBSD__
if (pledge("stdio rpath wpath cpath", NULL) == -1)
error("pledge");
#endif
fileNames.push_back(filename);
printNeeded = true;
patchElf();
return neededLibraries;
}

try {
return mainWrapped(argc, argv);
} catch (std::exception & e) {
fprintf(stderr, "patchelf: %s\n", e.what());
return 1;
}
void patchelf::replace_needed_library(const std::string& filename, const std::string& oldLib, const std::string& newLib)
{
fileNames.push_back(filename);
neededLibsToReplace[oldLib] = newLib;
patchElf();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

#include "elf.h"

namespace patchelf {
std::string get_rpath(const std::string& filename);
void set_rpath(const std::string& filename, const std::string& rp);
std::vector<std::string> get_needed_libraries(const std::string& filename);
void replace_needed_library(const std::string& filename, const std::string& oldLib, const std::string& newLib);
}

using FileContents = std::shared_ptr<std::vector<unsigned char>>;

#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Versym, class Elf_Verdef, class Elf_Verdaux, class Elf_Verneed, class Elf_Vernaux, class Elf_Rel, class Elf_Rela, unsigned ElfClass
Expand Down
4 changes: 1 addition & 3 deletions plugins/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ if(PL_GUI OR BUILD_ALL_PLUGINS)
message(STATUS "Using system's quazip from ${QUAZIP_LIBRARIES}")
endif()

add_subdirectory(patchelf::patchelf)

foreach(i IN ITEMS "" "_DEBUG" "_RELEASE" "_MINSIZEREL" "_RELWITHDEBINFO")
foreach(j IN ITEMS "RUNTIME" "ARCHIVE" "LIBRARY")
set(CMAKE_${j}_OUTPUT_DIRECTORY${i} ${STORE_${j}_OUTDIR${i}})
Expand Down Expand Up @@ -116,7 +114,7 @@ if(PL_GUI OR BUILD_ALL_PLUGINS)
PRIVATE ${COMPILE_OPTIONS_PRIVATE}
INTERFACE ${COMPILE_OPTIONS_INTERFACE})
target_compile_definitions(gui PUBLIC QT_NO_KEYWORDS)
target_link_libraries(gui PUBLIC hal::core hal::netlist PRIVATE ${Python3_LIBRARIES} pybind11::embed Qt5::Widgets Qt5::Concurrent Qt5::Svg QuaZip::QuaZip)
target_link_libraries(gui PUBLIC hal::core hal::netlist PRIVATE ${Python3_LIBRARIES} pybind11::embed Qt5::Widgets Qt5::Concurrent Qt5::Svg QuaZip::QuaZip patchelf)
add_dependencies(gui update_internal_gate_library_definitions)
get_property(GLDIR GLOBAL PROPERTY GATE_LIBS_DEFINITIONS)
file(WRITE "${RSRCROOT}/path/gate_library_definitions.txt" "${GLDIR}")
Expand Down
25 changes: 23 additions & 2 deletions plugins/gui/include/gui/plugin_relay/gui_plugin_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <QTableView>
#include <QItemDelegate>
#include <QMenu>
#include <QFileSystemWatcher>

#include "gui/gui_utils/netlist.h"
#include "hal_core/plugin_system/plugin_manager.h"
Expand All @@ -48,6 +49,25 @@ class QPushButton;
namespace hal {
class GuiExtensionInterface;

class ExternalBinaryPlugin : public QObject
{
Q_OBJECT
QString mPluginName;
QString mSourcePath;
QString mTargetPath;
enum DirectoryType { UnknownDir, LibDir, PluginDir };
static QString libquazipName();
QMultiMap<DirectoryType, QString> getLibraryRpath() const;
static QString halLibraryPath(DirectoryType dirType);
public:
QFileSystemWatcher* mFileWatcher;
ExternalBinaryPlugin(const QString& plugName, const QString& filename);
QString sourcePath() const { return mSourcePath; }
QString targetPath() const { return mTargetPath; }
QString pluginName() const { return mPluginName; }
void updateLibraryPath();
};

class GuiPluginEntry
{
public:
Expand All @@ -57,7 +77,7 @@ namespace hal {
QString mVersion;
QString mDescription;
QString mFilePath;
QString mExternalPath;
ExternalBinaryPlugin* mExternalBinaryPlugin;
QDateTime mFileModified;
QStringList mDependencies;
FacExtensionInterface::Feature mFeature;
Expand All @@ -70,6 +90,7 @@ namespace hal {
public:
GuiPluginEntry(const QFileInfo& info);
GuiPluginEntry(const QSettings* settings);
~GuiPluginEntry();
QVariant data(int icol) const;
QString name() const { return mName; }
void persist(QSettings* settings) const;
Expand Down Expand Up @@ -137,6 +158,7 @@ namespace hal {
void handlePluginLoaded(const QString& pluginName, const QString& path);
void handlePluginUnloaded(const QString& pluginName, const QString& path);
void handleRefresh();
void handleExternalBinaryPluginChanged();
public:
GuiPluginTable(GuiPluginManager* parent = nullptr);
~GuiPluginTable();
Expand Down Expand Up @@ -202,7 +224,6 @@ namespace hal {
QColor mHilightBackgroundColor;
QLabel* mIconLegend[4];

void setLdLibraryPath();
Q_SIGNALS:
void backToNetlist();
private Q_SLOTS:
Expand Down
Loading

0 comments on commit 3691e9e

Please sign in to comment.