# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# ident "@(#)coverage.pl 1.1 06/03/30 SMI"
# Purpose of this script is to take the coverage output from legion
# and map it to the dis-assembly of a binary (in this case, hypervisor)
# so that we can map out which code paths in Hypervisor have been
# q.dis - output from dis-assembly of q binary
# coverage.log - output from code coverage_dump tool in legion
# - read the coverage data a build up an array of addresses and ref_cnts
# - read the dis-assembly file and figure out the address offsets for
# - foreach line in the dis-assembly, get the ref_cnt from the coverage
# file and write out to new file.
# coverage.txt - A text file containing the dis output for the binary
# under examination with a ref_cnt per line showing how
# many times each instn was executed.
# coverage.html- A html file version of the coverage.txt file with
# un-executed code paths highlighted in red text.
my $covfile="coverage.log";
my $outfile_txt="coverage.txt";
my $outfile_html="coverage.html";
# to be parse from command line
my $num_addrs_executed = 0;
my $hv_base_addr_str = "";
# Figure out from args whether this is an N1, N2 or Rock Hypervisor
# we are analysing. The output from dis needs to have it's addresses
# aligned to the location in memory where Hypervisor runs from.
$hypervisor = "$ARGV[0]";
case
"n1" { print "Analysing Niagara1 hypervisor\n" }
case
"n2" { print "Analysing Niagara2 hypervisor\n" }
case
"rock" { print "Analysing Rock hypervisor\n" }
case
"" { die "Usage: coverage.pl [processor]\nValid processors, [n1|n2|rock]\n" }
else { die "Fatal: Unknown processor $hypervisor\n" }
# Load dis and coverage files
|| die "Cannot open $disfile: $!\n";
|| die "Cannot open $covfile: $!\n";
open(outf_txt
, ">$outfile_txt")
|| die "Cannot open $$outfile_txt: $!\n";
open(outf_html
, ">$outfile_html")
|| die "Cannot open $$outfile_html: $!\n";
# Print header of html and text files
# build up an array of the coverage log file output so that
# we can search it using the address as an index later
($cov_idx,$cov_addr,$cov_cnt,$cov_instn) = split(/:/);
$cov_cnt{$cov_addr} = hex($cov_cnt);
$cov_instn{$cov_addr} = $cov_instn;
# Accounting for coverage data
my $num_addrs = 0; # total number of PC samples
my $num_addrs_excuted = 0; # only incr when ref_cnt > 0
my $hv_base_addr = get_hv_base_addr
();
printf ("Hypervisor base address is 0x%llx\n", $hv_base_addr);
my $hv_addr_offset = 0x0;
# For each line of the dis output, check the coverage array
# for a ref_cnt. Then output the data into a new file using
# the text output and the html output.
next if (!/\s*([^:]+):\s*(.*)$/);
# Calculate the %pc address for this instruction
my $dis_addr += ($hv_base_addr + $hv_addr_offset);
# Map dis-assembly address to a legion address (offset in memory where HV
# runs from) so that it can match the coverage data.
case
"n1" { no warnings
; $dis_addr = (($dis_addr - hex('fff0000000')) + hex('400000')); }
case
"n2" { no warnings
; $dis_addr = (($dis_addr - hex('fff0000000')) + hex('100000')); }
case
"rock" { $dis_addr += (hex('100000')); }
else { die "Fatal: need to figure out addr conversion for $hypervisor" }
# convert the address to a string with "0x" and the hex number
# so that we can use it as an index into the coverage data array
my $index_addr = sprintf("0x%llx", $dis_addr);
$ref_cnt = $cov_cnt{$index_addr} if $cov_cnt{$index_addr};
$ref_str = sprintf("%d", $ref_cnt);
$num_addrs_executed += 1;
# Count number of %pc samples
# Ignore illtrap %pcs for coverage purposes
if (($dis_instn =~ /illtrap/) && (!$ref_cnt)) {
# Don't count or print illtrap %pcs that have no ref_cnt
# count number of %pcs whether they are executed or not
print_row
($index_addr, $ref_str, $dis_sym, $dis_instn);
# Calculate coverage accounting totals
$percentage = (($num_addrs_executed / ($num_addrs)) * 100);
$summary = sprintf ("Summary: Number of valid %%pc values in binary is %llu, coverage is [%.2f%%]\n",
$num_addrs, $percentage);
printf outf_txt
("%s", $summary);
printf outf_html
("<br>%s<br>\n", $summary);
print outf_txt
"Addr, Ref_Cnt, Label, Instruction (raw, decoded)\n";
print outf_html
<< "EOF";
<title
>Hypervisor Coverage data
for $hypervisor</title
>
<table WIDTH
="100%" NOSAVE
>
print outf_html
<< "EOF";
# print a row of the table using args passed in
if ($col_ref_str eq 'NIL') {
# Mark all NIL lines in red font
$font_head= "<font color=red>";
} elsif ($col_ref_str eq 'N/A') {
# Print this for each line whose ref_cnt is N/A
# Print this for each line whose ref_cnt is non-zero
print outf_html
"<tr>\n";
print outf_html
"\t<td>$font_head $col_idx $font_tail</td>\n";
print outf_html
"\t<td>$font_head $col_ref_str $font_tail</td>\n";
print outf_html
"\t<td>$font_head $col_sym $font_tail</td>\n";
print outf_html
"\t<td>$font_head $col_instn $font_tail</td>\n";
print outf_txt
"$col_idx, $col_ref_str, $col_sym, $col_instn\n";
# Get the base address of the hypervisor using /usr/ccs/bin/nm
# to lookup the address of the _START_ symbol
my $returncode = `/usr/ccs/bin/nm -xp q | grep _START_`;
($hv_base_addr_str,$ignore0,$ignore1) = split(/ /, $returncode);
return hex($hv_base_addr_str);