Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / debug / coverage.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: coverage.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.c 1.5 06/10/25 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <assert.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <thread.h>
#include <synch.h>
#include "ss_common.h"
#include "niagara.h"
#include "coverage.h"
#if 1
#define DBGP(s) do { s; } while (0)
#endif
void dbg_coverage(simcpu_t *sp, uint32_t rawi);
void dbg_coverage_parse(void);
void dbg_coverage_dump(void);
/* start/end for pc,instn coverage analysis */
uint32_t coverage_mode;
uint64_t start_pc = 0x0;
uint64_t end_pc = 0x0;
bool_t decode_instn = false;
void *coverage_data_filep;
coverage_info_t *coverage_bufp;
/*
* This will be called while parsing the conf file
* to allow this hook to parse specific options from
* the conf file.
*
* Format of coverage directive is:
* debug_hook [coverage] [start] [end];
*
* [coverage] - we've already parsed this. That's how we got here.
* [data_file] - name of the file to mmap (will contain coverage data)
* [start]
* [end] - only trace when %pc is within [start]-[end] range
*
* All samples for %pc within the range supplied will be stored
* in a data file (using the name provided in the directive). The
* results of the coverage run can be viewed by running the
* coverage_dump tool (in the build directory) at any time during
* or after the run.
* NOTE: this feature will not overwrite the data_file
*/
void
dbg_coverage_parse(void)
{
lexer_tok_t tok;
uint64_t num_of_pcs;
int shmflg;
uint64_t buf_size;
char data_file[256];
struct stat sb;
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
int fd;
DBGP(printf("\nInside dbg_coverage_parse()"));
/* Parse data_file to mmap in */
tok = lex_get_token();
strcpy(data_file, lex.strp);
lex_get(T_Number); /* start pc */
start_pc = lex.val;
lex_get(T_Number); /* end pc */
end_pc = lex.val;
if (end_pc < start_pc)
lex_fatal("end_pc needs to be larger than start_pc in conf file");
num_of_pcs = ((end_pc - start_pc) / 4) + 1;
buf_size = ((sizeof (coverage_info_t)) * num_of_pcs);
DBGP(printf("\ncoverage: start_pc=0x%llx, end_pc=0x%llx "\
"num_of_pcs=0x%llx, buf_size=0x%llx",
start_pc, end_pc, num_of_pcs, buf_size));
/*
* Setup mmap file.
*
* Create the empty data_file of size buf_size
* Then mmap it into memory.
*/
/* Make sure file does not exist */
if (stat(data_file, &sb) == 0)
lex_fatal("coverage: file %s already exists. Check conf file ",
data_file);
/* Create a new file */
if ((fd = open(data_file, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1)
fatal("Could not create data_file %s\n", data_file);
/* Set the size of the file by seeking to the end and write NULL */
if (lseek(fd, (off_t)buf_size-1, SEEK_SET) < 0)
fatal("Could not create data_file of size [0x%llx]", buf_size);
if (write(fd, "", 1) != 1)
fatal("Could not write to data_file of size [0x%llx]", buf_size);
/* mmap file file */
coverage_data_filep = mmap(NULL, buf_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (coverage_data_filep == MAP_FAILED)
fatal("Failed to mmap %s\n", data_file);
coverage_bufp = coverage_data_filep;
/*
* return to parse_debug_hook() which will take care of
* parsing the last semi colon.
*/
}
/*
* This function will get called before each instruction
* gets executed in execloop(). We use the coverage_dump tool
* in legion to read the datafile.
*/
void
dbg_coverage(simcpu_t *sp, uint32_t rawi)
{
extern uint32_t sim_atomic_add_32_nv(uint32_t *target, int32_t delta);
int idx = 0;
sparcv9_cpu_t *v9p = (sparcv9_cpu_t *)(sp->specificp);
/*
* Only store data when %pc is in Hypervisor and it is in range
* XXX FIXME: we could parse the state from the config file.
*/
if ((v9p->state != V9_HyperPriv) ||
(sp->pc <= start_pc) || (sp->pc >= end_pc)) {
return;
}
idx = ((sp->pc - start_pc) / 4);
/* Increment counter and copy instn into buffer once */
if (sim_atomic_add_32_nv(&(coverage_bufp[idx].count), 1) == 1) {
coverage_bufp[idx].pc = sp->pc;
coverage_bufp[idx].rawi = rawi;
}
}
void
dbg_coverage_dump(void)
{
printf("\ndbg_coverage_dump: caled with start=0x%llx, end=0x%llx",
start_pc, end_pc);
printf("\nuse legion's coverage_dump tool to read the data file");
}