jcov_events.c

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

C
932
字号
/* * @(#)jcov_events.c	1.29 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 "javavm/include/porting/ansi/stdlib.h"#include "javavm/include/porting/ansi/string.h"#include "jvmpi.h"#include "jcov.h"#include "jcov_jvm.h"#include "jcov_error.h"#include "jcov_crt.h"#include "jcov_util.h"#include "jcov_htables.h"#include "jcov_setup.h"#include "jcov_file.h"#include "jcov_java.h"jcov_list_t *thread_list = NULL;static long cnt_load_hooks = 0;static long cnt_loads = 0;static long cnt_req_loads = 0;static long cnt_prof = 0;static long cnt_skip = 0;JVMPI_RawMonitor jcov_threads_lock;JVMPI_RawMonitor jcov_cls_key_lock;JVMPI_RawMonitor jcov_cls_id_lock;JVMPI_RawMonitor jcov_cls_flt_lock;JVMPI_RawMonitor jcov_methods_lock;JVMPI_RawMonitor jcov_instr_count_lock;static jcov_thread_t *jcov_thread_new(JNIEnv *env_id);static jcov_hooked_class_t *jcov_hooked_class_new(void);static jcov_class_id_t *jcov_class_id_new(jobjectID id);#define METH_CACHE_SIZE 256 /* default size of cache for methods in a hooked class */#define LOCK(monitor)   (jvmpi_interface->RawMonitorEnter)(jcov_##monitor##_lock)#define UNLOCK(monitor) (jvmpi_interface->RawMonitorExit)(jcov_##monitor##_lock)#define CALL_DEPTH 2#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); \        goto cleanupAndFail; \    }#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); \        goto cleanupAndFail; \    }#define ERROR_VERBOSE(err_str) if (verbose_mode > 0) jcov_error(err_str)#define SKIP(n, ctx) (ctx).class_data += n ; (ctx).class_len -= n ;#define ASSRT_CP_ENTRY(cp_entry, x, n, ctx) if (!(cp_entry) || (cp_entry)->tag != x) { \        if ((ctx).hooked_class != NULL && ((ctx).hooked_class)->name != NULL) \            sprintf(info, "bad constant pool entry in : %s (assrt: %d)", ((ctx).hooked_class)->name, n); \        else \            sprintf(info, "bad constant pool entry (assrt: %d)", n); \        jcov_error(info); \        goto cleanupAndFail; \    }#define GET_CP_ENTRY(cp_entry, index, ctx) \    if (index >= (ctx).cp_size) { \        if ((ctx).hooked_class != NULL && ((ctx).hooked_class)->name != NULL) \            sprintf(info, "invalid constant pool index in %s : %d", ((ctx).hooked_class)->name, index); \        else \            sprintf(info, "invalid constant pool index"); \        jcov_error(info); \        goto cleanupAndFail; \    } \    cp_entry = (ctx).cp[index]static jcov_thread_t *find_thread(JNIEnv *env_id) {    jcov_list_t *l;    for (l = thread_list; l != NULL; l = l->next) {        jcov_thread_t *thread = (jcov_thread_t*)l->elem;        if (thread->id == env_id) {            return thread;        }    }    return NULL;}static void add_thread(jcov_thread_t *t) {    add_to_list(&thread_list, t);}static jcov_thread_t *find_or_add_thread(JNIEnv *env_id) {    jcov_thread_t *res;    LOCK(threads);    res = find_thread(env_id);    if (res == NULL) {        res = jcov_thread_new(env_id);        add_thread(res);    }    UNLOCK(threads);    return res;}static Bool jcov_parse_class_data(JNIEnv *env_id, bin_class_context_t *context) {    int err_code = 0;    INT32 x4;    UINT16 x2;    INT32 attr_len, skip;    char info[MAX_PATH_LEN];    int count, attr_count, where_line, non_abstract_met, i, j, k;    Bool crt_met = 0, cov_met = 0, caller_filt_ok = 0, filt_ok = 0;    cp_entry_t *cp_entry;    jcov_method_t *meth;    jcov_thread_t *this_thread;    jcov_hooked_class_t *hooked_class;    bin_class_context_t ctx = *context;    this_thread = find_or_add_thread(env_id);    ctx.cp = NULL;    hooked_class = jcov_hooked_class_new();    ctx.hooked_class = hooked_class;    context->hooked_class = hooked_class;    READ_AND_CHECK(x4, 4, ctx);    if (x4 != 0xCAFEBABE) {        ERROR_VERBOSE("wrong magic number");        goto cleanupAndFail;    }    SKIP(4, ctx); /* class file version number */    READ_AND_CHECK(ctx.cp_size, 2, ctx); /* number of items in constant pool */    ctx.cp = (cp_entry_t**)jcov_calloc(sizeof(cp_entry_t*) * ctx.cp_size);    for (i = 1; i < ctx.cp_size; i++) { /* read the whole cp */        ctx.cp[i] = read_next_cp_entry(&(ctx.class_data), &(ctx.class_len), &err_code);        if (err_code) {            jcov_error("bad constant pool format");            goto cleanupAndFail;        }        if (ctx.cp[i]->tag == JVM_CONSTANT_Long || ctx.cp[i]->tag == JVM_CONSTANT_Double) {            i++;        }    }    READ_AND_CHECK(x2, 2, ctx);    hooked_class->access_flags = x2 & JVM_RECOGNIZED_CLASS_MODIFIERS & ~JVM_ACC_SUPER;    if (hooked_class->access_flags & JVM_ACC_INTERFACE) {        hooked_class->access_flags &= ~JVM_ACC_ABSTRACT;    }    READ_AND_CHECK(x2, 2, ctx);    GET_CP_ENTRY(cp_entry, x2, ctx); /*this_class*/    ASSRT_CP_ENTRY(cp_entry, JVM_CONSTANT_Class, 0, ctx);    GET_CP_ENTRY(cp_entry, cp_entry->u.Class.name_index, ctx);    ASSRT_CP_ENTRY(cp_entry, JVM_CONSTANT_Utf8, 1, ctx);    caller_filt_ok = string_suits_filter(caller_filter, cp_entry->u.Utf8.bytes);    filt_ok        = string_suits_filter(class_filter, cp_entry->u.Utf8.bytes);    if ((caller_filter == NULL || !caller_filt_ok) && !filt_ok) {        goto cleanupAndFail;    }    hooked_class->name = jcov_strdup(cp_entry->u.Utf8.bytes);    if (!filt_ok) {        hooked_class->data_type = JCOV_SKIP_CLASS;    }    SKIP(2, ctx); /* super_class */    READ_AND_CHECK(x2, 2, ctx);    skip = x2 * 2;    SKIP(skip, ctx); /* skip interfaces */    READ_AND_CHECK(count, 2, ctx); /* fields_count */    for (i = 0; i < count; i++) {        SKIP(6, ctx);        /* attributes_count */        READ_AND_CHECK(attr_count, 2, ctx);        for (j = 0; j < attr_count; j++) {            SKIP(2, ctx); /* attribute_name_index */            READ_AND_CHECK(attr_len, 4, ctx);            SKIP(attr_len, ctx);        }    }    /*-- we're at methods section at last --*/    READ_AND_CHECK(hooked_class->methods_total, 2, ctx); /* methods_count */    hooked_class->method_cache = (jcov_method_t**)jcov_calloc(sizeof(jcov_method_t*) *                                                              hooked_class->methods_total);    non_abstract_met = 0;    for (i = 0; i < hooked_class->methods_total; i++) {        meth = (jcov_method_t*)jcov_calloc(sizeof(jcov_method_t));        meth->covtable_size = 0;        meth->covtable = NULL;        meth->pc_cache = NULL;        meth->pc_cache_size = 0;        READ_AND_CHECK(meth->access_flags, 2, ctx);        meth->access_flags &= JVM_RECOGNIZED_METHOD_MODIFIERS;        non_abstract_met |= !(meth->access_flags & JVM_ACC_ABSTRACT);        where_line = 0;        READ_AND_CHECK(x2, 2, ctx);        GET_CP_ENTRY(cp_entry, x2, ctx); /* method name */        ASSRT_CP_ENTRY(cp_entry, JVM_CONSTANT_Utf8, 2, ctx);        meth->name = jcov_strdup(cp_entry->u.Utf8.bytes);        READ_AND_CHECK(x2, 2, ctx);        GET_CP_ENTRY(cp_entry, x2, ctx); /* method signature */        ASSRT_CP_ENTRY(cp_entry, JVM_CONSTANT_Utf8, 3, ctx);        meth->signature = jcov_strdup(cp_entry->u.Utf8.bytes);        /* read the method's attributes */        READ_AND_CHECK(count, 2, ctx); /* attribute count */        for (j = 0; j < count; j++) {            READ_AND_CHECK(x2, 2, ctx);            GET_CP_ENTRY(cp_entry, x2, ctx);            ASSRT_CP_ENTRY(cp_entry, JVM_CONSTANT_Utf8, 4, ctx);            READ_AND_CHECK(attr_len, 4, ctx);            if (!filt_ok || strcmp(cp_entry->u.Utf8.bytes, CODE_ATTR_NAME)) {                SKIP(attr_len, ctx);                continue;            }            /* parse code attribute */            SKIP(4, ctx); /* max_stack and max_locals */            READ_AND_CHECK(skip, 4, ctx); /* code_count */            meth->pc_cache_size = skip;            ctx.code = ctx.class_data;            SKIP(skip, ctx);            READ_AND_CHECK(skip, 2, ctx);            skip *= 8; /* handlers_count * handler_size */            SKIP(skip, ctx);            READ_AND_CHECK(attr_count, 2, ctx); /* attributes_count */            for (k = 0; k < attr_count; k++) {                READ_AND_CHECK(x2, 2, ctx);                GET_CP_ENTRY(cp_entry, x2, ctx);                ASSRT_CP_ENTRY(cp_entry, JVM_CONSTANT_Utf8, 5, ctx);                READ_AND_CHECK(attr_len, 4, ctx);                if (!strcmp(cp_entry->u.Utf8.bytes, LINE_NUMBER_TABLE_ATTR_NAME)) {                    READ_AND_CHECK(x2, 2, ctx);                    if (x2 < 1) { /* lines_count */                        skip = attr_len - 2;                        SKIP(skip, ctx);                    } else {                        SKIP(2, ctx); /* 1st start_pc */                        READ_AND_CHECK(where_line, 2, ctx);                        skip = attr_len - 6;                        SKIP(skip, ctx);                    }                    continue;                }                if (jcov_data_type == JCOV_DATA_B &&                    !strcmp(cp_entry->u.Utf8.bytes, COV_TABLE_ATTR_NAME)) {                    read_cov_table(attr_len, meth, &ctx);                    cov_met = 1;                    ASSRT(!crt_met, 3, ctx);                    continue;                }                if (jcov_data_type == JCOV_DATA_B &&                    !strcmp(cp_entry->u.Utf8.bytes, CRT_TABLE_ATTR_NAME)) {                    read_crt_table(attr_len, meth, &ctx);                    crt_met = 1;                    ASSRT(!cov_met, 4, ctx);                    hooked_class->data_type = JCOV_DATA_C;                    continue;                }                SKIP(attr_len, ctx);            }        }        if (filt_ok && meth->covtable == NULL && jcov_data_type == JCOV_DATA_M) {            cov_item_t *cov_item = cov_item_new(0, CT_METHOD, INSTR_ANY, where_line, 0);            meth->covtable_size = 1;            meth->covtable = (cov_item_t*)jcov_calloc(sizeof(cov_item_t) * meth->covtable_size);            meth->covtable[0] = *cov_item;        } else if (filt_ok && meth->covtable == NULL && jcov_data_type == JCOV_DATA_B) {            /* covtable_size field used here to store the line num */            meth->covtable_size = where_line;        }        hooked_class->method_cache[i] = meth;    }    if (!non_abstract_met) {  /* interface encountered - skip it */        goto cleanupAndFail;    }

⌨️ 快捷键说明

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