jcov_crt.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 615 行 · 第 1/2 页

C
615
字号
/* * @(#)jcov_crt.c	1.8 06/10/10 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved.   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER   *    * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public License version   * 2 only, as published by the Free Software Foundation.    *    * This program is distributed in the hope that it will be useful, but   * WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * General Public License version 2 for more details (a copy is   * included at /legal/license.txt).    *    * You should have received a copy of the GNU General Public License   * version 2 along with this work; if not, write to the Free Software   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   * 02110-1301 USA    *    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa   * Clara, CA 95054 or visit www.sun.com if you need additional   * information or have any questions.  * */#include "jcov.h"#include "jcov_util.h"#include "jcov_types.h"#include "jcov_error.h"#include "jcov_crt.h"#include "jcov_jvm.h"#define ASSRT(cond, n, ctx) if (!(cond)) { \        if ((ctx).hooked_class != NULL && ((ctx).hooked_class)->name != NULL) \            sprintf(info, "assertion failure #%d in class: %s", n, ((ctx).hooked_class)->name); \        else \            sprintf(info, "assertion failure #%d (class unknown)", n); \        jcov_error(info); \        exit(1); \    }#define READ_AND_CHECK(dest, bytes_total, ctx) \    dest = read##bytes_total##bytes(&((ctx).class_data), &((ctx).class_len), &err_code); \    if (err_code) { \        if ((ctx).hooked_class != NULL && ((ctx).hooked_class)->name != NULL) \            sprintf(info, "bad class format : %s", ((ctx).hooked_class)->name); \        else \            sprintf(info, "bad class format"); \        jcov_error(info); \        exit(1); \    }cov_item_t *cov_item_new(UINT16 pc, UINT8 type, UINT8 instr_type, INT32 line, INT32 pos) {    cov_item_t *cov_item = (cov_item_t*)jcov_calloc(sizeof(cov_item_t));    cov_item->pc         = pc;    cov_item->type       = type;    cov_item->instr_type = instr_type;    cov_item->where_line = line;    cov_item->where_pos  = pos;    cov_item->count      = 0;    return cov_item;}static crt_entry_t *crt_entry_new(UINT16 pc_start, UINT16 pc_end,                                  INT32 rng_start, INT32 rng_end, UINT16 flags) {    crt_entry_t *crt_entry = (crt_entry_t*)jcov_calloc(sizeof(crt_entry_t));    crt_entry->pc_start  = pc_start;    crt_entry->pc_end    = pc_end;    crt_entry->rng_start = rng_start;    crt_entry->rng_end   = rng_end;    crt_entry->flags     = flags;    return crt_entry;}/* Note: CRT_ANY is used to represent the logical OR'ed value of all possible         CRT flags to be passed to the flags argument in get_crt_entry()         below. */#define CRT_ANY       ((UINT16)-1)static crt_entry_t *get_crt_entry(INT32 pc, jcov_list_t *map[], UINT16 flags) {    jcov_list_t *l = map[pc];    for (; l != NULL; l = l->next) {        crt_entry_t *e = (crt_entry_t*)l->elem;        if (e->flags & flags)            return e;    }    return NULL;}static cov_item_t *get_cov_item(INT32 pc, jcov_list_t *map[], UINT8 type) {    jcov_list_t *l = map[pc];    for (; l != NULL; l = l->next) {        cov_item_t *ci = (cov_item_t*)l->elem;        if (ci->type == type)            return ci;    }    return NULL;}static void gen_cov_for_if(UINT16              pc,                           crt_entry_t         *ce,                           jcov_list_t         *cov_map[],                           jcov_list_t         *crt_map[],                           bin_class_context_t *context) {    cov_item_t *cov_item;    UINT8 opc;    UINT16 targ_pc;    UINT8  *code = context->code;    UINT8  type = ce->flags & CRT_BRANCH_TRUE ? CT_BRANCH_FALSE : CT_BRANCH_TRUE;    UINT8  itype;    Bool is_if;    opc = code[pc] & 0xFF;    is_if = !(opc < opc_ifeq                            ||              (opc > opc_if_acmpne && opc < opc_ifnull) ||              opc > opc_ifnonnull);    itype = is_if ? INSTR_IF : INSTR_ANY;    cov_item = cov_item_new(pc, type, itype, ce->rng_start, ce->rng_end);    add_to_list(&(cov_map[pc]), cov_item);    type = type == CT_BRANCH_TRUE ? CT_BRANCH_FALSE : CT_BRANCH_TRUE;    cov_item = cov_item_new(pc, type, itype, ce->rng_start, ce->rng_end);    add_to_list(&(cov_map[pc]), cov_item);    if (!is_if)        return;    targ_pc = pc + INT16_AT(code, pc + 1);    if (get_cov_item(targ_pc, cov_map, CT_BLOCK) == NULL) {        ce = get_crt_entry(targ_pc, crt_map, CRT_STATEMENT);        if (ce != NULL) {            cov_item = cov_item_new(targ_pc, CT_BLOCK, INSTR_ANY, ce->rng_start, ce->rng_end);            add_to_list(&(cov_map[targ_pc]), cov_item);        }    }    targ_pc = pc + get_instr_size(pc, code);    if (get_cov_item(targ_pc, cov_map, CT_BLOCK) == NULL) {        ce = get_crt_entry(targ_pc, crt_map, CRT_STATEMENT);        if (ce != NULL) {            cov_item = cov_item_new(targ_pc, CT_BLOCK, INSTR_ANY, ce->rng_start, ce->rng_end);            add_to_list(&(cov_map[targ_pc]), cov_item);        }    }}static void gen_cov_for_switch(UINT8               *code,                               crt_entry_t         *crt_entry,                               jcov_list_t         *cov_list[],                               jcov_list_t         *map[],                               bin_class_context_t *context) {    INT32 n, off, def_off;    UINT8 type;    UINT16 cur_pc, i;    char info[MAX_PATH_LEN];    crt_entry_t *ce = NULL;    cov_item_t *def_item;    UINT16 pc = crt_entry->pc_start; /* get remembered pc */    if (cov_list[pc] != NULL) {        char *class = (context->hooked_class == NULL || context->hooked_class->name == NULL) ?            "UNKNOWN" : context->hooked_class->name;        sprintf(info, "invalid crt at switch instruction pc. Class: %s", class);        jcov_error(info);    }    switch (code[pc]) {    case opc_lookupswitch:        cur_pc = (pc + 4) & (~3);        off = INT32_AT(code, cur_pc) + pc;        def_off = off;        ce = get_crt_entry(off, map, CRT_FLOW_TARGET);        if (ce == NULL)            ce = get_crt_entry(off, map, CRT_ANY);        if (ce == NULL)            ce = crt_entry;        ASSRT(ce != NULL, 20, *context);        type = (ce->flags & CRT_FLOW_TARGET) ? CT_CASE : CT_SWITCH_WO_DEF;        def_item = cov_item_new(pc, type, INSTR_LOOKUPSW, ce->rng_start, ce->rng_end);        if (type == CT_SWITCH_WO_DEF && get_cov_item(off, cov_list, CT_BLOCK) == NULL) {            /* workaround a compiler bug */            cov_item_t *ci = cov_item_new((UINT16)off, CT_BLOCK, INSTR_ANY, ce->rng_start, ce->rng_end);            add_to_list(&(cov_list[off]), ci);        }        cur_pc += 4;        n = INT32_AT(code, cur_pc);        cur_pc += 4;        for (i = 0; i < n; i++) {            cur_pc += 4;            off = INT32_AT(code, cur_pc) + pc;            ce = get_crt_entry(off, map, CRT_FLOW_TARGET);            if (ce == NULL)                ce = get_crt_entry(off, map, CRT_ANY);            ASSRT(ce != NULL || off == def_off, 21, *context);            if (off != def_off) {                cov_item_t *ci = cov_item_new(pc, CT_CASE, INSTR_ANY, ce->rng_start, ce->rng_end);                add_to_list_end(&(cov_list[pc]), ci);            }            cur_pc += 4;        }        add_to_list_end(&(cov_list[pc]), def_item);        break;    case opc_tableswitch:        cur_pc = (pc + 4) & (~3);        off = INT32_AT(code, cur_pc) + pc;        def_off = off;        ce = get_crt_entry(off, map, CRT_FLOW_TARGET);        if (ce == NULL)            ce = get_crt_entry(off, map, CRT_ANY);        if (ce == NULL)            ce = crt_entry;        ASSRT(ce != NULL, 22, *context);        type = (ce->flags & CRT_FLOW_TARGET) ? CT_CASE : CT_SWITCH_WO_DEF;        def_item = cov_item_new(pc, type, INSTR_TABLESW, ce->rng_start, ce->rng_end);        if (type == CT_SWITCH_WO_DEF && get_cov_item(off, cov_list, CT_BLOCK) == NULL) {            /* workaround a compiler bug */            cov_item_t *ci = cov_item_new((UINT16)off, CT_BLOCK, INSTR_ANY, ce->rng_start, ce->rng_end);            add_to_list(&(cov_list[off]), ci);        }        cur_pc += 4;        n = INT32_AT(code, cur_pc + 4) - INT32_AT(code, cur_pc) + 1;        cur_pc += 8;        for (i = 0; i < n; i++) {            cov_item_t *ci;            off = INT32_AT(code, cur_pc) + pc;            ce = get_crt_entry(off, map, CRT_FLOW_TARGET);            if (ce == NULL)                ce = get_crt_entry(off, map, CRT_ANY);            ASSRT(ce != NULL || off == def_off, 23, *context);            type = (off != def_off);            ci = cov_item_new(pc, CT_CASE, INSTR_ANY, type ? ce->rng_start : 0, type ? ce->rng_end : 0);            add_to_list_end(&(cov_list[pc]), ci);            cur_pc += 4;        }        add_to_list_end(&(cov_list[pc]), def_item);        break;    default:        ASSRT(0, 24, *context);    }}static void gen_cov_table(jcov_list_t **cov_list, jcov_method_t *meth) {    SSIZE_T n = 0;    SSIZE_T code_len = meth->pc_cache_size;    int i;    for (i = 0; i < code_len; n += list_size(cov_list[i]), i++);    meth->covtable_size = n;    if (n == 0)        return;    meth->pc_cache = (int*)jcov_calloc(code_len * sizeof(int));    meth->covtable = (cov_item_t*)jcov_calloc(n * sizeof(cov_item_t));    for (i = 0, n = 0; i < code_len; i++) {        jcov_list_t *l = cov_list[i];        for (; l != NULL; l = l->next, n++) {            cov_item_t *ci = (cov_item_t*)l->elem;            meth->covtable[n] = *ci;            if (l->next == NULL)                meth->pc_cache[i] = n + 1;        }    }}static void gen_cov_for_catch(UINT16      catch_pc,                       jcov_list_t **cov_map,                       jcov_list_t **crt_map,                       UINT8       *code,                       SSIZE_T     code_len) {    crt_entry_t *res = NULL;    int catch_instr_len = 0;    Bool work_around = 0;    cov_item_t *cov_item;        if (catch_pc >= code_len)        return; /* konst: error? */    res = get_crt_entry(catch_pc, crt_map, CRT_STATEMENT);    if (res == NULL)        res = get_crt_entry(catch_pc, crt_map, CRT_BLOCK);        if (res == NULL) {        /* konst: currently, CRT entry's start PC for a catch handler is 1 instruction greater */        /* than actual catch handler's offset in bytecode - a compiler bug                     */        catch_instr_len = opc_lengths[code[catch_pc] & 0xFF];        if (catch_instr_len <= 0 || catch_instr_len > 5)            return; /* konst: error? */        catch_pc += catch_instr_len;        if (catch_pc >= code_len)            return; /* konst: error? */        res = get_crt_entry(catch_pc, crt_map, CRT_STATEMENT);        if (res == NULL)            res = get_crt_entry(catch_pc, crt_map, CRT_BLOCK);        if (res == NULL)            return; /* konst: error? */        work_around = 1;    }    cov_item = get_cov_item(catch_pc, cov_map, CT_BLOCK);    if (cov_item != NULL && work_around) {        cov_item->pc = catch_pc - catch_instr_len;        return;    }    if (cov_item == NULL) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?