📄 gcov.c
字号:
* 100), function_branches, function_name); fprintf (stdout, "%6.2lf%% of %d branches taken at least once in function %s\n", (((double) function_branches_taken / function_branches) * 100), function_branches, function_name); } else fprintf (stdout, "No branches in function %s\n", function_name); if (function_calls) fprintf (stdout, "%6.2lf%% of %d calls executed in function %s\n", (((double) function_calls_executed / function_calls) * 100), function_calls, function_name); else fprintf (stdout, "No calls in function %s\n", function_name); }}/* Calculate line execution counts, and output the data to a .tcov file. */static voidoutput_data (){ /* When scanning data, this is true only if the data applies to the current source file. */ int this_file; /* An array indexed by line number which indicates how many times that line was executed. */ long *line_counts; /* An array indexed by line number which indicates whether the line was present in the bb file (i.e. whether it had code associate with it). Lines never executed are those which both exist, and have zero execution counts. */ char *line_exists; /* An array indexed by line number, which contains a list of branch probabilities, one for each branch on that line. */ struct arcdata **branch_probs; struct sourcefile *s_ptr; char *source_file_name; FILE *source_file; struct bb_info_list *current_graph; int count; char *cptr; long block_num; long line_num; long last_line_num; int i; struct arcdata *a_ptr; /* Buffer used for reading in lines from the source file. */ char string[STRING_SIZE]; /* For calculating coverage at the file level. */ int total_source_lines; int total_source_lines_executed; int total_branches; int total_branches_executed; int total_branches_taken; int total_calls; int total_calls_executed; /* Now, for each source file, allocate an array big enough to hold a count for each line. Scan through the bb_data, and when the file name matches the current file name, then for each following line number, increment the line number execution count indicated by the execution count of the appropriate basic block. */ for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next) { /* If this is a relative file name, and an object directory has been specified, then make it relative to the object directory name. */ if (*s_ptr->name != '/' && object_directory != 0 && *object_directory != '\0') { int objdir_count = strlen (object_directory); source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2); strcpy (source_file_name, object_directory); if (object_directory[objdir_count - 1] != '/') source_file_name[objdir_count++] = '/'; strcpy (source_file_name + objdir_count, s_ptr->name); } else source_file_name = s_ptr->name; line_counts = (long *) xmalloc (sizeof (long) * s_ptr->maxlineno); bzero ((char *) line_counts, sizeof (long) * s_ptr->maxlineno); line_exists = xmalloc (s_ptr->maxlineno); bzero (line_exists, s_ptr->maxlineno); if (output_branch_probs) { branch_probs = (struct arcdata **) xmalloc (sizeof (struct arcdata **) * s_ptr->maxlineno); bzero ((char *) branch_probs, sizeof (struct arcdata **) * s_ptr->maxlineno); } /* There will be a zero at the beginning of the bb info, before the first list of line numbers, so must initialize block_num to 0. */ block_num = 0; this_file = 0; current_graph = 0; { /* Pointer into the bb_data, incremented while scanning the data. */ char *ptr = bb_data; for (count = 0; count < bb_data_size; count++) { long delim; __fetch_long (&line_num, ptr, 4); ptr += 4; if (line_num == -1) { /* Marks the beginning of a file name. Check to see whether this is the filename we are currently collecting data for. */ if (strcmp (s_ptr->name, ptr)) this_file = 0; else this_file = 1; /* Scan past the file name. */ do { count++; __fetch_long (&delim, ptr, 4); ptr += 4; } while (delim != line_num); } else if (line_num == -2) { /* Marks the start of a new function. Advance to the next program flow graph. */ if (! current_graph) current_graph = bb_graph_list; else { if (block_num == current_graph->num_blocks - 1) /* Last block falls through to exit. */ ; else if (block_num == current_graph->num_blocks - 2) { if (output_branch_probs && this_file) calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num); } else { fprintf (stderr, "didn't use all bb entries of graph, function %s\n", function_name); fprintf (stderr, "block_num = %d, num_blocks = %d\n", block_num, current_graph->num_blocks); } current_graph = current_graph->next; block_num = 0; if (output_function_summary && this_file) function_summary (); } if (output_function_summary) { function_source_lines = 0; function_source_lines_executed = 0; function_branches = 0; function_branches_executed = 0; function_branches_taken = 0; function_calls = 0; function_calls_executed = 0; } /* Save the function name for later use. */ function_name = ptr; /* Scan past the file name. */ do { count++; __fetch_long (&delim, ptr, 4); ptr += 4; } while (delim != line_num); } else if (line_num == 0) { /* Marks the end of a block. */ if (block_num >= current_graph->num_blocks) { fprintf (stderr, "ERROR: too many basic blocks in .bb file %s\n", function_name); abort (); } if (output_branch_probs && this_file) calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num); block_num++; } else if (this_file) { if (output_function_summary) { if (line_exists[line_num] == 0) function_source_lines++; if (line_counts[line_num] == 0 && current_graph->bb_graph[block_num].exec_count != 0) function_source_lines_executed++; } /* Accumulate execution data for this line number. */ line_counts[line_num] += current_graph->bb_graph[block_num].exec_count; line_exists[line_num] = 1; last_line_num = line_num; } } } if (output_function_summary && this_file) function_summary (); /* Calculate summary test coverage statistics. */ total_source_lines = 0; total_source_lines_executed = 0; total_branches = 0; total_branches_executed = 0; total_branches_taken = 0; total_calls = 0; total_calls_executed = 0; for (count = 1; count < s_ptr->maxlineno; count++) { if (line_exists[count]) { total_source_lines++; if (line_counts[count]) total_source_lines_executed++; } if (output_branch_probs) { for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next) { if (a_ptr->call_insn) { total_calls++; if (a_ptr->prob != -1) total_calls_executed++; } else { total_branches++; if (a_ptr->prob != -1) total_branches_executed++; if (a_ptr->prob > 0) total_branches_taken++; } } } } if (total_source_lines) fprintf (stdout, "%6.2lf%% of %d source lines executed in file %s\n", (((double) total_source_lines_executed / total_source_lines) * 100), total_source_lines, source_file_name); else fprintf (stdout, "No executable source lines in file %s\n", source_file_name); if (output_branch_probs) { if (total_branches) { fprintf (stdout, "%6.2lf%% of %d branches executed in file %s\n", (((double) total_branches_executed / total_branches) * 100), total_branches, source_file_name); fprintf (stdout, "%6.2lf%% of %d branches taken at least once in file %s\n", (((double) total_branches_taken / total_branches) * 100), total_branches, source_file_name); } else fprintf (stdout, "No branches in file %s\n", source_file_name); if (total_calls) fprintf (stdout, "%6.2lf%% of %d calls executed in file %s\n", (((double) total_calls_executed / total_calls) * 100), total_calls, source_file_name); else fprintf (stdout, "No calls in file %s\n", source_file_name); } if (output_gcov_file) { /* Now the statistics are ready. Read in the source file one line at a time, and output that line to the gcov file preceded by its execution count if non zero. */ source_file = fopen (source_file_name, "r"); if (source_file == NULL) { fprintf (stderr, "Could not open source file %s.\n", source_file_name); free (line_counts); free (line_exists); continue; } count = strlen (source_file_name); cptr = rindex (s_ptr->name, '/'); if (cptr) cptr = cptr + 1; else cptr = s_ptr->name; if (output_long_names && strcmp (cptr, input_file_name)) { gcov_file_name = xmalloc (count + 7 + strlen (input_file_name)); cptr = rindex (input_file_name, '/'); if (cptr) strcpy (gcov_file_name, cptr + 1); else strcpy (gcov_file_name, input_file_name); strcat (gcov_file_name, "."); cptr = rindex (source_file_name, '/'); if (cptr) strcat (gcov_file_name, cptr + 1); else strcat (gcov_file_name, source_file_name); } else { gcov_file_name = xmalloc (count + 6); cptr = rindex (source_file_name, '/'); if (cptr) strcpy (gcov_file_name, cptr + 1); else strcpy (gcov_file_name, source_file_name); } /* Don't strip off the ending for compatibility with tcov, since this results in confusion if there is more than one file with the same basename, e.g. tmp.c and tmp.h. */ strcat (gcov_file_name, ".gcov"); gcov_file = fopen (gcov_file_name, "w"); if (gcov_file == NULL) { fprintf (stderr, "Could not open output file %s.\n", gcov_file_name); fclose (source_file); free (line_counts); free (line_exists); continue; } fprintf (stdout, "Creating %s.\n", gcov_file_name); for (count = 1; count < s_ptr->maxlineno; count++) { char *retval; int len; retval = fgets (string, STRING_SIZE, source_file); /* For lines which don't exist in the .bb file, print nothing before the source line. For lines which exist but were never executed, print ###### before the source line. Otherwise, print the execution count before the source line. */ /* There are 16 spaces of indentation added before the source line so that tabs won't be messed up. */ if (line_exists[count]) { if (line_counts[count]) fprintf (gcov_file, "%12d %s", line_counts[count], string); else fprintf (gcov_file, " ###### %s", string); } else fprintf (gcov_file, "\t\t%s", string); /* In case the source file line is larger than our buffer, keep reading and outputting lines until we get a newline. */ len = strlen (string); while ((len == 0 || string[strlen (string) - 1] != '\n') && retval != NULL) { retval = fgets (string, STRING_SIZE, source_file); fputs (string, gcov_file); } if (output_branch_probs) { for (i = 0, a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next, i++) { if (a_ptr->call_insn) { if (a_ptr->prob == -1) fprintf (gcov_file, "call %d never executed\n", i); else fprintf (gcov_file, "call %d returns = %d%%\n", i, 100 - a_ptr->prob); } else { if (a_ptr->prob == -1) fprintf (gcov_file, "branch %d never executed\n", i); else fprintf (gcov_file, "branch %d taken = %d%%\n", i, a_ptr->prob); } } } /* Gracefully handle errors while reading the source file. */ if (retval == NULL) { fprintf (stderr, "Unexpected EOF while reading source file %s.\n", source_file_name); break; } } /* Handle all remaining source lines. There may be lines after the last line of code. */ { char *retval = fgets (string, STRING_SIZE, source_file); while (retval != NULL) { int len; fprintf (gcov_file, "\t\t%s", string); /* In case the source file line is larger than our buffer, keep reading and outputting lines until we get a newline. */ len = strlen (string); while ((len == 0 || string[strlen (string) - 1] != '\n') && retval != NULL) { retval = fgets (string, STRING_SIZE, source_file); fputs (string, gcov_file); } retval = fgets (string, STRING_SIZE, source_file); } } fclose (source_file); fclose (gcov_file); } free (line_counts); free (line_exists); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -