Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / debug / tools / coverage.pl
CommitLineData
920dae64
AT
1#!/pkg/gnu/bin/perl -w
2#
3# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
4# Use is subject to license terms.
5#
6# ident "@(#)coverage.pl 1.1 06/03/30 SMI"
7#
8# Purpose of this script is to take the coverage output from legion
9# and map it to the dis-assembly of a binary (in this case, hypervisor)
10# so that we can map out which code paths in Hypervisor have been
11# executed.
12#
13# Input:
14# q.dis - output from dis-assembly of q binary
15# coverage.log - output from code coverage_dump tool in legion
16#
17# Processing:
18# - read the coverage data a build up an array of addresses and ref_cnts
19# - read the dis-assembly file and figure out the address offsets for
20# each instruction.
21# - foreach line in the dis-assembly, get the ref_cnt from the coverage
22# file and write out to new file.
23#
24# Output:
25# coverage.txt - A text file containing the dis output for the binary
26# under examination with a ref_cnt per line showing how
27# many times each instn was executed.
28# coverage.html- A html file version of the coverage.txt file with
29# un-executed code paths highlighted in red text.
30#
31
32use strict;
33use Switch;
34
35# input files
36my $disfile = "q.dis";
37my $covfile="coverage.log";
38
39# output files
40my $outfile_txt="coverage.txt";
41my $outfile_html="coverage.html";
42
43# to be parse from command line
44my $hypervisor="";
45
46# init all variables
47my $cov_idx = 0;
48my $cov_addr = 0;
49my $cov_cnt = 0;
50my $cov_instn = 0;
51my $dis_sym = 0;
52my $dis_instn = 0;
53my $num_addrs_executed = 0;
54my $font_head = 0;
55my $font_tail = 0;
56my %cov_cnt;
57my %cov_instn;
58my $hv_base_addr_str = "";
59my $ignore0 = 0;
60my $ignore1 = 0;
61my $percentage = 0;
62my $summary = 0;
63my $ref_cnt = 0;
64my $ref_str = '';
65my $col_idx = 0;
66my $col_ref_str = "";
67my $col_sym = "";
68my $col_instn = "";
69
70sub main
71{
72 #
73 # Figure out from args whether this is an N1, N2 or Rock Hypervisor
74 # we are analysing. The output from dis needs to have it's addresses
75 # aligned to the location in memory where Hypervisor runs from.
76 #
77 $hypervisor = "$ARGV[0]";
78 switch ($hypervisor) {
79 case "n1" { print "Analysing Niagara1 hypervisor\n" }
80 case "n2" { print "Analysing Niagara2 hypervisor\n" }
81 case "rock" { print "Analysing Rock hypervisor\n" }
82 case "" { die "Usage: coverage.pl [processor]\nValid processors, [n1|n2|rock]\n" }
83 else { die "Fatal: Unknown processor $hypervisor\n" }
84 }
85
86 #
87 # Load dis and coverage files
88 #
89 open(dis_f, $disfile)
90 || die "Cannot open $disfile: $!\n";
91
92 open(cov_f, $covfile)
93 || die "Cannot open $covfile: $!\n";
94
95 #
96 # open output files
97 #
98 open(outf_txt, ">$outfile_txt")
99 || die "Cannot open $$outfile_txt: $!\n";
100
101 open(outf_html, ">$outfile_html")
102 || die "Cannot open $$outfile_html: $!\n";
103
104 # Print header of html and text files
105 print_header();
106
107 #
108 # build up an array of the coverage log file output so that
109 # we can search it using the address as an index later
110 #
111 while (<cov_f>) {
112 ($cov_idx,$cov_addr,$cov_cnt,$cov_instn) = split(/:/);
113 $cov_cnt{$cov_addr} = hex($cov_cnt);
114 $cov_instn{$cov_addr} = $cov_instn;
115 }
116
117 # Accounting for coverage data
118 my $num_addrs = 0; # total number of PC samples
119 my $num_addrs_excuted = 0; # only incr when ref_cnt > 0
120
121 my $hv_base_addr = get_hv_base_addr();
122 printf ("Hypervisor base address is 0x%llx\n", $hv_base_addr);
123 my $hv_addr_offset = 0x0;
124
125 #
126 # For each line of the dis output, check the coverage array
127 # for a ref_cnt. Then output the data into a new file using
128 # the text output and the html output.
129 #
130 while (<dis_f>) {
131
132 chomp;
133 next if (!/\s*([^:]+):\s*(.*)$/);
134
135 $dis_sym = $1;
136 $dis_instn = $2;
137
138 # Calculate the %pc address for this instruction
139 my $dis_addr += ($hv_base_addr + $hv_addr_offset);
140 $hv_addr_offset += 0x4;
141
142 #
143 # Map dis-assembly address to a legion address (offset in memory where HV
144 # runs from) so that it can match the coverage data.
145 #
146 switch ($hypervisor) {
147 case "n1" { no warnings; $dis_addr = (($dis_addr - hex('fff0000000')) + hex('400000')); }
148 case "n2" { no warnings; $dis_addr = (($dis_addr - hex('fff0000000')) + hex('100000')); }
149 case "rock" { $dis_addr += (hex('100000')); }
150 else { die "Fatal: need to figure out addr conversion for $hypervisor" }
151 }
152
153 #
154 # convert the address to a string with "0x" and the hex number
155 # so that we can use it as an index into the coverage data array
156 #
157 my $index_addr = sprintf("0x%llx", $dis_addr);
158
159 $ref_cnt = 0x0;
160 $ref_cnt = $cov_cnt{$index_addr} if $cov_cnt{$index_addr};
161
162 if ($ref_cnt == 0) {
163 # %pc not executed
164 $ref_str = 'NIL';
165 } else {
166 # %pc executed
167 $ref_str = sprintf("%d", $ref_cnt);
168 $num_addrs_executed += 1;
169 }
170
171 #
172 # Count number of %pc samples
173 # Ignore illtrap %pcs for coverage purposes
174 #
175 if (($dis_instn =~ /illtrap/) && (!$ref_cnt)) {
176 # Don't count or print illtrap %pcs that have no ref_cnt
177 } else {
178 # count number of %pcs whether they are executed or not
179 $num_addrs += 1;
180 print_row($index_addr, $ref_str, $dis_sym, $dis_instn);
181 }
182 }
183
184 #
185 # Calculate coverage accounting totals
186 #
187 $percentage = (($num_addrs_executed / ($num_addrs)) * 100);
188 $summary = sprintf ("Summary: Number of valid %%pc values in binary is %llu, coverage is [%.2f%%]\n",
189 $num_addrs, $percentage);
190 printf outf_txt ("%s", $summary);
191 printf outf_html ("<br>%s<br>\n", $summary);
192 printf ("%s", $summary);
193
194 print_footer();
195
196} #end main
197
198
199
200sub print_header
201{
202 print outf_txt "Addr, Ref_Cnt, Label, Instruction (raw, decoded)\n";
203
204 print outf_html << "EOF";
205<html>
206<head>
207<title>Hypervisor Coverage data for $hypervisor</title>
208</head>
209<body>
210<table WIDTH="100%" NOSAVE >
211EOF
212} # end print_header
213
214sub print_footer
215{
216 print outf_html << "EOF";
217</table>
218</verbatim>
219</body>
220</html>
221EOF
222
223} # end print_footer
224
225
226#
227# print a row of the table using args passed in
228#
229sub print_row
230{
231 $col_idx = $_[0];
232 $col_ref_str = $_[1];
233 $col_sym = $_[2];
234 $col_instn = $_[3];
235
236# chomp($col_instn);
237
238 $font_head="";
239 $font_tail="";
240
241 if ($col_ref_str eq 'NIL') {
242 # Mark all NIL lines in red font
243 $font_head= "<font color=red>";
244 $font_tail= "</font>";
245 print outf_txt " ";
246
247 } elsif ($col_ref_str eq 'N/A') {
248 # Print this for each line whose ref_cnt is N/A
249 print outf_txt " ";
250 } else {
251 # Print this for each line whose ref_cnt is non-zero
252 print outf_txt "-->";
253 }
254
255 #
256 # output to html file
257 #
258 print outf_html "<tr>\n";
259 print outf_html "\t<td>$font_head $col_idx $font_tail</td>\n";
260 print outf_html "\t<td>$font_head $col_ref_str $font_tail</td>\n";
261 print outf_html "\t<td>$font_head $col_sym $font_tail</td>\n";
262 print outf_html "\t<td>$font_head $col_instn $font_tail</td>\n";
263 print outf_html "</tr>";
264 print outf_html "\n";
265
266 #
267 # output to text file
268 #
269 print outf_txt "$col_idx, $col_ref_str, $col_sym, $col_instn\n";
270
271} # end print_row
272
273#
274# Get the base address of the hypervisor using /usr/ccs/bin/nm
275# to lookup the address of the _START_ symbol
276#
277sub get_hv_base_addr
278{
279 my $returncode = `/usr/ccs/bin/nm -xp q | grep _START_`;
280 ($hv_base_addr_str,$ignore0,$ignore1) = split(/ /, $returncode);
281 no warnings;
282 return hex($hv_base_addr_str);
283
284} # end get_hv_base_addr
285
286
287main();