Improve API for ELF RUN_PATH / RPATH

This commit is contained in:
Romain Thomas 2017-09-12 15:05:30 +02:00
parent 1e410e6c95
commit c375a47da7
7 changed files with 307 additions and 6 deletions

View File

@ -37,7 +37,12 @@ void init_ELF_DynamicEntryRpath_class(py::module& m) {
py::class_<DynamicEntryRpath, DynamicEntry>(m, "DynamicEntryRpath")
.def(py::init<const std::string &>(),
"Constructor from (r)path",
"path"_a)
"path"_a = "")
.def(py::init<const std::vector<std::string> &>(),
"Constructor from a list of paths",
"paths"_a)
.def_property("name",
[] (const DynamicEntryRpath& obj) {
return safe_string_converter(obj.name());
@ -52,6 +57,34 @@ void init_ELF_DynamicEntryRpath_class(py::module& m) {
static_cast<setter_t<const std::string&>>(&DynamicEntryRpath::rpath),
"Return path value")
.def_property("paths",
static_cast<getter_t<std::vector<std::string> >>(&DynamicEntryRpath::paths),
static_cast<setter_t<const std::vector<std::string>&>>(&DynamicEntryRpath::paths),
"Paths as a list")
.def("insert",
&DynamicEntryRpath::insert,
"Insert a ``path`` at the given ``position``",
"position"_a, "path"_a,
py::return_value_policy::reference)
.def("append",
&DynamicEntryRpath::append,
"Append the given ``path`` ",
"path"_a,
py::return_value_policy::reference)
.def("remove",
&DynamicEntryRpath::remove,
"Remove the given ``path`` ",
"path"_a,
py::return_value_policy::reference)
.def(py::self += std::string())
.def(py::self -= std::string())
.def("__eq__", &DynamicEntryRpath::operator==)
.def("__ne__", &DynamicEntryRpath::operator!=)
.def("__hash__",

View File

@ -37,21 +37,53 @@ void init_ELF_DynamicEntryRunPath_class(py::module& m) {
py::class_<DynamicEntryRunPath, DynamicEntry>(m, "DynamicEntryRunPath")
.def(py::init<const std::string &>(),
"Constructor from (run)path",
"path"_a)
"path"_a = "")
.def(py::init<const std::vector<std::string> &>(),
"Constructor from a list of paths",
"paths"_a)
.def_property("name",
[] (const DynamicEntryRunPath& obj) {
return safe_string_converter(obj.name());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryRunPath::name),
"Return path value")
"Runpath raw value")
.def_property("runpath",
[] (const DynamicEntryRunPath& obj) {
return safe_string_converter(obj.runpath());
},
static_cast<setter_t<const std::string&>>(&DynamicEntryRunPath::runpath),
"Return path value")
"Runpath raw value")
.def_property("paths",
static_cast<getter_t<std::vector<std::string> >>(&DynamicEntryRunPath::paths),
static_cast<setter_t<const std::vector<std::string>&>>(&DynamicEntryRunPath::paths),
"Paths as a list")
.def("insert",
&DynamicEntryRunPath::insert,
"Insert a ``path`` at the given ``position``",
"position"_a, "path"_a,
py::return_value_policy::reference)
.def("append",
&DynamicEntryRunPath::append,
"Append the given ``path`` ",
"path"_a,
py::return_value_policy::reference)
.def("remove",
&DynamicEntryRunPath::remove,
"Remove the given ``path`` ",
"path"_a,
py::return_value_policy::reference)
.def(py::self += std::string())
.def(py::self -= std::string())
.def("__eq__", &DynamicEntryRunPath::operator==)
.def("__ne__", &DynamicEntryRunPath::operator!=)

View File

@ -28,6 +28,7 @@ namespace ELF {
class DLL_PUBLIC DynamicEntryRpath : public DynamicEntry {
public:
static constexpr char delimiter = ':';
using DynamicEntry::DynamicEntry;
DynamicEntryRpath(const Elf64_Dyn* header);
@ -36,6 +37,9 @@ class DLL_PUBLIC DynamicEntryRpath : public DynamicEntry {
DynamicEntryRpath(const std::string& name = "");
//! @brief Constructor from a list of paths
DynamicEntryRpath(const std::vector<std::string>& paths);
DynamicEntryRpath& operator=(const DynamicEntryRpath&);
DynamicEntryRpath(const DynamicEntryRpath&);
@ -45,6 +49,22 @@ class DLL_PUBLIC DynamicEntryRpath : public DynamicEntry {
const std::string& rpath(void) const;
void rpath(const std::string& name);
//! @brief Paths as a list
std::vector<std::string> paths(void) const;
void paths(const std::vector<std::string>& paths);
//! @brief Insert a ``path`` at the given ``position``
DynamicEntryRpath& insert(size_t pos, const std::string path);
//! @brief Append the given ``path``
DynamicEntryRpath& append(const std::string& path);
//! @brief Remove the given ``path``
DynamicEntryRpath& remove(const std::string& path);
DynamicEntryRpath& operator+=(const std::string& path);
DynamicEntryRpath& operator-=(const std::string& path);
virtual void accept(Visitor& visitor) const override;
virtual std::ostream& print(std::ostream& os) const override;

View File

@ -27,23 +27,46 @@ namespace ELF {
class DLL_PUBLIC DynamicEntryRunPath : public DynamicEntry {
public:
static constexpr char delimiter = ':';
using DynamicEntry::DynamicEntry;
DynamicEntryRunPath(const Elf64_Dyn* header);
DynamicEntryRunPath(const Elf32_Dyn* header);
DynamicEntryRunPath(void);
//! @brief Constructor from (run)path
DynamicEntryRunPath(const std::string& name = "");
//! @brief Constructor from a list of paths
DynamicEntryRunPath(const std::vector<std::string>& paths);
DynamicEntryRunPath& operator=(const DynamicEntryRunPath&);
DynamicEntryRunPath(const DynamicEntryRunPath&);
//! @brief Runpath raw value
virtual const std::string& name(void) const override;
virtual void name(const std::string& name) override;
//! @brief Runpath raw value
const std::string& runpath(void) const;
void runpath(const std::string& runpath);
//! @brief Paths as a list
std::vector<std::string> paths(void) const;
void paths(const std::vector<std::string>& paths);
//! @brief Insert a ``path`` at the given ``position``
DynamicEntryRunPath& insert(size_t pos, const std::string path);
//! @brief Append the given ``path``
DynamicEntryRunPath& append(const std::string& path);
//! @brief Remove the given ``path``
DynamicEntryRunPath& remove(const std::string& path);
DynamicEntryRunPath& operator+=(const std::string& path);
DynamicEntryRunPath& operator-=(const std::string& path);
virtual void accept(Visitor& visitor) const override;
virtual std::ostream& print(std::ostream& os) const override;

View File

@ -16,6 +16,8 @@
#include "LIEF/ELF/DynamicEntryRpath.hpp"
#include <iomanip>
#include <numeric>
#include <sstream>
namespace LIEF {
namespace ELF {
@ -39,6 +41,14 @@ DynamicEntryRpath::DynamicEntryRpath(const std::string& rpath) :
{
}
DynamicEntryRpath::DynamicEntryRpath(const std::vector<std::string>& paths) :
DynamicEntry::DynamicEntry{DYNAMIC_TAGS::DT_RPATH, 0},
rpath_{""}
{
this->paths(paths);
}
const std::string& DynamicEntryRpath::name(void) const {
return this->rpath_;
}
@ -57,6 +67,70 @@ void DynamicEntryRpath::rpath(const std::string& rpath) {
this->name(rpath);
}
std::vector<std::string> DynamicEntryRpath::paths(void) const {
std::stringstream ss;
ss.str(this->rpath());
std::string path;
std::vector<std::string> paths;
while (std::getline(ss, path, DynamicEntryRpath::delimiter)) {
paths.push_back(path);
}
return paths;
}
void DynamicEntryRpath::paths(const std::vector<std::string>& paths) {
this->rpath_ = std::accumulate(
std::begin(paths),
std::end(paths),
std::string(""),
[] (std::string path, const std::string& new_entry) {
return path.empty() ? new_entry : path + DynamicEntryRpath::delimiter + new_entry;
});
}
DynamicEntryRpath& DynamicEntryRpath::append(const std::string& path) {
std::vector<std::string> paths = this->paths();
paths.push_back(path);
this->paths(paths);
return *this;
}
DynamicEntryRpath& DynamicEntryRpath::remove(const std::string& path) {
std::vector<std::string> paths = this->paths();
paths.erase(std::remove_if(
std::begin(paths),
std::end(paths),
[&path] (const std::string& p) {
return p == path;
}), std::end(paths));
this->paths(paths);
return *this;
}
DynamicEntryRpath& DynamicEntryRpath::insert(size_t pos, const std::string path) {
std::vector<std::string> paths = this->paths();
if (pos == paths.size()) {
return this->append(path);
}
if (pos > paths.size()) {
throw corrupted(std::to_string(pos) + " is out of ranges");
}
paths.insert(std::begin(paths) + pos, path);
this->paths(paths);
return *this;
}
DynamicEntryRpath& DynamicEntryRpath::operator+=(const std::string& path) {
return this->append(path);
}
DynamicEntryRpath& DynamicEntryRpath::operator-=(const std::string& path) {
return this->remove(path);
}
void DynamicEntryRpath::accept(Visitor& visitor) const {
DynamicEntry::accept(visitor);
visitor(*this); // Double dispatch to avoid down-casting

View File

@ -16,6 +16,8 @@
#include "LIEF/ELF/DynamicEntryRunPath.hpp"
#include <iomanip>
#include <numeric>
#include <sstream>
namespace LIEF {
namespace ELF {
@ -39,6 +41,16 @@ DynamicEntryRunPath::DynamicEntryRunPath(const std::string& runpath) :
{
}
DynamicEntryRunPath::DynamicEntryRunPath(const std::vector<std::string>& paths) :
DynamicEntry::DynamicEntry{DYNAMIC_TAGS::DT_RUNPATH, 0},
runpath_{""}
{
this->paths(paths);
}
const std::string& DynamicEntryRunPath::name(void) const {
return this->runpath_;
}
@ -52,11 +64,74 @@ const std::string& DynamicEntryRunPath::runpath(void) const {
return this->name();
}
void DynamicEntryRunPath::runpath(const std::string& runpath) {
this->name(runpath);
}
std::vector<std::string> DynamicEntryRunPath::paths(void) const {
std::stringstream ss;
ss.str(this->runpath());
std::string path;
std::vector<std::string> paths;
while (std::getline(ss, path, DynamicEntryRunPath::delimiter)) {
paths.push_back(path);
}
return paths;
}
void DynamicEntryRunPath::paths(const std::vector<std::string>& paths) {
this->runpath_ = std::accumulate(
std::begin(paths),
std::end(paths),
std::string(""),
[] (std::string path, const std::string& new_entry) {
return path.empty() ? new_entry : path + DynamicEntryRunPath::delimiter + new_entry;
});
}
DynamicEntryRunPath& DynamicEntryRunPath::append(const std::string& path) {
std::vector<std::string> paths = this->paths();
paths.push_back(path);
this->paths(paths);
return *this;
}
DynamicEntryRunPath& DynamicEntryRunPath::remove(const std::string& path) {
std::vector<std::string> paths = this->paths();
paths.erase(std::remove_if(
std::begin(paths),
std::end(paths),
[&path] (const std::string& p) {
return p == path;
}), std::end(paths));
this->paths(paths);
return *this;
}
DynamicEntryRunPath& DynamicEntryRunPath::insert(size_t pos, const std::string path) {
std::vector<std::string> paths = this->paths();
if (pos == paths.size()) {
return this->append(path);
}
if (pos > paths.size()) {
throw corrupted(std::to_string(pos) + " is out of ranges");
}
paths.insert(std::begin(paths) + pos, path);
this->paths(paths);
return *this;
}
DynamicEntryRunPath& DynamicEntryRunPath::operator+=(const std::string& path) {
return this->append(path);
}
DynamicEntryRunPath& DynamicEntryRunPath::operator-=(const std::string& path) {
return this->remove(path);
}
void DynamicEntryRunPath::accept(Visitor& visitor) const {
DynamicEntry::accept(visitor);
visitor(*this); // Double dispatch to avoid down-casting

View File

@ -157,6 +157,50 @@ class TestDynamic(TestCase):
self.assertTrue(all(e.tag != lief.ELF.DYNAMIC_TAGS.NEEDED for e in binadd.dynamic_entries))
def test_runpath_api(self):
sample = LibAddSample()
libadd = lief.parse(sample.libadd)
binadd = lief.parse(sample.binadd)
rpath = lief.ELF.DynamicEntryRunPath()
rpath = binadd.add(rpath)
self.logger.debug(rpath)
rpath += "/tmp"
self.logger.debug(rpath)
self.assertEqual(rpath.paths, ["/tmp"])
self.assertEqual(rpath.runpath, "/tmp")
rpath.insert(0, "/foo")
self.assertEqual(rpath.paths, ["/foo", "/tmp"])
self.assertEqual(rpath.runpath, "/foo:/tmp")
rpath.paths = ["/foo", "/tmp", "/bar"]
self.logger.debug(rpath)
self.assertEqual(rpath.paths, ["/foo", "/tmp", "/bar"])
self.assertEqual(rpath.runpath, "/foo:/tmp:/bar")
rpath -= "/tmp"
self.logger.debug(rpath)
self.assertEqual(rpath.runpath, "/foo:/bar")
rpath.remove("/foo").remove("/bar")
self.logger.debug(rpath)
self.assertEqual(rpath.runpath, "")
self.logger.debug(rpath)
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_change_libname(self):
@ -187,7 +231,7 @@ class TestDynamic(TestCase):
libadd_needed.name = new_name
# Add a RPATH entry
rpath = lief.ELF.DynamicEntryRpath(sample.directory)
rpath = lief.ELF.DynamicEntryRunPath(sample.directory)
rpath = binadd.add(rpath)
self.logger.debug(rpath)