1 /* 2 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. 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 Oracle 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 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 #include "jni.h" 46 #include "jvmti.h" 47 #include "jvmticmlr.h" 48 49 #include "agent_util.h" 50 51 /* Global static data */ 52 static char OUTPUT_FILE[] = "compiledMethodLoad.txt"; 53 static FILE *fp; 54 static jvmtiEnv *jvmti; 55 static jrawMonitorID lock; 56 57 /* print a jvmtiCompiledMethodLoadDummyRecord */ 58 void 59 print_dummy_record(jvmtiCompiledMethodLoadDummyRecord* record, 60 jvmtiEnv* jvmti, FILE* fp) { 61 62 if (record != NULL) { 63 fprintf(fp, "Dummy record detected containing message: %s\n", 64 (char *)record->message); 65 } 66 } 67 68 /* print the specified stack frames */ 69 void 70 print_stack_frames(PCStackInfo* record, jvmtiEnv *jvmti, FILE* fp) { 71 if (record != NULL && record->methods != NULL) { 72 int i; 73 74 for (i = 0; i < record->numstackframes; i++) { 75 jvmtiError err; 76 char* method_name = NULL; 77 char* class_name = NULL; 78 char* method_signature = NULL; 79 char* class_signature = NULL; 80 char* generic_ptr_method = NULL; 81 char* generic_ptr_class = NULL; 82 jmethodID id; 83 jclass declaringclassptr; 84 id = record->methods[i]; 85 86 err = (*jvmti)->GetMethodDeclaringClass(jvmti, id, 87 &declaringclassptr); 88 check_jvmti_error(jvmti, err, "get method declaring class"); 89 90 err = (*jvmti)->GetClassSignature(jvmti, declaringclassptr, 91 &class_signature, &generic_ptr_class); 92 check_jvmti_error(jvmti, err, "get class signature"); 93 94 err = (*jvmti)->GetMethodName(jvmti, id, &method_name, 95 &method_signature, &generic_ptr_method); 96 check_jvmti_error(jvmti, err, "get method name"); 97 98 fprintf(fp, "%s::%s %s %s @%d\n", class_signature, method_name, 99 method_signature, 100 generic_ptr_method == NULL ? "" : generic_ptr_method, 101 record->bcis[i]); 102 103 if (method_name != NULL) { 104 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)method_name); 105 check_jvmti_error(jvmti, err, "deallocate method_name"); 106 } 107 if (method_signature != NULL) { 108 err = (*jvmti)->Deallocate(jvmti, 109 (unsigned char*)method_signature); 110 check_jvmti_error(jvmti, err, "deallocate method_signature"); 111 } 112 if (generic_ptr_method != NULL) { 113 err = (*jvmti)->Deallocate(jvmti, 114 (unsigned char*)generic_ptr_method); 115 check_jvmti_error(jvmti, err, "deallocate generic_ptr_method"); 116 } 117 if (class_name != NULL) { 118 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)class_name); 119 check_jvmti_error(jvmti, err, "deallocate class_name"); 120 } 121 if (class_signature != NULL) { 122 err = (*jvmti)->Deallocate(jvmti, 123 (unsigned char*)class_signature); 124 check_jvmti_error(jvmti, err, "deallocate class_signature"); 125 } 126 if (generic_ptr_class != NULL) { 127 err = (*jvmti)->Deallocate(jvmti, 128 (unsigned char*)generic_ptr_class); 129 check_jvmti_error(jvmti, err, "deallocate generic_ptr_class"); 130 } 131 } 132 } 133 } 134 135 /* print a jvmtiCompiledMethodLoadInlineRecord */ 136 void 137 print_inline_info_record(jvmtiCompiledMethodLoadInlineRecord* record, 138 jvmtiEnv *jvmti, FILE* fp) { 139 140 if (record != NULL && record->pcinfo != NULL) { 141 int numpcs = record->numpcs; 142 int i; 143 144 for (i = 0; i < numpcs; i++) { 145 PCStackInfo pcrecord = (record->pcinfo[i]); 146 fprintf(fp, "PcDescriptor(pc=%p):\n", pcrecord.pc); 147 print_stack_frames(&pcrecord, jvmti, fp); 148 } 149 } 150 } 151 152 /* decode kind of CompiledMethodLoadRecord and print */ 153 void 154 print_records(jvmtiCompiledMethodLoadRecordHeader* list, jvmtiEnv *jvmti, 155 FILE* fp) 156 { 157 jvmtiCompiledMethodLoadRecordHeader* curr = list; 158 fprintf(fp, "\nPrinting PC Descriptors\n\n"); 159 while (curr != NULL) { 160 switch (curr->kind) { 161 case JVMTI_CMLR_DUMMY: 162 print_dummy_record((jvmtiCompiledMethodLoadDummyRecord *)curr, 163 jvmti, fp); 164 break; 165 166 case JVMTI_CMLR_INLINE_INFO: 167 print_inline_info_record( 168 (jvmtiCompiledMethodLoadInlineRecord *)curr, jvmti, fp); 169 break; 170 171 default: 172 fprintf(fp, "Warning: unrecognized record: kind=%d\n", curr->kind); 173 break; 174 } 175 176 curr = (jvmtiCompiledMethodLoadRecordHeader *)curr->next; 177 } 178 } 179 180 /* Callback for JVMTI_EVENT_COMPILED_METHOD_LOAD */ 181 void JNICALL 182 compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size, 183 const void* code_addr, jint map_length, const jvmtiAddrLocationMap* map, 184 const void* compile_info) 185 { 186 jvmtiError err; 187 char* name = NULL; 188 char* signature = NULL; 189 char* generic_ptr = NULL; 190 jvmtiCompiledMethodLoadRecordHeader* pcs; 191 192 err = (*jvmti)->RawMonitorEnter(jvmti, lock); 193 check_jvmti_error(jvmti, err, "raw monitor enter"); 194 195 err = (*jvmti)->GetMethodName(jvmti, method, &name, &signature, 196 &generic_ptr); 197 check_jvmti_error(jvmti, err, "get method name"); 198 199 fprintf(fp, "\nCompiled method load event\n"); 200 fprintf(fp, "Method name %s %s %s\n\n", name, signature, 201 generic_ptr == NULL ? "" : generic_ptr); 202 pcs = (jvmtiCompiledMethodLoadRecordHeader *)compile_info; 203 if (pcs != NULL) { 204 print_records(pcs, jvmti, fp); 205 } 206 207 if (name != NULL) { 208 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)name); 209 check_jvmti_error(jvmti, err, "deallocate name"); 210 } 211 if (signature != NULL) { 212 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)signature); 213 check_jvmti_error(jvmti, err, "deallocate signature"); 214 } 215 if (generic_ptr != NULL) { 216 err = (*jvmti)->Deallocate(jvmti, (unsigned char*)generic_ptr); 217 check_jvmti_error(jvmti, err, "deallocate generic_ptr"); 218 } 219 220 err = (*jvmti)->RawMonitorExit(jvmti, lock); 221 check_jvmti_error(jvmti, err, "raw monitor exit"); 222 } 223 224 /* Agent_OnLoad() is called first, we prepare for a COMPILED_METHOD_LOAD 225 * event here. 226 */ 227 JNIEXPORT jint JNICALL 228 DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 229 { 230 jint rc; 231 jvmtiError err; 232 jvmtiCapabilities capabilities; 233 jvmtiEventCallbacks callbacks; 234 235 fp = fopen(OUTPUT_FILE, "w"); 236 if (fp == NULL) { 237 fatal_error("ERROR: %s: Unable to create output file\n", OUTPUT_FILE); 238 return -1; 239 } 240 241 /* Get JVMTI environment */ 242 rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION); 243 if (rc != JNI_OK) { 244 fatal_error( 245 "ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc); 246 return -1; 247 } 248 249 /* add JVMTI capabilities */ 250 memset(&capabilities,0, sizeof(capabilities)); 251 capabilities.can_generate_compiled_method_load_events = 1; 252 err = (*jvmti)->AddCapabilities(jvmti, &capabilities); 253 check_jvmti_error(jvmti, err, "add capabilities"); 254 255 /* set JVMTI callbacks for events */ 256 memset(&callbacks, 0, sizeof(callbacks)); 257 callbacks.CompiledMethodLoad = &compiled_method_load; 258 err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks)); 259 check_jvmti_error(jvmti, err, "set event callbacks"); 260 261 /* enable JVMTI events */ 262 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 263 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL); 264 check_jvmti_error(jvmti, err, "set event notify"); 265 266 /* create coordination monitor */ 267 err = (*jvmti)->CreateRawMonitor(jvmti, "agent lock", &lock); 268 check_jvmti_error(jvmti, err, "create raw monitor"); 269 270 return 0; 271 } 272 273 /* Agent_OnUnload() is called last */ 274 JNIEXPORT void JNICALL 275 DEF_Agent_OnUnload(JavaVM *vm) 276 { 277 }