diff --git a/repos/base/include/base/shared_object.h b/repos/base/include/base/shared_object.h index fc24b71cf9..f4dd1622fe 100644 --- a/repos/base/include/base/shared_object.h +++ b/repos/base/include/base/shared_object.h @@ -149,6 +149,8 @@ class Genode::Dynamic_linker static void _for_each_loaded_object(Env &, For_each_fn const &); + static void *_respawn(Env &, char const *, char const *); + public: /** @@ -169,6 +171,31 @@ class Genode::Dynamic_linker _for_each_loaded_object(env, wrapped_fn); } + + /** + * Prevent loaded shared object 'name' to be unloaded + */ + static void keep(Env &, char const *name); + + typedef Shared_object::Invalid_rom_module Invalid_rom_module; + typedef Shared_object::Invalid_symbol Invalid_symbol; + + /** + * Replace executable binary + * + * \param binary_name ROM module name of new executable binary + * \param start_symbol symbol name of the binary's entry point + * + * \return pointer to entry point of the new executable + * + * \throw Invalid_rom_module + * \throw Invalid_symbol + */ + template + static T respawn(Env &env, char const *binary_name, char const *entrypoint_name) + { + return reinterpret_cast(_respawn(env, binary_name, entrypoint_name)); + } }; #endif /* _INCLUDE__BASE__SHARED_OBJECT_H_ */ diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 0afaeb5f61..aebb9d3dc0 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -107,6 +107,8 @@ _ZN6Genode13Shared_objectD2Ev T _ZN6Genode13sleep_foreverEv T _ZN6Genode14Capability_map6insertEmm T _ZN6Genode14Dynamic_linker23_for_each_loaded_objectERNS_3EnvERKNS0_11For_each_fnE T +_ZN6Genode14Dynamic_linker4keepERNS_3EnvEPKc T +_ZN6Genode14Dynamic_linker8_respawnERNS_3EnvEPKcS4_ T _ZN6Genode14Rpc_entrypoint13_free_rpc_capERNS_10Pd_sessionENS_17Native_capabilityE T _ZN6Genode14Rpc_entrypoint14_alloc_rpc_capERNS_10Pd_sessionENS_17Native_capabilityEm T _ZN6Genode14Rpc_entrypoint17_activation_entryEv T diff --git a/repos/base/src/lib/ldso/dependency.cc b/repos/base/src/lib/ldso/dependency.cc index cb66211c4e..50d8dafaac 100644 --- a/repos/base/src/lib/ldso/dependency.cc +++ b/repos/base/src/lib/ldso/dependency.cc @@ -35,6 +35,9 @@ Linker::Dependency::Dependency(Env &env, Allocator &md_alloc, Linker::Dependency::~Dependency() { + if (!_unload_on_destruct) + return; + if (!_obj.unload()) return; diff --git a/repos/base/src/lib/ldso/include/debug.h b/repos/base/src/lib/ldso/include/debug.h index e3099c6222..c59c793dce 100644 --- a/repos/base/src/lib/ldso/include/debug.h +++ b/repos/base/src/lib/ldso/include/debug.h @@ -103,6 +103,11 @@ struct Linker::Link_map static void add(Link_map *map) { + /* prevent duplicates */ + for (Link_map *m = first; m; m = m->next) + if (m == map) + return; + map->next = nullptr; if (!first) { first = map; diff --git a/repos/base/src/lib/ldso/include/linker.h b/repos/base/src/lib/ldso/include/linker.h index 8ce581902c..3dab1fef28 100644 --- a/repos/base/src/lib/ldso/include/linker.h +++ b/repos/base/src/lib/ldso/include/linker.h @@ -166,6 +166,8 @@ class Linker::Object : private Fifo::Element, virtual void relocate(Bind) = 0; + virtual bool keep() const = 0; + virtual void load() = 0; virtual bool unload() { return false;} @@ -219,6 +221,7 @@ class Linker::Dependency : public Fifo::Element, Noncopyable Object &_obj; Root_object *_root = nullptr; Allocator *_md_alloc = nullptr; + bool const _unload_on_destruct = true; /** * Check if file is in this dependency tree @@ -232,7 +235,10 @@ class Linker::Dependency : public Fifo::Element, Noncopyable /* * Called by 'Ld' constructor */ - Dependency(Object &obj, Root_object *root) : _obj(obj), _root(root) { } + Dependency(Object &obj, Root_object *root) + : + _obj(obj), _root(root), _unload_on_destruct(false) + { } Dependency(Env &, Allocator &, char const *path, Root_object *, Fifo &, Keep); @@ -282,7 +288,8 @@ class Linker::Root_object ~Root_object() { _deps.dequeue_all([&] (Dependency &d) { - destroy(_md_alloc, &d); }); + if (!d.obj().keep()) + destroy(_md_alloc, &d); }); } Link_map const &link_map() const @@ -303,6 +310,8 @@ class Linker::Root_object void enqueue(Dependency &dep) { _deps.enqueue(dep); } + void remove_dependency(Dependency &dep) { _deps.remove(dep); } + Fifo &deps() { return _deps; } }; diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index 69fac32a1b..c639c7ae65 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -84,10 +84,10 @@ class Linker::Elf_object : public Object, private Fifo::Element friend class Fifo; - Link_map _map { }; - unsigned _ref_count { 1 }; - unsigned const _keep { KEEP }; - bool _relocated { false }; + Link_map _map { }; + unsigned _ref_count { 1 }; + Keep _keep { KEEP }; + bool _relocated { false }; /* * Optional ELF file, skipped for initial 'Ld' initialization @@ -153,6 +153,7 @@ class Linker::Elf_object : public Object, private Fifo::Element /* remove from loaded objects list */ obj_list()->remove(*this); + Init::list()->remove(this); } /** @@ -191,6 +192,8 @@ class Linker::Elf_object : public Object, private Fifo::Element Link_map::add(&_map); }; + void force_keep() { _keep = KEEP; } + Link_map const &link_map() const override { return _map; } Dynamic const &dynamic() const override { return _dyn; } @@ -241,6 +244,8 @@ class Linker::Elf_object : public Object, private Fifo::Element void load() override { _ref_count++; } bool unload() override { return (_keep == DONT_KEEP) && !(--_ref_count); } + bool keep() const override { return _keep == KEEP; } + bool is_linker() const override { return false; } bool is_binary() const override { return false; } }; @@ -272,6 +277,8 @@ struct Linker::Ld : private Dependency, Elf_object bool is_linker() const override { return true; } + bool keep() const override { return true; } + /** * Entry point for jump relocations, it is called from assembly code and is implemented * right below) @@ -349,11 +356,11 @@ struct Linker::Binary : private Root_object, public Elf_object bool static_construction_finished = false; - Binary(Env &env, Allocator &md_alloc, Config const &config) + Binary(Env &env, Allocator &md_alloc, Config const &config, char const *name) : Root_object(md_alloc), - Elf_object(env, md_alloc, binary_name(), - *new (md_alloc) Dependency(*this, this), KEEP), + Elf_object(env, md_alloc, name, + *new (md_alloc) Dependency(*this, this), DONT_KEEP), _check_ctors(config.check_ctors()) { /* create dep for binary and linker */ @@ -697,6 +704,35 @@ void Genode::Dynamic_linker::_for_each_loaded_object(Env &, For_each_fn const &f } +void Dynamic_linker::keep(Env &, char const *binary) +{ + Elf_object::obj_list()->for_each([&] (Elf_object &obj) { + if (Object::Name(binary) == obj.name()) + obj.force_keep(); }); +} + + +void *Dynamic_linker::_respawn(Env &env, char const *binary, char const *entry_name) +{ + Object::Name const name(binary); + + /* unload original binary */ + binary_ptr->~Binary(); + + Config const config(env); + + /* load new binary */ + construct_at(binary_ptr, env, *heap(), config, name.string()); + + try { + return (void *)binary_ptr->lookup_symbol(entry_name); + } + catch (...) { } + + throw Dynamic_linker::Invalid_symbol(); +} + + void Component::construct(Genode::Env &env) { /* read configuration */ @@ -706,7 +742,7 @@ void Component::construct(Genode::Env &env) /* load binary and all dependencies */ try { - binary_ptr = unmanaged_singleton(env, *heap(), config); + binary_ptr = unmanaged_singleton(env, *heap(), config, binary_name()); } catch(Linker::Not_found &symbol) { error("LD: symbol not found: '", symbol, "'"); throw;