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