Luna/kernel/src/binfmt/BinaryFormat.h

115 lines
4.9 KiB
C
Raw Normal View History

#pragma once
#include "fs/VFS.h"
#include "memory/AddressSpace.h"
class BinaryFormatLoader : public Shareable
{
public:
/**
* @brief Determine if the given executable file matches this binary format.
*
* @return Result<bool> An error, or whether the file matches the binary format.
*/
virtual Result<bool> sniff() = 0;
/**
* @brief Load the given executable binary file into an address space.
*
* Depending on the binary format, this function may load an arbitrary interpreter instead, which will interpret the
* file on its own.
*
* @param space The address space to load the executable into.
* @return Result<u64> An error, or the entry point of the executable in memory.
*/
virtual Result<u64> load(AddressSpace* space) = 0;
/**
* @brief Return the short name associated with this format.
*
* @return StringView The format's name.
*/
virtual StringView format() const = 0;
/**
* @brief Transform an interpreted program's command line arguments.
*
* Example: A script 'foo.sh' with a shebang line '#!/bin/sh' is loaded using a BinaryFormatLoader.
*
* This function will then be called with path="/path/to/foo.sh" and args={"foo.sh", "--enable-bar"}
*
* The function should return {"/bin/sh", "/path/to/foo.sh", "--enable-bar"} (prepending the interpreter command
* line and substituting args[0] for the full path of the script).
*
* For native executable formats that do not require an interpreter (e.g. ELF), this function should just ignore
* path and return args unmodified.
*
* @param path The path (absolute or relative to the current process's working directory) of the current program
* file. This should be used instead of args[0] as arbitrary values can be passed there, leaving the interpreter
* unable to find the target program.
* @param args The original command line arguments passed to execve().
* @return Result<Vector<String>> An error, or the transformed command line arguments.
*/
virtual Result<Vector<String>> cmdline(const String& path, Vector<String> args) = 0;
virtual ~BinaryFormatLoader() = default;
/**
* @brief Construct a new BinaryFormatLoader.
*
* This should not be directly used, instead each subclass of BinaryFormatLoader should implement a static create()
* method which implements the binfmt_loader_creator_t type and register it using
* BinaryFormat::register_binary_format().
*
* Then, anyone that needs an appropriate BinaryFormatLoader for an executable file should call
* BinaryFormat::create_loader(), which will find an appropriate loader out of all default/registered loaders.
*
* @param inode The executable program file to load into memory.
* @param recursion_level In normal cases, 0. If the BinaryFormatLoader is created inside another loader (for
* example, a script loader loading the script's interpreter), the caller shall pass its recursion_level + 1 to
* BinaryFormat::create_loader(), which will forward it to this constructor. This avoids infinite recursion.
*/
BinaryFormatLoader(SharedPtr<VFS::Inode> inode, int recursion_level);
protected:
SharedPtr<VFS::Inode> m_inode;
int m_recursion_level;
};
/**
* @brief The factory function signature for binary format loaders.
*/
typedef Result<SharedPtr<BinaryFormatLoader>> (*binfmt_loader_creator_t)(SharedPtr<VFS::Inode>, void*, int);
namespace BinaryFormat
{
/**
* @brief Register the default binary format loaders.
*
* @return Result<void> Whether the operation succeeded.
*/
Result<void> init();
/**
* @brief Register a new binary format loader type.
*
* @param creator A factory function to create said binary format loader. The function shall be passed the inode to
* load the program from, the arbitrary argument passed to this function, and a recursion index to avoid infinite
* recursion.
* @param arg An arbitrary argument that will be passed to the above factory function.
* @return Result<void> Whether the operation succeeded.
*/
Result<void> register_binary_format(binfmt_loader_creator_t creator, void* arg);
/**
* @brief Create an appropriate loader object for an executable file.
*
* @param inode The executable file to create the loader for. If no appropriate loader could be found for this file
* type, this function shall return ENOEXEC.
* @param recursion_level In most cases, 0. If called inside another loader, the loader shall pass its
* own recursion_level variable + 1, to avoid infinite recursion. If recursion_level >= 8, this function shall
* immediately return ELOOP.
* @return Result<SharedPtr<BinaryFormatLoader>> An error, or the new loader object created for this file.
*/
Result<SharedPtr<BinaryFormatLoader>> create_loader(SharedPtr<VFS::Inode> inode, int recursion_level = 0);
}