OSDN Git Service

d70e4dddc8bf5a9d0129d686effb7c989dc2673a
[pf3gnuchains/gcc-fork.git] / gcc / gcov-dump.c
1 /* Dump a gcov file, for debugging use.
2    Copyright (C) 2002 Free Software Foundation, Inc.
3    Contributed by Nathan Sidwell <nathan@codesourcery.com>
4
5 Gcov is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 Gcov is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Gcov; see the file COPYING.  If not, write to
17 the Free Software Foundation, 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.  */
19
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "tm.h"
24 #include "version.h"
25 #include <getopt.h>
26 #define IN_GCOV (-1)
27 #include "gcov-io.h"
28 #include "gcov-io.c"
29
30 static void dump_file PARAMS ((const char *));
31 static void print_prefix PARAMS ((const char *, unsigned));
32 static void print_usage PARAMS ((void));
33 static void print_version PARAMS ((void));
34 static void tag_function PARAMS ((const char *, unsigned, unsigned));
35 static void tag_blocks PARAMS ((const char *, unsigned, unsigned));
36 static void tag_arcs PARAMS ((const char *, unsigned, unsigned));
37 static void tag_lines PARAMS ((const char *, unsigned, unsigned));
38 static void tag_counters PARAMS ((const char *, unsigned, unsigned));
39 static void tag_summary PARAMS ((const char *, unsigned, unsigned));
40 extern int main PARAMS ((int, char **));
41
42 typedef struct tag_format
43 {
44   unsigned tag;
45   char const *name;
46   void (*proc) (const char *, unsigned, unsigned);
47 } tag_format_t;
48
49 static int flag_dump_contents = 0;
50
51 static const struct option options[] =
52 {
53   { "help",                 no_argument,       NULL, 'h' },
54   { "version",              no_argument,       NULL, 'v' },
55   { "long",                 no_argument,       NULL, 'l' },
56 };
57
58 static const tag_format_t tag_table[] =
59 {
60   {0, "NOP", NULL},
61   {0, "UNKNOWN", NULL},
62   {0, "COUNTERS", tag_counters},
63   {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
64   {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
65   {GCOV_TAG_ARCS, "ARCS", tag_arcs},
66   {GCOV_TAG_LINES, "LINES", tag_lines},
67   {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
68   {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
69   {0, NULL, NULL}
70 };
71
72 int main (argc, argv)
73      int argc ATTRIBUTE_UNUSED;
74      char **argv;
75 {
76   int opt;
77
78   while ((opt = getopt_long (argc, argv, "hlv", options, NULL)) != -1)
79     {
80       switch (opt)
81         {
82         case 'h':
83           print_usage ();
84           break;
85         case 'v':
86           print_version ();
87           break;
88         case 'l':
89           flag_dump_contents = 1;
90           break;
91         default:
92           fprintf (stderr, "unknown flag `%c'\n", opt);
93         }
94     }
95   
96   while (argv[optind])
97     dump_file (argv[optind++]);
98   return 0;
99 }
100
101 static void
102 print_usage ()
103 {
104   printf ("Usage: gcov-dump [OPTION] ... gcovfiles\n");
105   printf ("Print coverage file contents\n");
106   printf ("  -h, --help           Print this help\n");
107   printf ("  -v, --version        Print version number\n");
108   printf ("  -l, --long           Dump record contents too\n");
109 }
110
111 static void
112 print_version ()
113 {
114   char v[4];
115   unsigned version = GCOV_VERSION;
116   unsigned ix;
117
118   for (ix = 4; ix--; version >>= 8)
119     v[ix] = version;
120   printf ("gcov %.4s (GCC %s)\n", v, version_string);
121   printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
122   printf ("This is free software; see the source for copying conditions.  There is NO\n\
123 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
124 }
125
126 static void
127 print_prefix (filename, depth)
128      const char *filename;
129      unsigned depth;
130 {
131   static const char prefix[] = "    ";
132   
133   printf ("%s:%.*s", filename, (int) depth, prefix);
134 }
135
136 static void
137 dump_file (filename)
138      const char *filename;
139 {
140   unsigned tags[4];
141   unsigned depth = 0;
142   
143   if (!gcov_open (filename, 1))
144     {
145       fprintf (stderr, "%s:cannot open\n", filename);
146       return;
147     }
148   
149   /* magic */
150   {
151     unsigned magic = gcov_read_unsigned ();
152     unsigned version = gcov_read_unsigned ();
153     const char *type = NULL;
154     char e[4], v[4], m[4];
155     unsigned expected = GCOV_VERSION;
156     unsigned ix;
157     int different = version != GCOV_VERSION;
158     
159     if (magic == GCOV_DATA_MAGIC)
160       type = "data";
161     else if (magic == GCOV_GRAPH_MAGIC)
162       type = "graph";
163     else
164       {
165         printf ("%s:not a gcov file\n", filename);
166         gcov_close ();
167         return;
168       }
169     for (ix = 4; ix--; expected >>= 8, version >>= 8, magic >>= 8)
170       {
171         e[ix] = expected;
172         v[ix] = version;
173         m[ix] = magic;
174       }
175     
176     printf ("%s:%s:magic `%.4s':version `%.4s'\n", filename, type, m, v);
177     if (different)
178       printf ("%s:warning:current version is `%.4s'\n", filename, e);
179   }
180
181   while (!gcov_is_eof ())
182     {
183       unsigned tag = gcov_read_unsigned ();
184       unsigned length = gcov_read_unsigned ();
185       unsigned long base = gcov_position ();
186       tag_format_t const *format;
187       unsigned tag_depth;
188       int error;
189       
190       if (!tag)
191         tag_depth = depth;
192       else
193         {
194           unsigned mask = GCOV_TAG_MASK (tag) >> 1;
195           
196           for (tag_depth = 4; mask; mask >>= 8)
197             {
198               if ((mask & 0xff) != 0xff)
199                 {
200                   printf ("%s:tag `%08x' is invalid\n", filename, tag);
201                   break;
202                 }
203               tag_depth--;
204             }
205         }
206       for (format = tag_table; format->name; format++)
207         if (format->tag == tag)
208           goto found;
209       format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
210     found:;
211       if (tag)
212         {
213           if (depth && depth < tag_depth)
214             {
215               if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
216                 printf ("%s:tag `%08x' is incorrectly nested\n",
217                         filename, tag);
218             }
219           depth = tag_depth;
220           tags[depth - 1] = tag;
221         }
222       
223       print_prefix (filename, tag_depth);
224       printf ("%08x:%4u:%s", tag, length, format->name);
225       if (format->proc)
226         (*format->proc) (filename, tag, length);
227       
228       printf ("\n");
229       if (flag_dump_contents && format->proc)
230         {
231           unsigned long actual_length = gcov_position () - base;
232           
233           if (actual_length > length)
234             printf ("%s:record size mismatch %lu bytes overread\n",
235                     filename, actual_length - length);
236           else if (length > actual_length)
237             printf ("%s:record size mismatch %lu bytes unread\n",
238                     filename, length - actual_length);
239         }
240       gcov_sync (base, length);
241       if ((error = gcov_is_error ()))
242         {
243           printf (error < 0 ? "%s:counter overflow at %lu\n" :
244                   "%s:read error at %lu\n", filename,
245                   (long unsigned) gcov_position ());
246           break;
247         }
248     }
249   gcov_close ();
250 }
251
252 static void
253 tag_function (filename, tag, length)
254      const char *filename ATTRIBUTE_UNUSED;
255      unsigned tag ATTRIBUTE_UNUSED;
256      unsigned length ATTRIBUTE_UNUSED;
257 {
258   unsigned long pos = gcov_position ();
259   
260   printf (" ident=%u", gcov_read_unsigned ());
261   printf (", checksum=0x%08x", gcov_read_unsigned ());
262
263   if (gcov_position () - pos < length)
264     {
265       const char *name;
266       
267       name = gcov_read_string ();
268       printf (", `%s'", name ? name : "NULL");
269       name = gcov_read_string ();
270       printf (" %s", name ? name : "NULL");
271       printf (":%u", gcov_read_unsigned ());
272     }
273 }
274
275 static void
276 tag_blocks (filename, tag, length)
277      const char *filename ATTRIBUTE_UNUSED;
278      unsigned tag ATTRIBUTE_UNUSED;
279      unsigned length ATTRIBUTE_UNUSED;
280 {
281   unsigned n_blocks = length / 4;
282   
283   printf (" %u blocks", n_blocks);
284
285   if (flag_dump_contents)
286     {
287       unsigned ix;
288
289       for (ix = 0; ix != n_blocks; ix++)
290         {
291           if (!(ix & 7))
292             printf ("\n%s:\t\t%u", filename, ix);
293           printf (" %04x", gcov_read_unsigned ());
294         }
295     }
296 }
297
298 static void
299 tag_arcs (filename, tag, length)
300      const char *filename ATTRIBUTE_UNUSED;
301      unsigned tag ATTRIBUTE_UNUSED;
302      unsigned length ATTRIBUTE_UNUSED;
303 {
304   unsigned n_arcs = (length - 4) / 8;
305
306   printf (" %u arcs", n_arcs);
307   if (flag_dump_contents)
308     {
309       unsigned ix;
310       unsigned blockno = gcov_read_unsigned ();
311
312       for (ix = 0; ix != n_arcs; ix++)
313         {
314           unsigned dst = gcov_read_unsigned ();
315           unsigned flags = gcov_read_unsigned ();
316           
317           if (!(ix & 3))
318             printf ("\n%s:\tblock %u:", filename, blockno);
319           printf (" %u:%04x", dst, flags);
320         }
321     }
322 }
323
324 static void
325 tag_lines (filename, tag, length)
326      const char *filename ATTRIBUTE_UNUSED;
327      unsigned tag ATTRIBUTE_UNUSED;
328      unsigned length ATTRIBUTE_UNUSED;
329 {
330   if (flag_dump_contents)
331     {
332       unsigned blockno = gcov_read_unsigned ();
333       char const *sep = NULL;
334
335       while (1)
336         {
337           const char *source = NULL;
338           unsigned lineno = gcov_read_unsigned ();
339           
340           if (!lineno)
341             {
342               source = gcov_read_string ();
343               if (!source)
344                 break;
345               sep = NULL;
346             }
347           
348           if (!sep)
349             {
350               printf ("\n%s:\tblock %u:", filename, blockno);
351               sep = "";
352             }
353           if (lineno)
354             {
355               printf ("%s%u", sep, lineno);
356               sep = ", ";
357             }
358           else
359             {
360               printf ("%s`%s'", sep, source);
361               sep = ":";
362             }
363         }
364     }
365 }
366
367 static void
368 tag_counters (filename, tag, length)
369      const char *filename ATTRIBUTE_UNUSED;
370      unsigned tag ATTRIBUTE_UNUSED;
371      unsigned length ATTRIBUTE_UNUSED;
372 {
373   static const char *const counter_names[] = GCOV_COUNTER_NAMES;
374   unsigned n_counts = length / 8;
375   
376   printf (" %s %u counts",
377           counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts);
378   if (flag_dump_contents)
379     {
380       unsigned ix;
381
382       for (ix = 0; ix != n_counts; ix++)
383         {
384           gcov_type count = gcov_read_counter ();
385           
386           if (!(ix & 7))
387             printf ("\n%s:\t\t%u", filename, ix);
388           printf (" ");
389           printf (HOST_WIDEST_INT_PRINT_DEC, count);
390         }
391     }
392 }
393
394 static void
395 tag_summary (filename, tag, length)
396      const char *filename ATTRIBUTE_UNUSED;
397      unsigned tag ATTRIBUTE_UNUSED;
398      unsigned length ATTRIBUTE_UNUSED;
399 {
400   struct gcov_summary summary;
401   unsigned ix;
402   
403   gcov_read_summary (&summary);
404   printf (" checksum=0x%08x", summary.checksum);
405   
406   for (ix = 0; ix != GCOV_COUNTERS; ix++)
407     {
408       printf ("\n%sL\t\tcounts=%u, runs=%u", filename,
409               summary.ctrs[ix].num, summary.ctrs[ix].runs);
410       
411       printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC,
412               (HOST_WIDEST_INT)summary.ctrs[ix].sum_all);
413       printf (", run_max=" HOST_WIDEST_INT_PRINT_DEC,
414               (HOST_WIDEST_INT)summary.ctrs[ix].run_max);
415       printf (", sum_max=" HOST_WIDEST_INT_PRINT_DEC,
416               (HOST_WIDEST_INT)summary.ctrs[ix].sum_max);
417     }
418 }