diff options
Diffstat (limited to 'tools/perf/jvmti/libjvmti.c')
| -rw-r--r-- | tools/perf/jvmti/libjvmti.c | 147 | 
1 files changed, 122 insertions, 25 deletions
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c index c62c9fc9a525..6add3e982614 100644 --- a/tools/perf/jvmti/libjvmti.c +++ b/tools/perf/jvmti/libjvmti.c @@ -47,6 +47,7 @@ do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,  			tab[lines].pc = (unsigned long)pc;  			tab[lines].line_number = loc_tab[i].line_number;  			tab[lines].discrim = 0; /* not yet used */ +			tab[lines].methodID = m;  			lines++;  		} else {  			break; @@ -125,6 +126,99 @@ get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **  	return JVMTI_ERROR_NONE;  } +static void +copy_class_filename(const char * class_sign, const char * file_name, char * result, size_t max_length) +{ +	/* +	* Assume path name is class hierarchy, this is a common practice with Java programs +	*/ +	if (*class_sign == 'L') { +		int j, i = 0; +		char *p = strrchr(class_sign, '/'); +		if (p) { +			/* drop the 'L' prefix and copy up to the final '/' */ +			for (i = 0; i < (p - class_sign); i++) +				result[i] = class_sign[i+1]; +		} +		/* +		* append file name, we use loops and not string ops to avoid modifying +		* class_sign which is used later for the symbol name +		*/ +		for (j = 0; i < (max_length - 1) && file_name && j < strlen(file_name); j++, i++) +			result[i] = file_name[j]; + +		result[i] = '\0'; +	} else { +		/* fallback case */ +		size_t file_name_len = strlen(file_name); +		strncpy(result, file_name, file_name_len < max_length ? file_name_len : max_length); +	} +} + +static jvmtiError +get_source_filename(jvmtiEnv *jvmti, jmethodID methodID, char ** buffer) +{ +	jvmtiError ret; +	jclass decl_class; +	char *file_name = NULL; +	char *class_sign = NULL; +	char fn[PATH_MAX]; +	size_t len; + +	ret = (*jvmti)->GetMethodDeclaringClass(jvmti, methodID, &decl_class); +	if (ret != JVMTI_ERROR_NONE) { +		print_error(jvmti, "GetMethodDeclaringClass", ret); +		return ret; +	} + +	ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name); +	if (ret != JVMTI_ERROR_NONE) { +		print_error(jvmti, "GetSourceFileName", ret); +		return ret; +	} + +	ret = (*jvmti)->GetClassSignature(jvmti, decl_class, &class_sign, NULL); +	if (ret != JVMTI_ERROR_NONE) { +		print_error(jvmti, "GetClassSignature", ret); +		goto free_file_name_error; +	} + +	copy_class_filename(class_sign, file_name, fn, PATH_MAX); +	len = strlen(fn); +	*buffer = malloc((len + 1) * sizeof(char)); +	if (!*buffer) { +		print_error(jvmti, "GetClassSignature", ret); +		ret = JVMTI_ERROR_OUT_OF_MEMORY; +		goto free_class_sign_error; +	} +	strcpy(*buffer, fn); +	ret = JVMTI_ERROR_NONE; + +free_class_sign_error: +	(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign); +free_file_name_error: +	(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name); + +	return ret; +} + +static jvmtiError +fill_source_filenames(jvmtiEnv *jvmti, int nr_lines, +		      const jvmti_line_info_t * line_tab, +		      char ** file_names) +{ +	int index; +	jvmtiError ret; + +	for (index = 0; index < nr_lines; ++index) { +		ret = get_source_filename(jvmti, line_tab[index].methodID, &(file_names[index])); +		if (ret != JVMTI_ERROR_NONE) +			return ret; +	} + +	return JVMTI_ERROR_NONE; +} +  static void JNICALL  compiled_method_load_cb(jvmtiEnv *jvmti,  			jmethodID method, @@ -135,16 +229,18 @@ compiled_method_load_cb(jvmtiEnv *jvmti,  			const void *compile_info)  {  	jvmti_line_info_t *line_tab = NULL; +	char ** line_file_names = NULL;  	jclass decl_class;  	char *class_sign = NULL;  	char *func_name = NULL;  	char *func_sign = NULL; -	char *file_name= NULL; +	char *file_name = NULL;  	char fn[PATH_MAX];  	uint64_t addr = (uint64_t)(uintptr_t)code_addr;  	jvmtiError ret;  	int nr_lines = 0; /* in line_tab[] */  	size_t len; +	int output_debug_info = 0;  	ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,  						&decl_class); @@ -158,6 +254,19 @@ compiled_method_load_cb(jvmtiEnv *jvmti,  		if (ret != JVMTI_ERROR_NONE) {  			warnx("jvmti: cannot get line table for method");  			nr_lines = 0; +		} else if (nr_lines > 0) { +			line_file_names = malloc(sizeof(char*) * nr_lines); +			if (!line_file_names) { +				warnx("jvmti: cannot allocate space for line table method names"); +			} else { +				memset(line_file_names, 0, sizeof(char*) * nr_lines); +				ret = fill_source_filenames(jvmti, nr_lines, line_tab, line_file_names); +				if (ret != JVMTI_ERROR_NONE) { +					warnx("jvmti: fill_source_filenames failed"); +				} else { +					output_debug_info = 1; +				} +			}  		}  	} @@ -181,33 +290,14 @@ compiled_method_load_cb(jvmtiEnv *jvmti,  		goto error;  	} -	/* -	 * Assume path name is class hierarchy, this is a common practice with Java programs -	 */ -	if (*class_sign == 'L') { -		int j, i = 0; -		char *p = strrchr(class_sign, '/'); -		if (p) { -			/* drop the 'L' prefix and copy up to the final '/' */ -			for (i = 0; i < (p - class_sign); i++) -				fn[i] = class_sign[i+1]; -		} -		/* -		 * append file name, we use loops and not string ops to avoid modifying -		 * class_sign which is used later for the symbol name -		 */ -		for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++) -			fn[i] = file_name[j]; -		fn[i] = '\0'; -	} else { -		/* fallback case */ -		strcpy(fn, file_name); -	} +	copy_class_filename(class_sign, file_name, fn, PATH_MAX); +  	/*  	 * write source line info record if we have it  	 */ -	if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines)) -		warnx("jvmti: write_debug_info() failed"); +	if (output_debug_info) +		if (jvmti_write_debug_info(jvmti_agent, addr, nr_lines, line_tab, (const char * const *) line_file_names)) +			warnx("jvmti: write_debug_info() failed");  	len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;  	{ @@ -223,6 +313,13 @@ error:  	(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);  	(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);  	free(line_tab); +	while (line_file_names && (nr_lines > 0)) { +	    if (line_file_names[nr_lines - 1]) { +	        free(line_file_names[nr_lines - 1]); +	    } +	    nr_lines -= 1; +	} +	free(line_file_names);  }  static void JNICALL  |