9 #include "jvmti_agent.h"
11 static int has_line_numbers;
15 compiled_method_load_cb(jvmtiEnv *jvmti,
18 void const *code_addr,
20 jvmtiAddrLocationMap const *map,
21 void const *compile_info __unused)
23 jvmtiLineNumberEntry *tab = NULL;
25 char *class_sign = NULL;
26 char *func_name = NULL;
27 char *func_sign = NULL;
28 char *file_name= NULL;
30 uint64_t addr = (uint64_t)(uintptr_t)code_addr;
35 ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
37 if (ret != JVMTI_ERROR_NONE) {
38 warnx("jvmti: cannot get declaring class");
42 if (has_line_numbers && map && map_length) {
44 ret = (*jvmti)->GetLineNumberTable(jvmti, method, &nr_lines, &tab);
45 if (ret != JVMTI_ERROR_NONE) {
46 warnx("jvmti: cannot get line table for method");
48 ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
49 if (ret != JVMTI_ERROR_NONE) {
50 warnx("jvmti: cannot get source filename ret=%d", ret);
56 ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
58 if (ret != JVMTI_ERROR_NONE) {
59 warnx("jvmti: getclassignature failed");
63 ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
65 if (ret != JVMTI_ERROR_NONE) {
66 warnx("jvmti: failed getmethodname");
71 * Assume path name is class hierarchy, this is a common practice with Java programs
73 if (*class_sign == 'L') {
75 char *p = strrchr(class_sign, '/');
77 /* drop the 'L' prefix and copy up to the final '/' */
78 for (i = 0; i < (p - class_sign); i++)
79 fn[i] = class_sign[i+1];
82 * append file name, we use loops and not string ops to avoid modifying
83 * class_sign which is used later for the symbol name
85 for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
90 strcpy(fn, file_name);
93 * write source line info record if we have it
95 if (jvmti_write_debug_info(jvmti_agent, addr, fn, map, tab, nr_lines))
96 warnx("jvmti: write_debug_info() failed");
98 len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
101 snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
102 if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
103 warnx("jvmti: write_code() failed");
106 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
107 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
108 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
109 (*jvmti)->Deallocate(jvmti, (unsigned char *)tab);
110 (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
114 code_generated_cb(jvmtiEnv *jvmti,
116 void const *code_addr,
119 uint64_t addr = (uint64_t)(unsigned long)code_addr;
122 ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
124 warnx("jvmti: write_code() failed for code_generated");
127 JNIEXPORT jint JNICALL
128 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
130 jvmtiEventCallbacks cb;
131 jvmtiCapabilities caps1;
132 jvmtiJlocationFormat format;
133 jvmtiEnv *jvmti = NULL;
136 jvmti_agent = jvmti_open();
138 warnx("jvmti: open_agent failed");
143 * Request a JVMTI interface version 1 environment
145 ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
147 warnx("jvmti: jvmti version 1 not supported");
152 * acquire method_load capability, we require it
153 * request line numbers (optional)
155 memset(&caps1, 0, sizeof(caps1));
156 caps1.can_generate_compiled_method_load_events = 1;
158 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
159 if (ret != JVMTI_ERROR_NONE) {
160 warnx("jvmti: acquire compiled_method capability failed");
163 ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
164 if (ret == JVMTI_ERROR_NONE && format == JVMTI_JLOCATION_JVMBCI) {
165 memset(&caps1, 0, sizeof(caps1));
166 caps1.can_get_line_numbers = 1;
167 caps1.can_get_source_file_name = 1;
168 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
169 if (ret == JVMTI_ERROR_NONE)
170 has_line_numbers = 1;
173 memset(&cb, 0, sizeof(cb));
175 cb.CompiledMethodLoad = compiled_method_load_cb;
176 cb.DynamicCodeGenerated = code_generated_cb;
178 ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
179 if (ret != JVMTI_ERROR_NONE) {
180 warnx("jvmti: cannot set event callbacks");
184 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
185 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
186 if (ret != JVMTI_ERROR_NONE) {
187 warnx("jvmti: setnotification failed for method_load");
191 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
192 JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
193 if (ret != JVMTI_ERROR_NONE) {
194 warnx("jvmti: setnotification failed on code_generated");
200 JNIEXPORT void JNICALL
201 Agent_OnUnload(JavaVM *jvm __unused)
205 ret = jvmti_close(jvmti_agent);
207 errx(1, "Error: op_close_agent()");