Beispiel #1
0
static void validate_lex_operand(Validator *val, MVMuint32 flags) {
    MVMuint16 lex_index, frame_index, i;
    MVMuint32 lex_count;
    MVMStaticFrame *frame = val->frame;

    /* Two steps forward, two steps back to keep the error reporting happy,
       and to make the endian conversion within ensure_bytes correct.
       (Both are using val->cur_op, and want it to have different values.) */
    ensure_bytes(val, 2);
    lex_index   = GET_UI16(val->cur_op, 0);
    val->cur_op += 2;
    ensure_bytes(val, 2);
    val->cur_op -= 2;
    frame_index = GET_UI16(val->cur_op, 2);

    for (i = frame_index; i; i--) {
        frame = frame->body.outer;
        if (!frame)
            fail(val, MSG(val, "lexical operand requires %" PRIu16
                          " more enclosing scopes"), i);
    }

    lex_count = frame->body.num_lexicals;
    if (lex_index >= lex_count)
        fail(val, MSG(val, "lexical operand index %" PRIu16
                      " out of range 0.. %" PRIu32), lex_index, lex_count - 1);

    val->cur_op += 4;
}
Beispiel #2
0
void
check_free_entry(byte *sp, byte *ep,
		 byte tag,
		 Uint16 ct_no, int ct_no_n,
		 Uint16 t_no, int t_no_n,
		 UWord ptr, int ptr_n,
		 Uint32 ti,int ti_n)
{
    byte *p = sp;
    Uint16 hdr;

    ASSERT(*p == tag);
    p++;

    hdr = GET_UI16(p);

    if (tag == ERTS_MT_CRR_FREE_BDY_TAG)
	check_ui(&hdr, &p, ct_no, ct_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ);
    check_ui(&hdr, &p, t_no, t_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ);
    check_ui(&hdr, &p, ptr,  ptr_n,  UI_MSB_EHF_MSK,   UI_MSB_EHF_SZ);
    check_ui(&hdr, &p, ti,   ti_n,   UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ);

    ASSERT(hdr == 0);
    ASSERT(p == ep);

}
Beispiel #3
0
void
check_alloc_entry(byte *sp, byte *ep,
		  byte tag,
		  Uint16 ct_no, int ct_no_n,
		  Uint16 t_no, int t_no_n,
		  UWord res, int res_n,
		  Uint size, int size_n,
		  Uint32 ti,int ti_n)
{
    byte *p = sp;
    Uint16 hdr;

    ASSERT(*p == tag);
    p++;

    hdr = GET_UI16(p);

    if (tag == ERTS_MT_CRR_ALLOC_BDY_TAG)
	check_ui(&hdr, &p, ct_no, ct_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ);
    check_ui(&hdr, &p, t_no, t_no_n, UI16_MSB_EHF_MSK, UI16_MSB_EHF_SZ);
    check_ui(&hdr, &p, res,  res_n,  UI_MSB_EHF_MSK,   UI_MSB_EHF_SZ);
    check_ui(&hdr, &p, size, size_n, UI_MSB_EHF_MSK,   UI_MSB_EHF_SZ);
    check_ui(&hdr, &p, ti,   ti_n,   UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ);

    ASSERT(hdr == 0);
    ASSERT(p == ep);
}
Beispiel #4
0
static void validate_block(Validator *val) {
    int block_id = val->cur_mark[1];

    switch (block_id) {
    case 'a': {
        MVMuint16 index;

        ensure_op(val, MVM_OP_prepargs);
        validate_operands(val);
        index = GET_UI16(val->cur_op, -2);
        val->cur_call  = val->cu->body.callsites[index];
        val->cur_arg   = 0;
        val->expected_named_arg    = 0;
        val->remaining_positionals = val->cur_call->num_pos;

        break;
    }

    default:
        fail(val, MSG(val, "unknown instruction block '%c'"), block_id);
    }

    while (val->cur_op < val->bc_end) {
        int type, id;

        read_op(val);
        type = val->cur_mark[0];
        id   = val->cur_mark[1];

        if (id != block_id)
            fail(val, MSG(val, "expected instruction marked '%c' but got '%c'"),
                 block_id, id);

        switch (type) {
        case MARK_body:
            break;
        case MARK_tail:
            goto terminate_block;
        default:
            fail_illegal_mark(val);
        }

        switch (block_id) {
        case 'a':
            validate_operands(val);
            validate_arg(val);
            break;
        }
    }

terminate_block:
    switch (block_id) {
    case 'a':
        validate_operands(val);
        ensure_no_remaining_positionals(val);
        break;
    }
}
Beispiel #5
0
void
check_time_inc_entry(byte *sp, byte *ep,
		     Uint32 secs, int secs_n,
		     Uint32 usecs, int usecs_n)
{
    byte *p = sp;
    Uint16 hdr;

    ASSERT(*p == ERTS_MT_TIME_INC_BDY_TAG);
    p++;

    hdr = GET_UI16(p);

    check_ui(&hdr, &p, secs,  secs_n,  UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ);
    check_ui(&hdr, &p, usecs, usecs_n, UI32_MSB_EHF_MSK, UI32_MSB_EHF_SZ);

    ASSERT(hdr == 0);
    ASSERT(p == ep);

}
Beispiel #6
0
static void validate_literal_operand(Validator *val, MVMuint32 flags) {
    MVMuint32 type = flags & MVM_operand_type_mask;
    MVMuint32 size;

    switch (type) {
    case MVM_operand_int8:
        size = 1;
        break;
    case MVM_operand_int16:
        size = 2;
        break;
    case MVM_operand_int32:
        size = 4;
        break;
    case MVM_operand_int64:
        size = 8;
        break;
    case MVM_operand_num32:
        size = 4;
        break;
    case MVM_operand_num64:
        size = 8;
        break;
    case MVM_operand_callsite:
        size = 2;
        break;
    case MVM_operand_coderef:
        size = 2;
        break;
    case MVM_operand_str:
        size = 4;
        break;
    case MVM_operand_ins:
        size = 4;
        break;

    case MVM_operand_obj:
    case MVM_operand_type_var:
        fail(val, MSG(val, "operand type %i can't be a literal"), type);

    default:
        fail(val, MSG(val, "unknown operand type %i"), type);
    }

    ensure_bytes(val, size);

    switch (type) {
    case MVM_operand_callsite: {
        MVMuint16 index = GET_UI16(val->cur_op, 0);
        MVMuint32 count = val->cu->body.orig_callsites;
        if (index >= count)
            fail(val, MSG(val, "callsite index %" PRIu16
                          " out of range 0..%" PRIu32), index, count - 1);
        break;
    }

    case MVM_operand_coderef: {
        MVMuint16 index = GET_UI16(val->cur_op, 0);
        MVMuint32 count = val->cu->body.orig_frames;
        if (index >= count)
            fail(val, MSG(val, "coderef index %" PRIu16
                          " out of range 0..%" PRIu32), index, count - 1);
        break;
    }

    case MVM_operand_str: {
        MVMuint32 index = GET_UI32(val->cur_op, 0);
        MVMuint32 count = val->cu->body.orig_strings;
        if (index >= count)
            fail(val, MSG(val, "string index %" PRIu32
                          " out of range 0..%" PRIu32), index, count - 1);
        break;
    }

    case MVM_operand_ins: {
        MVMuint32 offset = GET_UI32(val->cur_op, 0);
        if (offset >= val->bc_size)
            fail(val, MSG(val, "branch instruction offset %" PRIu32
                          " out of range 0..%" PRIu32), offset, val->bc_size - 1);
        val->labels[offset] |= MVM_BC_branch_target;
    }
    }

    val->cur_op += size;
}
Beispiel #7
0
static void build_cfg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMStaticFrame *sf,
                      MVMint32 *existing_deopts, MVMint32 num_existing_deopts) {
    MVMSpeshBB  *cur_bb, *prev_bb;
    MVMSpeshIns *last_ins;
    MVMint64     i;
    MVMint32     bb_idx;

    /* Temporary array of all MVMSpeshIns we create (one per instruction).
     * Overestimate at size. Has the flat view, matching the bytecode. */
    MVMSpeshIns **ins_flat = MVM_calloc(g->bytecode_size / 2, sizeof(MVMSpeshIns *));

    /* Temporary array where each byte in the input bytecode gets a 32-bit
     * integer. This is used for two things:
     * A) When we make the MVMSpeshIns for an instruction starting at the
     *    byte, we put the instruction index (into ins_flat) in the slot,
     *    shifting it by 2 bits to the left. We will use this to do fixups.
     * B) The first bit is "I have an incoming branch" - that is, start of
     *    a basic block. The second bit is "I can branch" - that is, end of
     *    a basic block. It's possible to have both bits set.
     * Anything that's just a zero has no instruction starting there. */
    MVMuint32 *byte_to_ins_flags = MVM_calloc(g->bytecode_size, sizeof(MVMuint32));

    /* Instruction to basic block mapping. Initialized later. */
    MVMSpeshBB **ins_to_bb = NULL;

    /* Make first pass through the bytecode. In this pass, we make MVMSpeshIns
     * nodes for each instruction and set the start/end of block bits. Also
     * set handler targets as basic block starters. */
    MVMCompUnit *cu       = sf->body.cu;
    MVMuint8    *pc       = g->bytecode;
    MVMuint8    *end      = g->bytecode + g->bytecode_size;
    MVMuint32    ins_idx  = 0;
    MVMuint8     next_bbs = 1; /* Next iteration (here, first) starts a BB. */
    for (i = 0; i < g->num_handlers; i++)
        byte_to_ins_flags[g->handlers[i].goto_offset] |= MVM_CFG_BB_START;
    while (pc < end) {
        /* Look up op info. */
        MVMuint16  opcode     = *(MVMuint16 *)pc;
        MVMuint8  *args       = pc + 2;
        MVMuint8   arg_size   = 0;
        const MVMOpInfo *info = get_op_info(tc, cu, opcode);

        /* Create an instruction node, add it, and record its position. */
        MVMSpeshIns *ins_node = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
        ins_flat[ins_idx] = ins_node;
        byte_to_ins_flags[pc - g->bytecode] |= ins_idx << 2;

        /* Did previous instruction end a basic block? */
        if (next_bbs) {
            byte_to_ins_flags[pc - g->bytecode] |= MVM_CFG_BB_START;
            next_bbs = 0;
        }

        /* Also check we're not already a BB start due to being a branch
         * target, in which case we should ensure our prior is marked as
         * a BB end. */
        else {
            if (byte_to_ins_flags[pc - g->bytecode] & MVM_CFG_BB_START) {
                MVMuint32 hunt = pc - g->bytecode;
                while (!byte_to_ins_flags[--hunt]);
                byte_to_ins_flags[hunt] |= MVM_CFG_BB_END;
            }
        }

        /* Store opcode */
        ins_node->info = info;

        /* Go over operands. */
        ins_node->operands = MVM_spesh_alloc(tc, g, info->num_operands * sizeof(MVMSpeshOperand));
        for (i = 0; i < info->num_operands; i++) {
            MVMuint8 flags = info->operands[i];
            MVMuint8 rw    = flags & MVM_operand_rw_mask;
            switch (rw) {
            case MVM_operand_read_reg:
            case MVM_operand_write_reg:
                ins_node->operands[i].reg.orig = GET_UI16(args, arg_size);
                arg_size += 2;
                break;
            case MVM_operand_read_lex:
            case MVM_operand_write_lex:
                ins_node->operands[i].lex.idx    = GET_UI16(args, arg_size);
                ins_node->operands[i].lex.outers = GET_UI16(args, arg_size + 2);
                arg_size += 4;
                break;
            case MVM_operand_literal: {
                MVMuint32 type = flags & MVM_operand_type_mask;
                switch (type) {
                case MVM_operand_int8:
                    ins_node->operands[i].lit_i8 = GET_I8(args, arg_size);
                    arg_size += 1;
                    break;
                case MVM_operand_int16:
                    ins_node->operands[i].lit_i16 = GET_I16(args, arg_size);
                    arg_size += 2;
                    break;
                case MVM_operand_int32:
                    ins_node->operands[i].lit_i32 = GET_I32(args, arg_size);
                    arg_size += 4;
                    break;
                case MVM_operand_int64:
                    ins_node->operands[i].lit_i64 = MVM_BC_get_I64(args, arg_size);
                    arg_size += 8;
                    break;
                case MVM_operand_num32:
                    ins_node->operands[i].lit_n32 = GET_N32(args, arg_size);
                    arg_size += 4;
                    break;
                case MVM_operand_num64:
                    ins_node->operands[i].lit_n64 = MVM_BC_get_N64(args, arg_size);
                    arg_size += 8;
                    break;
                case MVM_operand_callsite:
                    ins_node->operands[i].callsite_idx = GET_UI16(args, arg_size);
                    arg_size += 2;
                    break;
                case MVM_operand_coderef:
                    ins_node->operands[i].coderef_idx = GET_UI16(args, arg_size);
                    arg_size += 2;
                    break;
                case MVM_operand_str:
                    ins_node->operands[i].lit_str_idx = GET_UI32(args, arg_size);
                    arg_size += 4;
                    break;
                case MVM_operand_ins: {
                    /* Stash instruction offset. */
                    MVMuint32 target = GET_UI32(args, arg_size);
                    ins_node->operands[i].ins_offset = target;

                    /* This is a branching instruction, so it's a BB end. */
                    byte_to_ins_flags[pc - g->bytecode] |= MVM_CFG_BB_END;

                    /* Its target is a BB start, and any previous instruction
                     * we already passed needs marking as a BB end. */
                    byte_to_ins_flags[target] |= MVM_CFG_BB_START;
                    if (target > 0 && target < pc - g->bytecode) {
                        while (!byte_to_ins_flags[--target]);
                        byte_to_ins_flags[target] |= MVM_CFG_BB_END;
                    }

                    /* Next instruction is also a BB start. */
                    next_bbs = 1;

                    arg_size += 4;
                    break;
                }
                case MVM_operand_spesh_slot:
                    ins_node->operands[i].lit_i16 = GET_I16(args, arg_size);
                    arg_size += 2;
                    break;
                default:
                    MVM_exception_throw_adhoc(tc,
                        "Spesh: unknown operand type %d in graph building (op %s)",
                        (int)type, ins_node->info->name);
                }
            }
            break;
            }
        }

        /* We specially handle the jumplist case, which needs to mark all of
         * the possible places we could jump to in the following instructions
         * as starts of basic blocks. It is, in itself, the end of one. Note
         * we jump to the instruction after the n jump points if none match,
         * so that is marked too. */
        if (opcode == MVM_OP_jumplist) {
            MVMint64 n = MVM_BC_get_I64(args, 0);
            for (i = 0; i <= n; i++)
                byte_to_ins_flags[(pc - g->bytecode) + 12 + i * 6] |= MVM_CFG_BB_START;
            byte_to_ins_flags[pc - g->bytecode] |= MVM_CFG_BB_END;
        }

        /* Invocations, returns, and throws are basic block ends. */
        switch (opcode) {
        case MVM_OP_invoke_v:
        case MVM_OP_invoke_i:
        case MVM_OP_invoke_n:
        case MVM_OP_invoke_s:
        case MVM_OP_invoke_o:
        case MVM_OP_return_i:
        case MVM_OP_return_n:
        case MVM_OP_return_s:
        case MVM_OP_return_o:
        case MVM_OP_return:
        case MVM_OP_throwdyn:
        case MVM_OP_throwlex:
        case MVM_OP_throwlexotic:
        case MVM_OP_throwcatdyn:
        case MVM_OP_throwcatlex:
        case MVM_OP_throwcatlexotic:
        case MVM_OP_die:
        case MVM_OP_rethrow:
        case MVM_OP_resume:
            byte_to_ins_flags[pc - g->bytecode] |= MVM_CFG_BB_END;
            next_bbs = 1;
            break;
        }

        /* Final instruction is basic block end. */
        if (pc + 2 + arg_size == end)
            byte_to_ins_flags[pc - g->bytecode] |= MVM_CFG_BB_END;

        /* Caculate next instruction's PC. */
        pc += 2 + arg_size;

        /* If this is a deopt point opcode... */
        if (!existing_deopts && (info->deopt_point & MVM_DEOPT_MARK_ONE))
            add_deopt_annotation(tc, g, ins_node, pc, MVM_SPESH_ANN_DEOPT_ONE_INS);
        if (!existing_deopts && (info->deopt_point & MVM_DEOPT_MARK_ALL))
            add_deopt_annotation(tc, g, ins_node, pc, MVM_SPESH_ANN_DEOPT_ALL_INS);
        if (!existing_deopts && (info->deopt_point & MVM_DEOPT_MARK_OSR))
            add_deopt_annotation(tc, g, ins_node, pc, MVM_SPESH_ANN_DEOPT_OSR);

        /* Go to next instruction. */
        ins_idx++;
    }

    /* Annotate instructions that are handler-significant. */
    for (i = 0; i < g->num_handlers; i++) {
        MVMSpeshIns *start_ins = ins_flat[byte_to_ins_flags[g->handlers[i].start_offset] >> 2];
        MVMSpeshIns *end_ins   = ins_flat[byte_to_ins_flags[g->handlers[i].end_offset] >> 2];
        MVMSpeshIns *goto_ins  = ins_flat[byte_to_ins_flags[g->handlers[i].goto_offset] >> 2];
        MVMSpeshAnn *start_ann = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshAnn));
        MVMSpeshAnn *end_ann   = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshAnn));
        MVMSpeshAnn *goto_ann  = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshAnn));

        start_ann->next = start_ins->annotations;
        start_ann->type = MVM_SPESH_ANN_FH_START;
        start_ann->data.frame_handler_index = i;
        start_ins->annotations = start_ann;

        end_ann->next = end_ins->annotations;
        end_ann->type = MVM_SPESH_ANN_FH_END;
        end_ann->data.frame_handler_index = i;
        end_ins->annotations = end_ann;

        goto_ann->next = goto_ins->annotations;
        goto_ann->type = MVM_SPESH_ANN_FH_GOTO;
        goto_ann->data.frame_handler_index = i;
        goto_ins->annotations = goto_ann;
    }

    /* Annotate instructions that are inline start/end points. */
    for (i = 0; i < g->num_inlines; i++) {
        MVMSpeshIns *start_ins = ins_flat[byte_to_ins_flags[g->inlines[i].start] >> 2];
        MVMSpeshIns *end_ins   = ins_flat[byte_to_ins_flags[g->inlines[i].end] >> 2];
        MVMSpeshAnn *start_ann = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshAnn));
        MVMSpeshAnn *end_ann   = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshAnn));

        start_ann->next = start_ins->annotations;
        start_ann->type = MVM_SPESH_ANN_INLINE_START;
        start_ann->data.inline_idx = i;
        start_ins->annotations = start_ann;

        end_ann->next = end_ins->annotations;
        end_ann->type = MVM_SPESH_ANN_INLINE_END;
        end_ann->data.inline_idx = i;
        end_ins->annotations = end_ann;
    }

    /* Now for the second pass, where we assemble the basic blocks. Also we
     * build a lookup table of instructions that start a basic block to that
     * basic block, for the final CFG construction. We make the entry block a
     * special one, containing a noop; it will have any exception handler
     * targets linked from it, so they show up in the graph. */
    g->entry                  = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB));
    g->entry->first_ins       = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
    g->entry->first_ins->info = get_op_info(tc, cu, 0);
    g->entry->last_ins        = g->entry->first_ins;
    g->entry->idx             = 0;
    cur_bb                    = NULL;
    prev_bb                   = g->entry;
    last_ins                  = NULL;
    ins_to_bb                 = MVM_calloc(ins_idx, sizeof(MVMSpeshBB *));
    ins_idx                   = 0;
    bb_idx                    = 1;
    for (i = 0; i < g->bytecode_size; i++) {
        MVMSpeshIns *cur_ins;

        /* Skip zeros; no instruction here. */
        if (!byte_to_ins_flags[i])
            continue;

        /* Get current instruction. */
        cur_ins = ins_flat[byte_to_ins_flags[i] >> 2];

        /* Start of a basic block? */
        if (byte_to_ins_flags[i] & MVM_CFG_BB_START) {
            /* Should not already be in a basic block. */
            if (cur_bb) {
                MVM_spesh_graph_destroy(tc, g);
                MVM_exception_throw_adhoc(tc, "Spesh: confused during basic block analysis (in block)");
            }

            /* Create it, and set first instruction and index. */
            cur_bb = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB));
            cur_bb->first_ins = cur_ins;
            cur_bb->idx = bb_idx;
            bb_idx++;

            /* Record instruction -> BB start mapping. */
            ins_to_bb[ins_idx] = cur_bb;

            /* Link it to the previous one. */
            prev_bb->linear_next = cur_bb;
        }

        /* Should always be in a BB at this point. */
        if (!cur_bb) {
            MVM_spesh_graph_destroy(tc, g);
            MVM_exception_throw_adhoc(tc, "Spesh: confused during basic block analysis (no block)");
        }

        /* Add instruction into double-linked per-block instruction list. */
        if (last_ins) {
            last_ins->next = cur_ins;
            cur_ins->prev = last_ins;
        }
        last_ins = cur_ins;

        /* End of a basic block? */
        if (byte_to_ins_flags[i] & MVM_CFG_BB_END) {
            cur_bb->last_ins = cur_ins;
            prev_bb  = cur_bb;
            cur_bb   = NULL;
            last_ins = NULL;
        }

        ins_idx++;
    }
    g->num_bbs = bb_idx;

    /* Finally, link the basic blocks up to form a CFG. Along the way, any of
     * the instruction operands get the target BB stored. */
    cur_bb = g->entry;
    while (cur_bb) {
        /* If it's the first block, it's a special case; successors are the
         * real successor and all exception handlers. */
        if (cur_bb == g->entry) {
            cur_bb->num_succ = 1 + g->num_handlers;
            cur_bb->succ     = MVM_spesh_alloc(tc, g, cur_bb->num_succ * sizeof(MVMSpeshBB *));
            cur_bb->succ[0]  = cur_bb->linear_next;
            for (i = 0; i < g->num_handlers; i++) {
                MVMuint32 offset = g->handlers[i].goto_offset;
                cur_bb->succ[i + 1] = ins_to_bb[byte_to_ins_flags[offset] >> 2];
            }
        }

        /* Otherwise, consider the last instruction, to see how we leave the BB. */
        else {
            switch (cur_bb->last_ins->info->opcode) {
Beispiel #8
0
int unZ(char *archiveFilename, char *extractPath)
{
	FILE *fp;
	fchunk_t fc;

	unsigned int i, destsize;
	unsigned char header[256], *toc;

	unsigned int numFiles, compsize, tocOffset, tocSize, numDirs;
	direntry_t *dirs;

	destsize = strlen(extractPath);

	fp = fopen(archiveFilename, "rb");

	if (!fp)
	{
		printf("Error opening %s!\n", archiveFilename);
		return;
	}

	fseek(fp, 0, SEEK_END);
	compsize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	fread(header, 256, 1, fp);

	// check signature
	if (GET_UI32(header) != 0x8C655D13)
	{
		printf("Archive corrupt: Bad signature!\n");
		return 0;
	}

	//numFiles = GET_UI16(header + 12);

	// check size
	if (compsize != GET_UI32(header + 18))
	{
		printf("Archive corrupt: Incorrect size!\n");
		return 0;
	}

	// read toc
	tocOffset = GET_UI32(header + 41);
	tocSize = compsize - tocOffset;

	toc = malloc(tocSize);
	fseek(fp, tocOffset, SEEK_SET);
	fread(toc, 1, tocSize, fp);
	tocOffset = 0;


	// parse dirs
	numDirs = GET_UI16(header + 49);
	dirs = malloc(sizeof(*dirs) * numDirs);

	for (i = 0; i < numDirs; i++)
	{
		unsigned int dir_numFiles  = GET_UI16(toc + tocOffset);
		unsigned int dir_entrySize = GET_UI16(toc + tocOffset + 2);
		unsigned int dir_nameSize  = GET_UI16(toc + tocOffset + 4);

		dirs[i].name = malloc(destsize + 1 + dir_nameSize + 1);
		strcpy(dirs[i].name, extractPath);
		dirs[i].name[destsize] = '\\';
		memcpy(dirs[i].name + destsize + 1, toc + tocOffset + 6, dir_nameSize);
		dirs[i].name[destsize + 1 + dir_nameSize] = '\0';
		dirs[i].numFiles = dir_numFiles;

		tocOffset += dir_entrySize;
	}

	// parse and save files
	fseek(fp, 255, SEEK_SET);
	fc.fp = fp;
	for (i = 0; i < numDirs; i++)
	{
		unsigned int dir_nameSize;
		int j;

		_mkdir(extractPath);
		if (dirs[i].name[0])
			_mkdir(dirs[i].name);

		printf("Dir %s, %d files\n", dirs[i].name, dirs[i].numFiles);
		dir_nameSize = strlen(dirs[i].name);

		for (j = 0; j < dirs[i].numFiles; j++)
		{
			FILE *fpw;
			int blastErr;

			unsigned int file_decompressedSize = GET_UI32(toc + tocOffset + 3);
			unsigned int file_compressedSize   = GET_UI32(toc + tocOffset + 7);
			unsigned int file_modifiedDate     = GET_UI16(toc + tocOffset + 15);
			unsigned int file_modifiedTime     = GET_UI16(toc + tocOffset + 17);
			unsigned int file_entrySize        = GET_UI16(toc + tocOffset + 23);
			unsigned int file_nameSize         = toc[tocOffset + 29];

			char *filename;

			struct tm tmm;
			struct _utimbuf ut;

			filename = malloc(dir_nameSize + file_nameSize + 2);
			strcpy(filename, dirs[i].name);
			filename[dir_nameSize] = '\\';
			strncpy(filename + dir_nameSize + 1, toc + tocOffset + 30, file_nameSize);
			filename[dir_nameSize + 1 + file_nameSize] = '\0';

			printf("%s, %d bytes, %.3f%%\n", filename, file_decompressedSize, (float)file_compressedSize / file_decompressedSize * 100.0f);

			memset(&tmm, 0, sizeof(tmm));
			tmm.tm_year = ( file_modifiedDate           >> 9) + 80;
			tmm.tm_mon  = ((file_modifiedDate & 0x01E0) >> 5) - 1;
			tmm.tm_mday =   file_modifiedDate & 0x001F;
			tmm.tm_hour =   file_modifiedTime           >> 11;
			tmm.tm_min  =  (file_modifiedTime & 0x07E0) >> 5;
			tmm.tm_sec  =  (file_modifiedTime & 0x001F) * 2;

#if defined(SHOWTIME)
			printf("last modified %d %s %d %02d:%02d:%02d\n", 
				tmm.tm_year + 1900, months[tmm.tm_mon], tmm.tm_mday, tmm.tm_hour, tmm.tm_min, tmm.tm_sec);
#endif

			tocOffset += file_entrySize;

			fpw = fopen(filename, "wb");
			fc.size = file_compressedSize;

			blastErr = blast(inf, &fc, outf, fpw);

			if (blastErr == 1)
				printf("Error writing file!\n");
			else if (blastErr != 0)
				printf("Archive corrupt: Error decompressing, trying to continue");

			fclose(fpw);

			ut.actime = time(NULL);
			ut.modtime = mktime(&tmm);
			_utime(filename, &ut);

			free(filename);
		}
	}

	fclose(fp);

	for (i = 0; i < numDirs; i++)
		free(dirs[i].name);

	free(dirs);
	free(toc);

	return 0;
}
Beispiel #9
0
/* Validate that a static frame's bytecode is executable by the interpreter */
void MVM_validate_static_frame(MVMThreadContext *tc, MVMStaticFrame *static_frame) {
    
    MVMCompUnit *cu = static_frame->cu;
    MVMuint32 bytecode_size = static_frame->bytecode_size;
    MVMuint8 *bytecode_start = static_frame->bytecode;
    MVMuint8 *bytecode_end = bytecode_start + bytecode_size;
    /* current position in the bytestream */
    MVMuint8 *cur_op = bytecode_start;
    /* positions in the bytestream that are starts of ops and goto targets */
    MVMuint8 *labels = malloc(bytecode_size);
    MVMuint32 num_locals = static_frame->num_locals;
    MVMuint32 branch_target;
    MVMuint8 bank_num;
    MVMuint8 op_num;
    MVMOpInfo *op_info;
    MVMuint32 operand_size;
    MVMuint16 operand_target;
    MVMuint32 instruction = 0;
    MVMuint32 i;
    unsigned char op_rw;
    unsigned char op_type;
    unsigned char op_flags;
    MVMuint32 operand_type_var;
    MVMint64 num_jumplist_labels = 0;
    
    memset(labels, 0, bytecode_size);
    
    /* printf("bytecode_size %d cur_op %d bytecode_end %d difference %d", bytecode_size, (int)cur_op, (int)bytecode_end, (int)(bytecode_end - cur_op)); */
    while (cur_op < bytecode_end - 1) {
        labels[cur_op - bytecode_start] |= MVM_val_op_boundary;
        bank_num = *(cur_op++);
        op_num = *(cur_op++);
        operand_type_var = 0;
        op_info = MVM_op_get_op((unsigned char)bank_num, (unsigned char)op_num);
        if (!op_info) {
            cleanup_all(tc, labels);
            MVM_exception_throw_adhoc(tc,
                "Bytecode validation error: non-existent operation bank %u op %u",
                bank_num, op_num);
        }
        if (num_jumplist_labels != 0 && num_jumplist_labels-- != 0
                && (bank_num != MVM_OP_BANK_primitives || op_num != MVM_OP_goto)) {
            cleanup_all(tc, labels);
            MVM_exception_throw_adhoc(tc,
                "jumplist op must be followed by an additional %d goto ops", num_jumplist_labels + 1);
        }
        /*printf("validating op %s, (%d) bank %d", op_info->name, op_num, bank_num);*/
        for (i = 0; i < op_info->num_operands; i++) {
            op_flags = op_info->operands[i];
            op_rw   = op_flags & MVM_operand_rw_mask;
            op_type = op_flags & MVM_operand_type_mask;
            if (op_rw == MVM_operand_literal) {
                switch (op_type) {
                    case MVM_operand_int8:      operand_size = 1; break;
                    case MVM_operand_int16:     operand_size = 2; break;
                    case MVM_operand_int32:     operand_size = 4; break;
                    case MVM_operand_int64:
                        operand_size = 8;
                        if (bank_num == MVM_OP_BANK_primitives && op_num == MVM_OP_jumplist) {
                            if (cur_op + operand_size > bytecode_end)
                                throw_past_end(tc, labels);
                            num_jumplist_labels = GET_I64(cur_op, 0);
                            if (num_jumplist_labels < 0 || num_jumplist_labels > 4294967295u) {
                                cleanup_all(tc, labels);
                                MVM_exception_throw_adhoc(tc,
                                    "num_jumplist_labels %d out of range", num_jumplist_labels);
                            }
                        }
                        break;
                    case MVM_operand_num32:     operand_size = 4; break;
                    case MVM_operand_num64:     operand_size = 8; break;
                    case MVM_operand_callsite:
                        operand_size = 2;
                        if (cur_op + operand_size > bytecode_end)
                            throw_past_end(tc, labels);
                        operand_target = GET_UI16(cur_op, 0);
                        if (operand_target >= cu->num_callsites) {
                            cleanup_all(tc, labels);
                            MVM_exception_throw_adhoc(tc,
                                "Bytecode validation error: callsites index (%u) out of range; frame has %u callsites",
                                operand_target, cu->num_callsites);
                        }
                        break;
                        
                    case MVM_operand_coderef:
                        operand_size = 2;
                        if (cur_op + operand_size > bytecode_end)
                            throw_past_end(tc, labels);
                        operand_target = GET_UI16(cur_op, 0);
                        if (operand_target >= cu->num_frames) {
                            cleanup_all(tc, labels);
                            MVM_exception_throw_adhoc(tc,
                                "Bytecode validation error: coderef index (%u) out of range; frame has %u coderefs",
                                operand_target, cu->num_frames);
                        }
                        break; /* reset to 0 */
                    
                    case MVM_operand_str:
                        operand_size = 2;
                        if (cur_op + operand_size > bytecode_end)
                            throw_past_end(tc, labels);
                        operand_target = GET_UI16(cur_op, 0);
                        if (operand_target >= cu->num_strings) {
                            cleanup_all(tc, labels);
                            MVM_exception_throw_adhoc(tc,
                                "Bytecode validation error: strings index (%u) out of range (0-%u)",
                                operand_target, cu->num_strings - 1);
                        }
                        break;
                        
                    case MVM_operand_ins:
                        operand_size = 4;
                        if (cur_op + operand_size > bytecode_end)
                            throw_past_end(tc, labels);
                        branch_target = GET_UI32(cur_op, 0);
                        if (branch_target >= bytecode_size) {
                            cleanup_all(tc, labels);
                            MVM_exception_throw_adhoc(tc,
                                "Bytecode validation error: branch instruction offset (%u) out of range; frame has %u bytes",
                                branch_target, bytecode_size);
                        }
                        labels[branch_target] |= MVM_val_branch_target;
                        break;
                    
                    case MVM_operand_obj:
                    case MVM_operand_type_var:
                        cleanup_all(tc, labels);
                        MVM_exception_throw_adhoc(tc,
                            "Bytecode validation error: that operand type (%u) can't be a literal",
                            (MVMuint8)op_type);
                        break;
                    default: {
                        cleanup_all(tc, labels);
                        MVM_exception_throw_adhoc(tc,
                            "Bytecode validation error: non-existent operand type (%u)",
                            (MVMuint8)op_type);
                    }
                }
                if (cur_op + operand_size > bytecode_end)
                    throw_past_end(tc, labels);
            }
            else if (op_rw == MVM_operand_read_reg || op_rw == MVM_operand_write_reg) {
                /* register operand */
                operand_size = 2;
                if (cur_op + operand_size > bytecode_end)
                    throw_past_end(tc, labels);
                if (GET_REG(cur_op, 0) >= num_locals) {
                    cleanup_all(tc, labels);
                    MVM_exception_throw_adhoc(tc,
                        "Bytecode validation error: operand register index (%u) out of range; frame has %u locals; at byte %u",
                        GET_REG(cur_op, 0), num_locals, cur_op - bytecode_start);
                }
                if (op_type == MVM_operand_type_var) {
                    if (operand_type_var) {
                        /* XXX assume only one type variable */
                        if ((static_frame->local_types[GET_REG(cur_op, 0)] << 3) != operand_type_var) {
                            cleanup_all(tc, labels);
                            MVM_exception_throw_adhoc(tc,
                                "Bytecode validation error: inconsistent operand types %d and %d to op '%s' with a type variable, at instruction %d",
                                    static_frame->local_types[GET_REG(cur_op, 0)], operand_type_var >> 3, op_info->name, instruction);
                        }
                    }
                    else {
                        operand_type_var = (static_frame->local_types[GET_REG(cur_op, 0)] << 3);
                    }
                }
                else if ((static_frame->local_types[GET_REG(cur_op, 0)] << 3) != op_type) {
Beispiel #10
0
static void bytecode_dump_frame_internal(MVMThreadContext *tc, MVMStaticFrame *frame, MVMSpeshCandidate *maybe_candidate, MVMuint8 *frame_cur_op, char ***frame_lexicals, char **oo, MVMuint32 *os, MVMuint32 *ol) {
    /* since "references" are not a thing in C, keep a local copy of these
     * and update the passed-in pointers at the end of the function */
    char *o = *oo;
    MVMuint32 s = *os;
    MVMuint32 l = *ol;

    MVMuint32 i, j, k;

    /* mostly stolen from validation.c */
    MVMStaticFrame *static_frame = frame;
    MVMuint32 bytecode_size = maybe_candidate ? maybe_candidate->bytecode_size : static_frame->body.bytecode_size;
    MVMuint8 *bytecode_start = maybe_candidate ? maybe_candidate->bytecode : static_frame->body.bytecode;
    MVMuint8 *bytecode_end = bytecode_start + bytecode_size;
    /* current position in the bytestream */
    MVMuint8 *cur_op = bytecode_start;
    /* positions in the bytestream that are starts of ops and goto targets */
    MVMuint8 *labels = MVM_calloc(1, bytecode_size);
    MVMuint32 *jumps = MVM_calloc(1, sizeof(MVMuint32) * bytecode_size);
    char **lines = MVM_malloc(sizeof(char *) * bytecode_size);
    MVMuint32 *linelocs = MVM_malloc(sizeof(MVMuint32) * bytecode_size);
    MVMuint32 lineno = 0;
    MVMuint32 lineloc;
    MVMuint16 op_num;
    const MVMOpInfo *op_info;
    MVMuint32 operand_size = 0;
    unsigned char op_rw;
    unsigned char op_type;
    unsigned char op_flags;
    MVMOpInfo tmp_extop_info;
    /* stash the outer output buffer */
    MVMuint32 sP = s;
    MVMuint32 lP = l;
    char *oP = o;
    char *tmpstr;
    char mark_this_line = 0;
    MVMCompUnit *cu = static_frame->body.cu;

    while (cur_op < bytecode_end - 1) {

        /* allocate a line buffer */
        s = 200;
        l = 0;
        o = MVM_calloc(s, sizeof(char));

        lineloc = cur_op - bytecode_start;
        /* mark that this line starts at this point in the bytestream */
        linelocs[lineno] = lineloc;
        /* mark that this point in the bytestream is an op boundary */
        labels[lineloc] |= MVM_val_op_boundary;


        mark_this_line = 0;
        if (frame_cur_op) {
            if (frame_cur_op == cur_op || frame_cur_op == cur_op + 2) {
                mark_this_line = 1;
            }
        }

        if (mark_this_line) {
            a("-> ");
        } else {
            a("   ");
        }

        op_num = *((MVMint16 *)cur_op);
        cur_op += 2;
        if (op_num < MVM_OP_EXT_BASE) {
            op_info = MVM_op_get_op(op_num);
            if (op_info)
                a("%-18s ", op_info->name);
            else
                a("invalid OP        ");
        }
        else {
            MVMint16 ext_op_num = op_num - MVM_OP_EXT_BASE;
            if (0 <= ext_op_num && ext_op_num < cu->body.num_extops) {
                MVMExtOpRecord r = cu->body.extops[ext_op_num];
                MVMuint8 j;
                memset(&tmp_extop_info, 0, sizeof(MVMOpInfo));
                tmp_extop_info.name = MVM_string_utf8_encode_C_string(tc, r.name);
                memcpy(tmp_extop_info.operands, r.operand_descriptor, 8);
                for (j = 0; j < 8; j++)
                    if (tmp_extop_info.operands[j])
                        tmp_extop_info.num_operands++;
                    else
                        break;
                op_info = &tmp_extop_info;
                a("%-12s ", tmp_extop_info.name);
                MVM_free((void *)tmp_extop_info.name);
                tmp_extop_info.name = NULL;
            }
            else {
                a("Extension op %d out of range", (int)op_num);
            }
        }

        if (!op_info)
            continue;

        for (i = 0; i < op_info->num_operands; i++) {
            if (i) a(", ");
            op_flags = op_info->operands[i];
            op_rw   = op_flags & MVM_operand_rw_mask;
            op_type = op_flags & MVM_operand_type_mask;

            if (op_rw == MVM_operand_literal) {
                switch (op_type) {
                    case MVM_operand_int8:
                        operand_size = 1;
                        a("%"PRId8, GET_I8(cur_op, 0));
                        break;
                    case MVM_operand_int16:
                        operand_size = 2;
                        a("%"PRId16, GET_I16(cur_op, 0));
                        break;
                    case MVM_operand_int32:
                        operand_size = 4;
                        a("%"PRId32, GET_I32(cur_op, 0));
                        break;
                    case MVM_operand_int64:
                        operand_size = 8;
                        a("%"PRId64, MVM_BC_get_I64(cur_op, 0));
                        break;
                    case MVM_operand_uint8:
                        operand_size = 1;
                        a("%"PRIu8, GET_I8(cur_op, 0));
                        break;
                    case MVM_operand_uint16:
                        operand_size = 2;
                        a("%"PRIu16, GET_I16(cur_op, 0));
                        break;
                    case MVM_operand_uint32:
                        operand_size = 4;
                        a("%"PRIu32, GET_I32(cur_op, 0));
                        break;
                    case MVM_operand_uint64:
                        operand_size = 8;
                        a("%"PRIu64, MVM_BC_get_I64(cur_op, 0));
                        break;
                    case MVM_operand_num32:
                        operand_size = 4;
                        a("%f", GET_N32(cur_op, 0));
                        break;
                    case MVM_operand_num64:
                        operand_size = 8;
                        a("%f", MVM_BC_get_N64(cur_op, 0));
                        break;
                    case MVM_operand_callsite:
                        operand_size = 2;
                        a("Callsite_%"PRIu16, GET_UI16(cur_op, 0));
                        break;
                    case MVM_operand_coderef:
                        operand_size = 2;
                        a("Frame_%"PRIu16, GET_UI16(cur_op, 0));
                        break;
                    case MVM_operand_str:
                        operand_size = 4;
                        if (GET_UI32(cur_op, 0) < cu->body.num_strings) {
                            tmpstr = MVM_string_utf8_encode_C_string(
                                    tc, MVM_cu_string(tc, cu, GET_UI32(cur_op, 0)));
                            /* XXX C-string-literal escape the \ and '
                                and line breaks and non-ascii someday */
                            a("'%s'", tmpstr);
                            MVM_free(tmpstr);
                        }
                        else
                            a("invalid string index: %d", GET_UI32(cur_op, 0));
                        break;
                    case MVM_operand_ins:
                        operand_size = 4;
                        /* luckily all the ins operands are at the end
                        of op operands, so I can wait to resolve the label
                        to the end. */
                        if (GET_UI32(cur_op, 0) < bytecode_size) {
                            labels[GET_UI32(cur_op, 0)] |= MVM_val_branch_target;
                            jumps[lineno] = GET_UI32(cur_op, 0);
                        }
                        break;
                    case MVM_operand_obj:
                        /* not sure what a literal object is */
                        operand_size = 4;
                        break;
                    case MVM_operand_spesh_slot:
                        operand_size = 2;
                        a("sslot(%d)", GET_UI16(cur_op, 0));
                        break;
                    default:
                        fprintf(stderr, "what is an operand of type %d??\n", op_type);
                        abort(); /* never reached, silence compiler warnings */
                }
            }
            else if (op_rw == MVM_operand_read_reg || op_rw == MVM_operand_write_reg) {
                /* register operand */
                MVMuint8 frame_has_inlines = maybe_candidate && maybe_candidate->num_inlines ? 1 : 0;
                MVMuint16 *local_types = frame_has_inlines ? maybe_candidate->local_types : frame->body.local_types;
                MVMuint16 num_locals   = frame_has_inlines ? maybe_candidate->num_locals : frame->body.num_locals;
                operand_size = 2;
                a("loc_%u_%s", GET_REG(cur_op, 0),
                    get_typename(local_types[GET_REG(cur_op, 0)]));
            }
            else if (op_rw == MVM_operand_read_lex || op_rw == MVM_operand_write_lex) {
                /* lexical operand */
                MVMuint16 idx, frames, m;
                MVMStaticFrame *applicable_frame = static_frame;

                operand_size = 4;
                idx = GET_UI16(cur_op, 0);
                frames = GET_UI16(cur_op, 2);

                m = frames;
                while (m > 0) {
                    applicable_frame = applicable_frame->body.outer;
                    m--;
                }
                /* inefficient, I know. should use a hash. */
                for (m = 0; m < cu->body.num_frames; m++) {
                    if (get_frame(tc, cu, m) == applicable_frame) {
                        char *lexname = frame_lexicals ? frame_lexicals[m][idx] : "lex??";
                        a("lex_Frame_%u_%s_%s", m, lexname,
                            get_typename(applicable_frame->body.lexical_types[idx]));
                    }
                }
            }
            cur_op += operand_size;
        }

        lines[lineno++] = o;
    }
    {
        MVMuint32 *linelabels = MVM_calloc(lineno, sizeof(MVMuint32));
        MVMuint32 byte_offset = 0;
        MVMuint32 line_number = 0;
        MVMuint32 label_number = 1;
        MVMuint32 *annotations = MVM_calloc(lineno, sizeof(MVMuint32));

        for (; byte_offset < bytecode_size; byte_offset++) {
            if (labels[byte_offset] & MVM_val_branch_target) {
                /* found a byte_offset where a label should be.
                 now crawl up through the lines to find which line starts there */
                while (line_number < lineno && linelocs[line_number] != byte_offset) line_number++;
                if (line_number < lineno)
                    linelabels[line_number] = label_number++;
            }
        }
        o = oP;
        l = lP;
        s = sP;

        i = 0;
        /* resolve annotation line numbers */
        for (j = 0; j < frame->body.num_annotations; j++) {
            MVMuint32 ann_offset = GET_UI32(frame->body.annotations_data, j*12);
            for (; i < lineno; i++) {
                if (linelocs[i] == ann_offset) {
                    annotations[i] = j + 1;
                    break;
                }
            }
        }

        for (j = 0; j < lineno; j++) {
            if (annotations[j]) {
                MVMuint16 shi = GET_UI16(frame->body.annotations_data + 4, (annotations[j] - 1)*12);
                tmpstr = MVM_string_utf8_encode_C_string(
                    tc, MVM_cu_string(tc, cu, shi < cu->body.num_strings ? shi : 0));
                a("     annotation: %s:%u\n", tmpstr, GET_UI32(frame->body.annotations_data, (annotations[j] - 1)*12 + 8));
                MVM_free(tmpstr);
            }
            if (linelabels[j])
                a("     label_%u:\n", linelabels[j]);
            a("%05d   %s", j, lines[j]);
            MVM_free(lines[j]);
            if (jumps[j]) {
                /* horribly inefficient for large frames.  again, should use a hash */
                line_number = 0;
                while (line_number < lineno && linelocs[line_number] != jumps[j]) line_number++;
                if (line_number < lineno)
                    a("label_%u(%05u)", linelabels[line_number], line_number);
                else
                    a("label (invalid: %05u)", jumps[j]);
            }
            a("\n");
        }
        MVM_free(lines);
        MVM_free(jumps);
        MVM_free(linelocs);
        MVM_free(linelabels);
        MVM_free(labels);
        MVM_free(annotations);
    }

    *oo = o;
    *os = s;
    *ol = l;
}