mtrace.c

来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 831 行 · 第 1/2 页

C
831
字号
		  cnum-- ) {		ClassInfo *cp;	        int        mnum;				cp = gdata->classes + cnum;		stdout_message("Class %s %d calls\n", cp->name, cp->calls);		if ( cp->calls==0 ) continue;				/* Sort method table (in place) by number of method calls. */		/*  Note: Do not use this table after this qsort! */		qsort(cp->methods, cp->mcount, sizeof(MethodInfo),			    &method_compar);		for ( mnum=cp->mcount-1 ; mnum >= 0 ; mnum-- ) {		    MethodInfo *mp;		    mp = cp->methods + mnum;		    if ( mp->calls==0 ) continue;		    stdout_message("\tMethod %s %s %d calls %d returns\n",			mp->name, mp->signature, mp->calls, mp->returns);		}	    }	}	stdout_message("End Class Stats\n");	(void)fflush(stdout);        } exit_critical_section(jvmti);	}  /* Callback for JVMTI_EVENT_THREAD_START */static void JNICALLcbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread){    enter_critical_section(jvmti); {	/* It's possible we get here right after VmDeath event, be careful */	if ( !gdata->vm_is_dead ) {	    char  tname[MAX_THREAD_NAME_LENGTH];	    	    get_thread_name(jvmti, thread, tname, sizeof(tname));	    stdout_message("ThreadStart %s\n", tname);	}    } exit_critical_section(jvmti);}/* Callback for JVMTI_EVENT_THREAD_END */static void JNICALLcbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread){    enter_critical_section(jvmti); {	/* It's possible we get here right after VmDeath event, be careful */	if ( !gdata->vm_is_dead ) {	    char  tname[MAX_THREAD_NAME_LENGTH];	    	    get_thread_name(jvmti, thread, tname, sizeof(tname));	    stdout_message("ThreadEnd %s\n", tname);	}    } exit_critical_section(jvmti);}/* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */static void JNICALLcbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env,                jclass class_being_redefined, jobject loader,                const char* name, jobject protection_domain,                jint class_data_len, const unsigned char* class_data,                jint* new_class_data_len, unsigned char** new_class_data){    enter_critical_section(jvmti); {	/* It's possible we get here right after VmDeath event, be careful */	if ( !gdata->vm_is_dead ) {	    const char *classname;            /* Name could be NULL */	    if ( name == NULL ) {		classname = java_crw_demo_classname(class_data, class_data_len,			NULL);		if ( classname == NULL ) {		    fatal_error("ERROR: No classname inside classfile\n");		}	    } else {		classname = strdup(name);		if ( classname == NULL ) {		    fatal_error("ERROR: Out of malloc memory\n");		}	    }	    	    *new_class_data_len = 0;            *new_class_data     = NULL;            /* The tracker class itself? */            if ( interested((char*)classname, "", gdata->include, gdata->exclude) 		  &&  strcmp(classname, STRING(MTRACE_class)) != 0 ) {                jint           cnum;                int            system_class;                unsigned char *new_image;                long           new_length;		ClassInfo     *cp;                /* Get unique number for every class file image loaded */                cnum = gdata->ccount++;		/* Save away class information */		if ( gdata->classes == NULL ) {		    gdata->classes = (ClassInfo*)malloc(				gdata->ccount*sizeof(ClassInfo));                } else {		    gdata->classes = (ClassInfo*)				realloc((void*)gdata->classes,				gdata->ccount*sizeof(ClassInfo));		}		if ( gdata->classes == NULL ) {		    fatal_error("ERROR: Out of malloc memory\n");		}		cp           = gdata->classes + cnum;		cp->name     = (const char *)strdup(classname);		if ( cp->name == NULL ) {		    fatal_error("ERROR: Out of malloc memory\n");		}		cp->calls    = 0;		cp->mcount   = 0;		cp->methods  = NULL;                /* Is it a system class? If the class load is before VmStart		 *   then we will consider it a system class that should		 *   be treated carefully. (See java_crw_demo)		 */                system_class = 0;                if ( !gdata->vm_is_started ) {                    system_class = 1;                }                new_image = NULL;                new_length = 0;                /* Call the class file reader/write demo code */                java_crw_demo(cnum,                    classname,                    class_data,                    class_data_len,                    system_class,                    STRING(MTRACE_class), "L" STRING(MTRACE_class) ";",                    STRING(MTRACE_entry), "(II)V",                    STRING(MTRACE_exit), "(II)V",                    NULL, NULL,                    NULL, NULL,                    &new_image,                    &new_length,                    NULL,                    &mnum_callbacks);		/* If we got back a new class image, return it back as "the"		 *   new class image. This must be JVMTI Allocate space.		 */                if ( new_length > 0 ) {                    unsigned char *jvmti_space;                    jvmti_space = (unsigned char *)allocate(jvmti, (jint)new_length);                    (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);                    *new_class_data_len = (jint)new_length;                    *new_class_data     = jvmti_space; /* VM will deallocate */                }		/* Always free up the space we get from java_crw_demo() */                if ( new_image != NULL ) {                    (void)free((void*)new_image); /* Free malloc() space with free() */                }            }	    (void)free((void*)classname);	}    } exit_critical_section(jvmti);}/* Parse the options for this mtrace agent */static voidparse_agent_options(char *options){    char token[MAX_TOKEN_LENGTH];    char *next;    gdata->max_count = 10; /* Default max=n */        /* Parse options and set flags in gdata */    if ( options==NULL ) {	return;    }       /* Get the first token from the options string. */    next = get_token(options, ",=", token, sizeof(token));    /* While not at the end of the options string, process this option. */    while ( next != NULL ) {	if ( strcmp(token,"help")==0 ) {	    stdout_message("The mtrace JVMTI demo agent\n");	    stdout_message("\n");	    stdout_message(" java -agent:mtrace[=options] ...\n");	    stdout_message("\n");	    stdout_message("The options are comma separated:\n");	    stdout_message("\t help\t\t\t Print help information\n");	    stdout_message("\t max=n\t\t Only list top n classes\n");	    stdout_message("\t include=item\t\t Only these classes/methods\n");	    stdout_message("\t exclude=item\t\t Exclude these classes/methods\n");	    stdout_message("\n");	    stdout_message("item\t Qualified class and/or method names\n");	    stdout_message("\t\t e.g. (*.<init>;Foobar.method;sun.*)\n");	    stdout_message("\n");	    exit(0);	} else if ( strcmp(token,"max")==0 ) {            char number[MAX_TOKEN_LENGTH];	    	    /* Get the numeric option */	    next = get_token(next, ",=", number, (int)sizeof(number));	    /* Check for token scan error */	    if ( next==NULL ) {		fatal_error("ERROR: max=n option error\n");	    }	    /* Save numeric value */	    gdata->max_count = atoi(number);	} else if ( strcmp(token,"include")==0 ) {	    int   used;	    int   maxlen;	    maxlen = MAX_METHOD_NAME_LENGTH;	    if ( gdata->include == NULL ) {		gdata->include = (char*)calloc(maxlen+1, 1);		used = 0;	    } else {		used  = (int)strlen(gdata->include);		gdata->include[used++] = ',';		gdata->include[used] = 0;		gdata->include = (char*)			     realloc((void*)gdata->include, used+maxlen+1);	    }	    if ( gdata->include == NULL ) {		fatal_error("ERROR: Out of malloc memory\n");	    }	    /* Add this item to the list */	    next = get_token(next, ",=", gdata->include+used, maxlen);	    /* Check for token scan error */	    if ( next==NULL ) {		fatal_error("ERROR: include option error\n");	    }	} else if ( strcmp(token,"exclude")==0 ) {	    int   used;	    int   maxlen;	    maxlen = MAX_METHOD_NAME_LENGTH;	    if ( gdata->exclude == NULL ) {		gdata->exclude = (char*)calloc(maxlen+1, 1);		used = 0;	    } else {		used  = (int)strlen(gdata->exclude);		gdata->exclude[used++] = ',';		gdata->exclude[used] = 0;		gdata->exclude = (char*)			     realloc((void*)gdata->exclude, used+maxlen+1);	    }	    if ( gdata->exclude == NULL ) {		fatal_error("ERROR: Out of malloc memory\n");	    }	    /* Add this item to the list */	    next = get_token(next, ",=", gdata->exclude+used, maxlen);	    /* Check for token scan error */	    if ( next==NULL ) {		fatal_error("ERROR: exclude option error\n");	    }	} else if ( token[0]!=0 ) {	    /* We got a non-empty token and we don't know what it is. */	    fatal_error("ERROR: Unknown option: %s\n", token);	}	/* Get the next token (returns NULL if there are no more) */        next = get_token(next, ",=", token, sizeof(token));    }}/* Agent_OnLoad: This is called immediately after the shared library is  *   loaded. This is the first code executed. */JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved){    static GlobalAgentData data;    jvmtiEnv              *jvmti;    jvmtiError             error;    jint                   res;    jvmtiCapabilities      capabilities;    jvmtiEventCallbacks    callbacks;        /* Setup initial global agent data area      *   Use of static/extern data should be handled carefully here.     *   We need to make sure that we are able to cleanup after ourselves     *     so anything allocated in this library needs to be freed in     *     the Agent_OnUnload() function.     */    (void)memset((void*)&data, 0, sizeof(data));    gdata = &data;       /* First thing we need to do is get the jvmtiEnv* or JVMTI environment */    res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);    if (res != JNI_OK) {	/* This means that the VM was unable to obtain this version of the	 *   JVMTI interface, this is a fatal error.	 */	fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x),"                " is your JDK a 5.0 or newer version?"                " JNIEnv's GetEnv() returned %d\n",               JVMTI_VERSION_1, res);    }    /* Here we save the jvmtiEnv* for Agent_OnUnload(). */    gdata->jvmti = jvmti;       /* Parse any options supplied on java command line */    parse_agent_options(options);       /* Immediately after getting the jvmtiEnv* we need to ask for the     *   capabilities this agent will need. In this case we need to make     *   sure that we can get all class load hooks.     */    (void)memset(&capabilities,0, sizeof(capabilities));    capabilities.can_generate_all_class_hook_events  = 1;    error = (*jvmti)->AddCapabilities(jvmti, &capabilities);    check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities.");        /* Next we need to provide the pointers to the callback functions to     *   to this jvmtiEnv*     */    (void)memset(&callbacks,0, sizeof(callbacks));    /* JVMTI_EVENT_VM_START */    callbacks.VMStart           = &cbVMStart;          /* JVMTI_EVENT_VM_INIT */    callbacks.VMInit            = &cbVMInit;          /* JVMTI_EVENT_VM_DEATH */    callbacks.VMDeath           = &cbVMDeath;         /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */    callbacks.ClassFileLoadHook = &cbClassFileLoadHook;     /* JVMTI_EVENT_THREAD_START */    callbacks.ThreadStart       = &cbThreadStart;     /* JVMTI_EVENT_THREAD_END */    callbacks.ThreadEnd         = &cbThreadEnd;       error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks));    check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks");       /* At first the only initial events we are interested in are VM     *   initialization, VM death, and Class File Loads.      *   Once the VM is initialized we will request more events.     */    error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 			  JVMTI_EVENT_VM_START, (jthread)NULL);    check_jvmti_error(jvmti, error, "Cannot set event notification");    error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 			  JVMTI_EVENT_VM_INIT, (jthread)NULL);    check_jvmti_error(jvmti, error, "Cannot set event notification");    error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 			  JVMTI_EVENT_VM_DEATH, (jthread)NULL);    check_jvmti_error(jvmti, error, "Cannot set event notification");    error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 			  JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL);    check_jvmti_error(jvmti, error, "Cannot set event notification");       /* Here we create a raw monitor for our use in this agent to     *   protect critical sections of code.     */    error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock));    check_jvmti_error(jvmti, error, "Cannot create raw monitor");    /* Add demo jar file to boot classpath */    add_demo_jar_to_bootclasspath(jvmti, "mtrace");    /* We return JNI_OK to signify success */    return JNI_OK;}/* Agent_OnUnload: This is called immediately before the shared library is  *   unloaded. This is the last code executed. */JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm){    /* Make sure all malloc/calloc/strdup space is freed */    if ( gdata->include != NULL ) {	(void)free((void*)gdata->include);	gdata->include = NULL;    }    if ( gdata->exclude != NULL ) {	(void)free((void*)gdata->exclude);	gdata->exclude = NULL;    }    if ( gdata->classes != NULL ) {	int cnum;		for ( cnum = 0 ; cnum < gdata->ccount ; cnum++ ) {	    ClassInfo *cp;	    cp = gdata->classes + cnum;	    (void)free((void*)cp->name);	    if ( cp->mcount > 0 ) {	        int mnum;				for ( mnum = 0 ; mnum < cp->mcount ; mnum++ ) {		    MethodInfo *mp;		    mp = cp->methods + mnum;		    (void)free((void*)mp->name);		    (void)free((void*)mp->signature);		}		(void)free((void*)cp->methods);	    }	}	(void)free((void*)gdata->classes);	gdata->classes = NULL;    }}

⌨️ 快捷键说明

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