DoxigAlpha

init

Function parameters

Parameters

#

Type definitions in this namespace

Types

#

Functions in this namespace

Functions

#

Source

Implementation

#
fn init(allocator: Allocator, file: File) !Msf {
    const in = file.deprecatedReader();

    const superblock = try in.readStruct(pdb.SuperBlock);

    // Sanity checks
    if (!std.mem.eql(u8, &superblock.file_magic, pdb.SuperBlock.expect_magic))
        return error.InvalidDebugInfo;
    if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2)
        return error.InvalidDebugInfo;
    const file_len = try file.getEndPos();
    if (superblock.num_blocks * superblock.block_size != file_len)
        return error.InvalidDebugInfo;
    switch (superblock.block_size) {
        // llvm only supports 4096 but we can handle any of these values
        512, 1024, 2048, 4096 => {},
        else => return error.InvalidDebugInfo,
    }

    const dir_block_count = blockCountFromSize(superblock.num_directory_bytes, superblock.block_size);
    if (dir_block_count > superblock.block_size / @sizeOf(u32))
        return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.

    try file.seekTo(superblock.block_size * superblock.block_map_addr);
    const dir_blocks = try allocator.alloc(u32, dir_block_count);
    for (dir_blocks) |*b| {
        b.* = try in.readInt(u32, .little);
    }
    var directory = MsfStream.init(
        superblock.block_size,
        file,
        dir_blocks,
    );

    const begin = directory.pos;
    const stream_count = try directory.reader().readInt(u32, .little);
    const stream_sizes = try allocator.alloc(u32, stream_count);
    defer allocator.free(stream_sizes);

    // Microsoft's implementation uses @as(u32, -1) for inexistent streams.
    // These streams are not used, but still participate in the file
    // and must be taken into account when resolving stream indices.
    const Nil = 0xFFFFFFFF;
    for (stream_sizes) |*s| {
        const size = try directory.reader().readInt(u32, .little);
        s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.block_size);
    }

    const streams = try allocator.alloc(MsfStream, stream_count);
    for (streams, 0..) |*stream, i| {
        const size = stream_sizes[i];
        if (size == 0) {
            stream.* = MsfStream{
                .blocks = &[_]u32{},
            };
        } else {
            var blocks = try allocator.alloc(u32, size);
            var j: u32 = 0;
            while (j < size) : (j += 1) {
                const block_id = try directory.reader().readInt(u32, .little);
                const n = (block_id % superblock.block_size);
                // 0 is for pdb.SuperBlock, 1 and 2 for FPMs.
                if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len)
                    return error.InvalidBlockIndex;
                blocks[j] = block_id;
            }

            stream.* = MsfStream.init(
                superblock.block_size,
                file,
                blocks,
            );
        }
    }

    const end = directory.pos;
    if (end - begin != superblock.num_directory_bytes)
        return error.InvalidStreamDirectory;

    return Msf{
        .directory = directory,
        .streams = streams,
    };
}