800 lines · 31.4 KB · C++
RawDownload
                base = array_stack[--array_stack_pointer];                assert(base != nullptr); #ifndef NDEBUG                array_stack[array_stack_pointer] = nullptr;#endif                 break;            case datum_type_t::value_bit64:                data_dest = read_8byte_segments(reader, datum_type_t::value_bit64, count, data_dest);                break;            default:                throw module_reader_exception{ "Unknown item data type" };            }        }    }     // See module name in Dis VM specification (http://www.vitanuova.com/inferno/man/6/dis.html)    void read_module_name(util::buffered_reader_t &reader, vm_module_t &modobj)    {        auto string_buffer = std::vector<uint8_t>{};        if (!read_next_string(reader, string_buffer))            throw module_reader_exception{ "Failed to read module name" };         modobj.module_name = std::make_unique<vm_string_t>(string_buffer.size(), string_buffer.data());        assert(modobj.module_name->get_length() <= module_constants::max_module_name_bytes);    }     // See link section in Dis VM specification (http://www.vitanuova.com/inferno/man/6/dis.html)    void read_link_section(util::buffered_reader_t &reader, vm_module_t &modobj)    {        auto success = bool{};        const auto export_count = modobj.header.export_size;         // Allocate memory for the export entries        modobj.export_section.reserve(export_count);         for (auto c = word_t{ 0 }; c < export_count; ++c)        {            // Read in single export item            auto item = export_function_t{};             std::tie(success, item.pc) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read linkage pc" };             std::tie(success, item.frame_type) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read linkage frame type index" };             std::tie(success, item.sig) = read_next_word(reader);            if (!success) throw module_reader_exception{ "Failed to read linkage signature" };             auto string_buffer = std::vector<uint8_t>{};            if (!read_next_string(reader, string_buffer))                throw module_reader_exception{ "Failed to read linkage name" };             item.name = std::make_unique<vm_string_t>(string_buffer.size(), string_buffer.data());             const auto sig = item.sig;            modobj.export_section.emplace(sig, std::move(item));        }    }     // See import section in Dis VM specification (http://www.vitanuova.com/inferno/man/6/dis.html)    // [SPEC] The specification does not seem to match what is observed in an actual module.     //        The function is modeled after the disassembler (dis.b and libinterp/load.c) instead.    void read_import_section(util::buffered_reader_t &reader, vm_module_t &modobj)    {        auto success = bool{};        auto module_import_count = operand_t{};        std::tie(success, module_import_count) = read_next_operand(reader);        if (!success) throw module_reader_exception{ "Failed to read module import count" };         // Allocate memory for module imports        modobj.import_section.reserve(module_import_count);         for (auto c = operand_t{ 0 }; c < module_import_count; ++c)        {            // Read in single module import            import_vm_module_t module{};             auto func_import_count = operand_t{};            std::tie(success, func_import_count) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read function import count" };             // Allocate memory for function imports            module.functions.reserve(func_import_count);             for (auto k = operand_t{ 0 }; k < func_import_count; ++k)            {                // Read in single function import                import_function_t func{};                 std::tie(success, func.sig) = read_next_word(reader);                if (!success) throw module_reader_exception{ "Failed to read import function signature" };                 auto string_buffer = std::vector<uint8_t>{};                if (!read_next_string(reader, string_buffer))                    throw module_reader_exception{ "Failed to read import function name" };                 func.name = std::make_unique<vm_string_t>(string_buffer.size(), string_buffer.data());                 module.functions.push_back(std::move(func));            }             modobj.import_section.push_back(std::move(module));        }         byte_t value;        std::tie(success, value) = reader.get_next_byte();        if (!success || value != 0)            throw module_reader_exception{ "Failed to read final byte from import section" };    }     // See handler section in Dis VM specification (http://www.vitanuova.com/inferno/man/6/dis.html)    void read_handler_section(util::buffered_reader_t &reader, vm_module_t &modobj)    {        auto success = bool{};        auto handler_count = operand_t{};        std::tie(success, handler_count) = read_next_operand(reader);         // Allocate memory for handlers        modobj.handler_section.reserve(handler_count);         for (auto c = operand_t{ 0 }; c < handler_count; ++c)        {            // Read in single handler            handler_t handler{};             std::tie(success, handler.exception_offset) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read exception offset" };             std::tie(success, handler.begin_pc) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read handler begin program counter" };             std::tie(success, handler.end_pc) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read handler end program counter" };             auto type_desc_number = operand_t{};            std::tie(success, type_desc_number) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read handler type description ID" };             if (type_desc_number != module_constants::no_error_handle_type_desc)            {                assert(0 <= type_desc_number && type_desc_number < static_cast<operand_t>(modobj.type_section.size()));                handler.type_desc = modobj.type_section[type_desc_number];                assert(handler.type_desc != nullptr);            }             auto handler_cases = operand_t{};            std::tie(success, handler_cases) = read_next_operand(reader);             // [SPEC] The operand read above contains two pieces of data.            // The higher 16-bits represent the number of exception cases that catch exception types.            // The lower 16-bits represent the total number of handled cases.            // In the limbo language, strings and exceptions can be caught in an exception handler.            // Based on Inferno implementation libinterp/load.c.            handler.exception_type_count = word_t{ handler_cases >> 16 };            const auto total_count = (handler_cases & 0xffff);             // Allocate memory for exceptions plus the wild card.            handler.exception_table.reserve(total_count + 1);             for (auto k = operand_t{ 0 }; k < total_count; ++k)            {                // Read in single exception                exception_t except{};                 auto string_buffer = std::vector<uint8_t>{};                if (!read_next_string(reader, string_buffer))                    throw module_reader_exception{ "Failed to read exception name" };                 except.name = std::make_unique<vm_string_t>(string_buffer.size(), string_buffer.data());                 std::tie(success, except.pc) = read_next_operand(reader);                if (!success) throw module_reader_exception{ "Failed to read exception pc" };                 handler.exception_table.push_back(std::move(except));            }             // Read in wildcard exception            exception_t wildcard_exception{};            std::tie(success, wildcard_exception.pc) = read_next_operand(reader);            if (!success) throw module_reader_exception{ "Failed to read wildcard exception pc" };             handler.exception_table.push_back(std::move(wildcard_exception));             modobj.handler_section.push_back(std::move(handler));        }         byte_t value;        std::tie(success, value) = reader.get_next_byte();        if (!success || value != 0)            throw module_reader_exception{ "Failed to read final byte from handler section" };    }} export_function_t::export_function_t(export_function_t &&other)    : pc{ other.pc }    , frame_type{ other.frame_type }    , sig{ other.sig }    , name{ std::move(other.name) }{} export_function_t::~export_function_t(){    if (name != nullptr)        name->release();} import_function_t::import_function_t(import_function_t &&other)    : sig{ other.sig }    , name{ std::move(other.name) }{} import_function_t::~import_function_t(){    if (name != nullptr)        name->release();} import_vm_module_t::import_vm_module_t(import_vm_module_t &&other)    : functions{ std::move(other.functions) }{} exception_t::exception_t(exception_t &&other)    : pc{ other.pc }    , name{ std::move(other.name) }{} exception_t::~exception_t(){    if (name != nullptr)        name->release();} handler_t::handler_t(handler_t &&other)    : exception_offset{ other.exception_offset }    , begin_pc{ other.begin_pc }    , end_pc{ other.end_pc }    , type_desc{ std::move(other.type_desc) }    , exception_table{ std::move(other.exception_table) }    , exception_type_count{ other.exception_type_count }{} vm_module_t::~vm_module_t(){    if (module_name != nullptr)        module_name->release();     if (original_mp != nullptr)        original_mp->release();} std::unique_ptr<vm_module_t> disvm::read_module(const char *path){    assert(path != nullptr);     auto module_file = std::ifstream{ path, std::ifstream::binary };    if (!module_file.is_open())    {        assert(false && "Failed to open module");        throw vm_user_exception{ "Failed to open module" };    }     return read_module(module_file);} std::unique_ptr<runtime::vm_module_t> disvm::read_module(std::istream &data){    util::buffered_reader_t reader{ data };     auto modobj = std::make_unique<vm_module_t>();     read_header(reader, *modobj);     if (util::has_flag(modobj->header.runtime_flag, runtime_flags_t::has_import_deprecated))        throw module_reader_exception{ "Obsolete module" };     read_code_section(reader, *modobj);    read_type_section(reader, *modobj);    read_data_section(reader, *modobj);    read_module_name(reader, *modobj);    read_link_section(reader, *modobj);     if (util::has_flag(modobj->header.runtime_flag, runtime_flags_t::has_import))        read_import_section(reader, *modobj);     if (util::has_flag(modobj->header.runtime_flag, runtime_flags_t::has_handler))        read_handler_section(reader, *modobj);     // [TODO] Native code generation - runtime_flags_t::must_compile    assert(!util::has_flag(modobj->header.runtime_flag, runtime_flags_t::must_compile));     return modobj;}

Lines 501–800 of 800. Previous lines