863 lines · 26.5 KB · C++
RawDownload
//// Dis VM// File: sbl_reader.cpp// Author: arr// #include <cassert>#include <string>#include <vector>#include <cerrno>#include <memory>#include <vm_asm.h>#include <utils.h>#include <buffered_reader.h> using disvm::runtime::vm_pc_t; using disvm::symbol::advance_pc_t;using disvm::symbol::function_data_t;using disvm::symbol::function_name_format_t;using disvm::symbol::source_ref_t;using disvm::symbol::symbol_data_t;using disvm::symbol::symbol_pc_iter_t;using disvm::symbol::type_class_t; namespace{    enum class sbl_version_t    {        unknown,        sbl_2_0,        sbl_2_1,    };     struct header_t    {        sbl_version_t version_id;        std::string module_name;    };     using file_table_t = std::vector<std::string>;     struct sbl_read_context_t    {        int32_t pc_count;        int32_t last_file;        int32_t last_line;    };     struct pc_item_t    {        source_ref_t source;        int32_t debug_statement;    };     using pc_table_t = std::vector<pc_item_t>;     struct type_t    {        type_class_t type_class;        int32_t value_index_1;        int32_t value_index_2;    };     struct id_item_t    {        uint32_t offset;        std::string name;        source_ref_t source;        type_t type;    };     using id_table_t = std::vector<id_item_t>;     struct func_item_t    {        vm_pc_t entry_pc;        vm_pc_t limit_pc;        std::string name;        id_table_t args;        id_table_t locals;        type_t return_type;    };     using func_table_t = std::vector<func_item_t>;     struct name_source_size_t    {        std::string name;        source_ref_t source;        int32_t size_in_bytes;        id_table_t id_table;        std::unique_ptr<std::vector<name_source_size_t>> tag_table;    };     using adt_item_t = name_source_size_t;     struct tuple_item_t    {        int32_t size_in_bytes;        id_table_t id_table;    };     struct type_table_t    {        static const uint32_t string_table_mask;        static const uint32_t inner_type_table_mask;        static const uint32_t source_table_mask;        static const uint32_t adt_table_mask;        static const uint32_t tuple_type_mask;        static const uint32_t types_mask;         std::vector<type_t> types;        std::vector<std::string> strings_table;        std::vector<type_t> inner_type_table;        std::vector<source_ref_t> source_table;        std::vector<name_source_size_t> adt_table;        std::vector<tuple_item_t> tuple_table;         template<typename T>        const T &resolve_table_index(int32_t idx) const;    };     const uint32_t type_table_t::string_table_mask = 0x80000000;    const uint32_t type_table_t::inner_type_table_mask = 0x40000000;    const uint32_t type_table_t::source_table_mask = 0x20000000;    const uint32_t type_table_t::adt_table_mask = 0x10000000;    const uint32_t type_table_t::tuple_type_mask = 0x08000000;    const uint32_t type_table_t::types_mask = 0;     template<>    const std::string &type_table_t::resolve_table_index<std::string>(int32_t idx) const    {        const auto idx_local = idx & ~string_table_mask;        if (idx_local >= strings_table.size())            throw std::out_of_range{ "Invalid string table index" };         return strings_table[idx_local];    }     template<>    const type_t &type_table_t::resolve_table_index<type_t>(int32_t idx) const    {        if ((static_cast<uint32_t>(idx) & inner_type_table_mask) != 0)        {            const auto idx_local = idx & ~inner_type_table_mask;            if (idx_local >= inner_type_table.size())                throw std::out_of_range{ "Invalid inner type table index" };             return inner_type_table[idx_local];        }        else        {            if (0 > idx || static_cast<uint32_t>(idx) >= types.size())                throw std::out_of_range{ "Invalid type table index" };             return types[idx];        }    }     template<>    const source_ref_t &type_table_t::resolve_table_index<source_ref_t>(int32_t idx) const    {        const auto idx_local = idx & ~source_table_mask;        if (idx_local >= source_table.size())            throw std::out_of_range{ "Invalid source table index" };         return source_table[idx_local];    }     template<>    const name_source_size_t &type_table_t::resolve_table_index<name_source_size_t>(int32_t idx) const    {        const auto idx_local = idx & ~adt_table_mask;        if (idx_local >= adt_table.size())            throw std::out_of_range{ "Invalid adt table index" };         return adt_table[idx_local];    }     template<>    const tuple_item_t &type_table_t::resolve_table_index<tuple_item_t>(int32_t idx) const    {        const auto idx_local = idx & ~tuple_type_mask;        if (idx_local >= tuple_table.size())            throw std::out_of_range{ "Invalid tuple table index" };         return tuple_table[idx_local];    }     // sbl: header file-table pc-table type-table func-table data-table    struct sbl_file_t final    {        header_t header;         file_table_t file_table;        pc_table_t pc_table;        type_table_t type_table;        func_table_t func_table;        id_table_t data_table;    };     // header: <magic> '\n' module '\n'    // module: <string>    header_t read_header(disvm::util::buffered_reader_t &r)    {        header_t header;        auto v = r.get_as_string_until('\n');        if (v.compare("limbo .sbl 2.1") == 0)            header.version_id = sbl_version_t::sbl_2_1;        else if (v.compare("limbo .sbl 2.0") == 0)            header.version_id = sbl_version_t::sbl_2_0;        else            throw std::runtime_error{ "Unknown symbol file version" };         header.module_name = r.get_as_string_until('\n');         return header;    }     // file-table: <count> '\n' file*    // file: <string> '\n'    file_table_t read_file_table(disvm::util::buffered_reader_t &r)    {        auto count_str = r.get_as_string_until('\n');         file_table_t file_table;        const auto count = std::stoi(count_str);        file_table.resize(count);        for (auto i = 0; i < count; ++i)        {            auto file = r.get_as_string_until('\n');            file_table[i] = std::move(file);        }         return file_table;    }     // src: pos ',' pos    // pos: file':'? line'.'? char    // file: <int>    // line: <int>    // char: <int>    source_ref_t read_src_entry(const std::string &src_str, sbl_read_context_t &fc)    {        auto src_parts = disvm::util::split(src_str, ",");        if (src_parts.size() != 2)            throw std::runtime_error{ "Invalid source item" };         source_ref_t src;         // Initialize the source with the last state        src.begin_source_id = fc.last_file;        src.begin_line = fc.last_line;        src.end_line = fc.last_line;        for (auto i = std::size_t{ 0 }; i < src_parts.size(); ++i)        {            const auto &pos = src_parts[i];            const auto len = pos.length();             // Parse position            for (auto j = std::size_t{ 0 }; j < len; ++j)            {                auto consumed = std::size_t{ 0 };                auto v = std::stoi(pos.data() + j, &consumed);                j += consumed;                if (j >= len)                {                    if (i == 0)                        src.begin_column = v;                     src.end_column = v;                }                else if (pos[j] == '.')                {                    if (i == 0)                        src.begin_line = v;                     src.end_line = v;                    fc.last_line = v;                }                else if (pos[j] == ':')                {                    if (i == 0)                        src.begin_source_id = v;                     src.end_source_id = v;                    fc.last_file = v;                }            }        }         return src;    }     // pc-table: <count> '\n' pc-item*    // pc-item: src ' ' stmt '\n'    // stmt: <int>    pc_table_t read_pc_table(disvm::util::buffered_reader_t &r, sbl_read_context_t &fc)    {        auto count_str = r.get_as_string_until('\n');         uint32_t last_source = 0;        uint32_t last_line = 0;         pc_table_t pc_table;        const auto count = std::stoi(count_str);        pc_table.resize(count);        for (auto i = 0; i < count; ++i)        {            auto item = r.get_as_string_until('\n');             auto pc_item_parts = disvm::util::split(item);            if (pc_item_parts.size() != 2)                throw std::runtime_error{ "Invalid PC item" };             pc_item_t curr_item;            curr_item.source = read_src_entry(pc_item_parts[0], fc);            curr_item.debug_statement = std::stoi(pc_item_parts[1]);             // Record the current source and line ID since those are the new default values            last_source = curr_item.source.end_source_id;            last_line = curr_item.source.end_line;             pc_table[i] = std::move(curr_item);        }         fc.pc_count = count;        return pc_table;    }     // Forward declaration    type_t read_type(disvm::util::buffered_reader_t &, type_table_t &, sbl_read_context_t &);     // id-table: <count> '\n' id-item*    // id-item: id-offset ':' id-name ':' src ' ' type '\n'    // id-offset: <int>    // id-name: <string>    id_table_t read_id_table(disvm::util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)    {        auto count_str = r.get_as_string_until('\n');        int32_t count = std::stoi(count_str);         bool success;        uint8_t tmp;        id_table_t id_table;        id_table.resize(count);        for (auto i = 0; i < count; ++i)        {            const auto offset_part = r.get_as_string_until(':');            if (offset_part.empty())                throw std::runtime_error{ "Invalid ID table item (offset)" };             const auto name_part = r.get_as_string_until(':');            if (name_part.empty())                throw std::runtime_error{ "Invalid ID table item (name)" };             const auto source_part = r.get_as_string_until(' ');            if (source_part.empty())                throw std::runtime_error{ "Invalid ID table item (source)" };             id_item_t e;            e.offset = std::stoul(offset_part);            e.name = std::move(name_part);            e.source = read_src_entry(source_part, fc);            e.type = read_type(r, tt, fc);             std::tie(success, tmp) = r.get_next_byte();            if (!success || tmp != '\n')                throw std::runtime_error{ "Invalid ID table item" };             id_table[i] = std::move(e);        }         return id_table;    }     // adt-item: adt-name ' ' src ' ' size '\n' id-table    // adt-name: <string>    // size: <int>    //    // tag-table: <count> '\n' tag-item*    // tag-item: tag-name ':' src ' ' size '\n' id-table    //         | tag-name ':' src '\n'    // tag-name: <string>    name_source_size_t create_name_source_size(std::vector<std::string> &parts, disvm::util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)    {        assert(parts.size() == 2 || parts.size() == 3);        name_source_size_t item;        item.name = std::move(parts[0]);        item.source = read_src_entry(parts[1], fc);         if (parts.size() == 3)        {            item.size_in_bytes = std::stoi(parts[2]);            item.id_table = read_id_table(r, tt, fc);        }         return item;    }     // type:    //  '@' type-index '\n'       # Type table reference    //  'a' adt-item              # ADT    //  'p' adt-item tag-table    # ADT-Pick    //  't' size '.' id-table     # Tuple    //  'm' module '\n' src       # Module    //  'F' fn-name ' ' type      # Function    //  'A' type                  # Array    //  'C' type                  # Channel    //  'L' type                  # List    //  'R' type                  # Ref    //  'n'                       # No type    //  'N'                       # Nil    //  'B'                       # Big    //  'b'                       # Byte    //  'i'                       # Int    //  'f'                       # Real    //  's'                       # String    // type-index: <int>    type_t read_type(disvm::util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)    {        bool success;        uint8_t tc_byte;        std::tie(success, tc_byte) = r.get_next_byte();        if (!success)            throw std::runtime_error{ "Invalid type" };         const type_class_t tc = static_cast<type_class_t>(tc_byte);        type_t t{ tc, 0, 0 };        switch (t.type_class)        {        case type_class_t::none:        case type_class_t::nil:        case type_class_t::big:        case type_class_t::byte:        case type_class_t::integer:        case type_class_t::real:        case type_class_t::string:        case type_class_t::poly:            break;         case type_class_t::array:        case type_class_t::channel:        case type_class_t::list:        case type_class_t::ref:            t.value_index_1 = type_table_t::inner_type_table_mask | tt.inner_type_table.size();            tt.inner_type_table.push_back(read_type(r, tt, fc));            break;         case type_class_t::type_index:        {            auto type_index = r.get_as_string_until('\n');            const auto idx = std::stoi(type_index);            t.value_index_1 = type_table_t::types_mask | idx;            break;        }        case type_class_t::adt:        case type_class_t::adt_pick:        {            auto adt_line = r.get_as_string_until('\n');            auto adt_parts = disvm::util::split(adt_line);            if (adt_parts.size() != 3)                throw std::runtime_error{ "Invalid adt item" };             auto adt_item = create_name_source_size(adt_parts, r, tt, fc);             // Check if the adt has a tag table            if (t.type_class == type_class_t::adt_pick)            {                adt_item.tag_table = std::make_unique<std::vector<name_source_size_t>>();                auto tmp = r.get_as_string_until('\n');                 const auto count = std::stoi(tmp);                for (auto i = 0; i < count; ++i)                {                    tmp = r.get_as_string_until('\n');                    auto tag_parts = disvm::util::split(tmp, " :");                    if (tag_parts.size() != 2 && tag_parts.size() != 3)                        throw std::runtime_error{ "Invalid tag item" };                     auto tag = create_name_source_size(tag_parts, r, tt, fc);                    adt_item.tag_table->push_back(std::move(tag));                }            }             t.value_index_1 = type_table_t::adt_table_mask | tt.adt_table.size();            tt.adt_table.push_back(std::move(adt_item));            break;        }        case type_class_t::tuple:        {            // Record tuple size            t.value_index_1 = type_table_t::tuple_type_mask | tt.tuple_table.size();             tuple_item_t tuple{};            auto size_str = r.get_as_string_until('.');            tuple.size_in_bytes = std::stoi(size_str);             tuple.id_table = read_id_table(r, tt, fc);

Lines 1–500 of 863.