1 /* Dump a gcov file, for debugging use. 2 Copyright (C) 2002-2013 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 3, 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 COPYING3. If not see 17 <http://www.gnu.org/licenses/>. */ 18 19 #include "config.h" 20 #include "system.h" 21 #include "coretypes.h" 22 #include "tm.h" 23 #include "version.h" 24 #include "intl.h" 25 #include "diagnostic.h" 26 #include <getopt.h> 27 #define IN_GCOV (-1) 28 #include "gcov-io.h" 29 #include "gcov-io.c" 30 31 static void dump_gcov_file (const char *); 32 static void print_prefix (const char *, unsigned, gcov_position_t); 33 static void print_usage (void); 34 static void print_version (void); 35 static void tag_function (const char *, unsigned, unsigned); 36 static void tag_blocks (const char *, unsigned, unsigned); 37 static void tag_arcs (const char *, unsigned, unsigned); 38 static void tag_lines (const char *, unsigned, unsigned); 39 static void tag_counters (const char *, unsigned, unsigned); 40 static void tag_summary (const char *, unsigned, unsigned); 41 extern int main (int, char **); 42 43 typedef struct tag_format 44 { 45 unsigned tag; 46 char const *name; 47 void (*proc) (const char *, unsigned, unsigned); 48 } tag_format_t; 49 50 static int flag_dump_contents = 0; 51 static int flag_dump_positions = 0; 52 53 static const struct option options[] = 54 { 55 { "help", no_argument, NULL, 'h' }, 56 { "version", no_argument, NULL, 'v' }, 57 { "long", no_argument, NULL, 'l' }, 58 { "positions", no_argument, NULL, 'o' }, 59 { 0, 0, 0, 0 } 60 }; 61 62 static const tag_format_t tag_table[] = 63 { 64 {0, "NOP", NULL}, 65 {0, "UNKNOWN", NULL}, 66 {0, "COUNTERS", tag_counters}, 67 {GCOV_TAG_FUNCTION, "FUNCTION", tag_function}, 68 {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks}, 69 {GCOV_TAG_ARCS, "ARCS", tag_arcs}, 70 {GCOV_TAG_LINES, "LINES", tag_lines}, 71 {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary}, 72 {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, 73 {0, NULL, NULL} 74 }; 75 76 int 77 main (int argc ATTRIBUTE_UNUSED, char **argv) 78 { 79 int opt; 80 const char *p; 81 82 p = argv[0] + strlen (argv[0]); 83 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) 84 --p; 85 progname = p; 86 87 xmalloc_set_program_name (progname); 88 89 /* Unlock the stdio streams. */ 90 unlock_std_streams (); 91 92 gcc_init_libintl (); 93 94 diagnostic_initialize (global_dc, 0); 95 96 while ((opt = getopt_long (argc, argv, "hlpv", options, NULL)) != -1) 97 { 98 switch (opt) 99 { 100 case 'h': 101 print_usage (); 102 break; 103 case 'v': 104 print_version (); 105 break; 106 case 'l': 107 flag_dump_contents = 1; 108 break; 109 case 'p': 110 flag_dump_positions = 1; 111 break; 112 default: 113 fprintf (stderr, "unknown flag `%c'\n", opt); 114 } 115 } 116 117 while (argv[optind]) 118 dump_gcov_file (argv[optind++]); 119 return 0; 120 } 121 122 static void 123 print_usage (void) 124 { 125 printf ("Usage: gcov-dump [OPTION] ... gcovfiles\n"); 126 printf ("Print coverage file contents\n"); 127 printf (" -h, --help Print this help\n"); 128 printf (" -v, --version Print version number\n"); 129 printf (" -l, --long Dump record contents too\n"); 130 printf (" -p, --positions Dump record positions\n"); 131 } 132 133 static void 134 print_version (void) 135 { 136 printf ("gcov-dump %s%s\n", pkgversion_string, version_string); 137 printf ("Copyright (C) 2015 Free Software Foundation, Inc.\n"); 138 printf ("This is free software; see the source for copying conditions.\n" 139 "There is NO warranty; not even for MERCHANTABILITY or \n" 140 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"); 141 } 142 143 static void 144 print_prefix (const char *filename, unsigned depth, gcov_position_t position) 145 { 146 static const char prefix[] = " "; 147 148 printf ("%s:", filename); 149 if (flag_dump_positions) 150 printf ("%lu:", (unsigned long) position); 151 printf ("%.*s", (int) depth, prefix); 152 } 153 154 static void 155 dump_gcov_file (const char *filename) 156 { 157 unsigned tags[4]; 158 unsigned depth = 0; 159 160 if (!gcov_open (filename, 1)) 161 { 162 fprintf (stderr, "%s:cannot open\n", filename); 163 return; 164 } 165 166 /* magic */ 167 { 168 unsigned magic = gcov_read_unsigned (); 169 unsigned version; 170 const char *type = NULL; 171 int endianness = 0; 172 char m[4], v[4]; 173 174 if ((endianness = gcov_magic (magic, GCOV_DATA_MAGIC))) 175 type = "data"; 176 else if ((endianness = gcov_magic (magic, GCOV_NOTE_MAGIC))) 177 type = "note"; 178 else 179 { 180 printf ("%s:not a gcov file\n", filename); 181 gcov_close (); 182 return; 183 } 184 version = gcov_read_unsigned (); 185 GCOV_UNSIGNED2STRING (v, version); 186 GCOV_UNSIGNED2STRING (m, magic); 187 188 printf ("%s:%s:magic `%.4s':version `%.4s'%s\n", filename, type, 189 m, v, endianness < 0 ? " (swapped endianness)" : ""); 190 if (version != GCOV_VERSION) 191 { 192 char e[4]; 193 194 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 195 printf ("%s:warning:current version is `%.4s'\n", filename, e); 196 } 197 } 198 199 /* stamp */ 200 { 201 unsigned stamp = gcov_read_unsigned (); 202 203 printf ("%s:stamp %lu\n", filename, (unsigned long)stamp); 204 } 205 206 while (1) 207 { 208 gcov_position_t base, position = gcov_position (); 209 unsigned tag, length; 210 tag_format_t const *format; 211 unsigned tag_depth; 212 int error; 213 unsigned mask; 214 215 tag = gcov_read_unsigned (); 216 if (!tag) 217 break; 218 length = gcov_read_unsigned (); 219 base = gcov_position (); 220 mask = GCOV_TAG_MASK (tag) >> 1; 221 for (tag_depth = 4; mask; mask >>= 8) 222 { 223 if ((mask & 0xff) != 0xff) 224 { 225 printf ("%s:tag `%08x' is invalid\n", filename, tag); 226 break; 227 } 228 tag_depth--; 229 } 230 for (format = tag_table; format->name; format++) 231 if (format->tag == tag) 232 goto found; 233 format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1]; 234 found:; 235 if (tag) 236 { 237 if (depth && depth < tag_depth) 238 { 239 if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)) 240 printf ("%s:tag `%08x' is incorrectly nested\n", 241 filename, tag); 242 } 243 depth = tag_depth; 244 tags[depth - 1] = tag; 245 } 246 247 print_prefix (filename, tag_depth, position); 248 printf ("%08x:%4u:%s", tag, length, format->name); 249 if (format->proc) 250 (*format->proc) (filename, tag, length); 251 252 printf ("\n"); 253 if (flag_dump_contents && format->proc) 254 { 255 unsigned long actual_length = gcov_position () - base; 256 257 if (actual_length > length) 258 printf ("%s:record size mismatch %lu bytes overread\n", 259 filename, actual_length - length); 260 else if (length > actual_length) 261 printf ("%s:record size mismatch %lu bytes unread\n", 262 filename, length - actual_length); 263 } 264 gcov_sync (base, length); 265 if ((error = gcov_is_error ())) 266 { 267 printf (error < 0 ? "%s:counter overflow at %lu\n" : 268 "%s:read error at %lu\n", filename, 269 (long unsigned) gcov_position ()); 270 break; 271 } 272 } 273 gcov_close (); 274 } 275 276 static void 277 tag_function (const char *filename ATTRIBUTE_UNUSED, 278 unsigned tag ATTRIBUTE_UNUSED, unsigned length) 279 { 280 unsigned long pos = gcov_position (); 281 282 if (!length) 283 printf (" placeholder"); 284 else 285 { 286 printf (" ident=%u", gcov_read_unsigned ()); 287 printf (", lineno_checksum=0x%08x", gcov_read_unsigned ()); 288 printf (", cfg_checksum=0x%08x", gcov_read_unsigned ()); 289 290 if (gcov_position () - pos < length) 291 { 292 const char *name; 293 294 name = gcov_read_string (); 295 printf (", `%s'", name ? name : "NULL"); 296 name = gcov_read_string (); 297 printf (" %s", name ? name : "NULL"); 298 printf (":%u", gcov_read_unsigned ()); 299 } 300 } 301 } 302 303 static void 304 tag_blocks (const char *filename ATTRIBUTE_UNUSED, 305 unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 306 { 307 unsigned n_blocks = GCOV_TAG_BLOCKS_NUM (length); 308 309 printf (" %u blocks", n_blocks); 310 311 if (flag_dump_contents) 312 { 313 unsigned ix; 314 315 for (ix = 0; ix != n_blocks; ix++) 316 { 317 if (!(ix & 7)) 318 { 319 printf ("\n"); 320 print_prefix (filename, 0, gcov_position ()); 321 printf ("\t\t%u", ix); 322 } 323 printf (" %04x", gcov_read_unsigned ()); 324 } 325 } 326 } 327 328 static void 329 tag_arcs (const char *filename ATTRIBUTE_UNUSED, 330 unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 331 { 332 unsigned n_arcs = GCOV_TAG_ARCS_NUM (length); 333 334 printf (" %u arcs", n_arcs); 335 if (flag_dump_contents) 336 { 337 unsigned ix; 338 unsigned blockno = gcov_read_unsigned (); 339 340 for (ix = 0; ix != n_arcs; ix++) 341 { 342 unsigned dst, flags; 343 344 if (!(ix & 3)) 345 { 346 printf ("\n"); 347 print_prefix (filename, 0, gcov_position ()); 348 printf ("\tblock %u:", blockno); 349 } 350 dst = gcov_read_unsigned (); 351 flags = gcov_read_unsigned (); 352 printf (" %u:%04x", dst, flags); 353 if (flags) 354 { 355 char c = '('; 356 357 if (flags & GCOV_ARC_ON_TREE) 358 printf ("%ctree", c), c = ','; 359 if (flags & GCOV_ARC_FAKE) 360 printf ("%cfake", c), c = ','; 361 if (flags & GCOV_ARC_FALLTHROUGH) 362 printf ("%cfall", c), c = ','; 363 printf (")"); 364 } 365 } 366 } 367 } 368 369 static void 370 tag_lines (const char *filename ATTRIBUTE_UNUSED, 371 unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 372 { 373 if (flag_dump_contents) 374 { 375 unsigned blockno = gcov_read_unsigned (); 376 char const *sep = NULL; 377 378 while (1) 379 { 380 gcov_position_t position = gcov_position (); 381 const char *source = NULL; 382 unsigned lineno = gcov_read_unsigned (); 383 384 if (!lineno) 385 { 386 source = gcov_read_string (); 387 if (!source) 388 break; 389 sep = NULL; 390 } 391 392 if (!sep) 393 { 394 printf ("\n"); 395 print_prefix (filename, 0, position); 396 printf ("\tblock %u:", blockno); 397 sep = ""; 398 } 399 if (lineno) 400 { 401 printf ("%s%u", sep, lineno); 402 sep = ", "; 403 } 404 else 405 { 406 printf ("%s`%s'", sep, source); 407 sep = ":"; 408 } 409 } 410 } 411 } 412 413 static void 414 tag_counters (const char *filename ATTRIBUTE_UNUSED, 415 unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 416 { 417 static const char *const counter_names[] = GCOV_COUNTER_NAMES; 418 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length); 419 420 printf (" %s %u counts", 421 counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts); 422 if (flag_dump_contents) 423 { 424 unsigned ix; 425 426 for (ix = 0; ix != n_counts; ix++) 427 { 428 gcov_type count; 429 430 if (!(ix & 7)) 431 { 432 printf ("\n"); 433 print_prefix (filename, 0, gcov_position ()); 434 printf ("\t\t%u", ix); 435 } 436 437 count = gcov_read_counter (); 438 printf (" "); 439 printf (HOST_WIDEST_INT_PRINT_DEC, count); 440 } 441 } 442 } 443 444 static void 445 tag_summary (const char *filename ATTRIBUTE_UNUSED, 446 unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 447 { 448 struct gcov_summary summary; 449 unsigned ix, h_ix; 450 gcov_bucket_type *histo_bucket; 451 452 gcov_read_summary (&summary); 453 printf (" checksum=0x%08x", summary.checksum); 454 455 for (ix = 0; ix != GCOV_COUNTERS_SUMMABLE; ix++) 456 { 457 printf ("\n"); 458 print_prefix (filename, 0, 0); 459 printf ("\t\tcounts=%u, runs=%u", 460 summary.ctrs[ix].num, summary.ctrs[ix].runs); 461 462 printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC, 463 (HOST_WIDEST_INT)summary.ctrs[ix].sum_all); 464 printf (", run_max=" HOST_WIDEST_INT_PRINT_DEC, 465 (HOST_WIDEST_INT)summary.ctrs[ix].run_max); 466 printf (", sum_max=" HOST_WIDEST_INT_PRINT_DEC, 467 (HOST_WIDEST_INT)summary.ctrs[ix].sum_max); 468 if (ix != GCOV_COUNTER_ARCS) 469 continue; 470 printf ("\n"); 471 print_prefix (filename, 0, 0); 472 printf ("\t\tcounter histogram:"); 473 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) 474 { 475 histo_bucket = &summary.ctrs[ix].histogram[h_ix]; 476 if (!histo_bucket->num_counters) 477 continue; 478 printf ("\n"); 479 print_prefix (filename, 0, 0); 480 printf ("\t\t%d: num counts=%u, min counter=" 481 HOST_WIDEST_INT_PRINT_DEC ", cum_counter=" 482 HOST_WIDEST_INT_PRINT_DEC, 483 h_ix, histo_bucket->num_counters, 484 (HOST_WIDEST_INT)histo_bucket->min_value, 485 (HOST_WIDEST_INT)histo_bucket->cum_value); 486 } 487 } 488 } 489