Ping. Thanks, Sharad
On Wed, Jun 5, 2013 at 11:18 AM, Sharad Singhai <sing...@google.com> wrote: > Ping. > > Thanks, > Sharad > > > On Tue, May 28, 2013 at 11:35 AM, Sharad Singhai <sing...@google.com> wrote: >> Sorry, my patch had bad formatting in one of the functions >> (output_gcov_file). Here is the corrected version. >> >> Thanks, >> Sharad >> >> (2013-05-28 <sing...@google.com> >> >> * gcov.c (print_usage): Handle new option. >> (process_args): Ditto. >> (get_gcov_intermediate_filename): New function. >> (output_intermediate_file): New function. >> (output_gcov_file): New function >> (generate_results): Handle new option. >> (release_function): Relase demangled name. >> (read_graph_file): Handle demangled name. >> (output_lines): Ditto. >> * doc/gcov.texi: Document gcov intermediate format. >> >> testsuite/ChangeLog: >> >> 2013-05-28 Sharad Singhai <sing...@google.com> >> >> * g++.dg/gcov/gcov-8.C: New testcase. >> * lib/gcov.exp: Handle intermediate format. >> >> Index: doc/gcov.texi >> =================================================================== >> --- doc/gcov.texi (revision 199273) >> +++ doc/gcov.texi (working copy) >> @@ -122,15 +122,17 @@ gcov [@option{-v}|@option{--version}] [@option{-h} >> [@option{-a}|@option{--all-blocks}] >> [@option{-b}|@option{--branch-probabilities}] >> [@option{-c}|@option{--branch-counts}] >> - [@option{-u}|@option{--unconditional-branches}] >> + [@option{-d}|@option{--display-progress}] >> + [@option{-f}|@option{--function-summaries}] >> + [@option{-i}|@option{--intermediate-format}] >> + [@option{-l}|@option{--long-file-names}] >> + [@option{-m}|@option{--demangled-names}] >> [@option{-n}|@option{--no-output}] >> - [@option{-l}|@option{--long-file-names}] >> + [@option{-o}|@option{--object-directory} @var{directory|file}] >> [@option{-p}|@option{--preserve-paths}] >> [@option{-r}|@option{--relative-only}] >> - [@option{-f}|@option{--function-summaries}] >> - [@option{-o}|@option{--object-directory} @var{directory|file}] >> [@option{-s}|@option{--source-prefix} @var{directory}] >> - [@option{-d}|@option{--display-progress}] >> + [@option{-u}|@option{--unconditional-branches}] >> @var{files} >> @c man end >> @c man begin SEEALSO >> @@ -232,6 +234,50 @@ Unconditional branches are normally not interestin >> @itemx --display-progress >> Display the progress on the standard output. >> >> +@item -i >> +@itemx --intermediate-format >> +Output gcov file in an easy-to-parse intermediate text format that can >> +be used by @command{lcov} or other tools. The output is a single >> +@file{.gcov} file per @file{.gcda} file. No source code is required. >> + >> +The format of the intermediate @file{.gcov} file is plain text with >> +one entry per line >> + >> +@smallexample >> +file:@var{source_file_name} >> +function:@var{line_number},@var{execution_count},@var{function_name} >> +lcount:@var{line number},@var{execution_count} >> +branch:@var{line_number},@var{branch_coverage_type} >> + >> +Where the @var{branch_coverage_type} is >> + notexec (Branch not executed) >> + taken (Branch executed and taken) >> + nottaken (Branch executed, but not taken) >> + >> +There can be multiple @var{file} entries in an intermediate gcov >> +file. All entries following a @var{file} pertain to that source file >> +until the next @var{file} entry. >> +@end smallexample >> + >> +Here is a sample when @option{-i} is used in conjuction with >> @option{-b} option: >> + >> +@smallexample >> +file:array.cc >> +function:11,1,_Z3sumRKSt6vectorIPiSaIS0_EE >> +function:22,1,main >> +lcount:11,1 >> +lcount:12,1 >> +lcount:14,1 >> +branch:14,taken >> +lcount:26,1 >> +branch:28,nottaken >> +@end smallexample >> + >> +@item -m >> +@itemx --demangled-names >> +Display demangled function names in output. The default is to show >> +mangled function names. >> + >> @end table >> >> @command{gcov} should be run with the current directory the same as that >> Index: gcov.c >> =================================================================== >> --- gcov.c (revision 199273) >> +++ gcov.c (working copy) >> @@ -37,6 +37,7 @@ along with Gcov; see the file COPYING3. If not se >> #include "intl.h" >> #include "diagnostic.h" >> #include "version.h" >> +#include "demangle.h" >> >> #include <getopt.h> >> >> @@ -168,6 +169,7 @@ typedef struct function_info >> { >> /* Name of function. */ >> char *name; >> + char *demangled_name; >> unsigned ident; >> unsigned lineno_checksum; >> unsigned cfg_checksum; >> @@ -325,6 +327,14 @@ static int flag_gcov_file = 1; >> >> static int flag_display_progress = 0; >> >> +/* Output *.gcov file in intermediate format used by 'lcov'. */ >> + >> +static int flag_intermediate_format = 0; >> + >> +/* Output demangled function names. */ >> + >> +static int flag_demangled_names = 0; >> + >> /* For included files, make the gcov output file name include the name >> of the input source file. For example, if x.h is included in a.c, >> then the output file name is a.c##x.h.gcov instead of x.h.gcov. */ >> @@ -388,6 +398,7 @@ static void executed_summary (unsigned, unsigned); >> static void function_summary (const coverage_t *, const char *); >> static const char *format_gcov (gcov_type, gcov_type, int); >> static void accumulate_line_counts (source_t *); >> +static void output_gcov_file(const char *, source_t *); >> static int output_branch_count (FILE *, int, const arc_t *); >> static void output_lines (FILE *, const source_t *); >> static char *make_gcov_file_name (const char *, const char *); >> @@ -461,21 +472,23 @@ print_usage (int error_p) >> fnotice (file, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n"); >> fnotice (file, "Print code coverage information.\n\n"); >> fnotice (file, " -h, --help Print this help, >> then exit\n"); >> - fnotice (file, " -v, --version Print version >> number, then exit\n"); >> fnotice (file, " -a, --all-blocks Show information >> for every basic block\n"); >> fnotice (file, " -b, --branch-probabilities Include branch >> probabilities in output\n"); >> - fnotice (file, " -c, --branch-counts Given counts of >> branches taken\n\ >> + fnotice (file, " -c, --branch-counts Output counts of >> branches taken\n\ >> rather than percentages\n"); >> - fnotice (file, " -n, --no-output Do not create an >> output file\n"); >> + fnotice (file, " -d, --display-progress Display progress >> information\n"); >> + fnotice (file, " -f, --function-summaries Output summaries >> for each function\n"); >> + fnotice (file, " -i, --intermediate-format Output .gcov file >> in intermediate text format\n"); >> fnotice (file, " -l, --long-file-names Use long output >> file names for included\n\ >> source files\n"); >> - fnotice (file, " -f, --function-summaries Output summaries >> for each function\n"); >> + fnotice (file, " -m, --demangled-names Output demangled >> function names\n"); >> + fnotice (file, " -n, --no-output Do not create an >> output file\n"); >> fnotice (file, " -o, --object-directory DIR|FILE Search for object >> files in DIR or called FILE\n"); >> + fnotice (file, " -p, --preserve-paths Preserve all >> pathname components\n"); >> + fnotice (file, " -r, --relative-only Only show data >> for relative sources\n"); >> fnotice (file, " -s, --source-prefix DIR Source prefix to >> elide\n"); >> - fnotice (file, " -r, --relative-only Only show data >> for relative sources\n"); >> - fnotice (file, " -p, --preserve-paths Preserve all >> pathname components\n"); >> fnotice (file, " -u, --unconditional-branches Show >> unconditional branch counts too\n"); >> - fnotice (file, " -d, --display-progress Display progress >> information\n"); >> + fnotice (file, " -v, --version Print version >> number, then exit\n"); >> fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", >> bug_report_url); >> exit (status); >> @@ -503,9 +516,11 @@ static const struct option options[] = >> { "all-blocks", no_argument, NULL, 'a' }, >> { "branch-probabilities", no_argument, NULL, 'b' }, >> { "branch-counts", no_argument, NULL, 'c' }, >> + { "intermediate-format", no_argument, NULL, 'i' }, >> { "no-output", no_argument, NULL, 'n' }, >> { "long-file-names", no_argument, NULL, 'l' }, >> { "function-summaries", no_argument, NULL, 'f' }, >> + { "demangled-names", no_argument, NULL, 'm' }, >> { "preserve-paths", no_argument, NULL, 'p' }, >> { "relative-only", no_argument, NULL, 'r' }, >> { "object-directory", required_argument, NULL, 'o' }, >> @@ -523,7 +538,8 @@ process_args (int argc, char **argv) >> { >> int opt; >> >> - while ((opt = getopt_long (argc, argv, "abcdfhlno:s:pruv", options, >> NULL)) != -1) >> + while ((opt = getopt_long (argc, argv, "abcdfhilmno:s:pruv", >> options, NULL)) != >> + -1) >> { >> switch (opt) >> { >> @@ -545,6 +561,9 @@ process_args (int argc, char **argv) >> case 'l': >> flag_long_names = 1; >> break; >> + case 'm': >> + flag_demangled_names = 1; >> + break; >> case 'n': >> flag_gcov_file = 0; >> break; >> @@ -564,6 +583,10 @@ process_args (int argc, char **argv) >> case 'u': >> flag_unconditional = 1; >> break; >> + case 'i': >> + flag_intermediate_format = 1; >> + flag_gcov_file = 1; >> + break; >> case 'd': >> flag_display_progress = 1; >> break; >> @@ -579,6 +602,110 @@ process_args (int argc, char **argv) >> return optind; >> } >> >> +/* Get the name of the gcov file. The return value must be free'd. >> + >> + It appends the '.gcov' extension to the *basename* of the file. >> + The resulting file name will be in PWD. >> + >> + e.g., >> + input: foo.da, output: foo.da.gcov >> + input: a/b/foo.cc, output: foo.cc.gcov */ >> + >> +static char * >> +get_gcov_intermediate_filename (const char *file_name) >> +{ >> + const char *gcov = ".gcov"; >> + char *result; >> + const char *cptr; >> + >> + /* Find the 'basename'. */ >> + cptr = lbasename (file_name); >> + >> + result = XNEWVEC(char, strlen (cptr) + strlen (gcov) + 1); >> + sprintf (result, "%s%s", cptr, gcov); >> + >> + return result; >> +} >> + >> +/* Output the result in intermediate format used by 'lcov'. >> + >> +The intermediate format contains a single file named 'foo.cc.gcov', >> +with no source code included. A sample output is >> + >> +file:foo.cc >> +function:5,1,_Z3foov >> +function:13,1,main >> +function:19,1,_GLOBAL__sub_I__Z3foov >> +function:19,1,_Z41__static_initialization_and_destruction_0ii >> +lcount:5,1 >> +lcount:7,9 >> +lcount:9,8 >> +lcount:11,1 >> +file:/.../iostream >> +lcount:74,1 >> +file:/.../basic_ios.h >> +file:/.../ostream >> +file:/.../ios_base.h >> +function:157,0,_ZStorSt12_Ios_IostateS_ >> +lcount:157,0 >> +file:/.../char_traits.h >> +function:258,0,_ZNSt11char_traitsIcE6lengthEPKc >> +lcount:258,0 >> +... >> + >> +The default gcov outputs multiple files: 'foo.cc.gcov', >> +'iostream.gcov', 'ios_base.h.gcov', etc. with source code >> +included. Instead the intermediate format here outputs only a single >> +file 'foo.cc.gcov' similar to the above example. */ >> + >> +static void >> +output_intermediate_file (FILE *gcov_file, source_t *src) >> +{ >> + unsigned line_num; /* current line number. */ >> + const line_t *line; /* current line info ptr. */ >> + function_t *fn; /* current function info ptr. */ >> + >> + fprintf (gcov_file, "file:%s\n", src->name); /* source file name */ >> + >> + for (fn = src->functions; fn; fn = fn->line_next) >> + { >> + /* function:<name>,<line_number>,<execution_count> */ >> + fprintf (gcov_file, "function:%d,%s,%s\n", fn->line, >> + format_gcov (fn->blocks[0].count, 0, -1), >> + flag_demangled_names ? fn->demangled_name : fn->name); >> + } >> + >> + for (line_num = 1, line = &src->lines[line_num]; >> + line_num < src->num_lines; >> + line_num++, line++) >> + { >> + arc_t *arc; >> + if (line->exists) >> + fprintf (gcov_file, "lcount:%u,%s\n", line_num, >> + format_gcov (line->count, 0, -1)); >> + if (flag_branches) >> + for (arc = line->u.branches; arc; arc = arc->line_next) >> + { >> + if (!arc->is_unconditional && !arc->is_call_non_return) >> + { >> + const char *branch_type; >> + /* branch:<line_num>,<branch_coverage_type> >> + branch_coverage_type >> + : notexec (Branch not executed) >> + : taken (Branch executed and taken) >> + : nottaken (Branch executed, but not taken) >> + */ >> + if (arc->src->count) >> + branch_type = (arc->count > 0) ? "taken" : "nottaken"; >> + else >> + branch_type = "notexec"; >> + fprintf(gcov_file, "branch:%d,%s\n", line_num, branch_type); >> + } >> + } >> + } >> +} >> + >> + >> /* Process a single input file. */ >> >> static void >> @@ -655,11 +782,40 @@ process_file (const char *file_name) >> } >> >> static void >> +output_gcov_file(const char *file_name, source_t *src) >> +{ >> + char *gcov_file_name = make_gcov_file_name (file_name, >> src->coverage.name); >> + >> + if (src->coverage.lines) >> + { >> + FILE *gcov_file = fopen (gcov_file_name, "w"); >> + if (gcov_file) >> + { >> + fnotice (stdout, "Creating '%s'\n", gcov_file_name); >> + output_lines (gcov_file, src); >> + if (ferror (gcov_file)) >> + fnotice (stderr, "Error writing output file '%s'\n", >> gcov_file_name); >> + fclose (gcov_file); >> + } >> + else >> + fnotice (stderr, "Could not open output file '%s'\n", >> gcov_file_name); >> + } >> + else >> + { >> + unlink (gcov_file_name); >> + fnotice (stdout, "Removing '%s'\n", gcov_file_name); >> + } >> + free (gcov_file_name); >> +} >> + >> +static void >> generate_results (const char *file_name) >> { >> unsigned ix; >> source_t *src; >> function_t *fn; >> + FILE *gcov_intermediate_file = NULL; >> + char *gcov_intermediate_filename = NULL; >> >> for (ix = n_sources, src = sources; ix--; src++) >> if (src->num_lines) >> @@ -670,7 +826,7 @@ generate_results (const char *file_name) >> coverage_t coverage; >> >> memset (&coverage, 0, sizeof (coverage)); >> - coverage.name = fn->name; >> + coverage.name = flag_demangled_names ? fn->demangled_name : fn->name; >> add_line_counts (flag_function_summary ? &coverage : NULL, fn); >> if (flag_function_summary) >> { >> @@ -688,7 +844,21 @@ generate_results (const char *file_name) >> else >> file_name = canonicalize_name (file_name); >> } >> - >> + >> + if (flag_gcov_file && flag_intermediate_format) >> + { >> + /* Open the intermediate file. */ >> + gcov_intermediate_filename = >> + get_gcov_intermediate_filename (file_name); >> + gcov_intermediate_file = fopen (gcov_intermediate_filename, "w"); >> + if (!gcov_intermediate_file) >> + { >> + fnotice (stderr, "Cannot open intermediate output file %s\n", >> + gcov_intermediate_filename); >> + return; >> + } >> + } >> + >> for (ix = n_sources, src = sources; ix--; src++) >> { >> if (flag_relative_only) >> @@ -711,34 +881,21 @@ generate_results (const char *file_name) >> total_executed += src->coverage.lines_executed; >> if (flag_gcov_file) >> { >> - char *gcov_file_name >> - = make_gcov_file_name (file_name, src->coverage.name); >> + if (flag_intermediate_format) >> + /* Output the intermediate format without requiring source >> + files. This outputs a section to a *single* file. */ >> + output_intermediate_file (gcov_intermediate_file, src); >> + else >> + output_gcov_file (file_name, src); >> + fnotice (stdout, "\n"); >> + } >> + } >> >> - if (src->coverage.lines) >> - { >> - FILE *gcov_file = fopen (gcov_file_name, "w"); >> - >> - if (gcov_file) >> - { >> - fnotice (stdout, "Creating '%s'\n", gcov_file_name); >> - output_lines (gcov_file, src); >> - if (ferror (gcov_file)) >> - fnotice (stderr, "Error writing output file '%s'\n", >> - gcov_file_name); >> - fclose (gcov_file); >> - } >> - else >> - fnotice (stderr, "Could not open output file '%s'\n", >> - gcov_file_name); >> - } >> - else >> - { >> - unlink (gcov_file_name); >> - fnotice (stdout, "Removing '%s'\n", gcov_file_name); >> - } >> - free (gcov_file_name); >> - } >> - fnotice (stdout, "\n"); >> + if (flag_gcov_file && flag_intermediate_format) >> + { >> + /* Now we've finished writing the intermediate file. */ >> + fclose (gcov_intermediate_file); >> + XDELETEVEC (gcov_intermediate_filename); >> } >> >> if (!file_name) >> @@ -765,6 +922,9 @@ release_function (function_t *fn) >> } >> free (fn->blocks); >> free (fn->counts); >> + if (flag_demangled_names && fn->demangled_name != fn->name) >> + free (fn->demangled_name); >> + free (fn->name); >> } >> >> /* Release all memory used. */ >> @@ -1050,6 +1210,12 @@ read_graph_file (void) >> >> fn = XCNEW (function_t); >> fn->name = function_name; >> + if (flag_demangled_names) >> + { >> + fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS); >> + if (!fn->demangled_name) >> + fn->demangled_name = fn->name; >> + } >> fn->ident = ident; >> fn->lineno_checksum = lineno_checksum; >> fn->cfg_checksum = cfg_checksum; >> @@ -2277,7 +2443,8 @@ output_lines (FILE *gcov_file, const source_t *src >> if (arc->fake) >> return_count -= arc->count; >> >> - fprintf (gcov_file, "function %s", fn->name); >> + fprintf (gcov_file, "function %s", flag_demangled_names ? >> + fn->demangled_name : fn->name); >> fprintf (gcov_file, " called %s", >> format_gcov (called_count, 0, -1)); >> fprintf (gcov_file, " returned %s", >> Index: testsuite/lib/gcov.exp >> =================================================================== >> --- testsuite/lib/gcov.exp (revision 199273) >> +++ testsuite/lib/gcov.exp (working copy) >> @@ -70,7 +70,62 @@ proc verify-lines { testname testcase file } { >> return $failed >> } >> >> + >> # >> +# verify-intermediate -- check that intermediate file has certain lines >> +# >> +# TESTNAME is the name of the test, including unique flags. >> +# TESTCASE is the name of the test. >> +# FILE is the name of the gcov output file. >> +# >> +# Checks are very loose, they are based on certain tags being present >> +# in the output. They do not check for exact expected execution >> +# counts. For that the regular gcov format should be checked. >> +# >> +proc verify-intermediate { testname testcase file } { >> + set failed 0 >> + set srcfile 0 >> + set function 0 >> + set lcount 0 >> + set branch 0 >> + set fd [open $file r] >> + while { [gets $fd line] >= 0 } { >> + if [regexp "^file:" $line] { >> + incr srcfile >> + } >> + if [regexp "^function:(\[0-9\]+),(\[0-9\]+),.*" $line] { >> + incr function >> + } >> + if [regexp "^lcount:(\[0-9\]+),(\[0-9\]+)" $line] { >> + incr lcount >> + } >> + if [regexp "^branch:(\[0-9\]+),(taken|nottaken|notexec)" $line] { >> + incr branch >> + } >> + } >> + >> + # We should see at least one tag of each type >> + if {$srcfile == 0} { >> + fail "$testname expected 'file:' tag not found" >> + incr failed >> + } >> + if {$function == 0} { >> + fail "$testname expected 'function:' tag not found" >> + incr failed >> + } >> + if {$lcount == 0} { >> + fail "$testname expected 'lcount:' tag not found" >> + incr failed >> + } >> + if {$branch == 0} { >> + fail "$testname expected 'branch:' tag not found" >> + incr failed >> + } >> + return $failed >> +} >> + >> + >> +# >> # verify-branches -- check that branch percentages are as expected >> # >> # TESTNAME is the name of the test, including unique flags. >> @@ -248,6 +303,8 @@ proc run-gcov { args } { >> set gcov_args "" >> set gcov_verify_calls 0 >> set gcov_verify_branches 0 >> + set gcov_verify_lines 1 >> + set gcov_verify_intermediate 0 >> set xfailed 0 >> >> foreach a $args { >> @@ -255,6 +312,11 @@ proc run-gcov { args } { >> set gcov_verify_calls 1 >> } elseif { $a == "branches" } { >> set gcov_verify_branches 1 >> + } elseif { $a == "intermediate" } { >> + set gcov_verify_intermediate 1 >> + set gcov_verify_calls 0 >> + set gcov_verify_branches 0 >> + set gcov_verify_lines 0 >> } elseif { $gcov_args == "" } { >> set gcov_args $a >> } else { >> @@ -295,7 +357,12 @@ proc run-gcov { args } { >> remote_upload host $testcase.gcov $testcase.gcov >> >> # Check that line execution counts are as expected. >> - set lfailed [verify-lines $testname $testcase $testcase.gcov] >> + if { $gcov_verify_lines } { >> + # Check that line execution counts are as expected. >> + set lfailed [verify-lines $testname $testcase $testcase.gcov] >> + } else { >> + set lfailed 0 >> + } >> >> # If requested via the .x file, check that branch and call information >> # is correct. >> @@ -309,15 +376,21 @@ proc run-gcov { args } { >> } else { >> set cfailed 0 >> } >> + if { $gcov_verify_intermediate } { >> + # Check that intermediate format has the expected format >> + set ifailed [verify-intermediate $testname $testcase $testcase.gcov] >> + } else { >> + set ifailed 0 >> + } >> >> # Report whether the gcov test passed or failed. If there were >> # multiple failures then the message is a summary. >> - set tfailed [expr $lfailed + $bfailed + $cfailed] >> + set tfailed [expr $lfailed + $bfailed + $cfailed + $ifailed] >> if { $xfailed } { >> setup_xfail "*-*-*" >> } >> if { $tfailed > 0 } { >> - fail "$testname gcov: $lfailed failures in line counts, $bfailed in >> branch percentages, $cfailed in return percentages" >> + fail "$testname gcov: $lfailed failures in line counts, $bfailed in >> branch percentages, $cfailed in return percentages, $ifailed in >> intermediate format" >> } else { >> pass "$testname gcov" >> clean-gcov $testcase