summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.h20
-rw-r--r--Kernel/Syscalls/execve.cpp318
-rw-r--r--Kernel/Thread.cpp4
-rw-r--r--Libraries/LibELF/AuxiliaryVector.h8
-rw-r--r--Libraries/LibELF/Loader.cpp7
-rw-r--r--Libraries/LibELF/Loader.h5
6 files changed, 215 insertions, 147 deletions
diff --git a/Kernel/Process.h b/Kernel/Process.h
index e8e567f557..f21a79be01 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -421,6 +421,25 @@ public:
int exec(String path, Vector<String> arguments, Vector<String> environment, int recusion_depth = 0);
+ struct LoadResult {
+ FlatPtr load_offset { 0 };
+ FlatPtr entry_eip { 0 };
+ size_t size { 0 };
+ FlatPtr program_headers { 0 };
+ size_t num_program_headers { 0 };
+ AK::WeakPtr<Region> tls_region;
+ size_t tls_size { 0 };
+ size_t tls_alignment { 0 };
+ };
+
+ enum class ShouldAllocateTls {
+ No = 0,
+ Yes,
+ };
+
+ int load(NonnullRefPtr<FileDescription> main_program_description, RefPtr<FileDescription> interpreter_description);
+ KResultOr<LoadResult> load_elf_object(FileDescription& object_description, FlatPtr load_offset, ShouldAllocateTls);
+
bool is_superuser() const
{
return m_euid == 0;
@@ -563,6 +582,7 @@ private:
ThreadID m_exec_tid { 0 };
FlatPtr m_load_offset { 0U };
FlatPtr m_entry_eip { 0U };
+ int m_main_program_fd { -1 };
OwnPtr<ThreadTracer> m_tracer;
diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp
index 8d2b5af041..14ab994b64 100644
--- a/Kernel/Syscalls/execve.cpp
+++ b/Kernel/Syscalls/execve.cpp
@@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <AK/LexicalPath.h>
#include <AK/ScopeGuard.h>
#include <AK/TemporaryChange.h>
#include <Kernel/FileSystem/Custody.h>
@@ -45,15 +46,8 @@
namespace Kernel {
-int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags)
+static bool validate_stack_size(const Vector<String>& arguments, const Vector<String>& environment)
{
- ASSERT(is_user_process());
- ASSERT(!Processor::current().in_critical());
- auto path = main_program_description->absolute_path();
-#ifdef EXEC_DEBUG
- dbg() << "do_exec(" << path << ")";
-#endif
-
size_t total_blob_size = 0;
for (auto& a : arguments)
total_blob_size += a.length() + 1;
@@ -62,31 +56,100 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
size_t total_meta_size = sizeof(char*) * (arguments.size() + 1) + sizeof(char*) * (environment.size() + 1);
- // FIXME: How much stack space does process startup need?
- if ((total_blob_size + total_meta_size) >= Thread::default_userspace_stack_size)
- return -E2BIG;
-
- auto parts = path.split('/');
- if (parts.is_empty())
- return -ENOENT;
+ // FIXME: This doesn't account for the size of the auxiliary vector
+ return (total_blob_size + total_meta_size) < Thread::default_userspace_stack_size;
+}
- auto& inode = interpreter_description ? *interpreter_description->inode() : *main_program_description->inode();
+KResultOr<Process::LoadResult> Process::load_elf_object(FileDescription& object_description, FlatPtr load_offset, ShouldAllocateTls should_allocate_tls)
+{
+ auto& inode = *(object_description.inode());
auto vmobject = SharedInodeVMObject::create_with_inode(inode);
-
if (static_cast<const SharedInodeVMObject&>(*vmobject).writable_mappings()) {
dbg() << "Refusing to execute a write-mapped program";
- return -ETXTBSY;
+ return KResult(-ETXTBSY);
}
+ InodeMetadata loader_metadata = object_description.metadata();
- // Disable profiling temporarily in case it's running on this process.
- bool was_profiling = is_profiling();
- TemporaryChange profiling_disabler(m_profiling, false);
+ auto region = MM.allocate_kernel_region_with_vmobject(*vmobject, PAGE_ROUND_UP(loader_metadata.size), "ELF loading", Region::Access::Read);
+ if (!region) {
+ dbg() << "Could not allocate memory for ELF loading";
+ return KResult(-ENOMEM);
+ }
- // Mark this thread as the current thread that does exec
- // No other thread from this process will be scheduled to run
- auto current_thread = Thread::current();
- m_exec_tid = current_thread->tid();
+ Region* master_tls_region { nullptr };
+ size_t master_tls_size = 0;
+ size_t master_tls_alignment = 0;
+ m_entry_eip = 0;
+
+ MM.enter_process_paging_scope(*this);
+ String object_name = LexicalPath(object_description.absolute_path()).basename();
+ RefPtr<ELF::Loader> loader = ELF::Loader::create(region->vaddr().as_ptr(), loader_metadata.size, move(object_name));
+ loader->map_section_hook = [&](VirtualAddress vaddr, size_t size, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable, bool is_executable, const String& name) -> u8* {
+ ASSERT(size);
+ ASSERT(alignment == PAGE_SIZE);
+ int prot = 0;
+ if (is_readable)
+ prot |= PROT_READ;
+ if (is_writable)
+ prot |= PROT_WRITE;
+ if (is_executable)
+ prot |= PROT_EXEC;
+ if (auto* region = allocate_region_with_vmobject(vaddr.offset(load_offset), size, *vmobject, offset_in_image, String(name), prot)) {
+ region->set_shared(true);
+ return region->vaddr().as_ptr();
+ }
+ return nullptr;
+ };
+ loader->alloc_section_hook = [&](VirtualAddress vaddr, size_t size, size_t alignment, bool is_readable, bool is_writable, const String& name) -> u8* {
+ ASSERT(size);
+ ASSERT(alignment == PAGE_SIZE);
+ int prot = 0;
+ if (is_readable)
+ prot |= PROT_READ;
+ if (is_writable)
+ prot |= PROT_WRITE;
+ if (auto* region = allocate_region(vaddr.offset(load_offset), size, String(name), prot))
+ return region->vaddr().as_ptr();
+ return nullptr;
+ };
+ if (should_allocate_tls == ShouldAllocateTls::Yes) {
+ loader->tls_section_hook = [&](size_t size, size_t alignment) {
+ ASSERT(size);
+ master_tls_region = allocate_region({}, size, String(), PROT_READ | PROT_WRITE);
+ master_tls_size = size;
+ master_tls_alignment = alignment;
+ return master_tls_region->vaddr().as_ptr();
+ };
+ }
+
+ ASSERT(!Processor::current().in_critical());
+ bool success = loader->load();
+ if (!success) {
+ klog() << "do_exec: Failure loading program";
+ return KResult(-ENOEXEC);
+ }
+
+ if (!loader->entry().offset(load_offset).get()) {
+ klog() << "do_exec: Failure loading program, entry pointer is invalid! (" << loader->entry().offset(load_offset) << ")";
+ return KResult(-ENOEXEC);
+ }
+
+ // NOTE: At this point, we've committed to the new executable.
+
+ return LoadResult {
+ load_offset,
+ loader->entry().offset(load_offset).get(),
+ (size_t)loader_metadata.size,
+ VirtualAddress(loader->image().program_header_table_offset()).offset(load_offset).get(),
+ loader->image().program_header_count(),
+ master_tls_region ? master_tls_region->make_weak_ptr() : nullptr,
+ master_tls_size,
+ master_tls_alignment
+ };
+}
+int Process::load(NonnullRefPtr<FileDescription> main_program_description, RefPtr<FileDescription> interpreter_description)
+{
RefPtr<PageDirectory> old_page_directory;
NonnullOwnPtrVector<Region> old_regions;
@@ -98,123 +161,92 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
m_page_directory = PageDirectory::create_for_userspace(*this);
}
-#ifdef MM_DEBUG
- dbg() << "Process " << pid().value() << " exec: PD=" << m_page_directory.ptr() << " created";
-#endif
+ ArmedScopeGuard rollback_regions_guard([&]() {
+ ASSERT(Process::current() == this);
+ // Need to make sure we don't swap contexts in the middle
+ ScopedCritical critical;
+ m_page_directory = move(old_page_directory);
+ m_regions = move(old_regions);
+ MM.enter_process_paging_scope(*this);
+ });
+
+ if (!interpreter_description) {
+ auto result = load_elf_object(main_program_description, FlatPtr { 0 }, ShouldAllocateTls::Yes);
+ if (result.is_error())
+ return result.error();
+
+ m_load_offset = result.value().load_offset;
+ m_entry_eip = result.value().entry_eip;
+ m_master_tls_region = result.value().tls_region;
+ m_master_tls_size = result.value().tls_size;
+ m_master_tls_alignment = result.value().tls_alignment;
- InodeMetadata loader_metadata;
+ rollback_regions_guard.disarm();
+ return 0;
+ }
- // FIXME: Hoooo boy this is a hack if I ever saw one.
- // This is the 'random' offset we're giving to our ET_DYN executables to start as.
- // It also happens to be the static Virtual Address offset every static executable gets :)
- // Without this, some assumptions by the ELF loading hooks below are severely broken.
- // 0x08000000 is a verified random number chosen by random dice roll https://xkcd.com/221/
- m_load_offset = interpreter_description ? 0x08000000 : 0;
+ // TODO: This should be randomized for ASLR
+ constexpr FlatPtr interpreter_load_offset = 0x08000000;
- // FIXME: We should be able to load both the PT_INTERP interpreter and the main program... once the RTLD is smart enough
- if (interpreter_description) {
- loader_metadata = interpreter_description->metadata();
- // we don't need the interpreter file description after we've loaded (or not) it into memory
- interpreter_description = nullptr;
- } else {
- loader_metadata = main_program_description->metadata();
- }
+ auto interpreter_load_result = load_elf_object(*interpreter_description, interpreter_load_offset, ShouldAllocateTls::No);
+ if (interpreter_load_result.is_error())
+ return interpreter_load_result.error();
- auto region = MM.allocate_kernel_region_with_vmobject(*vmobject, PAGE_ROUND_UP(loader_metadata.size), "ELF loading", Region::Access::Read);
- if (!region)
- return -ENOMEM;
+ m_load_offset = interpreter_load_result.value().load_offset;
+ m_entry_eip = interpreter_load_result.value().entry_eip;
- Region* master_tls_region { nullptr };
- size_t master_tls_size = 0;
- size_t master_tls_alignment = 0;
- m_entry_eip = 0;
+ // TLS allocation will be done in userspace by the loader
+ m_master_tls_region = nullptr;
+ m_master_tls_size = 0;
+ m_master_tls_alignment = 0;
- MM.enter_process_paging_scope(*this);
- RefPtr<ELF::Loader> loader;
- {
- ArmedScopeGuard rollback_regions_guard([&]() {
- ASSERT(Process::current() == this);
- // Need to make sure we don't swap contexts in the middle
- ScopedCritical critical;
- m_page_directory = move(old_page_directory);
- m_regions = move(old_regions);
- MM.enter_process_paging_scope(*this);
- });
- loader = ELF::Loader::create(region->vaddr().as_ptr(), loader_metadata.size);
- // Load the correct executable -- either interp or main program.
- // FIXME: Once we actually load both interp and main, we'll need to be more clever about this.
- // In that case, both will be ET_DYN objects, so they'll both be completely relocatable.
- // That means, we can put them literally anywhere in User VM space (ASLR anyone?).
- // ALSO FIXME: Reminder to really really fix that 'totally random offset' business.
- loader->map_section_hook = [&](VirtualAddress vaddr, size_t size, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable, bool is_executable, const String& name) -> u8* {
- ASSERT(size);
- ASSERT(alignment == PAGE_SIZE);
- int prot = 0;
- if (is_readable)
- prot |= PROT_READ;
- if (is_writable)
- prot |= PROT_WRITE;
- if (is_executable)
- prot |= PROT_EXEC;
- if (auto* region = allocate_region_with_vmobject(vaddr.offset(m_load_offset), size, *vmobject, offset_in_image, String(name), prot)) {
- region->set_shared(true);
- return region->vaddr().as_ptr();
- }
- return nullptr;
- };
- loader->alloc_section_hook = [&](VirtualAddress vaddr, size_t size, size_t alignment, bool is_readable, bool is_writable, const String& name) -> u8* {
- ASSERT(size);
- ASSERT(alignment == PAGE_SIZE);
- int prot = 0;
- if (is_readable)
- prot |= PROT_READ;
- if (is_writable)
- prot |= PROT_WRITE;
- if (auto* region = allocate_region(vaddr.offset(m_load_offset), size, String(name), prot))
- return region->vaddr().as_ptr();
- return nullptr;
- };
+ rollback_regions_guard.disarm();
+ return 0;
+}
- // FIXME: Move TLS region allocation to userspace: LibC and the dynamic loader.
- // LibC if we end up with a statically linked executable, and the
- // dynamic loader so that it can create new TLS blocks for each shared library
- // that gets loaded as part of DT_NEEDED processing, and via dlopen()
- // If that doesn't happen quickly, at least pass the location of the TLS region
- // some ELF Auxiliary Vector so the loader can use it/create new ones as necessary.
- loader->tls_section_hook = [&](size_t size, size_t alignment) {
- ASSERT(size);
- master_tls_region = allocate_region({}, size, String(), PROT_READ | PROT_WRITE);
- master_tls_size = size;
- master_tls_alignment = alignment;
- return master_tls_region->vaddr().as_ptr();
- };
- ASSERT(!Processor::current().in_critical());
- bool success = loader->load();
- if (!success) {
- klog() << "do_exec: Failure loading " << path.characters();
- return -ENOEXEC;
- }
- // FIXME: Validate that this virtual address is within executable region,
- // instead of just non-null. You could totally have a DSO with entry point of
- // the beginning of the text segment.
- if (!loader->entry().offset(m_load_offset).get()) {
- klog() << "do_exec: Failure loading " << path.characters() << ", entry pointer is invalid! (" << loader->entry().offset(m_load_offset) << ")";
- return -ENOEXEC;
- }
+int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags)
+{
+ ASSERT(is_user_process());
+ ASSERT(!Processor::current().in_critical());
+ auto path = main_program_description->absolute_path();
+#ifdef EXEC_DEBUG
+ dbg() << "do_exec(" << path << ")";
+#endif
- rollback_regions_guard.disarm();
+ // FIXME: How much stack space does process startup need?
+ if (!validate_stack_size(arguments, environment))
+ return -E2BIG;
+
+ auto parts = path.split('/');
+ if (parts.is_empty())
+ return -ENOENT;
- // NOTE: At this point, we've committed to the new executable.
- m_entry_eip = loader->entry().offset(m_load_offset).get();
+ // Disable profiling temporarily in case it's running on this process.
+ bool was_profiling = is_profiling();
+ TemporaryChange profiling_disabler(m_profiling, false);
- kill_threads_except_self();
+ // Mark this thread as the current thread that does exec
+ // No other thread from this process will be scheduled to run
+ auto current_thread = Thread::current();
+ m_exec_tid = current_thread->tid();
-#ifdef EXEC_DEBUG
- klog() << "Memory layout after ELF load:";
- dump_regions();
+#ifdef MM_DEBUG
+ dbg() << "Process " << pid().value() << " exec: PD=" << m_page_directory.ptr() << " created";
#endif
+
+ int load_rc = load(main_program_description, interpreter_description);
+ if (load_rc) {
+ klog() << "do_exec: Failed to load main program or interpreter";
+ return load_rc;
}
+ kill_threads_except_self();
+
+#ifdef EXEC_DEBUG
+ klog() << "Memory layout after ELF load:";
+ dump_regions();
+#endif
+
m_executable = main_program_description->custody();
m_promises = m_execpromises;
@@ -222,10 +254,6 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
m_veil_state = VeilState::None;
m_unveiled_paths.clear();
- // Copy of the master TLS region that we will clone for new threads
- // FIXME: Handle this in userspace
- m_master_tls_region = master_tls_region ? master_tls_region->make_weak_ptr() : nullptr;
-
auto main_program_metadata = main_program_description->metadata();
if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) {
@@ -250,6 +278,14 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
description_and_flags = {};
}
+ if (interpreter_description) {
+ m_main_program_fd = alloc_fd();
+ ASSERT(m_main_program_fd >= 0);
+ main_program_description->seek(0, SEEK_SET);
+ main_program_description->set_readable(true);
+ m_fds[m_main_program_fd].set(move(main_program_description), FD_CLOEXEC);
+ }
+
new_main_thread = nullptr;
if (&current_thread->process() == this) {
new_main_thread = current_thread;
@@ -283,9 +319,6 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
m_name = parts.take_last();
new_main_thread->set_name(m_name);
- m_master_tls_size = master_tls_size;
- m_master_tls_alignment = master_tls_alignment;
-
// FIXME: PID/TID ISSUE
m_pid = new_main_thread->tid().value();
auto tsr_result = new_main_thread->make_thread_specific_region({});
@@ -325,7 +358,7 @@ Vector<AuxiliaryValue> Process::generate_auxiliary_vector() const
// PH*
auxv.append({ AuxiliaryValue::PageSize, PAGE_SIZE });
auxv.append({ AuxiliaryValue::BaseAddress, (void*)m_load_offset });
- // FLAGS
+
auxv.append({ AuxiliaryValue::Entry, (void*)m_entry_eip });
// NOTELF
auxv.append({ AuxiliaryValue::Uid, (long)m_uid });
@@ -350,6 +383,8 @@ Vector<AuxiliaryValue> Process::generate_auxiliary_vector() const
auxv.append({ AuxiliaryValue::ExecFilename, m_executable->absolute_path() });
+ auxv.append({ AuxiliaryValue::ExecFileDescriptor, m_main_program_fd });
+
auxv.append({ AuxiliaryValue::Null, 0L });
return auxv;
}
@@ -451,10 +486,12 @@ KResultOr<NonnullRefPtr<FileDescription>> Process::find_elf_interpreter_for_exec
return KResult(-ENOEXEC);
}
- if (!interpreter_interpreter_path.is_empty()) {
- dbg() << "exec(" << path << "): Interpreter (" << interpreter_description->absolute_path() << ") has its own interpreter (" << interpreter_interpreter_path << ")! No thank you!";
- return KResult(-ELOOP);
- }
+ // FIXME: Uncomment this
+ // How do we get gcc to not insert an interpreter section to /usr/lib/Loader.so itself?
+ // if (!interpreter_interpreter_path.is_empty()) {
+ // dbg() << "exec(" << path << "): Interpreter (" << interpreter_description->absolute_path() << ") has its own interpreter (" << interpreter_interpreter_path << ")! No thank you!";
+ // return KResult(-ELOOP);
+ // }
return interpreter_description;
}
@@ -608,4 +645,5 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
ASSERT(rc < 0); // We should never continue after a successful exec!
return rc;
}
+
}
diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp
index 969fee8c49..b52d545d58 100644
--- a/Kernel/Thread.cpp
+++ b/Kernel/Thread.cpp
@@ -1105,6 +1105,10 @@ Vector<FlatPtr> Thread::raw_backtrace(FlatPtr ebp, FlatPtr eip) const
KResult Thread::make_thread_specific_region(Badge<Process>)
{
+ // The process may not require a TLS region
+ if (!process().m_master_tls_region)
+ return KSuccess;
+
size_t thread_specific_region_alignment = max(process().m_master_tls_alignment, alignof(ThreadSpecificData));
m_thread_specific_region_size = align_up_to(process().m_master_tls_size, thread_specific_region_alignment) + sizeof(ThreadSpecificData);
auto* region = process().allocate_region({}, m_thread_specific_region_size, "Thread-specific", PROT_READ | PROT_WRITE, true);
diff --git a/Libraries/LibELF/AuxiliaryVector.h b/Libraries/LibELF/AuxiliaryVector.h
index 2acfb993bb..b47731c58d 100644
--- a/Libraries/LibELF/AuxiliaryVector.h
+++ b/Libraries/LibELF/AuxiliaryVector.h
@@ -46,7 +46,7 @@ typedef struct
#define AT_PAGESZ 6 /* a_val gives system page size in bytes */
#define AT_BASE 7 /* a_ptr holds base address that Loader was loaded into memory */
#define AT_FLAGS 8 /* a_val holds 1 bit flags. Undefined flags are 0 */
-#define AT_ENTRY 9 /* a_ptr holds entry point of application for loader */
+#define AT_ENTRY 9 /* a_ptr holds entry point of the main program */
#define AT_NOTELF 10 /* a_val non-zero if the program is not ELF */
#define AT_UID 11 /* a_val holds real user id of process */
#define AT_EUID 12 /* a_val holds effective user id of process */
@@ -60,6 +60,8 @@ typedef struct
#define AT_RANDOM 25 /* a_ptr points to 16 securely generated random bytes */
#define AT_HWCAP2 26 /* a_val holds extended hw feature mask. Currently 0 */
#define AT_EXECFN 31 /* a_ptr points to file name of executed program */
+#define AT_EXE_BASE 32 /* a_ptr holds base address where main program was loaded into memory */
+#define AT_EXE_SIZE 33 /* a_val holds the size of the main program in memory */
#ifdef __cplusplus
# include <AK/String.h>
@@ -89,7 +91,9 @@ struct AuxiliaryValue {
BasePlatform = AT_BASE_PLATFORM,
Random = AT_RANDOM,
HwCap2 = AT_HWCAP2,
- ExecFilename = AT_EXECFN
+ ExecFilename = AT_EXECFN,
+ ExeBaseAddress = AT_EXE_BASE,
+ ExeSize = AT_EXE_SIZE
};
AuxiliaryValue(Type type, long val)
diff --git a/Libraries/LibELF/Loader.cpp b/Libraries/LibELF/Loader.cpp
index 8f7ccc722f..35b787d662 100644
--- a/Libraries/LibELF/Loader.cpp
+++ b/Libraries/LibELF/Loader.cpp
@@ -40,8 +40,9 @@
namespace ELF {
-Loader::Loader(const u8* buffer, size_t size, bool verbose_logging)
+Loader::Loader(const u8* buffer, size_t size, String&& name, bool verbose_logging)
: m_image(buffer, size, verbose_logging)
+ , m_name(move(name))
{
if (m_image.is_valid())
m_symbol_count = m_image.symbol_count();
@@ -101,7 +102,7 @@ bool Loader::layout()
program_header.alignment(),
program_header.is_readable(),
program_header.is_writable(),
- String::format("elf-alloc-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : ""));
+ String::format("%s-alloc-%s%s", m_name.is_empty() ? "elf" : m_name.characters(), program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : ""));
if (!allocated_section) {
failed = true;
return;
@@ -133,7 +134,7 @@ bool Loader::layout()
program_header.is_readable(),
program_header.is_writable(),
program_header.is_executable(),
- String::format("elf-map-%s%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "", program_header.is_executable() ? "x" : ""));
+ String::format("%s-map-%s%s%s", m_name.is_empty() ? "elf" : m_name.characters(), program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "", program_header.is_executable() ? "x" : ""));
if (!mapped_section) {
failed = true;
}
diff --git a/Libraries/LibELF/Loader.h b/Libraries/LibELF/Loader.h
index 7a0b9c82d8..adb3b0b17c 100644
--- a/Libraries/LibELF/Loader.h
+++ b/Libraries/LibELF/Loader.h
@@ -45,7 +45,7 @@ namespace ELF {
class Loader : public RefCounted<Loader> {
public:
- static NonnullRefPtr<Loader> create(const u8* data, size_t size, bool verbose_logging = true) { return adopt(*new Loader(data, size, verbose_logging)); }
+ static NonnullRefPtr<Loader> create(const u8* data, size_t size, String&& name = String::empty(), bool verbose_logging = true) { return adopt(*new Loader(data, size, move(name), verbose_logging)); }
~Loader();
bool load();
@@ -67,11 +67,12 @@ public:
Optional<Image::Symbol> find_symbol(u32 address, u32* offset = nullptr) const;
private:
- explicit Loader(const u8*, size_t, bool verbose_logging);
+ explicit Loader(const u8*, size_t, String&& name, bool verbose_logging);
bool layout();
Image m_image;
+ String m_name;
size_t m_symbol_count { 0 };