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 + -
显示快捷键?