2023-07-30 18:25:44 +02:00
|
|
|
#pragma once
|
|
|
|
#include "fs/VFS.h"
|
|
|
|
#include "memory/AddressSpace.h"
|
|
|
|
|
|
|
|
class BinaryFormatLoader : public Shareable
|
|
|
|
{
|
|
|
|
public:
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @brief Determine if the given executable file matches this binary format.
|
|
|
|
*
|
|
|
|
* @return Result<bool> An error, or whether the file matches the binary format.
|
|
|
|
*/
|
2023-07-30 18:25:44 +02:00
|
|
|
virtual Result<bool> sniff() = 0;
|
2023-07-31 20:41:18 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*/
|
2023-07-30 18:25:44 +02:00
|
|
|
virtual Result<u64> load(AddressSpace* space) = 0;
|
|
|
|
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @brief Return the short name associated with this format.
|
|
|
|
*
|
|
|
|
* @return StringView The format's name.
|
|
|
|
*/
|
2023-07-30 18:25:44 +02:00
|
|
|
virtual StringView format() const = 0;
|
|
|
|
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @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;
|
2023-07-30 18:25:44 +02:00
|
|
|
|
|
|
|
virtual ~BinaryFormatLoader() = default;
|
|
|
|
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @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);
|
2023-07-30 18:25:44 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
SharedPtr<VFS::Inode> m_inode;
|
2023-07-31 20:41:18 +02:00
|
|
|
int m_recursion_level;
|
2023-07-30 18:25:44 +02:00
|
|
|
};
|
|
|
|
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @brief The factory function signature for binary format loaders.
|
|
|
|
*/
|
|
|
|
typedef Result<SharedPtr<BinaryFormatLoader>> (*binfmt_loader_creator_t)(SharedPtr<VFS::Inode>, void*, int);
|
2023-07-30 18:25:44 +02:00
|
|
|
|
|
|
|
namespace BinaryFormat
|
|
|
|
{
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @brief Register the default binary format loaders.
|
|
|
|
*
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
2023-07-30 18:25:44 +02:00
|
|
|
Result<void> init();
|
|
|
|
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*/
|
2023-07-30 18:25:44 +02:00
|
|
|
Result<void> register_binary_format(binfmt_loader_creator_t creator, void* arg);
|
|
|
|
|
2023-07-31 20:41:18 +02:00
|
|
|
/**
|
|
|
|
* @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);
|
2023-07-30 18:25:44 +02:00
|
|
|
}
|