libjvmti_oprofile.c

Go to the documentation of this file.
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         /* FIXME: likely to need a lower_bound on the array, but
00090          * documentation is a bit obscure about the contents of these
00091          * arrray
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     /* shut up compiler warning */
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     /* shut up compiler warning */
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     /* shut up compiler warning */
00226     jvmti_env = jvmti_env;
00227     if (debug) {
00228     /*  fprintf(stderr, "dyncode: name=%s, addr=%p, size=%i \n",
00229             name, code_addr, code_size); */
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     /* shut up compiler warning */
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     /* FIXME: settable through command line, default on/off? */
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     /* shut up compiler warning */
00324     jvm = jvm;
00325     if (op_close_agent(agent_hdl))
00326         perror("Error: op_close_agent()");
00327 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1