From 4b46abf813b801bc9d1555795fc5b9ce13c588ee Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 4 Jul 2018 18:48:04 +0200 Subject: [PATCH] base: rm first-class support for static binaries This patch removes the detection of statically linked executables from the base framework. It thereby fixes the corner cases encountered with Sculpt when obtaining the binaries of the runtime from the depot_rom service that is hosted within the runtime. Statically linked binaries and hybrid Linux/Genode (lx_hybrid) binaries can still be started by relabeling the ROM-session route of "ld.lib.so" to the binary name, pretending that the binary is the dynamic linker. This can be achieved via init's label rewriting mechanism: However, as this is quite cryptic and would need to be applied for all lx_hybrid components, the patch adds a shortcut to init's configuration. One can simply add the 'ld="no"' attribute to the node of the corresponding component: Fixes #2866 --- repos/base-linux/run/lx_fs.run | 2 +- repos/base-linux/run/lx_hybrid_ctors.run | 2 +- repos/base-linux/run/lx_hybrid_errno.run | 2 +- repos/base-linux/run/lx_hybrid_exception.run | 2 +- .../base-linux/run/lx_hybrid_pthread_ipc.run | 2 +- .../base-linux/src/lib/base/child_process.cc | 40 +++-------- repos/base-nova/run/platform.run | 2 +- repos/base/include/base/child.h | 40 +++++------ repos/base/src/lib/base/child.cc | 5 +- repos/base/src/lib/base/child_process.cc | 72 +++++++------------ repos/gems/run/cpu_load_display.run | 2 +- repos/gems/run/gpt_write.run | 2 +- repos/gems/run/leitzentrale.run | 2 +- repos/libports/run/avplay.run | 2 +- repos/libports/run/mesa.inc | 2 +- repos/libports/run/qt5_drivers.inc | 2 +- repos/libports/run/sdl.run | 2 +- .../drivers_interactive-linux/drivers.config | 2 +- repos/os/run/block_tester.run | 2 +- repos/os/run/demo.run | 2 +- repos/os/run/fb_bench.run | 2 +- repos/os/run/framebuffer.run | 2 +- repos/os/run/input.run | 2 +- repos/os/run/loader.run | 2 +- repos/os/run/lx_block.run | 2 +- repos/os/run/pointer.run | 2 +- repos/os/run/rom_to_file.run | 2 +- repos/os/src/init/child.cc | 4 ++ repos/os/src/init/child.h | 5 ++ repos/os/src/init/config.xsd | 1 + repos/ports/run/dosbox.run | 2 +- repos/ports/run/netperf.inc | 8 ++- repos/ports/run/seoul.inc | 5 +- repos/ports/run/virtualbox.run | 2 +- repos/ports/src/noux/child_policy.h | 2 + 35 files changed, 102 insertions(+), 130 deletions(-) diff --git a/repos/base-linux/run/lx_fs.run b/repos/base-linux/run/lx_fs.run index 5e8f6c653..8162b567f 100644 --- a/repos/base-linux/run/lx_fs.run +++ b/repos/base-linux/run/lx_fs.run @@ -32,7 +32,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_ctors.run b/repos/base-linux/run/lx_hybrid_ctors.run index f5064a40c..6fa4e07ec 100644 --- a/repos/base-linux/run/lx_hybrid_ctors.run +++ b/repos/base-linux/run/lx_hybrid_ctors.run @@ -32,7 +32,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_errno.run b/repos/base-linux/run/lx_hybrid_errno.run index 8f9548f76..2a47c87b8 100644 --- a/repos/base-linux/run/lx_hybrid_errno.run +++ b/repos/base-linux/run/lx_hybrid_errno.run @@ -25,7 +25,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_exception.run b/repos/base-linux/run/lx_hybrid_exception.run index 29ef601f5..18bc0d228 100644 --- a/repos/base-linux/run/lx_hybrid_exception.run +++ b/repos/base-linux/run/lx_hybrid_exception.run @@ -31,7 +31,7 @@ install_config { - + diff --git a/repos/base-linux/run/lx_hybrid_pthread_ipc.run b/repos/base-linux/run/lx_hybrid_pthread_ipc.run index d151fd5dd..1468b210a 100644 --- a/repos/base-linux/run/lx_hybrid_pthread_ipc.run +++ b/repos/base-linux/run/lx_hybrid_pthread_ipc.run @@ -28,7 +28,7 @@ install_config { - + diff --git a/repos/base-linux/src/lib/base/child_process.cc b/repos/base-linux/src/lib/base/child_process.cc index 9427d8b37..48fd021c3 100644 --- a/repos/base-linux/src/lib/base/child_process.cc +++ b/repos/base-linux/src/lib/base/child_process.cc @@ -50,7 +50,7 @@ void Child::Initial_thread::start(addr_t) { } /* * On Linux, the ELF loading is performed by the kernel */ -Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability, +Child::Process::Loaded_executable::Loaded_executable(Type, Dataspace_capability, Ram_session &, Region_map &, @@ -58,51 +58,27 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability, Parent_capability) { } -Child::Process::Process(Dataspace_capability elf_ds, +Child::Process::Process(Type type, Dataspace_capability ldso_ds, - Pd_session_capability, Pd_session &pd, - Ram_session &ram, Initial_thread_base &, Region_map &local_rm, Region_map &remote_rm, Parent_capability parent_cap) : - loaded_executable(elf_ds, ldso_ds, ram, local_rm, remote_rm, parent_cap) + loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap) { /* skip loading when called during fork */ - if (!elf_ds.valid()) + if (type == TYPE_FORKED) return; - /* attach ELF locally */ - addr_t elf_addr; - try { elf_addr = local_rm.attach(elf_ds); } - catch (Region_map::Invalid_dataspace) { - error("local attach of ELF executable failed (Invalid_dataspace)"); throw; } - catch (Region_map::Region_conflict) { - error("local attach of ELF executable failed (Region_conflict)"); throw; } - - /* setup ELF object and read program entry pointer */ - Elf_binary elf(elf_addr); - if (!elf.valid()) - throw Invalid_executable(); - - bool const dynamically_linked = elf.dynamically_linked(); - - local_rm.detach(elf_addr); - /* * If the specified executable is a dynamically linked program, we load * the dynamic linker instead. */ - if (dynamically_linked) { - - if (!ldso_ds.valid()) { - error("attempt to start dynamic executable without dynamic linker"); - throw Missing_dynamic_linker(); - } - - elf_ds = ldso_ds; + if (!ldso_ds.valid()) { + error("attempt to start dynamic executable without dynamic linker"); + throw Missing_dynamic_linker(); } pd.assign_parent(parent_cap); @@ -110,7 +86,7 @@ Child::Process::Process(Dataspace_capability elf_ds, Linux_native_pd_client lx_pd(static_cap_cast(pd.native_pd())); - lx_pd.start(elf_ds); + lx_pd.start(ldso_ds); } diff --git a/repos/base-nova/run/platform.run b/repos/base-nova/run/platform.run index a674eb9cb..0adfbcd62 100644 --- a/repos/base-nova/run/platform.run +++ b/repos/base-nova/run/platform.run @@ -24,7 +24,7 @@ set config { - + } append config " diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index ffab7cc50..ea001a4ea 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -222,6 +222,11 @@ struct Genode::Child_policy * would otherwise produce a deadlock. */ virtual Region_map *address_space(Pd_session &) { return nullptr; } + + /** + * Return true if ELF loading should be inhibited + */ + virtual bool forked() const { return false; } }; @@ -344,6 +349,8 @@ class Genode::Child : protected Rpc_object, class Missing_dynamic_linker : Exception { }; class Invalid_executable : Exception { }; + enum Type { TYPE_LOADED, TYPE_FORKED }; + struct Loaded_executable { /** @@ -368,7 +375,7 @@ class Genode::Child : protected Rpc_object, * \throw Out_of_ram * \throw Out_of_caps */ - Loaded_executable(Dataspace_capability elf_ds, + Loaded_executable(Type type, Dataspace_capability ldso_ds, Ram_session &ram, Region_map &local_rm, @@ -379,11 +386,6 @@ class Genode::Child : protected Rpc_object, /** * Constructor * - * \param ram RAM session used to allocate the BSS and - * DATA segments for the new process - * \param parent parent of the new protection domain - * \param name name of protection domain - * * \throw Missing_dynamic_linker * \throw Invalid_executable * \throw Region_map::Region_conflict @@ -391,25 +393,21 @@ class Genode::Child : protected Rpc_object, * \throw Out_of_ram * \throw Out_of_caps * - * The other arguments correspond to those of 'Child::Child'. - * * On construction of a protection domain, the initial thread is * started immediately. * - * The argument 'elf_ds' may be invalid to create an empty process. - * In this case, all process initialization steps except for the - * creation of the initial thread must be done manually, i.e., as - * done for implementing fork. + * The 'type' 'TYPE_FORKED' creates an empty process. In this case, + * all process initialization steps except for the creation of the + * initial thread must be done manually, i.e., as done for + * implementing fork. */ - Process(Dataspace_capability elf_ds, - Dataspace_capability ldso_ds, - Pd_session_capability pd_cap, - Pd_session &pd, - Ram_session &ram, - Initial_thread_base &initial_thread, - Region_map &local_rm, - Region_map &remote_rm, - Parent_capability parent); + Process(Type type, + Dataspace_capability ldso_ds, + Pd_session &pd, + Initial_thread_base &initial_thread, + Region_map &local_rm, + Region_map &remote_rm, + Parent_capability parent); ~Process(); }; diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 99b74f604..b2132f1e3 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -771,10 +771,11 @@ void Child::_try_construct_env_dependent_members() _policy.init(_cpu.session(), _cpu.cap()); + Process::Type const type = _policy.forked() + ? Process::TYPE_FORKED : Process::TYPE_LOADED; try { _initial_thread.construct(_cpu.session(), _pd.cap(), _policy.name()); - _process.construct(_binary.session().dataspace(), _linker_dataspace(), - _pd.cap(), _pd.session(), _pd.session(), + _process.construct(type, _linker_dataspace(), _pd.session(), *_initial_thread, _local_rm, Child_address_space(_pd.session(), _policy).region_map(), cap()); diff --git a/repos/base/src/lib/base/child_process.cc b/repos/base/src/lib/base/child_process.cc index 420005854..63d4c9945 100644 --- a/repos/base/src/lib/base/child_process.cc +++ b/repos/base/src/lib/base/child_process.cc @@ -24,53 +24,32 @@ using namespace Genode; -Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds, +Child::Process::Loaded_executable::Loaded_executable(Type type, Dataspace_capability ldso_ds, - Ram_session &ram, + Pd_session &pd, Region_map &local_rm, Region_map &remote_rm, Parent_capability parent_cap) { /* skip loading when called during fork */ - if (!elf_ds.valid()) + if (type == TYPE_FORKED) return; - /* attach ELF locally */ - addr_t elf_addr; - try { elf_addr = local_rm.attach(elf_ds); } - catch (Region_map::Invalid_dataspace) { - error("local attach of ELF executable failed (invalid dataspace)"); throw; } - catch (Region_map::Region_conflict) { - error("local attach of ELF executable failed (region conflict)"); throw; } - - /* setup ELF object and read program entry pointer */ - Elf_binary elf(elf_addr); - if (!elf.valid()) - throw Invalid_executable(); - - /* - * If the specified executable is a dynamically linked program, we load - * the dynamic linker instead. - */ - if (elf.dynamically_linked()) { - - local_rm.detach(elf_addr); - - if (!ldso_ds.valid()) { - error("attempt to start dynamic executable without dynamic linker"); - throw Missing_dynamic_linker(); - } - - try { elf_addr = local_rm.attach(ldso_ds); } - catch (Region_map::Invalid_dataspace) { - error("dynamic linker is an invalid dataspace"); throw; } - catch (Region_map::Region_conflict) { - error("region conflict while attaching dynamic linker"); throw; } - - elf_ds = ldso_ds; - elf = Elf_binary(elf_addr); + /* locally attach ELF binary of the dynamic linker */ + if (!ldso_ds.valid()) { + error("attempt to start dynamic executable without dynamic linker"); + throw Missing_dynamic_linker(); } + addr_t elf_addr = 0; + try { elf_addr = local_rm.attach(ldso_ds); } + catch (Region_map::Invalid_dataspace) { + error("dynamic linker is an invalid dataspace"); throw; } + catch (Region_map::Region_conflict) { + error("region conflict while attaching dynamic linker"); throw; } + + Elf_binary elf(elf_addr); + entry = elf.entry(); /* setup region map for the new pd */ @@ -105,7 +84,7 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds /* alloc dataspace */ Dataspace_capability ds_cap; - try { ds_cap = ram.alloc(size); } + try { ds_cap = pd.alloc(size); } catch (Out_of_ram) { error("allocation of read-write segment failed"); throw; }; @@ -141,7 +120,9 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds off_t const offset = 0; try { remote_rm.attach_at(ds_cap, addr, size, offset); } catch (Region_map::Region_conflict) { - error("region conflict while remotely attaching ELF segment"); throw; } + error("region conflict while remotely attaching ELF segment"); + error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset); + throw; } } else { @@ -153,12 +134,13 @@ Child::Process::Loaded_executable::Loaded_executable(Dataspace_capability elf_ds off_t const offset = seg.file_offset(); try { if (exec) - remote_rm.attach_executable(elf_ds, addr, size, offset); + remote_rm.attach_executable(ldso_ds, addr, size, offset); else - remote_rm.attach_at(elf_ds, addr, size, offset); + remote_rm.attach_at(ldso_ds, addr, size, offset); } catch (Region_map::Region_conflict) { error("region conflict while remotely attaching read-only ELF segment"); + error("addr=", (void *)addr, " size=", (void *)size, " offset=", (void *)offset); throw; } catch (Region_map::Invalid_dataspace) { @@ -194,17 +176,15 @@ void Child::Initial_thread::start(addr_t ip) } -Child::Process::Process(Dataspace_capability elf_ds, +Child::Process::Process(Type type, Dataspace_capability ldso_ds, - Pd_session_capability, Pd_session &pd, - Ram_session &ram, Initial_thread_base &initial_thread, Region_map &local_rm, Region_map &remote_rm, Parent_capability parent_cap) : - loaded_executable(elf_ds, ldso_ds, ram, local_rm, remote_rm, parent_cap) + loaded_executable(type, ldso_ds, pd, local_rm, remote_rm, parent_cap) { /* register parent interface for new protection domain */ pd.assign_parent(parent_cap); @@ -214,7 +194,7 @@ Child::Process::Process(Dataspace_capability elf_ds, * from another. In this case, the main thread will get manually * started after constructing the 'Process'. */ - if (!elf_ds.valid()) + if (type == TYPE_FORKED) return; /* start main thread */ diff --git a/repos/gems/run/cpu_load_display.run b/repos/gems/run/cpu_load_display.run index 41f52280b..f3a6dd55e 100644 --- a/repos/gems/run/cpu_load_display.run +++ b/repos/gems/run/cpu_load_display.run @@ -56,7 +56,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/gems/run/gpt_write.run b/repos/gems/run/gpt_write.run index 1ace87a05..43ed451a4 100644 --- a/repos/gems/run/gpt_write.run +++ b/repos/gems/run/gpt_write.run @@ -34,7 +34,7 @@ install_config { - + diff --git a/repos/gems/run/leitzentrale.run b/repos/gems/run/leitzentrale.run index 6e88ab8fe..97ba031aa 100644 --- a/repos/gems/run/leitzentrale.run +++ b/repos/gems/run/leitzentrale.run @@ -202,7 +202,7 @@ install_config { - + diff --git a/repos/libports/run/avplay.run b/repos/libports/run/avplay.run index 1691a7039..d99b97dd9 100644 --- a/repos/libports/run/avplay.run +++ b/repos/libports/run/avplay.run @@ -49,7 +49,7 @@ set config { } append_if [have_spec sdl] config { - + diff --git a/repos/libports/run/mesa.inc b/repos/libports/run/mesa.inc index ce8c82bbc..36704c861 100644 --- a/repos/libports/run/mesa.inc +++ b/repos/libports/run/mesa.inc @@ -53,7 +53,7 @@ set config { } append_if [have_spec linux] config { - + diff --git a/repos/libports/run/qt5_drivers.inc b/repos/libports/run/qt5_drivers.inc index 40921a13e..d6479742d 100644 --- a/repos/libports/run/qt5_drivers.inc +++ b/repos/libports/run/qt5_drivers.inc @@ -165,7 +165,7 @@ proc drivers_start_nodes { feature_arg } { } append_if [use_fb_sdl feature] start_nodes { - + diff --git a/repos/libports/run/sdl.run b/repos/libports/run/sdl.run index 9d99f707c..ab985fc2c 100644 --- a/repos/libports/run/sdl.run +++ b/repos/libports/run/sdl.run @@ -38,7 +38,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/recipes/raw/drivers_interactive-linux/drivers.config b/repos/os/recipes/raw/drivers_interactive-linux/drivers.config index 5f4e87482..36676a10f 100644 --- a/repos/os/recipes/raw/drivers_interactive-linux/drivers.config +++ b/repos/os/recipes/raw/drivers_interactive-linux/drivers.config @@ -13,7 +13,7 @@ - + diff --git a/repos/os/run/block_tester.run b/repos/os/run/block_tester.run index c718a7dbd..b43dc94e1 100644 --- a/repos/os/run/block_tester.run +++ b/repos/os/run/block_tester.run @@ -71,7 +71,7 @@ append_if [expr !$use_linux] config { append_if $use_linux config { - + diff --git a/repos/os/run/demo.run b/repos/os/run/demo.run index ebb095986..e8ec816d4 100644 --- a/repos/os/run/demo.run +++ b/repos/os/run/demo.run @@ -58,7 +58,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/run/fb_bench.run b/repos/os/run/fb_bench.run index 99afe92dc..b48876d71 100644 --- a/repos/os/run/fb_bench.run +++ b/repos/os/run/fb_bench.run @@ -61,7 +61,7 @@ append_if [have_spec gpio] config " " append_if [have_spec sdl] config { - + diff --git a/repos/os/run/framebuffer.run b/repos/os/run/framebuffer.run index 5430ac94e..85fa2a340 100644 --- a/repos/os/run/framebuffer.run +++ b/repos/os/run/framebuffer.run @@ -46,7 +46,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/run/input.run b/repos/os/run/input.run index 0eb19c0e2..8c1feb7f3 100644 --- a/repos/os/run/input.run +++ b/repos/os/run/input.run @@ -77,7 +77,7 @@ append_if [have_spec ps2] config { } append_if [have_spec sdl] config { - + diff --git a/repos/os/run/loader.run b/repos/os/run/loader.run index ad3c97b6e..bba24425a 100644 --- a/repos/os/run/loader.run +++ b/repos/os/run/loader.run @@ -41,7 +41,7 @@ append config { append_platform_drv_config append_if [have_spec sdl] config { - + diff --git a/repos/os/run/lx_block.run b/repos/os/run/lx_block.run index 0138bb9d0..df9181903 100644 --- a/repos/os/run/lx_block.run +++ b/repos/os/run/lx_block.run @@ -34,7 +34,7 @@ install_config { - + diff --git a/repos/os/run/pointer.run b/repos/os/run/pointer.run index 210c94bdd..a6e41863d 100644 --- a/repos/os/run/pointer.run +++ b/repos/os/run/pointer.run @@ -50,7 +50,7 @@ set config { - + diff --git a/repos/os/run/rom_to_file.run b/repos/os/run/rom_to_file.run index e41d26059..680e7fa22 100644 --- a/repos/os/run/rom_to_file.run +++ b/repos/os/run/rom_to_file.run @@ -44,7 +44,7 @@ install_config { - + diff --git a/repos/os/src/init/child.cc b/repos/os/src/init/child.cc index 67b386a7a..eaa7a7241 100644 --- a/repos/os/src/init/child.cc +++ b/repos/os/src/init/child.cc @@ -496,6 +496,10 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser label == _unique_name && _unique_name != _binary_name) return resolve_session_request(service_name, _binary_name); + /* supply binary as dynamic linker if '' */ + if (!_use_ld && service_name == Rom_session::service_name() && label == "ld.lib.so") + return resolve_session_request(service_name, _binary_name); + /* check for "session_requests" ROM request */ if (service_name == Rom_session::service_name() && label.last_element() == Session_requester::rom_name()) diff --git a/repos/os/src/init/child.h b/repos/os/src/init/child.h index 986789ba6..140a3f7e0 100644 --- a/repos/os/src/init/child.h +++ b/repos/os/src/init/child.h @@ -90,6 +90,11 @@ class Init::Child : Child_policy, Routed_service::Wakeup typedef String<80> Version; Version _version { _start_node->xml().attribute_value("version", Version()) }; + /* + * True if the binary is loaded with ld.lib.so + */ + bool const _use_ld = _start_node->xml().attribute_value("ld", true); + Default_route_accessor &_default_route_accessor; Default_caps_accessor &_default_caps_accessor; Ram_limit_accessor &_ram_limit_accessor; diff --git a/repos/os/src/init/config.xsd b/repos/os/src/init/config.xsd index 511aeaa95..e5da52ba8 100644 --- a/repos/os/src/init/config.xsd +++ b/repos/os/src/init/config.xsd @@ -144,6 +144,7 @@ + diff --git a/repos/ports/run/dosbox.run b/repos/ports/run/dosbox.run index 94fbe430f..e47b765e4 100644 --- a/repos/ports/run/dosbox.run +++ b/repos/ports/run/dosbox.run @@ -48,7 +48,7 @@ append config { } append_if [have_spec sdl] config { - + diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc index eb3557978..a4fce3829 100644 --- a/repos/ports/run/netperf.inc +++ b/repos/ports/run/netperf.inc @@ -216,8 +216,14 @@ append_if $use_usb_driver config { } +# don't use the dynamic linker for loading the lx_hybrid nic_drv on Linux +proc nic_drv_ld_attr {} { + if {[have_spec linux]} { return {ld="no"} } + return "" +} + append_if $use_nic_driver config { - + diff --git a/repos/ports/run/seoul.inc b/repos/ports/run/seoul.inc index 1f7fbf8a2..76dbc6b49 100644 --- a/repos/ports/run/seoul.inc +++ b/repos/ports/run/seoul.inc @@ -250,7 +250,7 @@ append_if $use_framebuffer config { if {!$use_fancy_stuff} { append config { - + } append config " " @@ -264,10 +264,9 @@ append_if [expr $use_nic_session && !$use_nic_bridge] config { append_if $use_framebuffer config { } append_if $use_genode_iso config { + - - } append config { diff --git a/repos/ports/run/virtualbox.run b/repos/ports/run/virtualbox.run index f366f697f..814b0b2cf 100644 --- a/repos/ports/run/virtualbox.run +++ b/repos/ports/run/virtualbox.run @@ -108,7 +108,7 @@ append_if [have_spec framebuffer] config { } append_if [have_spec sdl] config { - + diff --git a/repos/ports/src/noux/child_policy.h b/repos/ports/src/noux/child_policy.h index 51f9ad626..caad94efa 100644 --- a/repos/ports/src/noux/child_policy.h +++ b/repos/ports/src/noux/child_policy.h @@ -194,6 +194,8 @@ class Noux::Child_policy : public Genode::Child_policy { return &static_cast(pd).address_space_region_map(); } + + bool forked() const override { return _forked; } }; #endif /* _NOUX__CHILD_POLICY_H_ */