1 /*
2     Copyright (c) 1998--2006 Benhur Stein
3 
4     This file is part of Paj�.
5 
6     Paj� is free software; you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License as published by the
8     Free Software Foundation; either version 2 of the License, or (at your
9     option) any later version.
10 
11     Paj� is distributed in the hope that it will be useful, but WITHOUT ANY
12     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13     FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14     for more details.
15 
16     You should have received a copy of the GNU Lesser General Public License
17     along with Paj�; if not, write to the Free Software Foundation, Inc.,
18 	51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
19 */
20 
21 
22 //////////////////////////////////////////////////
23 /*      Author: Geovani Ricardo Wiedenhoft      */
24 /*      Email: grw@inf.ufsm.br                  */
25 //////////////////////////////////////////////////
26 
27 
28 #include "JRastro.h"
29 
30 /*Global agente, contem a JVMTI, monitores, ...*/
31 globalAgent *gagent;
32 /*Identifica as capacidades da JVM*/
33 jvmtiCapabilities capabilities;
34 /*Seta as funcoes para retorno dos eventos*/
35 jvmtiEventCallbacks callbacks;
36 
37 /*Identificador(contador) das threads*/
38 long threadId = 1;
39 /*Identificador da thread main == Identificador da JVM*/
40 long jrst_mainThread;
41 /*Somador aleatorio, obtido pelo tempo*/
42 long adder;
43 
44 /*Nome do arquivo com as opcoes dos eventos a serem selecionados*/
45 char eventsOptionName[MAX_NAME_OPTIONS];
46 /*Nome do arquivo com as opcoes das classes e metodos a serem selecionados*/
47 char methodsOptionName[MAX_NAME_OPTIONS];
48 
49 /*Variavel para indicar se sera rastreados os eventos monitorados*/
50 bool traces       = true;
51 /*Variavel para setar se todos as classes e metodos serao rastreados*/
52 bool tracesAll    = false;
53 /*Variavel para indicar se os metodos serao rastreados*/
54 bool methodsTrace = false;
55 /*Variavel para indicar se a alocacao e liberacao de memoria sera rastreado*/
56 bool memoryTrace  = false;
57 
58 /*Indica se ja ocorreu a inicializacao da JVM*/
59 bool initialized = false;
60 
61 /*Hash com as classes a serem redefinidas*/
62 hash_t h_class;
63 /*Hash com as opcoes, classes e metodos*/
64 hash_t h_options;
65 
66 /*Buffers*/
67 rst_buffer_t *ptr_loader    =  NULL;
68 rst_buffer_t *ptr_monitor   =  NULL;
69 rst_buffer_t *ptr_new_array =  NULL;
70 
71 
72 /*--------------------------------------------------
73 * void JNICALL jrst_event_VMStart(jvmtiEnv *jvmtiLocate, JNIEnv* jniEnv)
74 * {
75 * 	//jrst_enter_critical_section(GET_JVMTI());
76 *
77 * 	//jrst_exit_critical_section(GET_JVMTI());
78 * }
79 *--------------------------------------------------*/
80 
81 /*--------------------------------------------------
82 * //////////////////////////////////////////////////////////////////////////////
83 * / *const jniNativeInterface *original_jni_Functions;
84 * const jniNativeInterface *redirected_jni_Functions;
85 * int my_global_ref_count = 0;
86 *
87 * jobject MyNewGlobalRef(JNIEnv *jniEnv, jobject obj)
88 * {
89 * 	++my_global_ref_count;
90 * 	printf("count=[%d] aqui...\n",my_global_ref_count);
91 * 	return original_jni_Functions->NewGlobalRef(jniEnv, obj);
92 * }
93 *
94 * //////////////////////////////////////////////////////////////////////////////
95 * void jrst_JNI_function_interception(void)
96 * {
97 * 	jvmtiError err;
98 * 	printf("aqui...\n");
99 * 	err = (*GET_JVMTI())->GetJNIFunctionTable(GET_JVMTI(), &original_jni_Functions);
100 * 	if (err != JVMTI_ERROR_NONE) {
101 *         	 exit(1);
102 * 		 //die();
103 * 	}
104 * 	err = (*GET_JVMTI())->GetJNIFunctionTable(GET_JVMTI(), &redirected_jni_Functions);
105 * 	if (err != JVMTI_ERROR_NONE) {
106 *         	 exit(1);
107 * 		//die();
108 * 	}
109 * 	redirected_jni_Functions->NewGlobalRef = MyNewGlobalRef;
110 * 	err = (*GET_JVMTI())->SetJNIFunctionTable(GET_JVMTI(), redirected_jni_Functions);
111 * 	if (err != JVMTI_ERROR_NONE) {
112 *         	 exit(1);
113 * 		//die();
114 * 	}
115 * }
116 * * /
117 *
118 * //////////////////////////////////////////////////////////////////////////////
119 *--------------------------------------------------*/
120 //unsigned class_number=0;
121 static int class_number = 0;
122 
123 
jrst_event_ClassFileLoadHook(jvmtiEnv * jvmtiLocate,JNIEnv * jniEnv,jclass class_being_redefined,jobject loader,const char * name,jobject protection_domain,jint class_data_len,const unsigned char * class_data,jint * new_class_data_len,unsigned char ** new_class_data)124 void JNICALL jrst_event_ClassFileLoadHook(jvmtiEnv *jvmtiLocate, JNIEnv *jniEnv, jclass class_being_redefined, jobject loader, const char* name, jobject protection_domain, jint class_data_len, const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data)
125 {
126 	jrst_enter_critical_section(jvmtiLocate, gagent->monitor);
127 
128 
129 	if(initialized == false){
130 
131 		//if(jrst_trace_class((char *)name) == false || strcmp(name, "java/lang/ClassLoader") == 0 || strcmp(name, "java/util/Vector") == 0 || strcmp(name, "java/lang/CharacterDataLatin1") == 0 || strcmp(name, "java/lang/System") == 0 || strcmp(name, "java/lang/Character") == 0 || strcmp(name, "java/util/HashMap") == 0){
132 		if(jrst_trace_class((char *)name) == false){
133 			class_number++;
134 			jrst_exit_critical_section(jvmtiLocate, gagent->monitor);
135 			return;
136 		}
137 
138 		jvmtiClassDefinition definition;
139 		definition.class_byte_count = class_data_len;
140 		definition.class_bytes = class_data;
141 
142 		hash_insert(&h_class, (hash_key_t)name, (hash_data_t)&definition);
143 
144 		jrst_exit_critical_section(jvmtiLocate, gagent->monitor);
145 		return;
146 	}
147 
148 	jvmtiError err;
149 	int system_class = 0;
150 	unsigned char *new_file_image = NULL;
151 	long new_file_len = 0;
152 
153 
154 	if(class_being_redefined == NULL){
155 		//if(jrst_trace_class((char *)name) == false || strcmp(name,"org/lsc/JRastro/Instru") == 0 || strcmp(name,"sun/misc/GC") == 0 || strcmp(name, "java/lang/Math") == 0){
156 		if(jrst_trace_class((char *)name) == false || strcmp(name,"org/lsc/JRastro/Instru") == 0){
157 			class_number++;
158 			jrst_exit_critical_section(jvmtiLocate, gagent->monitor);
159 			return;
160 		}
161 	}else{
162 		system_class = 1;
163 	}
164 
165 	//Registro do identificador e nome da classe
166 	trace_event_class_load(class_number, (char*)name);
167 
168 //	printf("Classe name=[%s] class_number=[%d]\n",name,class_number);
169 
170 //	if(!methodsTrace){
171 //		jrst_exit_critical_section(jvmtiLocate, gagent->monitor);
172 //		return;
173 //	}
174 
175 	java_crw_demo(class_number,
176 				name,
177 				class_data,
178 				class_data_len,
179 				system_class,
180 				&new_file_image,
181 				&new_file_len,
182 				&jrst_trace_methods
183 	);
184 
185 	if(new_file_len > 0){
186 		unsigned char *jvmti_space;
187 		err = (*jvmtiLocate)->Allocate(jvmtiLocate,(jlong)new_file_len, &jvmti_space);
188 		jrst_check_error(jvmtiLocate, err, "Cannot Allocate memory");
189 
190 		(void)memcpy((void*)jvmti_space, (void *)new_file_image, (int)new_file_len);
191 		*new_class_data_len = (jint)new_file_len;
192 		*new_class_data = jvmti_space;
193 
194 	}
195 	class_number++;
196 
197 	jrst_exit_critical_section(jvmtiLocate, gagent->monitor);
198 }
199 
200 
201 //////////////////////////////////////////////////////////////////////////////
202 /*Evento de inicializacao da JVM*/
jrst_event_VMInit(jvmtiEnv * jvmtiLocate,JNIEnv * jniEnv,jthread thread)203 void JNICALL jrst_event_VMInit(jvmtiEnv *jvmtiLocate, JNIEnv *jniEnv, jthread thread)
204 {
205 	jrst_enter_critical_section(jvmtiLocate, gagent->monitor);
206 
207 	char name[MAX_NAME_THREAD];
208 
209 	/*------------------------------------------------*/
210 	/*Obtencao do numero aleatorio para somar com os threadId*/
211 	struct timeval rt;
212 	gettimeofday(&rt,NULL);
213 	adder = (long)rt.tv_usec;
214 	/*------------------------------------------------*/
215 	jrst_mainThread = threadId + adder;
216 	/*--------------------------------------------------
217 	* if(name != NULL){
218 	* 	printf("VMInit thread name=[%s]\n",name);
219 	* }
220 	*--------------------------------------------------*/
221 
222 	/*Funcao que abilita as opcoes dos eventos*/
223 	jrst_read_events_enable(jvmtiLocate);
224 
225 	jvmtiError error;
226 	jint class_count_ptr;
227 	jclass *classes_ptr;
228 	jvmtiClassDefinition definitions[300];
229 	hash_data_t *class = NULL;
230 	int count=0;
231 	int i;
232 
233 	error = (*jvmtiLocate)->GetLoadedClasses(jvmtiLocate, &class_count_ptr, &classes_ptr);
234 	jrst_check_error(jvmtiLocate, error, "Cannot Get Loaded Classes");
235 
236 	for(i=0; i < class_count_ptr; i++){
237 
238 		char *signature_ptr;
239 		char *generic_ptr;
240 		int size = 0;
241 		char *tmp;
242 
243 		error = (*jvmtiLocate)->GetClassSignature(jvmtiLocate, classes_ptr[i], &signature_ptr, &generic_ptr);
244 		jrst_check_error(jvmtiLocate, error, "Cannot Get Class Signature");
245 
246 		/*Tirar da signature o caracter 'L'*/
247 		tmp = (char *)signature_ptr + 1;
248 		/* -1 Pois comeca em 0 o vetor*/
249 		size = strlen(tmp) - 1;
250 		/*Tira da signature o caracter ';'*/
251 		tmp[size] = '\0';
252 
253 		class = hash_locate(&h_class, (hash_key_t)tmp);
254 
255 		if(class != NULL){
256 			definitions[count] = **(jvmtiClassDefinition **)class;
257 			definitions[count].klass = classes_ptr[i];
258 			count++;
259 
260 		}
261 
262 		error=(*jvmtiLocate)->Deallocate(jvmtiLocate, (unsigned char*)signature_ptr);
263 		jrst_check_error(jvmtiLocate, error, "Cannot deallocate memory");
264 		error=(*jvmtiLocate)->Deallocate(jvmtiLocate, (unsigned char*)generic_ptr);
265 		jrst_check_error(jvmtiLocate, error, "Cannot deallocate memory");
266 	}
267 
268 	initialized = true;
269 
270 	error=(*jvmtiLocate)->RedefineClasses(jvmtiLocate, count, definitions);
271 	jrst_check_error(jvmtiLocate, error, "Redefine Classes");
272 
273 	error=(*jvmtiLocate)->Deallocate(jvmtiLocate, (unsigned char*)classes_ptr);
274 	jrst_check_error(jvmtiLocate, error, "Cannot deallocate memory");
275 
276 	jrst_get_thread_name(jvmtiLocate, thread, name, MAX_NAME_THREAD);
277 
278 	trace_initialize(jvmtiLocate, thread, name);
279 
280 	if(traces){
281 		jrst_threads(jvmtiLocate);
282 	}
283 
284 	jrst_exit_critical_section(jvmtiLocate, gagent->monitor);
285 }
286 
287 
288 //////////////////////////////////////////////////////////////////////////////
289 /*--------------------------------------------------
290 * void JNICALL jrst_event_VMDeath(jvmtiEnv *jvmtiLocate, JNIEnv *jniEnv)
291 * {
292 * 	jrst_enter_critical_section(jvmtiLocate);
293 *
294 * 	printf("VM Death event\n");
295 *
296 * 	jrst_exit_critical_section(jvmtiLocate);
297 * }
298 *--------------------------------------------------*/
299 
300 //////////////////////////////////////////////////////////////////////////////
jrst_set_capabilities()301 void jrst_set_capabilities()
302 {
303 	jvmtiError error;
304 
305 	(void)memset(&capabilities, 0, sizeof(capabilities));
306 
307 	/*Abilitar as abilidades que se deseja monitorar*/
308 	error = (*GET_JVMTI())->GetPotentialCapabilities(GET_JVMTI(), &capabilities);
309 	jrst_check_error(GET_JVMTI(), error, "Cannot Get Potential Capabilities");
310 
311 	/*Verificacao de capacidades*/
312 	if(capabilities.can_signal_thread != 1 ||
313 	     capabilities.can_get_owned_monitor_info != 1 ||
314 	     capabilities.can_generate_exception_events != 1 ||
315 	     capabilities.can_generate_frame_pop_events != 1 ||
316 	     capabilities.can_generate_method_entry_events != 1 ||
317 	     capabilities.can_generate_method_exit_events != 1 ||
318 	     capabilities.can_generate_vm_object_alloc_events != 1 ||
319 	     capabilities.can_generate_object_free_events != 1 ||
320 	     capabilities.can_get_current_thread_cpu_time != 1 ||
321 	     capabilities.can_get_thread_cpu_time != 1 ||
322 	     capabilities.can_access_local_variables != 1 ||
323 	     capabilities.can_generate_compiled_method_load_events != 1 ||
324 	     capabilities.can_maintain_original_method_order != 1 ||
325 	     capabilities.can_generate_monitor_events != 1 ||
326 	     capabilities.can_generate_garbage_collection_events != 1 ||
327 	     capabilities.can_generate_all_class_hook_events != 1){
328 
329 		printf("JVMTI_ERROR: Cannot get capabilities\n");
330 		exit(1);
331 	}
332 
333 	error=(*GET_JVMTI())->AddCapabilities(GET_JVMTI(), &capabilities);
334 	jrst_check_error(GET_JVMTI(), error, "Cannot Enable JVMTI capabilities");
335 
336 }
337 
jrst_set_funcs()338 void jrst_set_funcs()
339 {
340 	jvmtiError error;
341 
342 	(void)memset(&callbacks, 0, sizeof(callbacks));
343 
344 	/*Abilitar as funcoes que serao chamadas*/
345 	callbacks.VMInit = &jrst_event_VMInit;
346 	callbacks.ClassFileLoadHook = &jrst_event_ClassFileLoadHook;
347 	callbacks.ThreadStart = &jrst_event_thread_start;
348 	callbacks.ThreadEnd = &jrst_event_thread_end;
349 	/*callbacks.VMObjectAlloc = &jrst_event_VMObject_alloc;*/
350 	callbacks.ObjectFree = &jrst_event_object_free;
351 	callbacks.GarbageCollectionStart = &jrst_event_garbage_collection_start;
352 	callbacks.GarbageCollectionFinish = &jrst_event_garbage_collection_finish;
353 	callbacks.Exception = &jrst_event_exception;
354 	/*callbacks.ExceptionCatch = &jrst_event_exception_catch;*/
355 	callbacks.FramePop = &jrst_event_frame_pop;
356 	callbacks.MonitorContendedEnter = &jrst_monitor_contended_enter;
357 	callbacks.MonitorContendedEntered = &jrst_monitor_contended_entered;
358 	callbacks.MonitorWait = &jrst_monitor_wait;
359 	callbacks.MonitorWaited = &jrst_monitor_waited;
360 	/*callbacks.VMStart = &jrst_event_VMStart;*/
361 	/*callbacks.VMDeath = &jrst_event_VMDeath;*/
362 
363 
364 	error=(*GET_JVMTI())->SetEventCallbacks(GET_JVMTI(), &callbacks,(jint)sizeof(callbacks));
365 	jrst_check_error(GET_JVMTI(), error, "Cannot set JVMTI callbacks");
366 }
367 
jrst_init()368 void jrst_init()
369 {
370 	jvmtiError error;
371 
372 	/*Abilita as funcoes JVMTI_EVENT_CLASS_FILE_LOAD_HOOK e JVMTI_EVENT_VM_INIT*/
373 
374 	error=(*GET_JVMTI())->SetEventNotificationMode(GET_JVMTI(), JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL);
375 	jrst_check_error(GET_JVMTI(), error, "Cannot set event notification <JVMTI_EVENT_CLASS_FILE_LOAD_HOOK>");
376 
377 	error=(*GET_JVMTI())->SetEventNotificationMode(GET_JVMTI(), JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread)NULL);
378 	jrst_check_error(GET_JVMTI(), error, "Cannot set event notification <JVMTI_EVENT_VM_INIT>");
379 
380 /*	error=(*GET_JVMTI())->SetEventNotificationMode(GET_JVMTI(), JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, (jthread)NULL);
381 	jrst_check_error(GET_JVMTI(), error, "Cannot set event notification <JVMTI_EVENT_VM_DEATH>");
382 
383 	error=(*GET_JVMTI())->SetEventNotificationMode(GET_JVMTI(), JVMTI_ENABLE, JVMTI_EVENT_VM_START, (jthread)NULL);
384 	jrst_check_error(GET_JVMTI(), error, "Cannot set event notification <JVMTI_EVENT_VM_START>");
385 */
386 
387 }
388 
jrst_create_monitor()389 void jrst_create_monitor()
390 {
391 	jvmtiError error;
392 
393 	/*Criacao dos monitores*/
394 	error=(*GET_JVMTI())->CreateRawMonitor(GET_JVMTI(), "agent", &(gagent->monitor));
395 	jrst_check_error(GET_JVMTI(), error, "Cannot create raw monitor");
396 
397 	error=(*GET_JVMTI())->CreateRawMonitor(GET_JVMTI(), "thread", &(gagent->monitor_thread));
398 	jrst_check_error(GET_JVMTI(), error, "Cannot create raw monitor");
399 
400 	error=(*GET_JVMTI())->CreateRawMonitor(GET_JVMTI(), "buffer", &(gagent->monitor_buffer));
401 	jrst_check_error(GET_JVMTI(), error, "Cannot create raw monitor");
402 
403 	error=(*GET_JVMTI())->CreateRawMonitor(GET_JVMTI(), "newArray", &(gagent->monitor_new_array));
404 	jrst_check_error(GET_JVMTI(), error, "Cannot create raw monitor");
405 
406 	error=(*GET_JVMTI())->CreateRawMonitor(GET_JVMTI(), "tag", &(gagent->monitor_tag));
407 	jrst_check_error(GET_JVMTI(), error, "Cannot create raw monitor");
408 
409 }
410 
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)411 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
412 {
413 	jint ret;
414 
415 	printf("[JRastro] Loading Agent_Onload...\n");
416 
417 	hash_initialize(&h_options, hash_value_string, hash_copy_string, hash_key_cmp_string, hash_destroy_string_list);
418 	hash_initialize(&h_class, hash_value_string, hash_copy_string_data, hash_key_cmp_string, hash_destroy_string_data);
419 
420 	gagent = (globalAgent *) malloc(sizeof(globalAgent));
421 
422 	ret=(*jvm)->GetEnv(jvm, (void **)&gagent->jvmti, JVMTI_VERSION_1_0);
423 	if(ret != JNI_OK || gagent->jvmti == NULL){
424 		printf("ERROR: Unable to access JVMTI Version 1 (0x%x),"
425 	                " is your J2SE a 1.5 or newer version?"
426 	                " JNIEnv's GetEnv() returned %d\n",
427                JVMTI_VERSION_1, ret);
428 		exit(1);
429 	}
430 
431 
432 	/*Le nomes dos arquivos "opcoes"*/
433 	jrst_read_names_options(options);
434 
435 	/*Funcao que abilita os methodos a serem rastreados*/
436 	jrst_read_class_methods_enable();
437 
438 	jrst_set_capabilities();
439 
440 	jrst_set_funcs();
441 
442 	jrst_init();
443 
444 	jrst_create_monitor();
445 
446 	return JNI_OK;
447 
448 }
449 
450 
451 //////////////////////////////////////////////////////////////////////////////
Agent_OnUnload(JavaVM * vm)452 JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
453 {
454 	//printf("Loading Agent_OnUnload ........");
455 	//extern int count;
456 	hash_finalize(&h_options);
457 	hash_finalize(&h_class);
458 
459 	if(traces){
460 		rst_flush_all();
461 	}
462 	printf("[JRastro] ................OK\n");
463 }
464 
465