00001
00028 #include <stdio.h>
00029 #include <jvmti.h>
00030 #include <string.h>
00031 #include <stdint.h>
00032 #include <stdlib.h>
00033 #include <errno.h>
00034
00035 #include "opagent.h"
00036
00037 static int debug = 0;
00038 static int can_get_line_numbers = 1;
00039 static op_agent_t agent_hdl;
00040
00045 static int handle_error(jvmtiError err, char const * msg, int severe)
00046 {
00047 if (err != JVMTI_ERROR_NONE) {
00048 fprintf(stderr, "%s: %s, err code %i\n",
00049 severe ? "Error" : "Warning", msg, err);
00050 }
00051 return err != JVMTI_ERROR_NONE;
00052 }
00053
00054
00061 static struct debug_line_info *
00062 create_debug_line_info(jint map_length, jvmtiAddrLocationMap const * map,
00063 jint entry_count, jvmtiLineNumberEntry* table_ptr,
00064 char const * source_filename)
00065 {
00066 struct debug_line_info * debug_line;
00067 int i, j;
00068 if (!debug) {
00069 fprintf(stderr, "Source %s l: %d\n", source_filename, map_length);
00070 for (i = 0; i < map_length; ++i) {
00071 fprintf(stderr, "%p %lld\t",
00072 map[i].start_address,
00073 (long long)map[i].location);
00074 }
00075 fprintf(stderr, "\n");
00076 for (i = 0; i < entry_count; ++i) {
00077 fprintf(stderr, "%lld %d\t",
00078 (long long)table_ptr[i].start_location,
00079 table_ptr[i].line_number);
00080 }
00081 fprintf(stderr, "\n");
00082 }
00083
00084 debug_line = calloc(map_length, sizeof(struct debug_line_info));
00085 if (!debug_line)
00086 return 0;
00087
00088 for (i = 0; i < map_length; ++i) {
00089
00090
00091
00092
00093 for (j = 0; j < entry_count - 1; ++j) {
00094 if (table_ptr[j].start_location > map[i].location)
00095 break;
00096 }
00097 debug_line[i].vma = (unsigned long)map[i].start_address;
00098 debug_line[i].lineno = table_ptr[j].line_number;
00099 debug_line[i].filename = source_filename;
00100 }
00101
00102 if (debug) {
00103 for (i = 0; i < map_length; ++i) {
00104 fprintf(stderr, "%d\t-> %lx %s:%d\t\n", i, debug_line[i].vma,
00105 debug_line[i].filename,debug_line[i].lineno);
00106 }
00107 fprintf(stderr, "\n");
00108 fflush(stderr);
00109 }
00110
00111 return debug_line;
00112 }
00113
00114
00115 static void JNICALL cb_compiled_method_load(jvmtiEnv * jvmti,
00116 jmethodID method, jint code_size, void const * code_addr,
00117 jint map_length, jvmtiAddrLocationMap const * map,
00118 void const * compile_info)
00119 {
00120 jclass declaring_class;
00121 char * class_signature = NULL;
00122 char * method_name = NULL;
00123 char * method_signature = NULL;
00124 jvmtiLineNumberEntry* table_ptr = NULL;
00125 char * source_filename = NULL;
00126 struct debug_line_info * debug_line = NULL;
00127 jvmtiError err;
00128
00129
00130 compile_info = compile_info;
00131
00132 err = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
00133 &declaring_class);
00134 if (handle_error(err, "GetMethodDeclaringClass()", 1))
00135 goto cleanup2;
00136
00137 if (can_get_line_numbers && map_length && map) {
00138 jint entry_count;
00139
00140 err = (*jvmti)->GetLineNumberTable(jvmti, method,
00141 &entry_count, &table_ptr);
00142 if (err == JVMTI_ERROR_NONE) {
00143 err = (*jvmti)->GetSourceFileName(jvmti,
00144 declaring_class, &source_filename);
00145 if (err == JVMTI_ERROR_NONE) {
00146 debug_line =
00147 create_debug_line_info(map_length, map,
00148 entry_count, table_ptr,
00149 source_filename);
00150 } else if (err != JVMTI_ERROR_ABSENT_INFORMATION) {
00151 handle_error(err, "GetSourceFileName()", 1);
00152 }
00153 } else if (err != JVMTI_ERROR_NATIVE_METHOD &&
00154 err != JVMTI_ERROR_ABSENT_INFORMATION) {
00155 handle_error(err, "GetLineNumberTable()", 1);
00156 }
00157 }
00158
00159 err = (*jvmti)->GetClassSignature(jvmti, declaring_class,
00160 &class_signature, NULL);
00161 if (handle_error(err, "GetClassSignature()", 1))
00162 goto cleanup1;
00163
00164 err = (*jvmti)->GetMethodName(jvmti, method, &method_name,
00165 &method_signature, NULL);
00166 if (handle_error(err, "GetMethodName()", 1))
00167 goto cleanup;
00168
00169 if (debug) {
00170 fprintf(stderr, "load: declaring_class=%p, class=%s, "
00171 "method=%s, signature=%s, addr=%p, size=%i \n",
00172 declaring_class, class_signature, method_name,
00173 method_signature, code_addr, code_size);
00174 }
00175
00176 {
00177 int cnt = strlen(method_name) + strlen(class_signature) +
00178 strlen(method_signature) + 2;
00179 char buf[cnt];
00180 strncpy(buf, class_signature, cnt - 1);
00181 strncat(buf, method_name, cnt - strlen(buf) - 1);
00182 strncat(buf, method_signature, cnt - strlen(buf) - 1);
00183 if (op_write_native_code(agent_hdl, buf,
00184 (uint64_t)(uintptr_t) code_addr,
00185 code_addr, code_size)) {
00186 perror("Error: op_write_native_code()");
00187 goto cleanup;
00188 }
00189 }
00190
00191 if (debug_line)
00192 if (op_write_debug_line_info(agent_hdl, code_addr, map_length,
00193 debug_line))
00194 perror("Error: op_write_debug_line_info()");
00195
00196 cleanup:
00197 (*jvmti)->Deallocate(jvmti, (unsigned char *)method_name);
00198 (*jvmti)->Deallocate(jvmti, (unsigned char *)method_signature);
00199 cleanup1:
00200 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_signature);
00201 (*jvmti)->Deallocate(jvmti, (unsigned char *)table_ptr);
00202 (*jvmti)->Deallocate(jvmti, (unsigned char *)source_filename);
00203 cleanup2:
00204 free(debug_line);
00205 }
00206
00207
00208 static void JNICALL cb_compiled_method_unload(jvmtiEnv * jvmti_env,
00209 jmethodID method, void const * code_addr)
00210 {
00211
00212 jvmti_env = jvmti_env;
00213 method = method;
00214
00215 if (debug)
00216 fprintf(stderr, "unload: addr=%p\n", code_addr);
00217 if (op_unload_native_code(agent_hdl, (uint64_t)(uintptr_t) code_addr))
00218 perror("Error: op_unload_native_code()");
00219 }
00220
00221
00222 static void JNICALL cb_dynamic_code_generated(jvmtiEnv * jvmti_env,
00223 char const * name, void const * code_addr, jint code_size)
00224 {
00225
00226 jvmti_env = jvmti_env;
00227 if (debug) {
00228
00229
00230 }
00231 if (op_write_native_code(agent_hdl, name,
00232 (uint64_t)(uintptr_t) code_addr,
00233 code_addr, code_size))
00234 perror("Error: op_write_native_code()");
00235 }
00236
00237
00238 JNIEXPORT jint JNICALL
00239 Agent_OnLoad(JavaVM * jvm, char * options, void * reserved)
00240 {
00241 jint rc;
00242 jvmtiEnv * jvmti = NULL;
00243 jvmtiEventCallbacks callbacks;
00244 jvmtiCapabilities caps;
00245 jvmtiJlocationFormat format;
00246 jvmtiError error;
00247
00248
00249 reserved = reserved;
00250
00251 if (options && !strcmp("version", options)) {
00252 fprintf(stderr, "jvmti_oprofile: current libopagent version %i.%i.\n",
00253 op_major_version(), op_minor_version());
00254 return -1;
00255 }
00256
00257 if (options && !strcmp("debug", options))
00258 debug = 1;
00259
00260 if (debug)
00261 fprintf(stderr, "jvmti_oprofile: agent activated\n");
00262
00263 agent_hdl = op_open_agent();
00264 if (!agent_hdl) {
00265 perror("Error: op_open_agent()");
00266 return -1;
00267 }
00268
00269 rc = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
00270 if (rc != JNI_OK) {
00271 fprintf(stderr, "Error: GetEnv(), rc=%i\n", rc);
00272 return -1;
00273 }
00274
00275 memset(&caps, '\0', sizeof(caps));
00276 caps.can_generate_compiled_method_load_events = 1;
00277 error = (*jvmti)->AddCapabilities(jvmti, &caps);
00278 if (handle_error(error, "AddCapabilities()", 1))
00279 return -1;
00280
00281
00282 error = (*jvmti)->GetJLocationFormat(jvmti, &format);
00283 if (!handle_error(error, "GetJLocationFormat", 1) &&
00284 format == JVMTI_JLOCATION_JVMBCI) {
00285 memset(&caps, '\0', sizeof(caps));
00286 caps.can_get_line_numbers = 1;
00287 caps.can_get_source_file_name = 1;
00288 error = (*jvmti)->AddCapabilities(jvmti, &caps);
00289 if (!handle_error(error, "AddCapabilities()", 1))
00290 can_get_line_numbers = 1;
00291 }
00292
00293 memset(&callbacks, 0, sizeof(callbacks));
00294 callbacks.CompiledMethodLoad = cb_compiled_method_load;
00295 callbacks.CompiledMethodUnload = cb_compiled_method_unload;
00296 callbacks.DynamicCodeGenerated = cb_dynamic_code_generated;
00297 error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks,
00298 sizeof(callbacks));
00299 if (handle_error(error, "SetEventCallbacks()", 1))
00300 return -1;
00301
00302 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
00303 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
00304 if (handle_error(error, "SetEventNotificationMode() "
00305 "JVMTI_EVENT_COMPILED_METHOD_LOAD", 1))
00306 return -1;
00307 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
00308 JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
00309 if (handle_error(error, "SetEventNotificationMode() "
00310 "JVMTI_EVENT_COMPILED_METHOD_UNLOAD", 1))
00311 return -1;
00312 error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
00313 JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
00314 if (handle_error(error, "SetEventNotificationMode() "
00315 "JVMTI_EVENT_DYNAMIC_CODE_GENERATED", 1))
00316 return -1;
00317 return 0;
00318 }
00319
00320
00321 JNIEXPORT void JNICALL Agent_OnUnload(JavaVM * jvm)
00322 {
00323
00324 jvm = jvm;
00325 if (op_close_agent(agent_hdl))
00326 perror("Error: op_close_agent()");
00327 }