]>
Commit | Line | Data |
---|---|---|
a5544970 | 1 | # Copyright (C) 1997-2019 Free Software Foundation, Inc. |
3f93d729 JJ |
2 | |
3 | # This program is free software; you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
cd976c16 | 5 | # the Free Software Foundation; either version 3 of the License, or |
3f93d729 JJ |
6 | # (at your option) any later version. |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
cd976c16 NC |
14 | # along with GCC; see the file COPYING3. If not see |
15 | # <http://www.gnu.org/licenses/>. | |
3f93d729 JJ |
16 | |
17 | # Verify various kinds of gcov output: line counts, branch percentages, | |
18 | # and call return percentages. None of this is language-specific. | |
19 | ||
20 | global GCOV | |
21 | ||
20d1af89 ML |
22 | # |
23 | # clean-gcov-file -- delete a working file the compiler creates for gcov | |
24 | # | |
25 | # TESTCASE is the name of the test. | |
26 | # SUFFIX is file suffix | |
27 | ||
28 | proc clean-gcov-file { testcase suffix } { | |
29 | set basename [file tail $testcase] | |
30 | set base [file rootname $basename] | |
31 | remote_file host delete $base.$suffix | |
32 | } | |
33 | ||
3f93d729 JJ |
34 | # |
35 | # clean-gcov -- delete the working files the compiler creates for gcov | |
36 | # | |
37 | # TESTCASE is the name of the test. | |
38 | # | |
39 | proc clean-gcov { testcase } { | |
20d1af89 ML |
40 | clean-gcov-file $testcase "gcno" |
41 | clean-gcov-file $testcase "gcda" | |
42 | clean-gcov-file $testcase "gcov" | |
43 | clean-gcov-file $testcase "h.gcov" | |
3f93d729 JJ |
44 | } |
45 | ||
46 | # | |
47 | # verify-lines -- check that line counts are as expected | |
48 | # | |
b616eb02 JJ |
49 | # TESTNAME is the name of the test, including unique flags. |
50 | # TESTCASE is the name of the test file. | |
3f93d729 JJ |
51 | # FILE is the name of the gcov output file. |
52 | # | |
b616eb02 | 53 | proc verify-lines { testname testcase file } { |
3f93d729 | 54 | #send_user "verify-lines\n" |
0e485da0 | 55 | global subdir |
b616eb02 | 56 | |
3f93d729 | 57 | set failed 0 |
d19202ba NS |
58 | set fd [open $file r] |
59 | while { [gets $fd line] >= 0 } { | |
d407ad67 SP |
60 | # We want to match both "-" and "#####" as count as well as numbers, |
61 | # since we want to detect lines that shouldn't be marked as covered. | |
ddd6f407 | 62 | if [regexp "^ *(\[^:]*): *(\[0-9\\-#]+):.*count\\((\[0-9\\-#=\\.kMGTPEZY\*]+)\\)(.*)" \ |
0e485da0 NS |
63 | "$line" all is n shouldbe rest] { |
64 | if [regexp "^ *{(.*)}" $rest all xfailed] { | |
65 | switch [dg-process-target $xfailed] { | |
66 | "N" { continue } | |
67 | "F" { setup_xfail "*-*-*" } | |
68 | } | |
69 | } | |
3f93d729 | 70 | if { $is == "" } { |
b616eb02 | 71 | fail "$testname line $n: no data available" |
3f93d729 JJ |
72 | incr failed |
73 | } elseif { $is != $shouldbe } { | |
b616eb02 | 74 | fail "$testname line $n: is $is:should be $shouldbe" |
3f93d729 | 75 | incr failed |
0e485da0 | 76 | } else { |
b616eb02 | 77 | pass "$testname count for line $n" |
3f93d729 | 78 | } |
3f93d729 JJ |
79 | } |
80 | } | |
2cc3d93e | 81 | close $fd |
fc8a650e SS |
82 | return $failed |
83 | } | |
84 | ||
85 | ||
3f93d729 JJ |
86 | # |
87 | # verify-branches -- check that branch percentages are as expected | |
88 | # | |
b616eb02 JJ |
89 | # TESTNAME is the name of the test, including unique flags. |
90 | # TESTCASE is the name of the test file. | |
3f93d729 JJ |
91 | # FILE is the name of the gcov output file. |
92 | # | |
93 | # Checks are based on comments in the source file. This means to look for | |
94 | # branch percentages 10 or 90, 20 or 80, and # 70 or 30: | |
95 | # /* branch(10, 20, 70) */ | |
96 | # This means that all specified percentages should have been seen by now: | |
97 | # /* branch(end) */ | |
98 | # All specified percentages must also be seen by the next branch(n) or | |
99 | # by the end of the file. | |
100 | # | |
101 | # Each check depends on the compiler having generated the expected | |
102 | # branch instructions. Don't check for branches that might be | |
103 | # optimized away or replaced with predicated instructions. | |
104 | # | |
b616eb02 | 105 | proc verify-branches { testname testcase file } { |
3f93d729 | 106 | #send_user "verify-branches\n" |
b616eb02 | 107 | |
3f93d729 | 108 | set failed 0 |
3f93d729 JJ |
109 | set shouldbe "" |
110 | set fd [open $file r] | |
111 | set n 0 | |
112 | while { [gets $fd line] >= 0 } { | |
d19202ba | 113 | regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n |
3f93d729 JJ |
114 | if [regexp "branch" $line] { |
115 | verbose "Processing branch line $n: $line" 3 | |
116 | if [regexp "branch\\((\[0-9 \]+)\\)" "$line" all new_shouldbe] { | |
117 | # All percentages in the current list should have been seen. | |
118 | if {[llength $shouldbe] != 0} { | |
b616eb02 | 119 | fail "$testname line $n: expected branch percentages not found: $shouldbe" |
3f93d729 JJ |
120 | incr failed |
121 | set shouldbe "" | |
122 | } | |
123 | set shouldbe $new_shouldbe | |
124 | #send_user "$n: looking for: $shouldbe\n" | |
125 | # Record the percentages to check for. Replace percentage | |
126 | # n > 50 with 100-n, since block ordering affects the | |
127 | # direction of a branch. | |
128 | for {set i 0} {$i < [llength $shouldbe]} {incr i} { | |
129 | set num [lindex $shouldbe $i] | |
130 | if {$num > 50} { | |
131 | set shouldbe [lreplace $shouldbe $i $i [expr 100 - $num]] | |
132 | } | |
133 | } | |
d19202ba | 134 | } elseif [regexp "branch +\[0-9\]+ taken (-\[0-9\]+)%" "$line" \ |
3f93d729 JJ |
135 | all taken] { |
136 | # Percentages should never be negative. | |
b616eb02 | 137 | fail "$testname line $n: negative percentage: $taken" |
3f93d729 | 138 | incr failed |
d19202ba | 139 | } elseif [regexp "branch +\[0-9\]+ taken (\[0-9\]+)%" "$line" \ |
3f93d729 JJ |
140 | all taken] { |
141 | #send_user "$n: taken = $taken\n" | |
142 | # Percentages should never be greater than 100. | |
143 | if {$taken > 100} { | |
b616eb02 | 144 | fail "$testname line $n: branch percentage greater than 100: $taken" |
3f93d729 JJ |
145 | incr failed |
146 | } | |
147 | if {$taken > 50} { | |
148 | set taken [expr 100 - $taken] | |
149 | } | |
150 | # If this percentage is one to check for then remove it | |
151 | # from the list. It's normal to ignore some reports. | |
152 | set i [lsearch $shouldbe $taken] | |
153 | if {$i != -1} { | |
154 | set shouldbe [lreplace $shouldbe $i $i] | |
155 | } | |
156 | } elseif [regexp "branch\\(end\\)" "$line"] { | |
157 | # All percentages in the list should have been seen by now. | |
158 | if {[llength $shouldbe] != 0} { | |
b616eb02 | 159 | fail "$testname line n: expected branch percentages not found: $shouldbe" |
3f93d729 JJ |
160 | incr failed |
161 | } | |
162 | set shouldbe "" | |
163 | } | |
164 | } | |
165 | } | |
166 | # All percentages in the list should have been seen. | |
167 | if {[llength $shouldbe] != 0} { | |
b616eb02 | 168 | fail "$testname line $n: expected branch percentages not found: $shouldbe" |
3f93d729 JJ |
169 | incr failed |
170 | } | |
171 | close $fd | |
d19202ba | 172 | return $failed |
3f93d729 JJ |
173 | } |
174 | ||
175 | # | |
176 | # verify-calls -- check that call return percentages are as expected | |
177 | # | |
b616eb02 JJ |
178 | # TESTNAME is the name of the test, including unique flags. |
179 | # TESTCASE is the name of the test file. | |
3f93d729 JJ |
180 | # FILE is the name of the gcov output file. |
181 | # | |
182 | # Checks are based on comments in the source file. This means to look for | |
183 | # call return percentages 50, 20, 33: | |
184 | # /* returns(50, 20, 33) */ | |
185 | # This means that all specified percentages should have been seen by now: | |
186 | # /* returns(end) */ | |
187 | # All specified percentages must also be seen by the next returns(n) or | |
188 | # by the end of the file. | |
189 | # | |
190 | # Each check depends on the compiler having generated the expected | |
191 | # call instructions. Don't check for calls that are inserted by the | |
192 | # compiler or that might be inlined. | |
193 | # | |
b616eb02 | 194 | proc verify-calls { testname testcase file } { |
3f93d729 | 195 | #send_user "verify-calls\n" |
b616eb02 | 196 | |
3f93d729 | 197 | set failed 0 |
3f93d729 JJ |
198 | set shouldbe "" |
199 | set fd [open $file r] | |
200 | set n 0 | |
201 | while { [gets $fd line] >= 0 } { | |
d19202ba | 202 | regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n |
27283c73 | 203 | if [regexp "return" $line] { |
3f93d729 JJ |
204 | verbose "Processing returns line $n: $line" 3 |
205 | if [regexp "returns\\((\[0-9 \]+)\\)" "$line" all new_shouldbe] { | |
206 | # All percentages in the current list should have been seen. | |
207 | if {[llength $shouldbe] != 0} { | |
b616eb02 | 208 | fail "$testname line $n: expected return percentages not found: $shouldbe" |
3f93d729 JJ |
209 | incr failed |
210 | set shouldbe "" | |
211 | } | |
212 | # Record the percentages to check for. | |
213 | set shouldbe $new_shouldbe | |
27283c73 | 214 | } elseif [regexp "call +\[0-9\]+ returned (-\[0-9\]+)%" "$line" \ |
3f93d729 JJ |
215 | all returns] { |
216 | # Percentages should never be negative. | |
b616eb02 | 217 | fail "$testname line $n: negative percentage: $returns" |
3f93d729 | 218 | incr failed |
27283c73 | 219 | } elseif [regexp "call +\[0-9\]+ returned (\[0-9\]+)%" "$line" \ |
3f93d729 JJ |
220 | all returns] { |
221 | # For branches we check that percentages are not greater than | |
222 | # 100 but call return percentages can be, as for setjmp(), so | |
223 | # don't count that as an error. | |
224 | # | |
225 | # If this percentage is one to check for then remove it | |
226 | # from the list. It's normal to ignore some reports. | |
227 | set i [lsearch $shouldbe $returns] | |
228 | if {$i != -1} { | |
229 | set shouldbe [lreplace $shouldbe $i $i] | |
230 | } | |
231 | } elseif [regexp "returns\\(end\\)" "$line"] { | |
232 | # All percentages in the list should have been seen by now. | |
233 | if {[llength $shouldbe] != 0} { | |
b616eb02 | 234 | fail "$testname line $n: expected return percentages not found: $shouldbe" |
3f93d729 JJ |
235 | incr failed |
236 | } | |
237 | set shouldbe "" | |
238 | } | |
239 | } | |
240 | } | |
241 | # All percentages in the list should have been seen. | |
242 | if {[llength $shouldbe] != 0} { | |
b616eb02 | 243 | fail "$testname line $n: expected return percentages not found: $shouldbe" |
3f93d729 JJ |
244 | incr failed |
245 | } | |
246 | close $fd | |
d19202ba | 247 | return $failed |
3f93d729 JJ |
248 | } |
249 | ||
250 | # Called by dg-final to run gcov and analyze the results. | |
251 | # | |
7ffe3584 MM |
252 | # ARGS consists of the optional strings "branches" and/or "calls", |
253 | # (indicating that these things should be verified) followed by a | |
254 | # list of arguments to provide to gcov, including the name of the | |
255 | # source file. | |
3f93d729 JJ |
256 | |
257 | proc run-gcov { args } { | |
258 | global GCOV | |
259 | global srcdir subdir | |
260 | ||
0e485da0 | 261 | set gcov_args "" |
7ffe3584 MM |
262 | set gcov_verify_calls 0 |
263 | set gcov_verify_branches 0 | |
fc8a650e SS |
264 | set gcov_verify_lines 1 |
265 | set gcov_verify_intermediate 0 | |
20d1af89 | 266 | set gcov_remove_gcda 0 |
0e485da0 | 267 | set xfailed 0 |
3f93d729 | 268 | |
7ffe3584 MM |
269 | foreach a $args { |
270 | if { $a == "calls" } { | |
271 | set gcov_verify_calls 1 | |
272 | } elseif { $a == "branches" } { | |
273 | set gcov_verify_branches 1 | |
fc8a650e SS |
274 | } elseif { $a == "intermediate" } { |
275 | set gcov_verify_intermediate 1 | |
276 | set gcov_verify_calls 0 | |
277 | set gcov_verify_branches 0 | |
278 | set gcov_verify_lines 0 | |
20d1af89 ML |
279 | } elseif { $a == "remove-gcda" } { |
280 | set gcov_remove_gcda 1 | |
0e485da0 NS |
281 | } elseif { $gcov_args == "" } { |
282 | set gcov_args $a | |
283 | } else { | |
284 | switch [dg-process-target $a] { | |
285 | "N" { return } | |
286 | "F" { set xfailed 1 } | |
287 | } | |
3f93d729 JJ |
288 | } |
289 | } | |
290 | ||
e3b205be | 291 | set testname [testname-for-summary] |
b616eb02 JJ |
292 | |
293 | # Extract the test file name from the arguments. | |
7ffe3584 MM |
294 | set testcase [lindex $gcov_args end] |
295 | ||
20d1af89 ML |
296 | if { $gcov_remove_gcda } { |
297 | verbose "Removing $testcase.gcda" | |
298 | clean-gcov-file $testcase "gcda" | |
299 | } | |
300 | ||
3f93d729 | 301 | verbose "Running $GCOV $testcase" 2 |
11289ef9 BE |
302 | set testcase [remote_download host $testcase] |
303 | set result [remote_exec host $GCOV $gcov_args] | |
3f93d729 | 304 | if { [lindex $result 0] != 0 } { |
0e485da0 NS |
305 | if { $xfailed } { |
306 | setup_xfail "*-*-*" | |
307 | } | |
b616eb02 | 308 | fail "$testname gcov failed: [lindex $result 1]" |
3f93d729 JJ |
309 | clean-gcov $testcase |
310 | return | |
311 | } | |
312 | ||
bebe0086 ML |
313 | set builtin_index [string first "File '<built-in>'" $result] |
314 | if { $builtin_index != -1 } { | |
315 | fail "$testname gcov failed: <built-in>.gcov should not be created" | |
316 | clean-gcov $testcase | |
317 | return | |
318 | } | |
319 | ||
3f93d729 JJ |
320 | # Get the gcov output file after making sure it exists. |
321 | set files [glob -nocomplain $testcase.gcov] | |
322 | if { $files == "" } { | |
0e485da0 NS |
323 | if { $xfailed } { |
324 | setup_xfail "*-*-*" | |
325 | } | |
bebe0086 | 326 | fail "$testname gcov failed: $testcase.gcov does not exist" |
3f93d729 | 327 | clean-gcov $testcase |
11289ef9 | 328 | return |
3f93d729 | 329 | } |
11289ef9 | 330 | remote_upload host $testcase.gcov $testcase.gcov |
3f93d729 | 331 | |
3f93d729 | 332 | # Check that line execution counts are as expected. |
fc8a650e SS |
333 | if { $gcov_verify_lines } { |
334 | # Check that line execution counts are as expected. | |
335 | set lfailed [verify-lines $testname $testcase $testcase.gcov] | |
336 | } else { | |
337 | set lfailed 0 | |
338 | } | |
3f93d729 JJ |
339 | |
340 | # If requested via the .x file, check that branch and call information | |
341 | # is correct. | |
7ffe3584 | 342 | if { $gcov_verify_branches } { |
b616eb02 | 343 | set bfailed [verify-branches $testname $testcase $testcase.gcov] |
3f93d729 JJ |
344 | } else { |
345 | set bfailed 0 | |
3f93d729 | 346 | } |
7ffe3584 | 347 | if { $gcov_verify_calls } { |
b616eb02 | 348 | set cfailed [verify-calls $testname $testcase $testcase.gcov] |
3f93d729 JJ |
349 | } else { |
350 | set cfailed 0 | |
3f93d729 | 351 | } |
fc8a650e SS |
352 | if { $gcov_verify_intermediate } { |
353 | # Check that intermediate format has the expected format | |
354 | set ifailed [verify-intermediate $testname $testcase $testcase.gcov] | |
355 | } else { | |
356 | set ifailed 0 | |
357 | } | |
3f93d729 JJ |
358 | |
359 | # Report whether the gcov test passed or failed. If there were | |
360 | # multiple failures then the message is a summary. | |
fc8a650e | 361 | set tfailed [expr $lfailed + $bfailed + $cfailed + $ifailed] |
0e485da0 NS |
362 | if { $xfailed } { |
363 | setup_xfail "*-*-*" | |
364 | } | |
3f93d729 | 365 | if { $tfailed > 0 } { |
fc8a650e | 366 | fail "$testname gcov: $lfailed failures in line counts, $bfailed in branch percentages, $cfailed in return percentages, $ifailed in intermediate format" |
70f6380d TV |
367 | if { $xfailed } { |
368 | clean-gcov $testcase | |
369 | } | |
3f93d729 | 370 | } else { |
b616eb02 | 371 | pass "$testname gcov" |
3f93d729 JJ |
372 | clean-gcov $testcase |
373 | } | |
374 | } |