Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / debug / tools / coverage_dump.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: coverage_dump.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)coverage_dump.c 1.6 06/10/25 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include "basics.h"
#include "fatal.h"
#include "coverage.h"
#if 1
#define DBGP(s) do { s } while (0)
#endif
void
usage(void)
{
printf("\nUsage: coverage_dump [- a] [-z] [-c num_samples] "\
"[-r] [-v] [-t] filename" \
"\n [-a | --all]" \
"\n - dump all samples (zero and non-zero)" \
"\n [-z | --zero]" \
"\n - dump only zero samples (%%pc never hit)" \
"\n [-c | --count num_of_samples]" \
"\n - dump first num_of_samples %%pc samples" \
"\n - if this option is not given, all non-zero "\
"samples are dumped " \
"\n [-r | --ref]" \
"\n - don't increment the ref count for each "\
"access to a %%pc "\
"\n instead print 0x1 (if it was ever executed) "\
"\n or a 0x0 (if it was never executed) "\
"\n [-v | --verbose]" \
"\n - decode and display the raw instns" \
"\n by default, only the raw instn gets dumped" \
"\n [-t | --titles]" \
"\n - print titles and footer " \
"\n " \
"\n filename" \
"\n The name of file with legion coverage data" \
"\n " \
"\n When run with no options, dump all non-zero samples" \
"\n " \
"\n This tool is meant to work with the debug_hook feature" \
"\n for gathering coverage data. You need to" \
"\n specify a range of %%pc addresses in the conf file " \
"\n under the cpu directive as follows:" \
"\n " \
"\n debug_hook coverage 0x100000 0x800000;" \
"\n " \
"\n");
}
bool_t
streq(char *a, char *b)
{
return (strcmp(a, b) == 0);
}
/*
* Attach to shared memory created by legion and
* dump out coverage statistics from the running
* system.
*/
int
main(int argc, char ** argv)
{
uint64_t buf_size;
uint64_t dump_count = 0;
uint64_t sample_count;
uint64_t low_pc = 0;
uint64_t high_pc = 0;
uint64_t i;
bool_t dump_all_samples = false;
bool_t dump_zero_samples = false;
bool_t verbose = false;
bool_t titles = false;
bool_t ref_only = false;
char instn_buf[160];
bool_t print_it = false;
char filename[256];
int fd;
struct stat sb;
uint64_t num_of_pcs = 0;
coverage_info_t coverage_buf;
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
char *p;
p = &(argv[i][1]);
if (streq(p, "a") || streq(p, "-all")) {
if (dump_zero_samples) {
printf("\nERROR: Cannot use both -a and -z");
usage();
exit(1);
}
dump_all_samples = true;
} else
if (streq(p, "z") || streq(p, "-zero")) {
if (dump_all_samples) {
printf("\nERROR: Cannot use both -a and -z");
usage();
exit(1);
}
dump_zero_samples = true;
} else
if (streq(p, "c") || streq(p, "-count")) {
if (++i >= argc) {
usage();
exit(1);
}
dump_count = atol(argv[i]);
if (dump_count == 0) {
printf("\nERROR: Invalid value for count");
usage();
exit(1);
}
} else
if (streq(p, "r") || streq(p, "-ref")) {
ref_only = true;
} else
if (streq(p, "v") || streq(p, "-verbose")) {
verbose = true;
} else
if (streq(p, "t") || streq(p, "-titles")) {
titles = true;
} else {
printf("\nERROR: Illegal option %s", p);
usage();
exit(1);
}
}
/*
* Assume any non option provided is the name of the coverage
* data file.
*/
if (i == (argc - 1)) {
strcpy(filename, argv[i]);
} else {
printf("\nERROR: no filename specified");
usage();
exit(1);
}
/*
* Open the dump_file and get it's size.
*
* In order to figure out how many samples are in this file
* we divide the file size by the size of this struct.
* We can then then either dump them all, or dump just the first n
* if the -c flag is specified.
*/
if (stat(filename, &sb) == -1)
fatal("Error: dump_file %s does not exist.", filename);
sample_count = (sb.st_size / (sizeof (coverage_info_t)));
if ((fd = open(filename, O_RDONLY)) == -1)
fatal("Could not open dump_file %s\n", filename);
/*
* Depending on whether a specific number of samples was
* given at the command line or not, we either dump them
* all or just the first n samples.
* The -a flag determines whether we print the zero samples.
* The -z flag determines whether we only print the zero samples.
*/
if (dump_count != 0) {
num_of_pcs = dump_count; /* value from command line */
} else {
num_of_pcs = sample_count;
}
if (titles) {
printf("\nOpened data file : [%s] ", filename);
printf("\nSize of file in bytes : [0x%llx] ", sb.st_size);
printf("\nNumber of %%pc samples : [0x%llx] ", sample_count);
printf("\nIndx:%%pc:Ref_Cnt:Raw_Instn Decoded_Inst\n");
}
for (i = 0; i < num_of_pcs; i++) {
/* Read from the file */
if (read(fd, &coverage_buf, sizeof (coverage_info_t)) !=
sizeof (coverage_info_t)) {
perror("read");
fatal("Error reading from file %s\n", filename);
}
/* Gather stats for the end */
if (coverage_buf.count != 0) {
/* save the last non-zero count %pc */
high_pc = coverage_buf.pc;
if (low_pc == 0) {
/* save the first non-zero count %pc */
low_pc = coverage_buf.pc;
}
}
/* Figure out whether to print this sample or not */
print_it = false;
if (dump_all_samples) {
print_it = true;
} else if (dump_zero_samples) {
if (coverage_buf.count == 0)
print_it = true;
} else if (coverage_buf.count != 0) {
print_it = true;
}
if (print_it) {
if (ref_only) {
if (coverage_buf.count > 0x1)
coverage_buf.count = 0x1; /* reset to 0x1 */
}
printf("0x%llx:0x%llx:0x%x:0x%08x",
i, coverage_buf.pc, coverage_buf.count,
coverage_buf.rawi);
if (verbose) {
if (coverage_buf.count != 0) {
sparcv9_idis(instn_buf, sizeof (instn_buf),
coverage_buf.rawi, coverage_buf.pc);
} else {
sprintf(instn_buf, ":N/A", "%s");
}
printf(":%s", instn_buf);
}
printf("\n");
}
}
if (titles) {
printf("\nLoweset/Highest %%pc : [0x%llx] [0x%llx]\n",
low_pc, high_pc);
}
close(fd);
return (0);
}