1/* Dump a gcov file, for debugging use. 2 Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 3 Contributed by Nathan Sidwell <nathan@codesourcery.com> 4 5Gcov is free software; you can redistribute it and/or modify 6it under the terms of the GNU General Public License as published by 7the Free Software Foundation; either version 2, or (at your option) 8any later version. 9 10Gcov is distributed in the hope that it will be useful, 11but WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with Gcov; see the file COPYING. If not, write to 17the Free Software Foundation, 51 Franklin Street, Fifth Floor, 18Boston, MA 02110-1301, 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 30static void dump_file (const char *); 31static void print_prefix (const char *, unsigned, gcov_position_t); 32static void print_usage (void); 33static void print_version (void); 34static void tag_function (const char *, unsigned, unsigned); 35static void tag_blocks (const char *, unsigned, unsigned); 36static void tag_arcs (const char *, unsigned, unsigned); 37static void tag_lines (const char *, unsigned, unsigned); 38static void tag_counters (const char *, unsigned, unsigned); 39static void tag_summary (const char *, unsigned, unsigned); 40extern int main (int, char **); 41 42typedef struct tag_format 43{ 44 unsigned tag; 45 char const *name; 46 void (*proc) (const char *, unsigned, unsigned); 47} tag_format_t; 48 49static int flag_dump_contents = 0; 50static int flag_dump_positions = 0; 51 52static 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 61static 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 75int 76main (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 109static void 110print_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 120static void 121print_version (void) 122{ 123 printf ("gcov-dump (GCC) %s\n", version_string); 124 printf ("Copyright (C) 2006 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 130static void 131print_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 141static void 142dump_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 263static void 264tag_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 284static void 285tag_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 309static void 310tag_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 338static void 339tag_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 382static void 383tag_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 413static void 414tag_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; 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} 438