1*c87b03e5Sespie /* Gcov.c: prepend line execution counts and branch probabilities to a
2*c87b03e5Sespie source file.
3*c87b03e5Sespie Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
4*c87b03e5Sespie 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
5*c87b03e5Sespie Contributed by James E. Wilson of Cygnus Support.
6*c87b03e5Sespie Mangled by Bob Manson of Cygnus Support.
7*c87b03e5Sespie
8*c87b03e5Sespie Gcov is free software; you can redistribute it and/or modify
9*c87b03e5Sespie it under the terms of the GNU General Public License as published by
10*c87b03e5Sespie the Free Software Foundation; either version 2, or (at your option)
11*c87b03e5Sespie any later version.
12*c87b03e5Sespie
13*c87b03e5Sespie Gcov is distributed in the hope that it will be useful,
14*c87b03e5Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
15*c87b03e5Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*c87b03e5Sespie GNU General Public License for more details.
17*c87b03e5Sespie
18*c87b03e5Sespie You should have received a copy of the GNU General Public License
19*c87b03e5Sespie along with Gcov; see the file COPYING. If not, write to
20*c87b03e5Sespie the Free Software Foundation, 59 Temple Place - Suite 330,
21*c87b03e5Sespie Boston, MA 02111-1307, USA. */
22*c87b03e5Sespie
23*c87b03e5Sespie /* ??? The code in final.c that produces the struct bb assumes that there is
24*c87b03e5Sespie no padding between the fields. This is not necessary true. The current
25*c87b03e5Sespie code can only be trusted if longs and pointers are the same size. */
26*c87b03e5Sespie
27*c87b03e5Sespie /* ??? No need to print an execution count on every line, could just print
28*c87b03e5Sespie it on the first line of each block, and only print it on a subsequent
29*c87b03e5Sespie line in the same block if the count changes. */
30*c87b03e5Sespie
31*c87b03e5Sespie /* ??? Print a list of the ten blocks with the highest execution counts,
32*c87b03e5Sespie and list the line numbers corresponding to those blocks. Also, perhaps
33*c87b03e5Sespie list the line numbers with the highest execution counts, only printing
34*c87b03e5Sespie the first if there are several which are all listed in the same block. */
35*c87b03e5Sespie
36*c87b03e5Sespie /* ??? Should have an option to print the number of basic blocks, and the
37*c87b03e5Sespie percent of them that are covered. */
38*c87b03e5Sespie
39*c87b03e5Sespie /* ??? Does not correctly handle the case where two .bb files refer to the
40*c87b03e5Sespie same included source file. For example, if one has a short file containing
41*c87b03e5Sespie only inline functions, which is then included in two other files, then
42*c87b03e5Sespie there will be two .bb files which refer to the include file, but there
43*c87b03e5Sespie is no way to get the total execution counts for the included file, can
44*c87b03e5Sespie only get execution counts for one or the other of the including files. */
45*c87b03e5Sespie
46*c87b03e5Sespie #include "config.h"
47*c87b03e5Sespie #include "system.h"
48*c87b03e5Sespie #include "intl.h"
49*c87b03e5Sespie #include "version.h"
50*c87b03e5Sespie #undef abort
51*c87b03e5Sespie
52*c87b03e5Sespie #include <getopt.h>
53*c87b03e5Sespie
54*c87b03e5Sespie typedef HOST_WIDEST_INT gcov_type;
55*c87b03e5Sespie #include "gcov-io.h"
56*c87b03e5Sespie
57*c87b03e5Sespie /* The .bb file format consists of several lists of 4-byte integers
58*c87b03e5Sespie which are the line numbers of each basic block in the file. Each
59*c87b03e5Sespie list is terminated by a zero. These lists correspond to the basic
60*c87b03e5Sespie blocks in the reconstructed program flow graph.
61*c87b03e5Sespie
62*c87b03e5Sespie A line number of -1 indicates that a source file name (padded to a
63*c87b03e5Sespie long boundary) follows. The padded file name is followed by
64*c87b03e5Sespie another -1 to make it easy to scan past file names. A -2 indicates
65*c87b03e5Sespie that a function name (padded to a long boundary) follows; the name
66*c87b03e5Sespie is followed by another -2 to make it easy to scan past the function
67*c87b03e5Sespie name.
68*c87b03e5Sespie
69*c87b03e5Sespie The .bbg file contains enough info to enable gcov to reconstruct the
70*c87b03e5Sespie program flow graph. The first word is the number of basic blocks,
71*c87b03e5Sespie the second word is the number of arcs, followed by the list of arcs
72*c87b03e5Sespie (source bb, dest bb pairs), then a -1, then the number of instrumented
73*c87b03e5Sespie arcs followed by the instrumented arcs, followed by another -1. This
74*c87b03e5Sespie is repeated for each function.
75*c87b03e5Sespie
76*c87b03e5Sespie The .da file contains the execution count for each instrumented branch.
77*c87b03e5Sespie
78*c87b03e5Sespie The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
79*c87b03e5Sespie and the .da files are created when an executable compiled with
80*c87b03e5Sespie -fprofile-arcs is run. */
81*c87b03e5Sespie
82*c87b03e5Sespie /* The functions in this file for creating and solution program flow graphs
83*c87b03e5Sespie are very similar to functions in the gcc source file profile.c. */
84*c87b03e5Sespie
85*c87b03e5Sespie /* This is the size of the buffer used to read in source file lines. */
86*c87b03e5Sespie
87*c87b03e5Sespie #define STRING_SIZE 200
88*c87b03e5Sespie
89*c87b03e5Sespie /* One copy of this structure is created for each source file mentioned in the
90*c87b03e5Sespie .bb file. */
91*c87b03e5Sespie
92*c87b03e5Sespie struct sourcefile
93*c87b03e5Sespie {
94*c87b03e5Sespie char *name;
95*c87b03e5Sespie int maxlineno;
96*c87b03e5Sespie struct sourcefile *next;
97*c87b03e5Sespie };
98*c87b03e5Sespie
99*c87b03e5Sespie /* This points to the head of the sourcefile structure list. */
100*c87b03e5Sespie
101*c87b03e5Sespie struct sourcefile *sources;
102*c87b03e5Sespie
103*c87b03e5Sespie /* One of these is dynamically created whenever we identify an arc in the
104*c87b03e5Sespie function. */
105*c87b03e5Sespie
106*c87b03e5Sespie struct adj_list
107*c87b03e5Sespie {
108*c87b03e5Sespie int source;
109*c87b03e5Sespie int target;
110*c87b03e5Sespie gcov_type arc_count;
111*c87b03e5Sespie unsigned int count_valid : 1;
112*c87b03e5Sespie unsigned int on_tree : 1;
113*c87b03e5Sespie unsigned int fake : 1;
114*c87b03e5Sespie unsigned int fall_through : 1;
115*c87b03e5Sespie #if 0
116*c87b03e5Sespie /* Not needed for gcov, but defined in profile.c. */
117*c87b03e5Sespie rtx branch_insn;
118*c87b03e5Sespie #endif
119*c87b03e5Sespie struct adj_list *pred_next;
120*c87b03e5Sespie struct adj_list *succ_next;
121*c87b03e5Sespie };
122*c87b03e5Sespie
123*c87b03e5Sespie /* Count the number of basic blocks, and create an array of these structures,
124*c87b03e5Sespie one for each bb in the function. */
125*c87b03e5Sespie
126*c87b03e5Sespie struct bb_info
127*c87b03e5Sespie {
128*c87b03e5Sespie struct adj_list *succ;
129*c87b03e5Sespie struct adj_list *pred;
130*c87b03e5Sespie gcov_type succ_count;
131*c87b03e5Sespie gcov_type pred_count;
132*c87b03e5Sespie gcov_type exec_count;
133*c87b03e5Sespie unsigned int count_valid : 1;
134*c87b03e5Sespie unsigned int on_tree : 1;
135*c87b03e5Sespie #if 0
136*c87b03e5Sespie /* Not needed for gcov, but defined in profile.c. */
137*c87b03e5Sespie rtx first_insn;
138*c87b03e5Sespie #endif
139*c87b03e5Sespie };
140*c87b03e5Sespie
141*c87b03e5Sespie /* When outputting branch probabilities, one of these structures is created
142*c87b03e5Sespie for each branch/call. */
143*c87b03e5Sespie
144*c87b03e5Sespie struct arcdata
145*c87b03e5Sespie {
146*c87b03e5Sespie gcov_type hits;
147*c87b03e5Sespie gcov_type total;
148*c87b03e5Sespie int call_insn;
149*c87b03e5Sespie struct arcdata *next;
150*c87b03e5Sespie };
151*c87b03e5Sespie
152*c87b03e5Sespie /* Used to save the list of bb_graphs, one per function. */
153*c87b03e5Sespie
154*c87b03e5Sespie struct bb_info_list
155*c87b03e5Sespie {
156*c87b03e5Sespie /* Indexed by block number, holds the basic block graph for one function. */
157*c87b03e5Sespie struct bb_info *bb_graph;
158*c87b03e5Sespie int num_blocks;
159*c87b03e5Sespie struct bb_info_list *next;
160*c87b03e5Sespie };
161*c87b03e5Sespie
162*c87b03e5Sespie /* Used to hold information about each line. */
163*c87b03e5Sespie struct line_info
164*c87b03e5Sespie {
165*c87b03e5Sespie gcov_type count; /* execution count */
166*c87b03e5Sespie struct arcdata *branches; /* list of branch probabilities for line. */
167*c87b03e5Sespie unsigned exists : 1; /* has code associated with it. */
168*c87b03e5Sespie };
169*c87b03e5Sespie
170*c87b03e5Sespie struct coverage
171*c87b03e5Sespie {
172*c87b03e5Sespie int lines;
173*c87b03e5Sespie int lines_executed;
174*c87b03e5Sespie
175*c87b03e5Sespie int branches;
176*c87b03e5Sespie int branches_executed;
177*c87b03e5Sespie int branches_taken;
178*c87b03e5Sespie
179*c87b03e5Sespie int calls;
180*c87b03e5Sespie int calls_executed;
181*c87b03e5Sespie
182*c87b03e5Sespie char *name;
183*c87b03e5Sespie };
184*c87b03e5Sespie
185*c87b03e5Sespie /* Holds a list of function basic block graphs. */
186*c87b03e5Sespie
187*c87b03e5Sespie static struct bb_info_list *bb_graph_list = 0;
188*c87b03e5Sespie
189*c87b03e5Sespie /* Modification time of data files. */
190*c87b03e5Sespie
191*c87b03e5Sespie static time_t bb_file_time;
192*c87b03e5Sespie
193*c87b03e5Sespie /* Name and file pointer of the input file for the basic block graph. */
194*c87b03e5Sespie
195*c87b03e5Sespie static char *bbg_file_name;
196*c87b03e5Sespie static FILE *bbg_file;
197*c87b03e5Sespie
198*c87b03e5Sespie /* Name and file pointer of the input file for the arc count data. */
199*c87b03e5Sespie
200*c87b03e5Sespie static char *da_file_name;
201*c87b03e5Sespie static FILE *da_file;
202*c87b03e5Sespie
203*c87b03e5Sespie /* Name and file pointer of the input file for the basic block line counts. */
204*c87b03e5Sespie
205*c87b03e5Sespie static char *bb_file_name;
206*c87b03e5Sespie static FILE *bb_file;
207*c87b03e5Sespie
208*c87b03e5Sespie /* Holds the entire contents of the bb_file read into memory. */
209*c87b03e5Sespie
210*c87b03e5Sespie static char *bb_data;
211*c87b03e5Sespie
212*c87b03e5Sespie /* Size of bb_data array in longs. */
213*c87b03e5Sespie
214*c87b03e5Sespie static long bb_data_size;
215*c87b03e5Sespie
216*c87b03e5Sespie /* Name of the file mentioned on the command line. */
217*c87b03e5Sespie
218*c87b03e5Sespie static char *input_file_name = 0;
219*c87b03e5Sespie
220*c87b03e5Sespie /* Output branch probabilities if true. */
221*c87b03e5Sespie
222*c87b03e5Sespie static int output_branch_probs = 0;
223*c87b03e5Sespie
224*c87b03e5Sespie /* Output a gcov file if this is true. This is on by default, and can
225*c87b03e5Sespie be turned off by the -n option. */
226*c87b03e5Sespie
227*c87b03e5Sespie static int output_gcov_file = 1;
228*c87b03e5Sespie
229*c87b03e5Sespie /* For included files, make the gcov output file name include the name of
230*c87b03e5Sespie the input source file. For example, if x.h is included in a.c, then the
231*c87b03e5Sespie output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
232*c87b03e5Sespie when a single source file is specified. */
233*c87b03e5Sespie
234*c87b03e5Sespie static int output_long_names = 0;
235*c87b03e5Sespie
236*c87b03e5Sespie /* Output summary info for each function. */
237*c87b03e5Sespie
238*c87b03e5Sespie static int output_function_summary = 0;
239*c87b03e5Sespie
240*c87b03e5Sespie /* Object directory file prefix. This is the directory/file
241*c87b03e5Sespie where .bb and .bbg files are looked for, if nonzero. */
242*c87b03e5Sespie
243*c87b03e5Sespie static char *object_directory = 0;
244*c87b03e5Sespie
245*c87b03e5Sespie /* Preserve all pathname components. Needed when object files and
246*c87b03e5Sespie source files are in subdirectories. */
247*c87b03e5Sespie static int preserve_paths = 0;
248*c87b03e5Sespie
249*c87b03e5Sespie /* Output the number of times a branch was taken as opposed to the percentage
250*c87b03e5Sespie of times it was taken. Turned on by the -c option */
251*c87b03e5Sespie
252*c87b03e5Sespie static int output_branch_counts = 0;
253*c87b03e5Sespie
254*c87b03e5Sespie /* Forward declarations. */
255*c87b03e5Sespie static void process_args PARAMS ((int, char **));
256*c87b03e5Sespie static void open_files PARAMS ((void));
257*c87b03e5Sespie static void read_files PARAMS ((void));
258*c87b03e5Sespie static void scan_for_source_files PARAMS ((void));
259*c87b03e5Sespie static void output_data PARAMS ((struct sourcefile *));
260*c87b03e5Sespie static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
261*c87b03e5Sespie static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
262*c87b03e5Sespie static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
263*c87b03e5Sespie static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
264*c87b03e5Sespie static gcov_type *read_profile PARAMS ((char *, long, int));
265*c87b03e5Sespie static void create_program_flow_graph PARAMS ((struct bb_info_list *));
266*c87b03e5Sespie static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
267*c87b03e5Sespie static void accumulate_branch_counts PARAMS ((struct coverage *,
268*c87b03e5Sespie struct arcdata *));
269*c87b03e5Sespie static void calculate_branch_probs PARAMS ((struct bb_info *,
270*c87b03e5Sespie struct line_info *,
271*c87b03e5Sespie struct coverage *));
272*c87b03e5Sespie static void function_summary PARAMS ((struct coverage *, const char *));
273*c87b03e5Sespie static void init_line_info PARAMS ((struct line_info *,
274*c87b03e5Sespie struct coverage *, long));
275*c87b03e5Sespie static void output_line_info PARAMS ((FILE *, const struct line_info *,
276*c87b03e5Sespie const struct coverage *, long));
277*c87b03e5Sespie static char *make_gcov_file_name PARAMS ((char *));
278*c87b03e5Sespie static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
279*c87b03e5Sespie int));
280*c87b03e5Sespie
281*c87b03e5Sespie extern int main PARAMS ((int, char **));
282*c87b03e5Sespie
283*c87b03e5Sespie int
main(argc,argv)284*c87b03e5Sespie main (argc, argv)
285*c87b03e5Sespie int argc;
286*c87b03e5Sespie char **argv;
287*c87b03e5Sespie {
288*c87b03e5Sespie struct sourcefile *s_ptr;
289*c87b03e5Sespie
290*c87b03e5Sespie gcc_init_libintl ();
291*c87b03e5Sespie
292*c87b03e5Sespie process_args (argc, argv);
293*c87b03e5Sespie
294*c87b03e5Sespie open_files ();
295*c87b03e5Sespie
296*c87b03e5Sespie read_files ();
297*c87b03e5Sespie
298*c87b03e5Sespie scan_for_source_files ();
299*c87b03e5Sespie
300*c87b03e5Sespie for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
301*c87b03e5Sespie output_data (s_ptr);
302*c87b03e5Sespie
303*c87b03e5Sespie return 0;
304*c87b03e5Sespie }
305*c87b03e5Sespie
306*c87b03e5Sespie static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
307*c87b03e5Sespie static void
fnotice(FILE * file,const char * msgid,...)308*c87b03e5Sespie fnotice VPARAMS ((FILE *file, const char *msgid, ...))
309*c87b03e5Sespie {
310*c87b03e5Sespie VA_OPEN (ap, msgid);
311*c87b03e5Sespie VA_FIXEDARG (ap, FILE *, file);
312*c87b03e5Sespie VA_FIXEDARG (ap, const char *, msgid);
313*c87b03e5Sespie
314*c87b03e5Sespie vfprintf (file, _(msgid), ap);
315*c87b03e5Sespie VA_CLOSE (ap);
316*c87b03e5Sespie }
317*c87b03e5Sespie
318*c87b03e5Sespie /* More 'friendly' abort that prints the line and file.
319*c87b03e5Sespie config.h can #define abort fancy_abort if you like that sort of thing. */
320*c87b03e5Sespie extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
321*c87b03e5Sespie
322*c87b03e5Sespie void
fancy_abort()323*c87b03e5Sespie fancy_abort ()
324*c87b03e5Sespie {
325*c87b03e5Sespie fnotice (stderr, "Internal gcov abort.\n");
326*c87b03e5Sespie exit (FATAL_EXIT_CODE);
327*c87b03e5Sespie }
328*c87b03e5Sespie
329*c87b03e5Sespie /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
330*c87b03e5Sespie otherwise the output of --help. */
331*c87b03e5Sespie
332*c87b03e5Sespie static void
print_usage(error_p)333*c87b03e5Sespie print_usage (error_p)
334*c87b03e5Sespie int error_p;
335*c87b03e5Sespie {
336*c87b03e5Sespie FILE *file = error_p ? stderr : stdout;
337*c87b03e5Sespie int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
338*c87b03e5Sespie fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
339*c87b03e5Sespie fnotice (file, "Print code coverage information.\n\n");
340*c87b03e5Sespie fnotice (file, " -h, --help Print this help, then exit\n");
341*c87b03e5Sespie fnotice (file, " -v, --version Print version number, then exit\n");
342*c87b03e5Sespie fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
343*c87b03e5Sespie fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
344*c87b03e5Sespie rather than percentages\n");
345*c87b03e5Sespie fnotice (file, " -n, --no-output Do not create an output file\n");
346*c87b03e5Sespie fnotice (file, " -l, --long-file-names Use long output file names for included\n\
347*c87b03e5Sespie source files\n");
348*c87b03e5Sespie fnotice (file, " -f, --function-summaries Output summaries for each function\n");
349*c87b03e5Sespie fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
350*c87b03e5Sespie fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
351*c87b03e5Sespie fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
352*c87b03e5Sespie bug_report_url);
353*c87b03e5Sespie exit (status);
354*c87b03e5Sespie }
355*c87b03e5Sespie
356*c87b03e5Sespie /* Print version information and exit. */
357*c87b03e5Sespie
358*c87b03e5Sespie static void
print_version()359*c87b03e5Sespie print_version ()
360*c87b03e5Sespie {
361*c87b03e5Sespie fnotice (stdout, "gcov (GCC) %s\n", version_string);
362*c87b03e5Sespie fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
363*c87b03e5Sespie fnotice (stdout,
364*c87b03e5Sespie "This is free software; see the source for copying conditions. There is NO\n\
365*c87b03e5Sespie warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
366*c87b03e5Sespie exit (SUCCESS_EXIT_CODE);
367*c87b03e5Sespie }
368*c87b03e5Sespie
369*c87b03e5Sespie static const struct option options[] =
370*c87b03e5Sespie {
371*c87b03e5Sespie { "help", no_argument, NULL, 'h' },
372*c87b03e5Sespie { "version", no_argument, NULL, 'v' },
373*c87b03e5Sespie { "branch-probabilities", no_argument, NULL, 'b' },
374*c87b03e5Sespie { "branch-counts", no_argument, NULL, 'c' },
375*c87b03e5Sespie { "no-output", no_argument, NULL, 'n' },
376*c87b03e5Sespie { "long-file-names", no_argument, NULL, 'l' },
377*c87b03e5Sespie { "function-summaries", no_argument, NULL, 'f' },
378*c87b03e5Sespie { "preserve-paths", no_argument, NULL, 'p' },
379*c87b03e5Sespie { "object-directory", required_argument, NULL, 'o' },
380*c87b03e5Sespie { "object-file", required_argument, NULL, 'o' },
381*c87b03e5Sespie };
382*c87b03e5Sespie
383*c87b03e5Sespie /* Parse the command line. */
384*c87b03e5Sespie
385*c87b03e5Sespie static void
process_args(argc,argv)386*c87b03e5Sespie process_args (argc, argv)
387*c87b03e5Sespie int argc;
388*c87b03e5Sespie char **argv;
389*c87b03e5Sespie {
390*c87b03e5Sespie int opt;
391*c87b03e5Sespie
392*c87b03e5Sespie while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
393*c87b03e5Sespie {
394*c87b03e5Sespie switch (opt)
395*c87b03e5Sespie {
396*c87b03e5Sespie case 'h':
397*c87b03e5Sespie print_usage (false);
398*c87b03e5Sespie /* print_usage will exit. */
399*c87b03e5Sespie case 'v':
400*c87b03e5Sespie print_version ();
401*c87b03e5Sespie /* print_version will exit. */
402*c87b03e5Sespie case 'b':
403*c87b03e5Sespie output_branch_probs = 1;
404*c87b03e5Sespie break;
405*c87b03e5Sespie case 'c':
406*c87b03e5Sespie output_branch_counts = 1;
407*c87b03e5Sespie break;
408*c87b03e5Sespie case 'n':
409*c87b03e5Sespie output_gcov_file = 0;
410*c87b03e5Sespie break;
411*c87b03e5Sespie case 'l':
412*c87b03e5Sespie output_long_names = 1;
413*c87b03e5Sespie break;
414*c87b03e5Sespie case 'f':
415*c87b03e5Sespie output_function_summary = 1;
416*c87b03e5Sespie break;
417*c87b03e5Sespie case 'o':
418*c87b03e5Sespie object_directory = optarg;
419*c87b03e5Sespie break;
420*c87b03e5Sespie case 'p':
421*c87b03e5Sespie preserve_paths = 1;
422*c87b03e5Sespie break;
423*c87b03e5Sespie default:
424*c87b03e5Sespie print_usage (true);
425*c87b03e5Sespie /* print_usage will exit. */
426*c87b03e5Sespie }
427*c87b03e5Sespie }
428*c87b03e5Sespie
429*c87b03e5Sespie if (optind != argc - 1)
430*c87b03e5Sespie print_usage (true);
431*c87b03e5Sespie
432*c87b03e5Sespie input_file_name = argv[optind];
433*c87b03e5Sespie }
434*c87b03e5Sespie
435*c87b03e5Sespie
436*c87b03e5Sespie /* Find and open the .bb, .da, and .bbg files. If OBJECT_DIRECTORY is
437*c87b03e5Sespie not specified, these are looked for in the current directory, and
438*c87b03e5Sespie named from the basename of the input_file_name sans extension. If
439*c87b03e5Sespie OBJECT_DIRECTORY is specified and is a directory, the files are in
440*c87b03e5Sespie that directory, but named from the basename of the input_file_name,
441*c87b03e5Sespie sans extension. Otherwise OBJECT_DIRECTORY is taken to be the name
442*c87b03e5Sespie of the object *file*, and the data files are named from that. */
443*c87b03e5Sespie
444*c87b03e5Sespie static void
open_files()445*c87b03e5Sespie open_files ()
446*c87b03e5Sespie {
447*c87b03e5Sespie char *cptr;
448*c87b03e5Sespie char *name;
449*c87b03e5Sespie int length = strlen (input_file_name);
450*c87b03e5Sespie int base;
451*c87b03e5Sespie
452*c87b03e5Sespie if (object_directory && object_directory[0])
453*c87b03e5Sespie {
454*c87b03e5Sespie struct stat status;
455*c87b03e5Sespie
456*c87b03e5Sespie length += strlen (object_directory) + 2;
457*c87b03e5Sespie name = xmalloc (length);
458*c87b03e5Sespie name[0] = 0;
459*c87b03e5Sespie
460*c87b03e5Sespie base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
461*c87b03e5Sespie strcat (name, object_directory);
462*c87b03e5Sespie if (base && name[strlen (name) - 1] != '/')
463*c87b03e5Sespie strcat (name, "/");
464*c87b03e5Sespie }
465*c87b03e5Sespie else
466*c87b03e5Sespie {
467*c87b03e5Sespie name = xmalloc (length + 1);
468*c87b03e5Sespie name[0] = 0;
469*c87b03e5Sespie base = 1;
470*c87b03e5Sespie }
471*c87b03e5Sespie
472*c87b03e5Sespie if (base)
473*c87b03e5Sespie {
474*c87b03e5Sespie /* Append source file name */
475*c87b03e5Sespie cptr = strrchr (input_file_name, '/');
476*c87b03e5Sespie cptr = cptr ? cptr + 1 : input_file_name;
477*c87b03e5Sespie
478*c87b03e5Sespie strcat (name, cptr);
479*c87b03e5Sespie }
480*c87b03e5Sespie /* Remove the extension. */
481*c87b03e5Sespie cptr = strrchr (name, '.');
482*c87b03e5Sespie if (cptr)
483*c87b03e5Sespie *cptr = 0;
484*c87b03e5Sespie
485*c87b03e5Sespie length = strlen (name);
486*c87b03e5Sespie da_file_name = xmalloc (length + 4);
487*c87b03e5Sespie bb_file_name = xmalloc (length + 4);
488*c87b03e5Sespie bbg_file_name = xmalloc (length + 5);
489*c87b03e5Sespie
490*c87b03e5Sespie strcpy (da_file_name, name);
491*c87b03e5Sespie strcpy (bb_file_name, name);
492*c87b03e5Sespie strcpy (bbg_file_name, name);
493*c87b03e5Sespie strcpy (da_file_name + length, ".da");
494*c87b03e5Sespie strcpy (bb_file_name + length, ".bb");
495*c87b03e5Sespie strcpy (bbg_file_name + length, ".bbg");
496*c87b03e5Sespie
497*c87b03e5Sespie bb_file = fopen (bb_file_name, "rb");
498*c87b03e5Sespie if (bb_file == NULL)
499*c87b03e5Sespie {
500*c87b03e5Sespie fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
501*c87b03e5Sespie exit (FATAL_EXIT_CODE);
502*c87b03e5Sespie }
503*c87b03e5Sespie
504*c87b03e5Sespie bbg_file = fopen (bbg_file_name, "rb");
505*c87b03e5Sespie if (bbg_file == NULL)
506*c87b03e5Sespie {
507*c87b03e5Sespie fnotice (stderr, "Could not open program flow graph file %s.\n",
508*c87b03e5Sespie bbg_file_name);
509*c87b03e5Sespie exit (FATAL_EXIT_CODE);
510*c87b03e5Sespie }
511*c87b03e5Sespie
512*c87b03e5Sespie {
513*c87b03e5Sespie struct stat status;
514*c87b03e5Sespie
515*c87b03e5Sespie if (!fstat (fileno (bb_file), &status))
516*c87b03e5Sespie bb_file_time = status.st_mtime;
517*c87b03e5Sespie }
518*c87b03e5Sespie
519*c87b03e5Sespie /* If none of the functions in the file were executed, then there won't
520*c87b03e5Sespie be a .da file. Just assume that all counts are zero in this case. */
521*c87b03e5Sespie da_file = fopen (da_file_name, "rb");
522*c87b03e5Sespie if (da_file == NULL)
523*c87b03e5Sespie {
524*c87b03e5Sespie fnotice (stderr, "Could not open data file %s.\n", da_file_name);
525*c87b03e5Sespie fnotice (stderr, "Assuming that all execution counts are zero.\n");
526*c87b03e5Sespie }
527*c87b03e5Sespie
528*c87b03e5Sespie /* Check for empty .bbg file. This indicates that there is no executable
529*c87b03e5Sespie code in this source file. */
530*c87b03e5Sespie /* Set the EOF condition if at the end of file. */
531*c87b03e5Sespie ungetc (getc (bbg_file), bbg_file);
532*c87b03e5Sespie if (feof (bbg_file))
533*c87b03e5Sespie {
534*c87b03e5Sespie fnotice (stderr, "No executable code associated with file %s.\n",
535*c87b03e5Sespie input_file_name);
536*c87b03e5Sespie exit (FATAL_EXIT_CODE);
537*c87b03e5Sespie }
538*c87b03e5Sespie }
539*c87b03e5Sespie
540*c87b03e5Sespie /* Initialize a new arc. */
541*c87b03e5Sespie
542*c87b03e5Sespie static void
init_arc(arcptr,source,target,bb_graph)543*c87b03e5Sespie init_arc (arcptr, source, target, bb_graph)
544*c87b03e5Sespie struct adj_list *arcptr;
545*c87b03e5Sespie int source, target;
546*c87b03e5Sespie struct bb_info *bb_graph;
547*c87b03e5Sespie {
548*c87b03e5Sespie arcptr->target = target;
549*c87b03e5Sespie arcptr->source = source;
550*c87b03e5Sespie
551*c87b03e5Sespie arcptr->arc_count = 0;
552*c87b03e5Sespie arcptr->count_valid = 0;
553*c87b03e5Sespie arcptr->on_tree = 0;
554*c87b03e5Sespie arcptr->fake = 0;
555*c87b03e5Sespie arcptr->fall_through = 0;
556*c87b03e5Sespie
557*c87b03e5Sespie arcptr->succ_next = bb_graph[source].succ;
558*c87b03e5Sespie bb_graph[source].succ = arcptr;
559*c87b03e5Sespie bb_graph[source].succ_count++;
560*c87b03e5Sespie
561*c87b03e5Sespie arcptr->pred_next = bb_graph[target].pred;
562*c87b03e5Sespie bb_graph[target].pred = arcptr;
563*c87b03e5Sespie bb_graph[target].pred_count++;
564*c87b03e5Sespie }
565*c87b03e5Sespie
566*c87b03e5Sespie /* Reverse the arcs on an arc list. */
567*c87b03e5Sespie
568*c87b03e5Sespie static struct adj_list *
reverse_arcs(arcptr)569*c87b03e5Sespie reverse_arcs (arcptr)
570*c87b03e5Sespie struct adj_list *arcptr;
571*c87b03e5Sespie {
572*c87b03e5Sespie struct adj_list *prev = 0;
573*c87b03e5Sespie struct adj_list *next;
574*c87b03e5Sespie
575*c87b03e5Sespie for ( ; arcptr; arcptr = next)
576*c87b03e5Sespie {
577*c87b03e5Sespie next = arcptr->succ_next;
578*c87b03e5Sespie arcptr->succ_next = prev;
579*c87b03e5Sespie prev = arcptr;
580*c87b03e5Sespie }
581*c87b03e5Sespie
582*c87b03e5Sespie return prev;
583*c87b03e5Sespie }
584*c87b03e5Sespie
585*c87b03e5Sespie /* Reads profiles from the .da file and compute a hybrid profile. */
586*c87b03e5Sespie
587*c87b03e5Sespie static gcov_type *
read_profile(function_name,cfg_checksum,instr_arcs)588*c87b03e5Sespie read_profile (function_name, cfg_checksum, instr_arcs)
589*c87b03e5Sespie char *function_name;
590*c87b03e5Sespie long cfg_checksum;
591*c87b03e5Sespie int instr_arcs;
592*c87b03e5Sespie {
593*c87b03e5Sespie int i;
594*c87b03e5Sespie int okay = 1;
595*c87b03e5Sespie gcov_type *profile;
596*c87b03e5Sespie char *function_name_buffer;
597*c87b03e5Sespie int function_name_buffer_len;
598*c87b03e5Sespie
599*c87b03e5Sespie profile = xmalloc (sizeof (gcov_type) * instr_arcs);
600*c87b03e5Sespie function_name_buffer_len = strlen (function_name) + 1;
601*c87b03e5Sespie function_name_buffer = xmalloc (function_name_buffer_len + 1);
602*c87b03e5Sespie
603*c87b03e5Sespie for (i = 0; i < instr_arcs; i++)
604*c87b03e5Sespie profile[i] = 0;
605*c87b03e5Sespie
606*c87b03e5Sespie if (!da_file)
607*c87b03e5Sespie return profile;
608*c87b03e5Sespie
609*c87b03e5Sespie rewind (da_file);
610*c87b03e5Sespie while (1)
611*c87b03e5Sespie {
612*c87b03e5Sespie long magic, extra_bytes;
613*c87b03e5Sespie long func_count;
614*c87b03e5Sespie int i;
615*c87b03e5Sespie
616*c87b03e5Sespie if (__read_long (&magic, da_file, 4) != 0)
617*c87b03e5Sespie break;
618*c87b03e5Sespie
619*c87b03e5Sespie if (magic != -123)
620*c87b03e5Sespie {
621*c87b03e5Sespie okay = 0;
622*c87b03e5Sespie break;
623*c87b03e5Sespie }
624*c87b03e5Sespie
625*c87b03e5Sespie if (__read_long (&func_count, da_file, 4) != 0)
626*c87b03e5Sespie {
627*c87b03e5Sespie okay = 0;
628*c87b03e5Sespie break;
629*c87b03e5Sespie }
630*c87b03e5Sespie
631*c87b03e5Sespie if (__read_long (&extra_bytes, da_file, 4) != 0)
632*c87b03e5Sespie {
633*c87b03e5Sespie okay = 0;
634*c87b03e5Sespie break;
635*c87b03e5Sespie }
636*c87b03e5Sespie
637*c87b03e5Sespie /* skip extra data emited by __bb_exit_func. */
638*c87b03e5Sespie fseek (da_file, extra_bytes, SEEK_CUR);
639*c87b03e5Sespie
640*c87b03e5Sespie for (i = 0; i < func_count; i++)
641*c87b03e5Sespie {
642*c87b03e5Sespie long arc_count;
643*c87b03e5Sespie long chksum;
644*c87b03e5Sespie int j;
645*c87b03e5Sespie
646*c87b03e5Sespie if (__read_gcov_string
647*c87b03e5Sespie (function_name_buffer, function_name_buffer_len, da_file,
648*c87b03e5Sespie -1) != 0)
649*c87b03e5Sespie {
650*c87b03e5Sespie okay = 0;
651*c87b03e5Sespie break;
652*c87b03e5Sespie }
653*c87b03e5Sespie
654*c87b03e5Sespie if (__read_long (&chksum, da_file, 4) != 0)
655*c87b03e5Sespie {
656*c87b03e5Sespie okay = 0;
657*c87b03e5Sespie break;
658*c87b03e5Sespie }
659*c87b03e5Sespie
660*c87b03e5Sespie if (__read_long (&arc_count, da_file, 4) != 0)
661*c87b03e5Sespie {
662*c87b03e5Sespie okay = 0;
663*c87b03e5Sespie break;
664*c87b03e5Sespie }
665*c87b03e5Sespie
666*c87b03e5Sespie if (strcmp (function_name_buffer, function_name) != 0
667*c87b03e5Sespie || arc_count != instr_arcs || chksum != cfg_checksum)
668*c87b03e5Sespie {
669*c87b03e5Sespie /* skip */
670*c87b03e5Sespie if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
671*c87b03e5Sespie {
672*c87b03e5Sespie okay = 0;
673*c87b03e5Sespie break;
674*c87b03e5Sespie }
675*c87b03e5Sespie }
676*c87b03e5Sespie else
677*c87b03e5Sespie {
678*c87b03e5Sespie gcov_type tmp;
679*c87b03e5Sespie
680*c87b03e5Sespie for (j = 0; j < arc_count; j++)
681*c87b03e5Sespie if (__read_gcov_type (&tmp, da_file, 8) != 0)
682*c87b03e5Sespie {
683*c87b03e5Sespie okay = 0;
684*c87b03e5Sespie break;
685*c87b03e5Sespie }
686*c87b03e5Sespie else
687*c87b03e5Sespie {
688*c87b03e5Sespie profile[j] += tmp;
689*c87b03e5Sespie }
690*c87b03e5Sespie }
691*c87b03e5Sespie }
692*c87b03e5Sespie
693*c87b03e5Sespie if (!okay)
694*c87b03e5Sespie break;
695*c87b03e5Sespie
696*c87b03e5Sespie }
697*c87b03e5Sespie
698*c87b03e5Sespie free (function_name_buffer);
699*c87b03e5Sespie
700*c87b03e5Sespie if (!okay)
701*c87b03e5Sespie {
702*c87b03e5Sespie fprintf (stderr, ".da file corrupted!\n");
703*c87b03e5Sespie free (profile);
704*c87b03e5Sespie abort ();
705*c87b03e5Sespie }
706*c87b03e5Sespie
707*c87b03e5Sespie return profile;
708*c87b03e5Sespie }
709*c87b03e5Sespie
710*c87b03e5Sespie /* Construct the program flow graph from the .bbg file, and read in the data
711*c87b03e5Sespie in the .da file. */
712*c87b03e5Sespie
713*c87b03e5Sespie static void
create_program_flow_graph(bptr)714*c87b03e5Sespie create_program_flow_graph (bptr)
715*c87b03e5Sespie struct bb_info_list *bptr;
716*c87b03e5Sespie {
717*c87b03e5Sespie long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
718*c87b03e5Sespie int i;
719*c87b03e5Sespie struct adj_list *arcptr;
720*c87b03e5Sespie struct bb_info *bb_graph;
721*c87b03e5Sespie long cfg_checksum;
722*c87b03e5Sespie long instr_arcs = 0;
723*c87b03e5Sespie gcov_type *profile;
724*c87b03e5Sespie int profile_pos = 0;
725*c87b03e5Sespie char *function_name;
726*c87b03e5Sespie long function_name_len, tmp;
727*c87b03e5Sespie
728*c87b03e5Sespie /* Read function name. */
729*c87b03e5Sespie __read_long (&tmp, bbg_file, 4); /* ignore -1. */
730*c87b03e5Sespie __read_long (&function_name_len, bbg_file, 4);
731*c87b03e5Sespie function_name = xmalloc (function_name_len + 1);
732*c87b03e5Sespie fread (function_name, 1, function_name_len + 1, bbg_file);
733*c87b03e5Sespie
734*c87b03e5Sespie /* Skip padding. */
735*c87b03e5Sespie tmp = (function_name_len + 1) % 4;
736*c87b03e5Sespie
737*c87b03e5Sespie if (tmp)
738*c87b03e5Sespie fseek (bbg_file, 4 - tmp, SEEK_CUR);
739*c87b03e5Sespie
740*c87b03e5Sespie __read_long (&tmp, bbg_file, 4); /* ignore -1. */
741*c87b03e5Sespie
742*c87b03e5Sespie /* Read the cfg checksum. */
743*c87b03e5Sespie __read_long (&cfg_checksum, bbg_file, 4);
744*c87b03e5Sespie
745*c87b03e5Sespie /* Read the number of blocks. */
746*c87b03e5Sespie __read_long (&num_blocks, bbg_file, 4);
747*c87b03e5Sespie
748*c87b03e5Sespie /* Create an array of size bb number of bb_info structs. */
749*c87b03e5Sespie bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
750*c87b03e5Sespie
751*c87b03e5Sespie bptr->bb_graph = bb_graph;
752*c87b03e5Sespie bptr->num_blocks = num_blocks;
753*c87b03e5Sespie
754*c87b03e5Sespie /* Read and create each arc from the .bbg file. */
755*c87b03e5Sespie __read_long (&number_arcs, bbg_file, 4);
756*c87b03e5Sespie for (i = 0; i < num_blocks; i++)
757*c87b03e5Sespie {
758*c87b03e5Sespie int j;
759*c87b03e5Sespie
760*c87b03e5Sespie __read_long (&num_arcs_per_block, bbg_file, 4);
761*c87b03e5Sespie for (j = 0; j < num_arcs_per_block; j++)
762*c87b03e5Sespie {
763*c87b03e5Sespie if (number_arcs-- < 0)
764*c87b03e5Sespie abort ();
765*c87b03e5Sespie
766*c87b03e5Sespie src = i;
767*c87b03e5Sespie __read_long (&dest, bbg_file, 4);
768*c87b03e5Sespie
769*c87b03e5Sespie arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
770*c87b03e5Sespie init_arc (arcptr, src, dest, bb_graph);
771*c87b03e5Sespie
772*c87b03e5Sespie __read_long (&flag_bits, bbg_file, 4);
773*c87b03e5Sespie if (flag_bits & 0x1)
774*c87b03e5Sespie arcptr->on_tree++;
775*c87b03e5Sespie else
776*c87b03e5Sespie instr_arcs++;
777*c87b03e5Sespie arcptr->fake = !! (flag_bits & 0x2);
778*c87b03e5Sespie arcptr->fall_through = !! (flag_bits & 0x4);
779*c87b03e5Sespie }
780*c87b03e5Sespie }
781*c87b03e5Sespie
782*c87b03e5Sespie if (number_arcs)
783*c87b03e5Sespie abort ();
784*c87b03e5Sespie
785*c87b03e5Sespie /* Read and ignore the -1 separating the arc list from the arc list of the
786*c87b03e5Sespie next function. */
787*c87b03e5Sespie __read_long (&src, bbg_file, 4);
788*c87b03e5Sespie if (src != -1)
789*c87b03e5Sespie abort ();
790*c87b03e5Sespie
791*c87b03e5Sespie /* Must reverse the order of all succ arcs, to ensure that they match
792*c87b03e5Sespie the order of the data in the .da file. */
793*c87b03e5Sespie
794*c87b03e5Sespie for (i = 0; i < num_blocks; i++)
795*c87b03e5Sespie if (bb_graph[i].succ)
796*c87b03e5Sespie bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
797*c87b03e5Sespie
798*c87b03e5Sespie /* Read profile from the .da file. */
799*c87b03e5Sespie
800*c87b03e5Sespie profile = read_profile (function_name, cfg_checksum, instr_arcs);
801*c87b03e5Sespie
802*c87b03e5Sespie /* For each arc not on the spanning tree, set its execution count from
803*c87b03e5Sespie the .da file. */
804*c87b03e5Sespie
805*c87b03e5Sespie /* The first count in the .da file is the number of times that the function
806*c87b03e5Sespie was entered. This is the exec_count for block zero. */
807*c87b03e5Sespie
808*c87b03e5Sespie /* This duplicates code in branch_prob in profile.c. */
809*c87b03e5Sespie
810*c87b03e5Sespie for (i = 0; i < num_blocks; i++)
811*c87b03e5Sespie for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
812*c87b03e5Sespie if (! arcptr->on_tree)
813*c87b03e5Sespie {
814*c87b03e5Sespie arcptr->arc_count = profile[profile_pos++];
815*c87b03e5Sespie arcptr->count_valid = 1;
816*c87b03e5Sespie bb_graph[i].succ_count--;
817*c87b03e5Sespie bb_graph[arcptr->target].pred_count--;
818*c87b03e5Sespie }
819*c87b03e5Sespie free (profile);
820*c87b03e5Sespie free (function_name);
821*c87b03e5Sespie }
822*c87b03e5Sespie
823*c87b03e5Sespie static void
solve_program_flow_graph(bptr)824*c87b03e5Sespie solve_program_flow_graph (bptr)
825*c87b03e5Sespie struct bb_info_list *bptr;
826*c87b03e5Sespie {
827*c87b03e5Sespie int passes, changes;
828*c87b03e5Sespie gcov_type total;
829*c87b03e5Sespie int i;
830*c87b03e5Sespie struct adj_list *arcptr;
831*c87b03e5Sespie struct bb_info *bb_graph;
832*c87b03e5Sespie int num_blocks;
833*c87b03e5Sespie
834*c87b03e5Sespie num_blocks = bptr->num_blocks;
835*c87b03e5Sespie bb_graph = bptr->bb_graph;
836*c87b03e5Sespie
837*c87b03e5Sespie /* For every block in the file,
838*c87b03e5Sespie - if every exit/entrance arc has a known count, then set the block count
839*c87b03e5Sespie - if the block count is known, and every exit/entrance arc but one has
840*c87b03e5Sespie a known execution count, then set the count of the remaining arc
841*c87b03e5Sespie
842*c87b03e5Sespie As arc counts are set, decrement the succ/pred count, but don't delete
843*c87b03e5Sespie the arc, that way we can easily tell when all arcs are known, or only
844*c87b03e5Sespie one arc is unknown. */
845*c87b03e5Sespie
846*c87b03e5Sespie /* The order that the basic blocks are iterated through is important.
847*c87b03e5Sespie Since the code that finds spanning trees starts with block 0, low numbered
848*c87b03e5Sespie arcs are put on the spanning tree in preference to high numbered arcs.
849*c87b03e5Sespie Hence, most instrumented arcs are at the end. Graph solving works much
850*c87b03e5Sespie faster if we propagate numbers from the end to the start.
851*c87b03e5Sespie
852*c87b03e5Sespie This takes an average of slightly more than 3 passes. */
853*c87b03e5Sespie
854*c87b03e5Sespie changes = 1;
855*c87b03e5Sespie passes = 0;
856*c87b03e5Sespie while (changes)
857*c87b03e5Sespie {
858*c87b03e5Sespie passes++;
859*c87b03e5Sespie changes = 0;
860*c87b03e5Sespie
861*c87b03e5Sespie for (i = num_blocks - 1; i >= 0; i--)
862*c87b03e5Sespie {
863*c87b03e5Sespie if (! bb_graph[i].count_valid)
864*c87b03e5Sespie {
865*c87b03e5Sespie if (bb_graph[i].succ_count == 0)
866*c87b03e5Sespie {
867*c87b03e5Sespie total = 0;
868*c87b03e5Sespie for (arcptr = bb_graph[i].succ; arcptr;
869*c87b03e5Sespie arcptr = arcptr->succ_next)
870*c87b03e5Sespie total += arcptr->arc_count;
871*c87b03e5Sespie bb_graph[i].exec_count = total;
872*c87b03e5Sespie bb_graph[i].count_valid = 1;
873*c87b03e5Sespie changes = 1;
874*c87b03e5Sespie }
875*c87b03e5Sespie else if (bb_graph[i].pred_count == 0)
876*c87b03e5Sespie {
877*c87b03e5Sespie total = 0;
878*c87b03e5Sespie for (arcptr = bb_graph[i].pred; arcptr;
879*c87b03e5Sespie arcptr = arcptr->pred_next)
880*c87b03e5Sespie total += arcptr->arc_count;
881*c87b03e5Sespie bb_graph[i].exec_count = total;
882*c87b03e5Sespie bb_graph[i].count_valid = 1;
883*c87b03e5Sespie changes = 1;
884*c87b03e5Sespie }
885*c87b03e5Sespie }
886*c87b03e5Sespie if (bb_graph[i].count_valid)
887*c87b03e5Sespie {
888*c87b03e5Sespie if (bb_graph[i].succ_count == 1)
889*c87b03e5Sespie {
890*c87b03e5Sespie total = 0;
891*c87b03e5Sespie /* One of the counts will be invalid, but it is zero,
892*c87b03e5Sespie so adding it in also doesn't hurt. */
893*c87b03e5Sespie for (arcptr = bb_graph[i].succ; arcptr;
894*c87b03e5Sespie arcptr = arcptr->succ_next)
895*c87b03e5Sespie total += arcptr->arc_count;
896*c87b03e5Sespie /* Calculate count for remaining arc by conservation. */
897*c87b03e5Sespie total = bb_graph[i].exec_count - total;
898*c87b03e5Sespie /* Search for the invalid arc, and set its count. */
899*c87b03e5Sespie for (arcptr = bb_graph[i].succ; arcptr;
900*c87b03e5Sespie arcptr = arcptr->succ_next)
901*c87b03e5Sespie if (! arcptr->count_valid)
902*c87b03e5Sespie break;
903*c87b03e5Sespie if (! arcptr)
904*c87b03e5Sespie abort ();
905*c87b03e5Sespie arcptr->count_valid = 1;
906*c87b03e5Sespie arcptr->arc_count = total;
907*c87b03e5Sespie bb_graph[i].succ_count--;
908*c87b03e5Sespie
909*c87b03e5Sespie bb_graph[arcptr->target].pred_count--;
910*c87b03e5Sespie changes = 1;
911*c87b03e5Sespie }
912*c87b03e5Sespie if (bb_graph[i].pred_count == 1)
913*c87b03e5Sespie {
914*c87b03e5Sespie total = 0;
915*c87b03e5Sespie /* One of the counts will be invalid, but it is zero,
916*c87b03e5Sespie so adding it in also doesn't hurt. */
917*c87b03e5Sespie for (arcptr = bb_graph[i].pred; arcptr;
918*c87b03e5Sespie arcptr = arcptr->pred_next)
919*c87b03e5Sespie total += arcptr->arc_count;
920*c87b03e5Sespie /* Calculate count for remaining arc by conservation. */
921*c87b03e5Sespie total = bb_graph[i].exec_count - total;
922*c87b03e5Sespie /* Search for the invalid arc, and set its count. */
923*c87b03e5Sespie for (arcptr = bb_graph[i].pred; arcptr;
924*c87b03e5Sespie arcptr = arcptr->pred_next)
925*c87b03e5Sespie if (! arcptr->count_valid)
926*c87b03e5Sespie break;
927*c87b03e5Sespie if (! arcptr)
928*c87b03e5Sespie abort ();
929*c87b03e5Sespie arcptr->count_valid = 1;
930*c87b03e5Sespie arcptr->arc_count = total;
931*c87b03e5Sespie bb_graph[i].pred_count--;
932*c87b03e5Sespie
933*c87b03e5Sespie bb_graph[arcptr->source].succ_count--;
934*c87b03e5Sespie changes = 1;
935*c87b03e5Sespie }
936*c87b03e5Sespie }
937*c87b03e5Sespie }
938*c87b03e5Sespie }
939*c87b03e5Sespie
940*c87b03e5Sespie /* If the graph has been correctly solved, every block will have a
941*c87b03e5Sespie succ and pred count of zero. */
942*c87b03e5Sespie for (i = 0; i < num_blocks; i++)
943*c87b03e5Sespie if (bb_graph[i].succ_count || bb_graph[i].pred_count)
944*c87b03e5Sespie abort ();
945*c87b03e5Sespie }
946*c87b03e5Sespie
947*c87b03e5Sespie
948*c87b03e5Sespie static void
read_files()949*c87b03e5Sespie read_files ()
950*c87b03e5Sespie {
951*c87b03e5Sespie struct stat buf;
952*c87b03e5Sespie struct bb_info_list *list_end = 0;
953*c87b03e5Sespie struct bb_info_list *b_ptr;
954*c87b03e5Sespie
955*c87b03e5Sespie while (! feof (bbg_file))
956*c87b03e5Sespie {
957*c87b03e5Sespie b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
958*c87b03e5Sespie
959*c87b03e5Sespie b_ptr->next = 0;
960*c87b03e5Sespie if (list_end)
961*c87b03e5Sespie list_end->next = b_ptr;
962*c87b03e5Sespie else
963*c87b03e5Sespie bb_graph_list = b_ptr;
964*c87b03e5Sespie list_end = b_ptr;
965*c87b03e5Sespie
966*c87b03e5Sespie /* Read in the data in the .bbg file and reconstruct the program flow
967*c87b03e5Sespie graph for one function. */
968*c87b03e5Sespie create_program_flow_graph (b_ptr);
969*c87b03e5Sespie
970*c87b03e5Sespie /* Set the EOF condition if at the end of file. */
971*c87b03e5Sespie ungetc (getc (bbg_file), bbg_file);
972*c87b03e5Sespie }
973*c87b03e5Sespie
974*c87b03e5Sespie /* Calculate all of the basic block execution counts and branch
975*c87b03e5Sespie taken probabilities. */
976*c87b03e5Sespie
977*c87b03e5Sespie for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
978*c87b03e5Sespie solve_program_flow_graph (b_ptr);
979*c87b03e5Sespie
980*c87b03e5Sespie /* Read in all of the data from the .bb file. This info will be accessed
981*c87b03e5Sespie sequentially twice. */
982*c87b03e5Sespie stat (bb_file_name, &buf);
983*c87b03e5Sespie bb_data_size = buf.st_size / 4;
984*c87b03e5Sespie
985*c87b03e5Sespie bb_data = (char *) xmalloc ((unsigned) buf.st_size);
986*c87b03e5Sespie fread (bb_data, sizeof (char), buf.st_size, bb_file);
987*c87b03e5Sespie
988*c87b03e5Sespie fclose (bb_file);
989*c87b03e5Sespie if (da_file)
990*c87b03e5Sespie fclose (da_file);
991*c87b03e5Sespie fclose (bbg_file);
992*c87b03e5Sespie }
993*c87b03e5Sespie
994*c87b03e5Sespie
995*c87b03e5Sespie /* Scan the data in the .bb file to find all source files referenced,
996*c87b03e5Sespie and the largest line number mentioned in each one. */
997*c87b03e5Sespie
998*c87b03e5Sespie static void
scan_for_source_files()999*c87b03e5Sespie scan_for_source_files ()
1000*c87b03e5Sespie {
1001*c87b03e5Sespie struct sourcefile *s_ptr = NULL;
1002*c87b03e5Sespie char *ptr;
1003*c87b03e5Sespie long count;
1004*c87b03e5Sespie long line_num;
1005*c87b03e5Sespie
1006*c87b03e5Sespie /* Search the bb_data to find:
1007*c87b03e5Sespie 1) The number of sources files contained herein, and
1008*c87b03e5Sespie 2) The largest line number for each source file. */
1009*c87b03e5Sespie
1010*c87b03e5Sespie ptr = bb_data;
1011*c87b03e5Sespie sources = 0;
1012*c87b03e5Sespie for (count = 0; count < bb_data_size; count++)
1013*c87b03e5Sespie {
1014*c87b03e5Sespie __fetch_long (&line_num, ptr, 4);
1015*c87b03e5Sespie ptr += 4;
1016*c87b03e5Sespie if (line_num == -1)
1017*c87b03e5Sespie {
1018*c87b03e5Sespie /* A source file name follows. Check to see if we already have
1019*c87b03e5Sespie a sourcefile structure for this file. */
1020*c87b03e5Sespie s_ptr = sources;
1021*c87b03e5Sespie while (s_ptr && strcmp (s_ptr->name, ptr))
1022*c87b03e5Sespie s_ptr = s_ptr->next;
1023*c87b03e5Sespie
1024*c87b03e5Sespie if (s_ptr == 0)
1025*c87b03e5Sespie {
1026*c87b03e5Sespie /* No sourcefile structure for this file name exists, create
1027*c87b03e5Sespie a new one, and append it to the front of the sources list. */
1028*c87b03e5Sespie s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
1029*c87b03e5Sespie s_ptr->name = xstrdup (ptr);
1030*c87b03e5Sespie s_ptr->maxlineno = 0;
1031*c87b03e5Sespie s_ptr->next = sources;
1032*c87b03e5Sespie sources = s_ptr;
1033*c87b03e5Sespie }
1034*c87b03e5Sespie
1035*c87b03e5Sespie /* Scan past the file name. */
1036*c87b03e5Sespie {
1037*c87b03e5Sespie long delim;
1038*c87b03e5Sespie do {
1039*c87b03e5Sespie count++;
1040*c87b03e5Sespie __fetch_long (&delim, ptr, 4);
1041*c87b03e5Sespie ptr += 4;
1042*c87b03e5Sespie } while (delim != line_num);
1043*c87b03e5Sespie }
1044*c87b03e5Sespie }
1045*c87b03e5Sespie else if (line_num == -2)
1046*c87b03e5Sespie {
1047*c87b03e5Sespie long delim;
1048*c87b03e5Sespie
1049*c87b03e5Sespie /* A function name follows. Ignore it. */
1050*c87b03e5Sespie do {
1051*c87b03e5Sespie count++;
1052*c87b03e5Sespie __fetch_long (&delim, ptr, 4);
1053*c87b03e5Sespie ptr += 4;
1054*c87b03e5Sespie } while (delim != line_num);
1055*c87b03e5Sespie }
1056*c87b03e5Sespie /* There will be a zero before the first file name, in which case s_ptr
1057*c87b03e5Sespie will still be uninitialized. So, only try to set the maxlineno
1058*c87b03e5Sespie field if line_num is nonzero. */
1059*c87b03e5Sespie else if (line_num > 0)
1060*c87b03e5Sespie {
1061*c87b03e5Sespie if (s_ptr->maxlineno <= line_num)
1062*c87b03e5Sespie s_ptr->maxlineno = line_num + 1;
1063*c87b03e5Sespie }
1064*c87b03e5Sespie else if (line_num < 0)
1065*c87b03e5Sespie {
1066*c87b03e5Sespie /* Don't know what this is, but it's garbage. */
1067*c87b03e5Sespie abort ();
1068*c87b03e5Sespie }
1069*c87b03e5Sespie }
1070*c87b03e5Sespie }
1071*c87b03e5Sespie
1072*c87b03e5Sespie
1073*c87b03e5Sespie /* Increment totals in FUNCTION according to arc A_PTR. */
1074*c87b03e5Sespie
1075*c87b03e5Sespie static void
accumulate_branch_counts(function,a_ptr)1076*c87b03e5Sespie accumulate_branch_counts (function, a_ptr)
1077*c87b03e5Sespie struct coverage *function;
1078*c87b03e5Sespie struct arcdata *a_ptr;
1079*c87b03e5Sespie {
1080*c87b03e5Sespie if (a_ptr->call_insn)
1081*c87b03e5Sespie {
1082*c87b03e5Sespie function->calls++;
1083*c87b03e5Sespie if (a_ptr->total)
1084*c87b03e5Sespie function->calls_executed++;
1085*c87b03e5Sespie }
1086*c87b03e5Sespie else
1087*c87b03e5Sespie {
1088*c87b03e5Sespie function->branches++;
1089*c87b03e5Sespie if (a_ptr->total)
1090*c87b03e5Sespie function->branches_executed++;
1091*c87b03e5Sespie if (a_ptr->hits)
1092*c87b03e5Sespie function->branches_taken++;
1093*c87b03e5Sespie }
1094*c87b03e5Sespie }
1095*c87b03e5Sespie
1096*c87b03e5Sespie /* Calculate the branch taken probabilities for all arcs branches at the
1097*c87b03e5Sespie end of this block. */
1098*c87b03e5Sespie
1099*c87b03e5Sespie static void
calculate_branch_probs(block_ptr,line_info,function)1100*c87b03e5Sespie calculate_branch_probs (block_ptr, line_info, function)
1101*c87b03e5Sespie struct bb_info *block_ptr;
1102*c87b03e5Sespie struct line_info *line_info;
1103*c87b03e5Sespie struct coverage *function;
1104*c87b03e5Sespie {
1105*c87b03e5Sespie gcov_type total;
1106*c87b03e5Sespie struct adj_list *arcptr;
1107*c87b03e5Sespie
1108*c87b03e5Sespie total = block_ptr->exec_count;
1109*c87b03e5Sespie for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
1110*c87b03e5Sespie {
1111*c87b03e5Sespie struct arcdata *a_ptr;
1112*c87b03e5Sespie
1113*c87b03e5Sespie /* Ignore fall through arcs as they aren't really branches. */
1114*c87b03e5Sespie if (arcptr->fall_through)
1115*c87b03e5Sespie continue;
1116*c87b03e5Sespie
1117*c87b03e5Sespie a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
1118*c87b03e5Sespie a_ptr->total = total;
1119*c87b03e5Sespie a_ptr->hits = total ? arcptr->arc_count : 0;
1120*c87b03e5Sespie a_ptr->call_insn = arcptr->fake;
1121*c87b03e5Sespie
1122*c87b03e5Sespie if (function)
1123*c87b03e5Sespie accumulate_branch_counts (function, a_ptr);
1124*c87b03e5Sespie /* Prepend the new branch to the list. */
1125*c87b03e5Sespie a_ptr->next = line_info->branches;
1126*c87b03e5Sespie line_info->branches = a_ptr;
1127*c87b03e5Sespie }
1128*c87b03e5Sespie }
1129*c87b03e5Sespie
1130*c87b03e5Sespie /* Format a HOST_WIDE_INT as either a percent ratio, or absolute
1131*c87b03e5Sespie count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
1132*c87b03e5Sespie If DP is zero, no decimal point is printed. Only print 100% when
1133*c87b03e5Sespie TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
1134*c87b03e5Sespie format TOP. Return pointer to a static string. */
1135*c87b03e5Sespie
1136*c87b03e5Sespie static char const *
format_hwint(top,bottom,dp)1137*c87b03e5Sespie format_hwint (top, bottom, dp)
1138*c87b03e5Sespie HOST_WIDEST_INT top, bottom;
1139*c87b03e5Sespie int dp;
1140*c87b03e5Sespie {
1141*c87b03e5Sespie static char buffer[20];
1142*c87b03e5Sespie
1143*c87b03e5Sespie if (dp >= 0)
1144*c87b03e5Sespie {
1145*c87b03e5Sespie float ratio = bottom ? (float)top / bottom : 0;
1146*c87b03e5Sespie int ix;
1147*c87b03e5Sespie unsigned limit = 100;
1148*c87b03e5Sespie unsigned percent;
1149*c87b03e5Sespie
1150*c87b03e5Sespie for (ix = dp; ix--; )
1151*c87b03e5Sespie limit *= 10;
1152*c87b03e5Sespie
1153*c87b03e5Sespie percent = (unsigned) (ratio * limit + (float)0.5);
1154*c87b03e5Sespie if (percent <= 0 && top)
1155*c87b03e5Sespie percent = 1;
1156*c87b03e5Sespie else if (percent >= limit && top != bottom)
1157*c87b03e5Sespie percent = limit - 1;
1158*c87b03e5Sespie ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
1159*c87b03e5Sespie if (dp)
1160*c87b03e5Sespie {
1161*c87b03e5Sespie dp++;
1162*c87b03e5Sespie do
1163*c87b03e5Sespie {
1164*c87b03e5Sespie buffer[ix+1] = buffer[ix];
1165*c87b03e5Sespie ix--;
1166*c87b03e5Sespie }
1167*c87b03e5Sespie while (dp--);
1168*c87b03e5Sespie buffer[ix + 1] = '.';
1169*c87b03e5Sespie }
1170*c87b03e5Sespie }
1171*c87b03e5Sespie else
1172*c87b03e5Sespie sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, top);
1173*c87b03e5Sespie
1174*c87b03e5Sespie return buffer;
1175*c87b03e5Sespie }
1176*c87b03e5Sespie
1177*c87b03e5Sespie
1178*c87b03e5Sespie /* Output summary info for a function. */
1179*c87b03e5Sespie
1180*c87b03e5Sespie static void
function_summary(function,title)1181*c87b03e5Sespie function_summary (function, title)
1182*c87b03e5Sespie struct coverage *function;
1183*c87b03e5Sespie const char *title;
1184*c87b03e5Sespie {
1185*c87b03e5Sespie if (function->lines)
1186*c87b03e5Sespie fnotice (stdout, "%s of %d lines executed in %s %s\n",
1187*c87b03e5Sespie format_hwint (function->lines_executed,
1188*c87b03e5Sespie function->lines, 2),
1189*c87b03e5Sespie function->lines, title, function->name);
1190*c87b03e5Sespie else
1191*c87b03e5Sespie fnotice (stdout, "No executable lines in %s %s\n",
1192*c87b03e5Sespie title, function->name);
1193*c87b03e5Sespie
1194*c87b03e5Sespie if (output_branch_probs)
1195*c87b03e5Sespie {
1196*c87b03e5Sespie if (function->branches)
1197*c87b03e5Sespie {
1198*c87b03e5Sespie fnotice (stdout, "%s of %d branches executed in %s %s\n",
1199*c87b03e5Sespie format_hwint (function->branches_executed,
1200*c87b03e5Sespie function->branches, 2),
1201*c87b03e5Sespie function->branches, title, function->name);
1202*c87b03e5Sespie fnotice (stdout,
1203*c87b03e5Sespie "%s of %d branches taken at least once in %s %s\n",
1204*c87b03e5Sespie format_hwint (function->branches_taken,
1205*c87b03e5Sespie function->branches, 2),
1206*c87b03e5Sespie function->branches, title, function->name);
1207*c87b03e5Sespie }
1208*c87b03e5Sespie else
1209*c87b03e5Sespie fnotice (stdout, "No branches in %s %s\n", title, function->name);
1210*c87b03e5Sespie if (function->calls)
1211*c87b03e5Sespie fnotice (stdout, "%s of %d calls executed in %s %s\n",
1212*c87b03e5Sespie format_hwint (function->calls_executed,
1213*c87b03e5Sespie function->calls, 2),
1214*c87b03e5Sespie function->calls, title, function->name);
1215*c87b03e5Sespie else
1216*c87b03e5Sespie fnotice (stdout, "No calls in %s %s\n", title, function->name);
1217*c87b03e5Sespie }
1218*c87b03e5Sespie }
1219*c87b03e5Sespie
1220*c87b03e5Sespie /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
1221*c87b03e5Sespie affect name generation. With preserve_paths we create a filename
1222*c87b03e5Sespie from all path components of the source file, replacing '/' with
1223*c87b03e5Sespie '#', without it we simply take the basename component. With
1224*c87b03e5Sespie long_output_names we prepend the processed name of the input file
1225*c87b03e5Sespie to each output name (except when the current source file is the
1226*c87b03e5Sespie input file, so you don't get a double concatenation). The two
1227*c87b03e5Sespie components are separated by '##'. Also '.' filename components are
1228*c87b03e5Sespie removed and '..' components are renamed to '^'. */
1229*c87b03e5Sespie
1230*c87b03e5Sespie static char *
make_gcov_file_name(src_name)1231*c87b03e5Sespie make_gcov_file_name (src_name)
1232*c87b03e5Sespie char *src_name;
1233*c87b03e5Sespie {
1234*c87b03e5Sespie char *cptr;
1235*c87b03e5Sespie char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
1236*c87b03e5Sespie
1237*c87b03e5Sespie name[0] = 0;
1238*c87b03e5Sespie if (output_long_names && strcmp (src_name, input_file_name))
1239*c87b03e5Sespie {
1240*c87b03e5Sespie /* Generate the input filename part. */
1241*c87b03e5Sespie cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
1242*c87b03e5Sespie cptr = cptr ? cptr + 1 : input_file_name;
1243*c87b03e5Sespie strcat (name, cptr);
1244*c87b03e5Sespie strcat (name, "##");
1245*c87b03e5Sespie }
1246*c87b03e5Sespie
1247*c87b03e5Sespie /* Generate the source filename part. */
1248*c87b03e5Sespie cptr = preserve_paths ? NULL : strrchr (src_name, '/');
1249*c87b03e5Sespie cptr = cptr ? cptr + 1 : src_name;
1250*c87b03e5Sespie strcat (name, cptr);
1251*c87b03e5Sespie
1252*c87b03e5Sespie if (preserve_paths)
1253*c87b03e5Sespie {
1254*c87b03e5Sespie /* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
1255*c87b03e5Sespie char *prev;
1256*c87b03e5Sespie
1257*c87b03e5Sespie for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
1258*c87b03e5Sespie {
1259*c87b03e5Sespie unsigned shift = 0;
1260*c87b03e5Sespie
1261*c87b03e5Sespie if (prev + 1 == cptr && prev[0] == '.')
1262*c87b03e5Sespie {
1263*c87b03e5Sespie /* Remove '.' */
1264*c87b03e5Sespie shift = 2;
1265*c87b03e5Sespie }
1266*c87b03e5Sespie else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
1267*c87b03e5Sespie {
1268*c87b03e5Sespie /* Convert '..' */
1269*c87b03e5Sespie shift = 1;
1270*c87b03e5Sespie prev[1] = '^';
1271*c87b03e5Sespie }
1272*c87b03e5Sespie else
1273*c87b03e5Sespie *cptr++ = '#';
1274*c87b03e5Sespie if (shift)
1275*c87b03e5Sespie {
1276*c87b03e5Sespie cptr = prev;
1277*c87b03e5Sespie do
1278*c87b03e5Sespie prev[0] = prev[shift];
1279*c87b03e5Sespie while (*prev++);
1280*c87b03e5Sespie }
1281*c87b03e5Sespie }
1282*c87b03e5Sespie }
1283*c87b03e5Sespie
1284*c87b03e5Sespie /* Don't strip off the ending for compatibility with tcov, since
1285*c87b03e5Sespie this results in confusion if there is more than one file with the
1286*c87b03e5Sespie same basename, e.g. tmp.c and tmp.h. */
1287*c87b03e5Sespie strcat (name, ".gcov");
1288*c87b03e5Sespie return name;
1289*c87b03e5Sespie }
1290*c87b03e5Sespie
1291*c87b03e5Sespie /* Scan through the bb_data, and when the file name matches the
1292*c87b03e5Sespie source file name, then for each following line number, increment
1293*c87b03e5Sespie the line number execution count indicated by the execution count of
1294*c87b03e5Sespie the appropriate basic block. */
1295*c87b03e5Sespie
1296*c87b03e5Sespie static void
init_line_info(line_info,total,maxlineno)1297*c87b03e5Sespie init_line_info (line_info, total, maxlineno)
1298*c87b03e5Sespie struct line_info *line_info;
1299*c87b03e5Sespie struct coverage *total;
1300*c87b03e5Sespie long maxlineno;
1301*c87b03e5Sespie {
1302*c87b03e5Sespie long block_num = 0; /* current block number */
1303*c87b03e5Sespie struct bb_info *block_ptr = NULL; /* current block ptr */
1304*c87b03e5Sespie struct coverage function;
1305*c87b03e5Sespie struct coverage *func_ptr = NULL;
1306*c87b03e5Sespie struct bb_info_list *current_graph = NULL; /* Graph for current function. */
1307*c87b03e5Sespie int is_this_file = 0; /* We're scanning a block from the desired file. */
1308*c87b03e5Sespie char *ptr = bb_data;
1309*c87b03e5Sespie long count;
1310*c87b03e5Sespie long line_num;
1311*c87b03e5Sespie struct line_info *line_ptr = 0; /* line info ptr. */
1312*c87b03e5Sespie
1313*c87b03e5Sespie memset (&function, 0, sizeof (function));
1314*c87b03e5Sespie if (output_function_summary)
1315*c87b03e5Sespie func_ptr = &function;
1316*c87b03e5Sespie
1317*c87b03e5Sespie for (count = 0; count < bb_data_size; count++)
1318*c87b03e5Sespie {
1319*c87b03e5Sespie __fetch_long (&line_num, ptr, 4);
1320*c87b03e5Sespie ptr += 4;
1321*c87b03e5Sespie if (line_num < 0)
1322*c87b03e5Sespie {
1323*c87b03e5Sespie long delim;
1324*c87b03e5Sespie
1325*c87b03e5Sespie if (line_num == -1)
1326*c87b03e5Sespie {
1327*c87b03e5Sespie /* Marks the beginning of a file name. Check to see
1328*c87b03e5Sespie whether this is the filename we are currently
1329*c87b03e5Sespie collecting data for. */
1330*c87b03e5Sespie is_this_file = !strcmp (total->name, ptr);
1331*c87b03e5Sespie }
1332*c87b03e5Sespie else if (line_num == -2)
1333*c87b03e5Sespie {
1334*c87b03e5Sespie /* Marks the start of a new function. Advance to the
1335*c87b03e5Sespie next program flow graph. */
1336*c87b03e5Sespie if (!current_graph)
1337*c87b03e5Sespie current_graph = bb_graph_list;
1338*c87b03e5Sespie else
1339*c87b03e5Sespie {
1340*c87b03e5Sespie if (block_num == current_graph->num_blocks - 1)
1341*c87b03e5Sespie /* Last block falls through to exit. */
1342*c87b03e5Sespie ;
1343*c87b03e5Sespie else if (block_num == current_graph->num_blocks - 2)
1344*c87b03e5Sespie {
1345*c87b03e5Sespie if (output_branch_probs && is_this_file)
1346*c87b03e5Sespie calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1347*c87b03e5Sespie }
1348*c87b03e5Sespie else
1349*c87b03e5Sespie {
1350*c87b03e5Sespie fnotice (stderr,
1351*c87b03e5Sespie "didn't use all bb entries of graph, function %s\n",
1352*c87b03e5Sespie function.name);
1353*c87b03e5Sespie fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
1354*c87b03e5Sespie block_num, current_graph->num_blocks);
1355*c87b03e5Sespie }
1356*c87b03e5Sespie if (func_ptr && is_this_file)
1357*c87b03e5Sespie function_summary (func_ptr, "function");
1358*c87b03e5Sespie current_graph = current_graph->next;
1359*c87b03e5Sespie }
1360*c87b03e5Sespie block_num = 0;
1361*c87b03e5Sespie block_ptr = current_graph->bb_graph;
1362*c87b03e5Sespie memset (&function, 0, sizeof (function));
1363*c87b03e5Sespie function.name = ptr;
1364*c87b03e5Sespie }
1365*c87b03e5Sespie else
1366*c87b03e5Sespie {
1367*c87b03e5Sespie fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
1368*c87b03e5Sespie abort ();
1369*c87b03e5Sespie }
1370*c87b03e5Sespie
1371*c87b03e5Sespie /* Scan past the string. */
1372*c87b03e5Sespie for (delim = 0; delim != line_num; count++)
1373*c87b03e5Sespie {
1374*c87b03e5Sespie __fetch_long (&delim, ptr, 4);
1375*c87b03e5Sespie ptr += 4;
1376*c87b03e5Sespie }
1377*c87b03e5Sespie }
1378*c87b03e5Sespie else if (!line_num)
1379*c87b03e5Sespie {
1380*c87b03e5Sespie /* Marks the end of a block. */
1381*c87b03e5Sespie if (block_num >= current_graph->num_blocks)
1382*c87b03e5Sespie {
1383*c87b03e5Sespie fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
1384*c87b03e5Sespie function.name);
1385*c87b03e5Sespie abort ();
1386*c87b03e5Sespie }
1387*c87b03e5Sespie
1388*c87b03e5Sespie if (output_branch_probs && is_this_file)
1389*c87b03e5Sespie calculate_branch_probs (block_ptr, line_ptr, func_ptr);
1390*c87b03e5Sespie
1391*c87b03e5Sespie block_num++;
1392*c87b03e5Sespie block_ptr++;
1393*c87b03e5Sespie }
1394*c87b03e5Sespie else if (is_this_file)
1395*c87b03e5Sespie {
1396*c87b03e5Sespie if (line_num >= maxlineno)
1397*c87b03e5Sespie {
1398*c87b03e5Sespie fnotice (stderr, "ERROR: out of range line number in function %s\n",
1399*c87b03e5Sespie function.name);
1400*c87b03e5Sespie abort ();
1401*c87b03e5Sespie }
1402*c87b03e5Sespie
1403*c87b03e5Sespie line_ptr = &line_info[line_num];
1404*c87b03e5Sespie if (func_ptr)
1405*c87b03e5Sespie {
1406*c87b03e5Sespie if (!line_ptr->exists)
1407*c87b03e5Sespie func_ptr->lines++;
1408*c87b03e5Sespie if (!line_ptr->count && block_ptr->exec_count)
1409*c87b03e5Sespie func_ptr->lines_executed++;
1410*c87b03e5Sespie }
1411*c87b03e5Sespie
1412*c87b03e5Sespie /* Accumulate execution data for this line number. */
1413*c87b03e5Sespie line_ptr->count += block_ptr->exec_count;
1414*c87b03e5Sespie line_ptr->exists = 1;
1415*c87b03e5Sespie }
1416*c87b03e5Sespie }
1417*c87b03e5Sespie
1418*c87b03e5Sespie if (func_ptr && is_this_file)
1419*c87b03e5Sespie function_summary (func_ptr, "function");
1420*c87b03e5Sespie
1421*c87b03e5Sespie /* Calculate summary test coverage statistics. */
1422*c87b03e5Sespie for (line_num = 1, line_ptr = &line_info[line_num];
1423*c87b03e5Sespie line_num < maxlineno; line_num++, line_ptr++)
1424*c87b03e5Sespie {
1425*c87b03e5Sespie struct arcdata *a_ptr, *prev, *next;
1426*c87b03e5Sespie
1427*c87b03e5Sespie if (line_ptr->exists)
1428*c87b03e5Sespie {
1429*c87b03e5Sespie total->lines++;
1430*c87b03e5Sespie if (line_ptr->count)
1431*c87b03e5Sespie total->lines_executed++;
1432*c87b03e5Sespie }
1433*c87b03e5Sespie
1434*c87b03e5Sespie /* Total and reverse the branch information. */
1435*c87b03e5Sespie for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
1436*c87b03e5Sespie {
1437*c87b03e5Sespie next = a_ptr->next;
1438*c87b03e5Sespie a_ptr->next = prev;
1439*c87b03e5Sespie prev = a_ptr;
1440*c87b03e5Sespie
1441*c87b03e5Sespie accumulate_branch_counts (total, a_ptr);
1442*c87b03e5Sespie }
1443*c87b03e5Sespie line_ptr->branches = prev;
1444*c87b03e5Sespie }
1445*c87b03e5Sespie }
1446*c87b03e5Sespie
1447*c87b03e5Sespie /* Read in the source file one line at a time, and output that line to
1448*c87b03e5Sespie the gcov file preceded by its execution count and other
1449*c87b03e5Sespie information. */
1450*c87b03e5Sespie
1451*c87b03e5Sespie static void
output_line_info(gcov_file,line_info,total,maxlineno)1452*c87b03e5Sespie output_line_info (gcov_file, line_info, total, maxlineno)
1453*c87b03e5Sespie FILE *gcov_file;
1454*c87b03e5Sespie const struct line_info *line_info;
1455*c87b03e5Sespie const struct coverage *total;
1456*c87b03e5Sespie long maxlineno;
1457*c87b03e5Sespie {
1458*c87b03e5Sespie FILE *source_file;
1459*c87b03e5Sespie long line_num; /* current line number */
1460*c87b03e5Sespie const struct line_info *line_ptr; /* current line info ptr. */
1461*c87b03e5Sespie char string[STRING_SIZE]; /* line buffer. */
1462*c87b03e5Sespie char const *retval = ""; /* status of source file reading. */
1463*c87b03e5Sespie
1464*c87b03e5Sespie fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
1465*c87b03e5Sespie fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
1466*c87b03e5Sespie
1467*c87b03e5Sespie source_file = fopen (total->name, "r");
1468*c87b03e5Sespie if (!source_file)
1469*c87b03e5Sespie {
1470*c87b03e5Sespie fnotice (stderr, "Could not open source file %s.\n", total->name);
1471*c87b03e5Sespie retval = NULL;
1472*c87b03e5Sespie }
1473*c87b03e5Sespie else
1474*c87b03e5Sespie {
1475*c87b03e5Sespie struct stat status;
1476*c87b03e5Sespie
1477*c87b03e5Sespie if (!fstat (fileno (source_file), &status)
1478*c87b03e5Sespie && status.st_mtime > bb_file_time)
1479*c87b03e5Sespie {
1480*c87b03e5Sespie fnotice (stderr, "Warning: source file %s is newer than %s\n",
1481*c87b03e5Sespie total->name, bb_file_name);
1482*c87b03e5Sespie fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
1483*c87b03e5Sespie "-", 0);
1484*c87b03e5Sespie }
1485*c87b03e5Sespie }
1486*c87b03e5Sespie
1487*c87b03e5Sespie for (line_num = 1, line_ptr = &line_info[line_num];
1488*c87b03e5Sespie line_num < maxlineno; line_num++, line_ptr++)
1489*c87b03e5Sespie {
1490*c87b03e5Sespie /* For lines which don't exist in the .bb file, print '-' before
1491*c87b03e5Sespie the source line. For lines which exist but were never
1492*c87b03e5Sespie executed, print '#####' before the source line. Otherwise,
1493*c87b03e5Sespie print the execution count before the source line. There are
1494*c87b03e5Sespie 16 spaces of indentation added before the source line so that
1495*c87b03e5Sespie tabs won't be messed up. */
1496*c87b03e5Sespie fprintf (gcov_file, "%9s:%5ld:",
1497*c87b03e5Sespie !line_ptr->exists ? "-"
1498*c87b03e5Sespie : !line_ptr->count ? "#####"
1499*c87b03e5Sespie : format_hwint (line_ptr->count, 0, -1), line_num);
1500*c87b03e5Sespie
1501*c87b03e5Sespie if (retval)
1502*c87b03e5Sespie {
1503*c87b03e5Sespie /* Copy source line. */
1504*c87b03e5Sespie do
1505*c87b03e5Sespie {
1506*c87b03e5Sespie retval = fgets (string, STRING_SIZE, source_file);
1507*c87b03e5Sespie if (!retval)
1508*c87b03e5Sespie {
1509*c87b03e5Sespie fnotice (stderr,
1510*c87b03e5Sespie "Unexpected EOF while reading source file %s.\n",
1511*c87b03e5Sespie total->name);
1512*c87b03e5Sespie break;
1513*c87b03e5Sespie }
1514*c87b03e5Sespie fputs (retval, gcov_file);
1515*c87b03e5Sespie }
1516*c87b03e5Sespie while (!retval[0] || retval[strlen (retval) - 1] != '\n');
1517*c87b03e5Sespie }
1518*c87b03e5Sespie if (!retval)
1519*c87b03e5Sespie fputs ("??\n", gcov_file);
1520*c87b03e5Sespie
1521*c87b03e5Sespie if (output_branch_probs)
1522*c87b03e5Sespie {
1523*c87b03e5Sespie int i;
1524*c87b03e5Sespie struct arcdata *a_ptr;
1525*c87b03e5Sespie
1526*c87b03e5Sespie for (i = 0, a_ptr = line_ptr->branches; a_ptr;
1527*c87b03e5Sespie a_ptr = a_ptr->next, i++)
1528*c87b03e5Sespie {
1529*c87b03e5Sespie if (a_ptr->call_insn)
1530*c87b03e5Sespie {
1531*c87b03e5Sespie if (a_ptr->total == 0)
1532*c87b03e5Sespie fnotice (gcov_file, "call %2d never executed\n", i);
1533*c87b03e5Sespie else
1534*c87b03e5Sespie fnotice
1535*c87b03e5Sespie (gcov_file, "call %2d returns %s\n", i,
1536*c87b03e5Sespie format_hwint (a_ptr->total - a_ptr->hits,
1537*c87b03e5Sespie a_ptr->total,
1538*c87b03e5Sespie -output_branch_counts));
1539*c87b03e5Sespie }
1540*c87b03e5Sespie else
1541*c87b03e5Sespie {
1542*c87b03e5Sespie if (a_ptr->total == 0)
1543*c87b03e5Sespie fnotice (gcov_file, "branch %2d never executed\n", i);
1544*c87b03e5Sespie else
1545*c87b03e5Sespie fnotice
1546*c87b03e5Sespie (gcov_file, "branch %2d taken %s\n", i,
1547*c87b03e5Sespie format_hwint (a_ptr->hits, a_ptr->total,
1548*c87b03e5Sespie -output_branch_counts));
1549*c87b03e5Sespie }
1550*c87b03e5Sespie }
1551*c87b03e5Sespie }
1552*c87b03e5Sespie }
1553*c87b03e5Sespie
1554*c87b03e5Sespie /* Handle all remaining source lines. There may be lines after the
1555*c87b03e5Sespie last line of code. */
1556*c87b03e5Sespie if (retval)
1557*c87b03e5Sespie {
1558*c87b03e5Sespie for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
1559*c87b03e5Sespie {
1560*c87b03e5Sespie fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
1561*c87b03e5Sespie
1562*c87b03e5Sespie while (!retval[0] || retval[strlen (retval) - 1] != '\n')
1563*c87b03e5Sespie {
1564*c87b03e5Sespie retval = fgets (string, STRING_SIZE, source_file);
1565*c87b03e5Sespie if (!retval)
1566*c87b03e5Sespie break;
1567*c87b03e5Sespie fputs (retval, gcov_file);
1568*c87b03e5Sespie }
1569*c87b03e5Sespie }
1570*c87b03e5Sespie }
1571*c87b03e5Sespie
1572*c87b03e5Sespie if (source_file)
1573*c87b03e5Sespie fclose (source_file);
1574*c87b03e5Sespie }
1575*c87b03e5Sespie
1576*c87b03e5Sespie /* Calculate line execution counts, and output a .gcov file for source
1577*c87b03e5Sespie file S_PTR. Allocate an array big enough to hold a count for each
1578*c87b03e5Sespie line. Scan through the bb_data, and when the file name matches the
1579*c87b03e5Sespie current file name, then for each following line number, increment
1580*c87b03e5Sespie the line number execution count indicated by the execution count of
1581*c87b03e5Sespie the appropriate basic block. */
1582*c87b03e5Sespie
1583*c87b03e5Sespie static void
output_data(s_ptr)1584*c87b03e5Sespie output_data (s_ptr)
1585*c87b03e5Sespie struct sourcefile *s_ptr;
1586*c87b03e5Sespie {
1587*c87b03e5Sespie struct line_info *line_info /* line info data */
1588*c87b03e5Sespie = (struct line_info *) xcalloc (s_ptr->maxlineno,
1589*c87b03e5Sespie sizeof (struct line_info));
1590*c87b03e5Sespie long line_num;
1591*c87b03e5Sespie struct coverage total;
1592*c87b03e5Sespie
1593*c87b03e5Sespie memset (&total, 0, sizeof (total));
1594*c87b03e5Sespie total.name = s_ptr->name;
1595*c87b03e5Sespie
1596*c87b03e5Sespie init_line_info (line_info, &total, s_ptr->maxlineno);
1597*c87b03e5Sespie function_summary (&total, "file");
1598*c87b03e5Sespie
1599*c87b03e5Sespie if (output_gcov_file)
1600*c87b03e5Sespie {
1601*c87b03e5Sespie /* Now the statistics are ready. Read in the source file one
1602*c87b03e5Sespie line at a time, and output that line to the gcov file
1603*c87b03e5Sespie preceded by its execution information. */
1604*c87b03e5Sespie
1605*c87b03e5Sespie char *gcov_file_name = make_gcov_file_name (total.name);
1606*c87b03e5Sespie FILE *gcov_file = fopen (gcov_file_name, "w");
1607*c87b03e5Sespie
1608*c87b03e5Sespie if (gcov_file)
1609*c87b03e5Sespie {
1610*c87b03e5Sespie fnotice (stdout, "Creating %s.\n", gcov_file_name);
1611*c87b03e5Sespie output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
1612*c87b03e5Sespie if (ferror (gcov_file))
1613*c87b03e5Sespie fnotice (stderr, "Error writing output file %s.\n",
1614*c87b03e5Sespie gcov_file_name);
1615*c87b03e5Sespie fclose (gcov_file);
1616*c87b03e5Sespie }
1617*c87b03e5Sespie else
1618*c87b03e5Sespie fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
1619*c87b03e5Sespie free (gcov_file_name);
1620*c87b03e5Sespie }
1621*c87b03e5Sespie
1622*c87b03e5Sespie /* Free data. */
1623*c87b03e5Sespie for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
1624*c87b03e5Sespie {
1625*c87b03e5Sespie struct arcdata *branch, *next;
1626*c87b03e5Sespie
1627*c87b03e5Sespie for (branch = line_info[line_num].branches; branch; branch = next)
1628*c87b03e5Sespie {
1629*c87b03e5Sespie next = branch->next;
1630*c87b03e5Sespie free (branch);
1631*c87b03e5Sespie }
1632*c87b03e5Sespie }
1633*c87b03e5Sespie free (line_info);
1634*c87b03e5Sespie }
1635