1 /* 2 * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Sun Microsystems nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "jni.h" 37 #include "jvmti.h" 38 #include "jvmticmlr.h" 39 40 #include "agent_util.h" 41 42 /* Global static data */ 43 static char OUTPUT_FILE[] = "compiledMethodLoad.txt"; 44 static FILE *fp; 45 static jvmtiEnv *jvmti; 46 static jrawMonitorID lock; 47 48 /* print a jvmtiCompiledMethodLoadDummyRecord */ 49 void 50 print_dummy_record(jvmtiCompiledMethodLoadDummyRecord* record, 51 jvmtiEnv* jvmti, FILE* fp) { 52 53 if (record != NULL) { 54 fprintf(fp, "Dummy record detected containing message: %s\n", 55 (char *)record->message); 56 } 57 } 58 59 /* print the specified stack frames */ 60 void 61 print_stack_frames(PCStackInfo* record, jvmtiEnv *jvmti, FILE* fp) { 62 if (record != NULL && record->methods != NULL) { 63 int i; 64 65 for (i = 0; i < record->numstackframes; i++) { 66 jvmtiError err; 67 char* method_name = NULL; 68 char* class_name = NULL; 69 char* method_signature = NULL; 70 char* class_signature = NULL; 71 char* generic_ptr_method = NULL; 72 char* generic_ptr_class = NULL; 73 jmethodID id; 74 jclass declaringclassptr; 75 id = record->methods[i]; 76 77 err = (*jvmti)->GetMethodDeclaringClass(jvmti, id, 78 &declaringclassptr); 79 check_jvmti_error(jvmti, err, "get method declaring class"); 80 81 err = (*jvmti)->GetClassSignature(jvmti, declaringclassptr, 82 &class_signature, &generic_ptr_class); 83 check_jvmti_error(jvmti, err, "get class signature"); 84 85 err = (*jvmti)->GetMethodName(jvmti, id, &method_name, 86 &method_signature, &generic_ptr_method); 87 check_jvmti_error(jvmti, err, "get method name"); 88 89 fprintf(fp, "%s::%s %s %s @%d\n", class_signature, method_name, 90 method_signature, 91 generic_ptr_method == NULL ? "" : generic_ptr_method, 92 record->bcis[i]); 93 94 if (method_name != NULL) { 95 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)method_name); 96 check_jvmti_error(jvmti, err, "deallocate method_name"); 97 } 98 if (method_signature != NULL) { 99 err = (*jvmti)->Deallocate(jvmti, 100 (unsigned char*)method_signature); 101 check_jvmti_error(jvmti, err, "deallocate method_signature"); 102 } 103 if (generic_ptr_method != NULL) { 104 err = (*jvmti)->Deallocate(jvmti, 105 (unsigned char*)generic_ptr_method); 106 check_jvmti_error(jvmti, err, "deallocate generic_ptr_method"); 107 } 108 if (class_name != NULL) { 109 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)class_name); 110 check_jvmti_error(jvmti, err, "deallocate class_name"); 111 } 112 if (class_signature != NULL) { 113 err = (*jvmti)->Deallocate(jvmti, 114 (unsigned char*)class_signature); 115 check_jvmti_error(jvmti, err, "deallocate class_signature"); 116 } 117 if (generic_ptr_class != NULL) { 118 err = (*jvmti)->Deallocate(jvmti, 119 (unsigned char*)generic_ptr_class); 120 check_jvmti_error(jvmti, err, "deallocate generic_ptr_class"); 121 } 122 } 123 } 124 } 125 126 /* print a jvmtiCompiledMethodLoadInlineRecord */ 127 void 128 print_inline_info_record(jvmtiCompiledMethodLoadInlineRecord* record, 129 jvmtiEnv *jvmti, FILE* fp) { 130 131 if (record != NULL && record->pcinfo != NULL) { 132 int numpcs = record->numpcs; 133 int i; 134 135 for (i = 0; i < numpcs; i++) { 136 PCStackInfo pcrecord = (record->pcinfo[i]); 137 fprintf(fp, "PcDescriptor(pc=0x%lx):\n", (jint)(pcrecord.pc)); 138 print_stack_frames(&pcrecord, jvmti, fp); 139 } 140 } 141 } 142 143 /* decode kind of CompiledMethodLoadRecord and print */ 144 void 145 print_records(jvmtiCompiledMethodLoadRecordHeader* list, jvmtiEnv *jvmti, 146 FILE* fp) 147 { 148 jvmtiCompiledMethodLoadRecordHeader* curr = list; 149 fprintf(fp, "\nPrinting PC Descriptors\n\n"); 150 while (curr != NULL) { 151 switch (curr->kind) { 152 case JVMTI_CMLR_DUMMY: 153 print_dummy_record((jvmtiCompiledMethodLoadDummyRecord *)curr, 154 jvmti, fp); 155 break; 156 157 case JVMTI_CMLR_INLINE_INFO: 158 print_inline_info_record( 159 (jvmtiCompiledMethodLoadInlineRecord *)curr, jvmti, fp); 160 break; 161 162 default: 163 fprintf(fp, "Warning: unrecognized record: kind=%d\n", curr->kind); 164 break; 165 } 166 167 curr = (jvmtiCompiledMethodLoadRecordHeader *)curr->next; 168 } 169 } 170 171 /* Callback for JVMTI_EVENT_COMPILED_METHOD_LOAD */ 172 void JNICALL 173 compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size, 174 const void* code_addr, jint map_length, const jvmtiAddrLocationMap* map, 175 const void* compile_info) 176 { 177 jvmtiError err; 178 char* name = NULL; 179 char* signature = NULL; 180 char* generic_ptr = NULL; 181 jvmtiCompiledMethodLoadRecordHeader* pcs; 182 183 err = (*jvmti)->RawMonitorEnter(jvmti, lock); 184 check_jvmti_error(jvmti, err, "raw monitor enter"); 185 186 err = (*jvmti)->GetMethodName(jvmti, method, &name, &signature, 187 &generic_ptr); 188 check_jvmti_error(jvmti, err, "get method name"); 189 190 fprintf(fp, "\nCompiled method load event\n"); 191 fprintf(fp, "Method name %s %s %s\n\n", name, signature, 192 generic_ptr == NULL ? "" : generic_ptr); 193 pcs = (jvmtiCompiledMethodLoadRecordHeader *)compile_info; 194 if (pcs != NULL) { 195 print_records(pcs, jvmti, fp); 196 } 197 198 if (name != NULL) { 199 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)name); 200 check_jvmti_error(jvmti, err, "deallocate name"); 201 } 202 if (signature != NULL) { 203 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)signature); 204 check_jvmti_error(jvmti, err, "deallocate signature"); 205 } 206 if (generic_ptr != NULL) { 207 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)generic_ptr); 208 check_jvmti_error(jvmti, err, "deallocate generic_ptr"); 209 } 210 211 err = (*jvmti)->RawMonitorExit(jvmti, lock); 212 check_jvmti_error(jvmti, err, "raw monitor exit"); 213 } 214 215 /* Agent_OnLoad() is called first, we prepare for a COMPILED_METHOD_LOAD 216 * event here. 217 */ 218 JNIEXPORT jint JNICALL 219 Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 220 { 221 jint rc; 222 jvmtiError err; 223 jvmtiCapabilities capabilities; 224 jvmtiEventCallbacks callbacks; 225 226 fp = fopen(OUTPUT_FILE, "w"); 227 if (fp == NULL) { 228 fatal_error("ERROR: %s: Unable to create output file\n", OUTPUT_FILE); 229 return -1; 230 } 231 232 /* Get JVMTI environment */ 233 rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION); 234 if (rc != JNI_OK) { 235 fatal_error( 236 "ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc); 237 return -1; 238 } 239 240 /* add JVMTI capabilities */ 241 memset(&capabilities,0, sizeof(capabilities)); 242 capabilities.can_generate_compiled_method_load_events = 1; 243 err = (*jvmti)->AddCapabilities(jvmti, &capabilities); 244 check_jvmti_error(jvmti, err, "add capabilities"); 245 246 /* set JVMTI callbacks for events */ 247 memset(&callbacks, 0, sizeof(callbacks)); 248 callbacks.CompiledMethodLoad = &compiled_method_load; 249 err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks)); 250 check_jvmti_error(jvmti, err, "set event callbacks"); 251 252 /* enable JVMTI events */ 253 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 254 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL); 255 check_jvmti_error(jvmti, err, "set event notify"); 256 257 /* create coordination monitor */ 258 err = (*jvmti)->CreateRawMonitor(jvmti, "agent lock", &lock); 259 check_jvmti_error(jvmti, err, "create raw monitor"); 260 261 return 0; 262 } 263 264 /* Agent_OnUnload() is called last */ 265 JNIEXPORT void JNICALL 266 Agent_OnUnload(JavaVM *vm) 267 { 268 }