├── Command.md ├── SourceCode └── gcc │ ├── gcc.c │ ├── gcc.h │ ├── gccbug.in │ ├── gccspec.c │ ├── gcov-dump.c │ ├── gcov-io.c │ ├── gcov-io.h │ ├── gcov-iov.c │ └── gcov.c ├── example ├── output │ ├── amber.png │ ├── emerald.png │ ├── example │ │ ├── index-sort-f.html │ │ ├── index-sort-l.html │ │ ├── index.html │ │ ├── test.c.func-sort-c.html │ │ ├── test.c.func.html │ │ └── test.c.gcov.html │ ├── gcov.css │ ├── glass.png │ ├── index-sort-f.html │ ├── index-sort-l.html │ ├── index.html │ ├── ruby.png │ ├── snow.png │ └── updown.png ├── test ├── test.c ├── test.c.gcov ├── test.gcda └── test.gcno ├── picture ├── 2017-10-28 11-05-11屏幕截图.png ├── baogao.png ├── block.png ├── blockarcs.png ├── chazhuang.png ├── daiam.png ├── fugailv.png ├── gcno.png ├── gcov.png ├── gcov过程.PNG ├── info.png ├── shengcheng.png ├── 代码.png └── 带桩点基本块流图.png ├── readme.md └── reference.md /Command.md: -------------------------------------------------------------------------------- 1 | # 常用命令 2 | [TOC] 3 | 4 | ## 卸载软件: 5 | 6 | 1. 浏览已安装程序 7 | - 浏览所有已安装程序 8 | `dpkg --list` 9 | - 浏览有关qq的应用程序 10 | `dpkg -l | grep qq` 11 | 2. 卸载 12 | - 完全卸载 13 | `sudo apt-get --purge remove name` 14 | - 正常卸载 15 | `sudo spt-get remove name` 16 | 17 | ## 查看进程 18 | `ps -aux` 19 | 找到进程,`sudo kill PID`解决 20 | 21 | -------------------------------------------------------------------------------- /SourceCode/gcc/gcc.h: -------------------------------------------------------------------------------- 1 | /* Header file for modules that link with gcc.c 2 | Copyright (C) 1999, 2000, 2001, 2003, 2004, 2007, 2008 3 | Free Software Foundation, Inc. 4 | 5 | This file is part of GCC. 6 | 7 | GCC is free software; you can redistribute it and/or modify it under 8 | the terms of the GNU General Public License as published by the Free 9 | Software Foundation; either version 3, or (at your option) any later 10 | version. 11 | 12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with GCC; see the file COPYING3. If not see 19 | . */ 20 | 21 | #ifndef GCC_GCC_H 22 | #define GCC_GCC_H 23 | 24 | #include "version.h" 25 | 26 | /* The mapping of a spec function name to the C function that 27 | implements it. */ 28 | struct spec_function 29 | { 30 | const char *name; 31 | const char *(*func) (int, const char **); 32 | }; 33 | 34 | /* This defines which switch letters take arguments. */ 35 | 36 | #define DEFAULT_SWITCH_TAKES_ARG(CHAR) \ 37 | ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \ 38 | || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \ 39 | || (CHAR) == 'I' || (CHAR) == 'J' || (CHAR) == 'm' \ 40 | || (CHAR) == 'x' || (CHAR) == 'L' || (CHAR) == 'A' \ 41 | || (CHAR) == 'V' || (CHAR) == 'B' || (CHAR) == 'b') 42 | 43 | /* This defines which multi-letter switches take arguments. */ 44 | 45 | #define DEFAULT_WORD_SWITCH_TAKES_ARG(STR) \ 46 | (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext") \ 47 | || !strcmp (STR, "Tbss") || !strcmp (STR, "include") \ 48 | || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \ 49 | || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \ 50 | || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \ 51 | || !strcmp (STR, "iquote") || !strcmp (STR, "isystem") \ 52 | || !strcmp (STR, "isysroot") \ 53 | || !strcmp (STR, "-param") || !strcmp (STR, "specs") \ 54 | || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ") \ 55 | || !strcmp (STR, "fintrinsic-modules-path") || !strcmp (STR, "dumpbase")) 56 | 57 | 58 | /* These are exported by gcc.c. */ 59 | extern int do_spec (const char *); 60 | extern void record_temp_file (const char *, int, int); 61 | extern void fatal (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; 62 | extern void error (const char *, ...) ATTRIBUTE_PRINTF_1; 63 | extern void pfatal_with_name (const char *) ATTRIBUTE_NORETURN; 64 | extern void set_input (const char *); 65 | 66 | /* Spec files linked with gcc.c must provide definitions for these. */ 67 | 68 | /* Called before processing to change/add/remove arguments. */ 69 | extern void lang_specific_driver (int *, const char *const **, int *); 70 | 71 | /* Called before linking. Returns 0 on success and -1 on failure. */ 72 | extern int lang_specific_pre_link (void); 73 | 74 | extern int n_infiles; 75 | 76 | /* Number of extra output files that lang_specific_pre_link may generate. */ 77 | extern int lang_specific_extra_outfiles; 78 | 79 | /* A vector of corresponding output files is made up later. */ 80 | 81 | extern const char **outfiles; 82 | 83 | #endif /* ! GCC_GCC_H */ 84 | -------------------------------------------------------------------------------- /SourceCode/gcc/gccbug.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Submit a problem report to a GNATS site. 3 | # Copyright (C) 1993, 2000, 2001, 2002, 2003, 2007 Free Software Foundation, Inc. 4 | # Contributed by Brendan Kehoe (brendan@cygnus.com), based on a 5 | # version written by Heinz G. Seidl (hgs@cygnus.com). 6 | # 7 | # This file is part of GNU GNATS. 8 | # 9 | # GNU GNATS is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 3, or (at your option) 12 | # any later version. 13 | # 14 | # GNU GNATS is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with GNU GNATS; see the file COPYING3. If not see 21 | # . 22 | 23 | # The version of this send-pr. 24 | VERSION=3.113 25 | 26 | # The submitter-id for your site. 27 | SUBMITTER=net 28 | 29 | # The default mail address for PR submissions. 30 | GNATS_ADDR=gcc-gnats@gcc.gnu.org 31 | 32 | # The default release for this host. 33 | # We have to guess at what program_transform_name might have done. 34 | # "sed 1q" because neither "head -1" nor "head -n 1" is universal, argh. 35 | 36 | DEFAULT_GCC="`echo $0 | sed -e 's/bug//'`" 37 | DEFAULT_RELEASE="`$DEFAULT_GCC --version | sed 1q`" 38 | 39 | # The default organization. 40 | DEFAULT_ORGANIZATION= 41 | 42 | # What mailer to use. This must come after the config file, since it is 43 | # host-dependent. 44 | # Copied from cvsbug 45 | if [ -f /usr/sbin/sendmail ]; then 46 | MAIL_AGENT="/usr/sbin/sendmail -oi -t" 47 | else 48 | MAIL_AGENT="/usr/lib/sendmail -oi -t" 49 | fi 50 | MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'` 51 | if [ ! -f "$MAILER" ] ; then 52 | echo "$COMMAND: Cannot file mail program \"$MAILER\"." 53 | echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file." 54 | exit 1 55 | fi 56 | 57 | 58 | # How to read the passwd database. 59 | PASSWD="cat /etc/passwd" 60 | 61 | ECHON=bsd 62 | 63 | if [ $ECHON = bsd ] ; then 64 | ECHON1="echo -n" 65 | ECHON2= 66 | elif [ $ECHON = sysv ] ; then 67 | ECHON1=echo 68 | ECHON2='\c' 69 | else 70 | ECHON1=echo 71 | ECHON2= 72 | fi 73 | 74 | # 75 | 76 | if [ -z "$TMPDIR" ]; then 77 | TMPDIR=/tmp 78 | else 79 | if [ "`echo $TMPDIR | grep '/$'`" != "" ]; then 80 | TMPDIR="`echo $TMPDIR | sed -e 's,/$,,'`" 81 | fi 82 | fi 83 | 84 | if [ @have_mktemp_command@ = yes ]; then 85 | TEMP0=`mktemp $TMPDIR/poXXXXXX` || exit 1 86 | TEMP=`mktemp $TMPDIR/pXXXXXX` || exit 1 87 | BAD=`mktemp $TMPDIR/pbadXXXXXX` || exit 1 88 | REF=`mktemp $TMPDIR/pfXXXXXX` || exit 1 89 | REMOVE_TEMP="rm -f $TEMP0 $TEMP $BAD $REF" 90 | else 91 | TEMPD=$TMPDIR/pd$$ 92 | TEMP0=$TEMPD/po$$ 93 | TEMP=$TEMPD/p$$ 94 | BAD=$TEMPD/pbad$$ 95 | REF=$TEMPD/pf$$ 96 | mkdir $TEMPD || exit 1 97 | REMOVE_TEMP="rm -rf $TEMPD" 98 | fi 99 | 100 | # find a user name 101 | if [ "$LOGNAME" = "" ]; then 102 | if [ "$USER" != "" ]; then 103 | LOGNAME="$USER" 104 | else 105 | LOGNAME="UNKNOWN" 106 | fi 107 | fi 108 | 109 | FROM="$LOGNAME" 110 | REPLY_TO="${REPLY_TO:-${REPLYTO:-$LOGNAME}}" 111 | 112 | # Find out the name of the originator of this PR. 113 | if [ -n "$NAME" ]; then 114 | ORIGINATOR="$NAME" 115 | elif [ -f $HOME/.fullname ]; then 116 | ORIGINATOR="`sed -e '1q' $HOME/.fullname`" 117 | else 118 | # Must use temp file due to incompatibilities in quoting behavior 119 | # and to protect shell metacharacters in the expansion of $LOGNAME 120 | $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP0 121 | ORIGINATOR="`cat $TEMP0`" 122 | rm -f $TEMP0 123 | fi 124 | 125 | if [ -n "$ORGANIZATION" ]; then 126 | if [ -f "$ORGANIZATION" ]; then 127 | ORGANIZATION="`cat $ORGANIZATION`" 128 | fi 129 | else 130 | if [ -n "$DEFAULT_ORGANIZATION" ]; then 131 | ORGANIZATION="$DEFAULT_ORGANIZATION" 132 | elif [ -f $HOME/.organization ]; then 133 | ORGANIZATION="`cat $HOME/.organization`" 134 | fi 135 | fi 136 | 137 | # If they don't have a preferred editor set, then use 138 | if [ -z "$VISUAL" ]; then 139 | if [ -z "$EDITOR" ]; then 140 | EDIT=vi 141 | else 142 | EDIT="$EDITOR" 143 | fi 144 | else 145 | EDIT="$VISUAL" 146 | fi 147 | 148 | # Find out some information. 149 | SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \ 150 | ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""` 151 | ARCH=`[ -f /bin/arch ] && /bin/arch` 152 | MACHINE=`[ -f /bin/machine ] && /bin/machine` 153 | 154 | COMMAND=`echo $0 | sed -e 's,.*/,,'` 155 | USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [-s severity] 156 | [-c address] [--request-id] [--version]" 157 | REMOVE= 158 | BATCH= 159 | CC= 160 | SEVERITY_C= 161 | 162 | while [ $# -gt 0 ]; do 163 | case "$1" in 164 | -r) ;; # Ignore for backward compat. 165 | -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; $REMOVE_TEMP; exit 1; fi 166 | shift ; GNATS_ADDR="$1" 167 | EXPLICIT_GNATS_ADDR=true 168 | ;; 169 | -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; $REMOVE_TEMP; exit 1; fi 170 | shift ; IN_FILE="$1" 171 | if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then 172 | echo "$COMMAND: cannot read $IN_FILE" 173 | $REMOVE_TEMP 174 | exit 1 175 | fi 176 | ;; 177 | -b | --batch) BATCH=true ;; 178 | -c | --cc) if [ $# -eq 1 ]; then echo "$USAGE"; $REMOVE_TEMP; exit 1; fi 179 | shift ; CC="$1" 180 | ;; 181 | -s | --severity) if [ $# -eq 1 ]; then echo "$USAGE"; $REMOVE_TEMP; exit 1; fi 182 | shift ; SEVERITY_C="$1" 183 | ;; 184 | -p | -P | --print) PRINT=true ;; 185 | -L | --list) FORMAT=norm ;; 186 | -l | -CL | --lisp) FORMAT=lisp ;; 187 | --request-id) REQUEST_ID=true ;; 188 | -h | --help) echo "$USAGE"; $REMOVE_TEMP; exit 0 ;; 189 | -V | --version) cat < max) { max = length($0); } } 214 | END {print max + 1;}'` 215 | c=`expr 70 / $l` 216 | if [ $c -eq 0 ]; then c=1; fi 217 | echo "$CATEGORIES" | \ 218 | awk 'BEGIN {print "Known categories:"; i = 0 } 219 | { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } } 220 | END { print ""; }' 221 | $REMOVE_TEMP 222 | exit 0 223 | ;; 224 | esac 225 | 226 | ORIGINATOR_C='' 227 | ORGANIZATION_C='' 228 | SYNOPSIS_C='' 229 | if [ -z "$SEVERITY_C" ]; then 230 | SEVERITY_C='<[ non-critical | serious | critical ] (one line)>' 231 | fi 232 | PRIORITY_C='<[ low | medium ] (one line)>' 233 | CATEGORY_C='' 234 | RELEASE_C='' 235 | ENVIRONMENT_C='' 236 | DESCRIPTION_C='' 237 | HOW_TO_REPEAT_C='' 238 | FIX_C='' 239 | 240 | # Catch some signals. ($xs kludge needed by Sun /bin/sh) 241 | xs=0 242 | trap '$REMOVE_TEMP; exit $xs' 0 243 | trap 'echo "$COMMAND: Aborting ..."; $REMOVE_TEMP; xs=1; exit' 1 3 13 15 244 | 245 | # If they told us to use a specific file, then do so. 246 | if [ -n "$IN_FILE" ]; then 247 | if [ "$IN_FILE" = "-" ]; then 248 | # The PR is coming from the standard input. 249 | if [ -n "$EXPLICIT_GNATS_ADDR" ]; then 250 | sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP 251 | else 252 | cat > $TEMP 253 | fi 254 | else 255 | # Use the file they named. 256 | if [ -n "$EXPLICIT_GNATS_ADDR" ]; then 257 | sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP 258 | else 259 | cat $IN_FILE > $TEMP 260 | fi 261 | fi 262 | else 263 | 264 | if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then 265 | # If their PR_FORM points to a bogus entry, then bail. 266 | if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then 267 | echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM" 268 | sleep 1 269 | PRINT_INTERN=bad_prform 270 | fi 271 | fi 272 | 273 | if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then 274 | cp $PR_FORM $TEMP || 275 | ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit ) 276 | else 277 | for file in $TEMP $REF ; do 278 | cat > $file << '__EOF__' 279 | SEND-PR: -*- send-pr -*- 280 | SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as 281 | SEND-PR: will all comments (text enclosed in `<' and `>'). 282 | SEND-PR: 283 | SEND-PR: Please consult the GCC manual if you are not sure how to 284 | SEND-PR: fill out a problem report. 285 | SEND-PR: Note that the Synopsis field is mandatory. The Subject (for 286 | SEND-PR: the mail) will be made the same as Synopsis unless explicitly 287 | SEND-PR: changed. 288 | SEND-PR: 289 | SEND-PR: Choose from the following categories: 290 | SEND-PR: 291 | __EOF__ 292 | 293 | # Format the categories so they fit onto lines. 294 | l=`echo "$CATEGORIES" | \ 295 | awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } } 296 | END {print max + 1;}'` 297 | c=`expr 61 / $l` 298 | if [ $c -eq 0 ]; then c=1; fi 299 | echo "$CATEGORIES" | \ 300 | awk 'BEGIN {printf "SEND-PR: "; i = 0 } 301 | { printf ("%-'$l'.'$l's", $0); 302 | if ((++i % '$c') == 0) { printf "\nSEND-PR: " } } 303 | END { printf "\nSEND-PR:\n"; }' >> $file 304 | 305 | cat >> $file << __EOF__ 306 | To: $GNATS_ADDR 307 | Subject: 308 | From: $FROM 309 | Reply-To: $REPLYTO 310 | Cc: $CC 311 | X-send-pr-version: $VERSION 312 | X-GNATS-Notify: 313 | 314 | 315 | >Submitter-Id: $SUBMITTER 316 | >Originator: $ORIGINATOR 317 | >Organization: ${ORGANIZATION-$ORGANIZATION_C} 318 | >Confidential: no 319 | SEND-PR: Leave "Confidential" as "no"; all GCC PRs are public. 320 | >Synopsis: $SYNOPSIS_C 321 | >Severity: $SEVERITY_C 322 | SEND-PR: critical GCC is completely not operational; no work-around known. 323 | SEND-PR: serious GCC is not working properly; a work-around is possible. 324 | SEND-PR: non-critical Report indicates minor problem. 325 | >Priority: $PRIORITY_C 326 | SEND-PR: medium The problem should be solved in the next release. 327 | SEND-PR: low The problem should be solve in a future release. 328 | >Category: $CATEGORY_C 329 | >Class: <[ doc-bug | accepts-illegal | rejects-legal | wrong-code | ice-on-legal-code| ice-on-illegal-code | pessimizes-code | sw-bug | change-request | support ] (one line)> 330 | SEND-PR: doc-bug The documentation is incorrect. 331 | SEND-PR: accepts-illegal GCC fails to reject erroneous code. 332 | SEND-PR: rejects-legal GCC gives an error message for correct code. 333 | SEND-PR: wrong-code The machine code generated by gcc is incorrect. 334 | SEND-PR: ice-on-legal-code GCC gives an Internal Compiler Error (ICE) 335 | SEND-PR: for correct code 336 | SEND-PR: ice-on-illegal-code GCC gives an ICE instead of reporting an error 337 | SEND-PR: pessimizes-code GCC misses an important optimization opportunity 338 | SEND-PR: sw-bug Software bug of some other class than above 339 | SEND-PR: change-request A feature in GCC is missing. 340 | SEND-PR: support I need help with gcc. 341 | >Release: ${DEFAULT_RELEASE-$RELEASE_C} 342 | >Environment: 343 | `[ -n "$SYSTEM" ] && echo System: $SYSTEM` 344 | `[ -n "$ARCH" ] && echo Architecture: $ARCH` 345 | `[ -n "$MACHINE" ] && echo Machine: $MACHINE` 346 | $ENVIRONMENT_C 347 | host: @host@ 348 | build: @build@ 349 | target: @target@ 350 | __EOF__ 351 | cat >> $file << \__EOF__ 352 | configured with: @gcc_config_arguments@ 353 | __EOF__ 354 | cat >> $file << __EOF__ 355 | >Description: 356 | $DESCRIPTION_C 357 | >How-To-Repeat: 358 | $HOW_TO_REPEAT_C 359 | >Fix: 360 | $FIX_C 361 | __EOF__ 362 | done 363 | fi 364 | 365 | if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then 366 | cat $TEMP 367 | xs=0; exit 368 | fi 369 | 370 | chmod u+w $TEMP 371 | if [ -z "$REQUEST_ID" ]; then 372 | eval $EDIT $TEMP 373 | else 374 | ed -s $TEMP << '__EOF__' 375 | /^Subject/s/^Subject:.*/Subject: request for a customer id/ 376 | /^>Category/s/^>Category:.*/>Category: send-pr/ 377 | w 378 | q 379 | __EOF__ 380 | fi 381 | 382 | if cmp -s $REF $TEMP ; then 383 | echo "$COMMAND: problem report not filled out, therefore not sent" 384 | xs=1; exit 385 | fi 386 | fi 387 | 388 | # 389 | # Check the enumeration fields 390 | 391 | # This is a "sed-subroutine" with one keyword parameter 392 | # (with workaround for Sun sed bug) 393 | # 394 | SED_CMD=' 395 | /$PATTERN/{ 396 | s||| 397 | s|<.*>|| 398 | s|^[ ]*|| 399 | s|[ ]*$|| 400 | p 401 | q 402 | }' 403 | 404 | 405 | while [ -z "$REQUEST_ID" ]; do 406 | CNT=0 407 | 408 | # 1) Confidential 409 | # 410 | PATTERN=">Confidential:" 411 | CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 412 | case "$CONFIDENTIAL" in 413 | no) CNT=`expr $CNT + 1` ;; 414 | *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;; 415 | esac 416 | # 417 | # 2) Severity 418 | # 419 | PATTERN=">Severity:" 420 | SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 421 | case "$SEVERITY" in 422 | ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;; 423 | *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'." 424 | esac 425 | # 426 | # 3) Priority 427 | # 428 | PATTERN=">Priority:" 429 | PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 430 | case "$PRIORITY" in 431 | ""|low|medium) CNT=`expr $CNT + 1` ;; 432 | high) echo "$COMMAND: \`Priority: high' is reserved for GCC maintainers." ;; 433 | *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'." 434 | esac 435 | # 436 | # 4) Category 437 | # 438 | PATTERN=">Category:" 439 | CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 440 | FOUND= 441 | for C in $CATEGORIES 442 | do 443 | if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi 444 | done 445 | if [ -n "$FOUND" ]; then 446 | CNT=`expr $CNT + 1` 447 | else 448 | if [ -z "$CATEGORY" ]; then 449 | echo "$COMMAND: you must include a Category: field in your report." 450 | else 451 | echo "$COMMAND: \`$CATEGORY' is not a known category." 452 | fi 453 | fi 454 | # 455 | # 5) Class 456 | # 457 | PATTERN=">Class:" 458 | CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP` 459 | case "$CLASS" in 460 | ""|doc-bug|accepts-illegal|rejects-legal|wrong-code|ice-on-legal-code|ice-on-illegal-code|pessimizes-code|sw-bug|change-request|support) CNT=`expr $CNT + 1` ;; 461 | *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'." 462 | esac 463 | # 464 | # 6) Check that synopsis is not empty 465 | # 466 | if grep "^>Synopsis:[ ]*${SYNOPSIS_C}\$" $TEMP > /dev/null 467 | then 468 | echo "$COMMAND: Synopsis must not be empty." 469 | else 470 | CNT=`expr $CNT + 1` 471 | fi 472 | 473 | [ $CNT -lt 6 -a -z "$BATCH" ] && 474 | echo "Errors were found with the problem report." 475 | 476 | while true; do 477 | if [ -z "$BATCH" ]; then 478 | $ECHON1 "a)bort, e)dit or s)end? $ECHON2" 479 | read input 480 | else 481 | if [ $CNT -eq 6 ]; then 482 | input=s 483 | else 484 | input=a 485 | fi 486 | fi 487 | case "$input" in 488 | a*) 489 | if [ -z "$BATCH" ]; then 490 | echo "$COMMAND: the problem report remains in $BAD and is not sent." 491 | REMOVE_TEMP="rm -f $TEMP0 $TEMP $REF" 492 | mv $TEMP $BAD 493 | else 494 | echo "$COMMAND: the problem report is not sent." 495 | fi 496 | xs=1; exit 497 | ;; 498 | e*) 499 | eval $EDIT $TEMP 500 | continue 2 501 | ;; 502 | s*) 503 | break 2 504 | ;; 505 | esac 506 | done 507 | done 508 | 509 | # 510 | # Make sure the mail has got a Subject. If not, use the same as 511 | # in Synopsis. 512 | # 513 | 514 | if grep '^Subject:[ ]*$' $TEMP > /dev/null 515 | then 516 | SYNOPSIS=`grep '^>Synopsis:' $TEMP | sed -e 's/^>Synopsis:[ ]*//'` 517 | ed -s $TEMP << __EOF__ 518 | /^Subject:/s/:.*\$/: $SYNOPSIS/ 519 | w 520 | q 521 | __EOF__ 522 | fi 523 | 524 | # 525 | # Remove comments and send the problem report 526 | # (we have to use patterns, where the comment contains regex chars) 527 | # 528 | # /^>Originator:/s;$ORIGINATOR;; 529 | sed -e " 530 | /^SEND-PR:/d 531 | /^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;; 532 | /^>Confidential:/s;<.*>;; 533 | /^>Synopsis:/s;$SYNOPSIS_C;; 534 | /^>Severity:/s;<.*>;; 535 | /^>Priority:/s;<.*>;; 536 | /^>Category:/s;$CATEGORY_C;; 537 | /^>Class:/s;<.*>;; 538 | /^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;; 539 | /^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;; 540 | /^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;; 541 | /^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;; 542 | /^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;; 543 | " $TEMP > $REF 544 | 545 | if $MAIL_AGENT < $REF; then 546 | echo "$COMMAND: problem report sent" 547 | xs=0; exit 548 | else 549 | echo "$COMMAND: mysterious mail failure." 550 | if [ -z "$BATCH" ]; then 551 | echo "$COMMAND: the problem report remains in $BAD and is not sent." 552 | REMOVE_TEMP="rm -f $TEMP0 $TEMP $REF" 553 | mv $REF $BAD 554 | else 555 | echo "$COMMAND: the problem report is not sent." 556 | fi 557 | xs=1; exit 558 | fi 559 | -------------------------------------------------------------------------------- /SourceCode/gcc/gccspec.c: -------------------------------------------------------------------------------- 1 | /* Specific flags and argument handling of the C front-end. 2 | Copyright (C) 1999, 2001, 2003, 2007 Free Software Foundation, Inc. 3 | 4 | This file is part of GCC. 5 | 6 | GCC is free software; you can redistribute it and/or modify it under 7 | the terms of the GNU General Public License as published by the Free 8 | Software Foundation; either version 3, or (at your option) any later 9 | version. 10 | 11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with GCC; see the file COPYING3. If not see 18 | . */ 19 | 20 | #include "config.h" 21 | #include "system.h" 22 | #include "coretypes.h" 23 | #include "tm.h" 24 | #include "gcc.h" 25 | 26 | /* Filter argc and argv before processing by the gcc driver proper. */ 27 | void 28 | lang_specific_driver (int *in_argc ATTRIBUTE_UNUSED, 29 | const char *const **in_argv ATTRIBUTE_UNUSED, 30 | int *in_added_libraries ATTRIBUTE_UNUSED) 31 | { 32 | /* Systems which use the NeXT runtime by default should arrange 33 | for the shared libgcc to be used when -fgnu-runtime is passed 34 | through specs. */ 35 | #if defined(ENABLE_SHARED_LIBGCC) && ! defined(NEXT_OBJC_RUNTIME) 36 | int i; 37 | 38 | /* The new argument list will be contained in this. */ 39 | const char **arglist; 40 | 41 | /* True if we should add -shared-libgcc to the command-line. */ 42 | int shared_libgcc = 0; 43 | 44 | /* The total number of arguments with the new stuff. */ 45 | int argc; 46 | 47 | /* The argument list. */ 48 | const char *const *argv; 49 | 50 | argc = *in_argc; 51 | argv = *in_argv; 52 | 53 | for (i = 1; i < argc; i++) 54 | { 55 | if (argv[i][0] == '-') 56 | { 57 | if (strcmp (argv[i], "-static-libgcc") == 0 58 | || strcmp (argv[i], "-static") == 0) 59 | return; 60 | } 61 | else 62 | { 63 | int len; 64 | 65 | /* If the filename ends in .m or .mi, we are compiling ObjC 66 | and want to pass -shared-libgcc. */ 67 | len = strlen (argv[i]); 68 | if ((len > 2 && argv[i][len - 2] == '.' && argv[i][len - 1] == 'm') 69 | || (len > 3 && argv[i][len - 3] == '.' && argv[i][len - 2] == 'm' 70 | && argv[i][len - 1] == 'i')) 71 | shared_libgcc = 1; 72 | } 73 | } 74 | 75 | if (shared_libgcc) 76 | { 77 | /* Make sure to have room for the trailing NULL argument. */ 78 | arglist = XNEWVEC (const char *, argc + 2); 79 | 80 | i = 0; 81 | do 82 | { 83 | arglist[i] = argv[i]; 84 | i++; 85 | } 86 | while (i < argc); 87 | 88 | arglist[i++] = "-shared-libgcc"; 89 | 90 | arglist[i] = NULL; 91 | 92 | *in_argc = i; 93 | *in_argv = arglist; 94 | } 95 | #endif 96 | } 97 | 98 | /* Called before linking. Returns 0 on success and -1 on failure. */ 99 | int 100 | lang_specific_pre_link (void) 101 | { 102 | return 0; /* Not used for C. */ 103 | } 104 | 105 | /* Number of extra output files that lang_specific_pre_link may generate. */ 106 | int lang_specific_extra_outfiles = 0; /* Not used for C. */ 107 | -------------------------------------------------------------------------------- /SourceCode/gcc/gcov-dump.c: -------------------------------------------------------------------------------- 1 | /* Dump a gcov file, for debugging use. 2 | Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 3 | Free Software Foundation, Inc. 4 | Contributed by Nathan Sidwell 5 | 6 | Gcov is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 3, or (at your option) 9 | any later version. 10 | 11 | Gcov is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with Gcov; see the file COPYING3. If not see 18 | . */ 19 | 20 | #include "config.h" 21 | #include "system.h" 22 | #include "coretypes.h" 23 | #include "tm.h" 24 | #include "version.h" 25 | #include 26 | #define IN_GCOV (-1) 27 | #include "gcov-io.h" 28 | #include "gcov-io.c" 29 | 30 | static void dump_file (const char *); 31 | static void print_prefix (const char *, unsigned, gcov_position_t); 32 | static void print_usage (void); 33 | static void print_version (void); 34 | static void tag_function (const char *, unsigned, unsigned); 35 | static void tag_blocks (const char *, unsigned, unsigned); 36 | static void tag_arcs (const char *, unsigned, unsigned); 37 | static void tag_lines (const char *, unsigned, unsigned); 38 | static void tag_counters (const char *, unsigned, unsigned); 39 | static void tag_summary (const char *, unsigned, unsigned); 40 | extern int main (int, char **); 41 | 42 | typedef struct tag_format 43 | { 44 | unsigned tag; 45 | char const *name; 46 | void (*proc) (const char *, unsigned, unsigned); 47 | } tag_format_t; 48 | 49 | static int flag_dump_contents = 0; 50 | static int flag_dump_positions = 0; 51 | 52 | static const struct option options[] = 53 | { 54 | { "help", no_argument, NULL, 'h' }, 55 | { "version", no_argument, NULL, 'v' }, 56 | { "long", no_argument, NULL, 'l' }, 57 | { "positions", no_argument, NULL, 'o' }, 58 | { 0, 0, 0, 0 } 59 | }; 60 | 61 | static const tag_format_t tag_table[] = 62 | { 63 | {0, "NOP", NULL}, 64 | {0, "UNKNOWN", NULL}, 65 | {0, "COUNTERS", tag_counters}, 66 | {GCOV_TAG_FUNCTION, "FUNCTION", tag_function}, 67 | {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks}, 68 | {GCOV_TAG_ARCS, "ARCS", tag_arcs}, 69 | {GCOV_TAG_LINES, "LINES", tag_lines}, 70 | {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary}, 71 | {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, 72 | {0, NULL, NULL} 73 | }; 74 | 75 | int 76 | main (int argc ATTRIBUTE_UNUSED, char **argv) 77 | { 78 | int opt; 79 | 80 | /* Unlock the stdio streams. */ 81 | unlock_std_streams (); 82 | 83 | while ((opt = getopt_long (argc, argv, "hlpv", options, NULL)) != -1) 84 | { 85 | switch (opt) 86 | { 87 | case 'h': 88 | print_usage (); 89 | break; 90 | case 'v': 91 | print_version (); 92 | break; 93 | case 'l': 94 | flag_dump_contents = 1; 95 | break; 96 | case 'p': 97 | flag_dump_positions = 1; 98 | break; 99 | default: 100 | fprintf (stderr, "unknown flag `%c'\n", opt); 101 | } 102 | } 103 | 104 | while (argv[optind]) 105 | dump_file (argv[optind++]); 106 | return 0; 107 | } 108 | 109 | static void 110 | print_usage (void) 111 | { 112 | printf ("Usage: gcov-dump [OPTION] ... gcovfiles\n"); 113 | printf ("Print coverage file contents\n"); 114 | printf (" -h, --help Print this help\n"); 115 | printf (" -v, --version Print version number\n"); 116 | printf (" -l, --long Dump record contents too\n"); 117 | printf (" -p, --positions Dump record positions\n"); 118 | } 119 | 120 | static void 121 | print_version (void) 122 | { 123 | printf ("gcov-dump %s%s\n", pkgversion_string, version_string); 124 | printf ("Copyright (C) 2009 Free Software Foundation, Inc.\n"); 125 | printf ("This is free software; see the source for copying conditions.\n" 126 | "There is NO warranty; not even for MERCHANTABILITY or \n" 127 | "FITNESS FOR A PARTICULAR PURPOSE.\n\n"); 128 | } 129 | 130 | static void 131 | print_prefix (const char *filename, unsigned depth, gcov_position_t position) 132 | { 133 | static const char prefix[] = " "; 134 | 135 | printf ("%s:", filename); 136 | if (flag_dump_positions) 137 | printf ("%lu:", (unsigned long) position); 138 | printf ("%.*s", (int) depth, prefix); 139 | } 140 | 141 | static void 142 | dump_file (const char *filename) 143 | { 144 | unsigned tags[4]; 145 | unsigned depth = 0; 146 | 147 | if (!gcov_open (filename, 1)) 148 | { 149 | fprintf (stderr, "%s:cannot open\n", filename); 150 | return; 151 | } 152 | 153 | /* magic */ 154 | { 155 | unsigned magic = gcov_read_unsigned (); 156 | unsigned version; 157 | const char *type = NULL; 158 | int endianness = 0; 159 | char m[4], v[4]; 160 | 161 | if ((endianness = gcov_magic (magic, GCOV_DATA_MAGIC))) 162 | type = "data"; 163 | else if ((endianness = gcov_magic (magic, GCOV_NOTE_MAGIC))) 164 | type = "note"; 165 | else 166 | { 167 | printf ("%s:not a gcov file\n", filename); 168 | gcov_close (); 169 | return; 170 | } 171 | version = gcov_read_unsigned (); 172 | GCOV_UNSIGNED2STRING (v, version); 173 | GCOV_UNSIGNED2STRING (m, magic); 174 | 175 | printf ("%s:%s:magic `%.4s':version `%.4s'%s\n", filename, type, 176 | m, v, endianness < 0 ? " (swapped endianness)" : ""); 177 | if (version != GCOV_VERSION) 178 | { 179 | char e[4]; 180 | 181 | GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 182 | printf ("%s:warning:current version is `%.4s'\n", filename, e); 183 | } 184 | } 185 | 186 | /* stamp */ 187 | { 188 | unsigned stamp = gcov_read_unsigned (); 189 | 190 | printf ("%s:stamp %lu\n", filename, (unsigned long)stamp); 191 | } 192 | 193 | while (1) 194 | { 195 | gcov_position_t base, position = gcov_position (); 196 | unsigned tag, length; 197 | tag_format_t const *format; 198 | unsigned tag_depth; 199 | int error; 200 | unsigned mask; 201 | 202 | tag = gcov_read_unsigned (); 203 | if (!tag) 204 | break; 205 | length = gcov_read_unsigned (); 206 | base = gcov_position (); 207 | mask = GCOV_TAG_MASK (tag) >> 1; 208 | for (tag_depth = 4; mask; mask >>= 8) 209 | { 210 | if ((mask & 0xff) != 0xff) 211 | { 212 | printf ("%s:tag `%08x' is invalid\n", filename, tag); 213 | break; 214 | } 215 | tag_depth--; 216 | } 217 | for (format = tag_table; format->name; format++) 218 | if (format->tag == tag) 219 | goto found; 220 | format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1]; 221 | found:; 222 | if (tag) 223 | { 224 | if (depth && depth < tag_depth) 225 | { 226 | if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)) 227 | printf ("%s:tag `%08x' is incorrectly nested\n", 228 | filename, tag); 229 | } 230 | depth = tag_depth; 231 | tags[depth - 1] = tag; 232 | } 233 | 234 | print_prefix (filename, tag_depth, position); 235 | printf ("%08x:%4u:%s", tag, length, format->name); 236 | if (format->proc) 237 | (*format->proc) (filename, tag, length); 238 | 239 | printf ("\n"); 240 | if (flag_dump_contents && format->proc) 241 | { 242 | unsigned long actual_length = gcov_position () - base; 243 | 244 | if (actual_length > length) 245 | printf ("%s:record size mismatch %lu bytes overread\n", 246 | filename, actual_length - length); 247 | else if (length > actual_length) 248 | printf ("%s:record size mismatch %lu bytes unread\n", 249 | filename, length - actual_length); 250 | } 251 | gcov_sync (base, length); 252 | if ((error = gcov_is_error ())) 253 | { 254 | printf (error < 0 ? "%s:counter overflow at %lu\n" : 255 | "%s:read error at %lu\n", filename, 256 | (long unsigned) gcov_position ()); 257 | break; 258 | } 259 | } 260 | gcov_close (); 261 | } 262 | 263 | static void 264 | tag_function (const char *filename ATTRIBUTE_UNUSED, 265 | unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 266 | { 267 | unsigned long pos = gcov_position (); 268 | 269 | printf (" ident=%u", gcov_read_unsigned ()); 270 | printf (", checksum=0x%08x", gcov_read_unsigned ()); 271 | 272 | if (gcov_position () - pos < length) 273 | { 274 | const char *name; 275 | 276 | name = gcov_read_string (); 277 | printf (", `%s'", name ? name : "NULL"); 278 | name = gcov_read_string (); 279 | printf (" %s", name ? name : "NULL"); 280 | printf (":%u", gcov_read_unsigned ()); 281 | } 282 | } 283 | 284 | static void 285 | tag_blocks (const char *filename ATTRIBUTE_UNUSED, 286 | unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 287 | { 288 | unsigned n_blocks = GCOV_TAG_BLOCKS_NUM (length); 289 | 290 | printf (" %u blocks", n_blocks); 291 | 292 | if (flag_dump_contents) 293 | { 294 | unsigned ix; 295 | 296 | for (ix = 0; ix != n_blocks; ix++) 297 | { 298 | if (!(ix & 7)) 299 | { 300 | printf ("\n"); 301 | print_prefix (filename, 0, gcov_position ()); 302 | printf ("\t\t%u", ix); 303 | } 304 | printf (" %04x", gcov_read_unsigned ()); 305 | } 306 | } 307 | } 308 | 309 | static void 310 | tag_arcs (const char *filename ATTRIBUTE_UNUSED, 311 | unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 312 | { 313 | unsigned n_arcs = GCOV_TAG_ARCS_NUM (length); 314 | 315 | printf (" %u arcs", n_arcs); 316 | if (flag_dump_contents) 317 | { 318 | unsigned ix; 319 | unsigned blockno = gcov_read_unsigned (); 320 | 321 | for (ix = 0; ix != n_arcs; ix++) 322 | { 323 | unsigned dst, flags; 324 | 325 | if (!(ix & 3)) 326 | { 327 | printf ("\n"); 328 | print_prefix (filename, 0, gcov_position ()); 329 | printf ("\tblock %u:", blockno); 330 | } 331 | dst = gcov_read_unsigned (); 332 | flags = gcov_read_unsigned (); 333 | printf (" %u:%04x", dst, flags); 334 | } 335 | } 336 | } 337 | 338 | static void 339 | tag_lines (const char *filename ATTRIBUTE_UNUSED, 340 | unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 341 | { 342 | if (flag_dump_contents) 343 | { 344 | unsigned blockno = gcov_read_unsigned (); 345 | char const *sep = NULL; 346 | 347 | while (1) 348 | { 349 | gcov_position_t position = gcov_position (); 350 | const char *source = NULL; 351 | unsigned lineno = gcov_read_unsigned (); 352 | 353 | if (!lineno) 354 | { 355 | source = gcov_read_string (); 356 | if (!source) 357 | break; 358 | sep = NULL; 359 | } 360 | 361 | if (!sep) 362 | { 363 | printf ("\n"); 364 | print_prefix (filename, 0, position); 365 | printf ("\tblock %u:", blockno); 366 | sep = ""; 367 | } 368 | if (lineno) 369 | { 370 | printf ("%s%u", sep, lineno); 371 | sep = ", "; 372 | } 373 | else 374 | { 375 | printf ("%s`%s'", sep, source); 376 | sep = ":"; 377 | } 378 | } 379 | } 380 | } 381 | 382 | static void 383 | tag_counters (const char *filename ATTRIBUTE_UNUSED, 384 | unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 385 | { 386 | static const char *const counter_names[] = GCOV_COUNTER_NAMES; 387 | unsigned n_counts = GCOV_TAG_COUNTER_NUM (length); 388 | 389 | printf (" %s %u counts", 390 | counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts); 391 | if (flag_dump_contents) 392 | { 393 | unsigned ix; 394 | 395 | for (ix = 0; ix != n_counts; ix++) 396 | { 397 | gcov_type count; 398 | 399 | if (!(ix & 7)) 400 | { 401 | printf ("\n"); 402 | print_prefix (filename, 0, gcov_position ()); 403 | printf ("\t\t%u", ix); 404 | } 405 | 406 | count = gcov_read_counter (); 407 | printf (" "); 408 | printf (HOST_WIDEST_INT_PRINT_DEC, count); 409 | } 410 | } 411 | } 412 | 413 | static void 414 | tag_summary (const char *filename ATTRIBUTE_UNUSED, 415 | unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) 416 | { 417 | struct gcov_summary summary; 418 | unsigned ix; 419 | 420 | gcov_read_summary (&summary); 421 | printf (" checksum=0x%08x", summary.checksum); 422 | 423 | for (ix = 0; ix != GCOV_COUNTERS_SUMMABLE; ix++) 424 | { 425 | printf ("\n"); 426 | print_prefix (filename, 0, 0); 427 | printf ("\t\tcounts=%u, runs=%u", 428 | summary.ctrs[ix].num, summary.ctrs[ix].runs); 429 | 430 | printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC, 431 | (HOST_WIDEST_INT)summary.ctrs[ix].sum_all); 432 | printf (", run_max=" HOST_WIDEST_INT_PRINT_DEC, 433 | (HOST_WIDEST_INT)summary.ctrs[ix].run_max); 434 | printf (", sum_max=" HOST_WIDEST_INT_PRINT_DEC, 435 | (HOST_WIDEST_INT)summary.ctrs[ix].sum_max); 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /SourceCode/gcc/gcov-io.c: -------------------------------------------------------------------------------- 1 | /* File format for coverage information 2 | Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007, 3 | 2008 Free Software Foundation, Inc. 4 | Contributed by Bob Manson . 5 | Completely remangled by Nathan Sidwell . 6 | 7 | This file is part of GCC. 8 | 9 | GCC is free software; you can redistribute it and/or modify it under 10 | the terms of the GNU General Public License as published by the Free 11 | Software Foundation; either version 3, or (at your option) any later 12 | version. 13 | 14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 | for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with GCC; see the file COPYING3. If not see 21 | . */ 22 | 23 | /* Routines declared in gcov-io.h. This file should be #included by 24 | another source file, after having #included gcov-io.h. */ 25 | 26 | #if !IN_GCOV 27 | static void gcov_write_block (unsigned); 28 | static gcov_unsigned_t *gcov_write_words (unsigned); 29 | #endif 30 | static const gcov_unsigned_t *gcov_read_words (unsigned); 31 | #if !IN_LIBGCOV 32 | static void gcov_allocate (unsigned); 33 | #endif 34 | 35 | static inline gcov_unsigned_t from_file (gcov_unsigned_t value) 36 | { 37 | #if !IN_LIBGCOV 38 | if (gcov_var.endian) 39 | { 40 | value = (value >> 16) | (value << 16); 41 | value = ((value & 0xff00ff) << 8) | ((value >> 8) & 0xff00ff); 42 | } 43 | #endif 44 | return value; 45 | } 46 | 47 | /* Open a gcov file. NAME is the name of the file to open and MODE 48 | indicates whether a new file should be created, or an existing file 49 | opened for modification. If MODE is >= 0 an existing file will be 50 | opened, if possible, and if MODE is <= 0, a new file will be 51 | created. Use MODE=0 to attempt to reopen an existing file and then 52 | fall back on creating a new one. Return zero on failure, >0 on 53 | opening an existing file and <0 on creating a new one. */ 54 | 55 | GCOV_LINKAGE int 56 | #if IN_LIBGCOV 57 | gcov_open (const char *name) 58 | #else 59 | gcov_open (const char *name, int mode) 60 | #endif 61 | { 62 | #if IN_LIBGCOV 63 | const int mode = 0; 64 | #endif 65 | #if GCOV_LOCKED 66 | struct flock s_flock; 67 | int fd; 68 | 69 | s_flock.l_type = F_WRLCK; 70 | s_flock.l_whence = SEEK_SET; 71 | s_flock.l_start = 0; 72 | s_flock.l_len = 0; /* Until EOF. */ 73 | s_flock.l_pid = getpid (); 74 | #endif 75 | 76 | gcc_assert (!gcov_var.file); 77 | gcov_var.start = 0; 78 | gcov_var.offset = gcov_var.length = 0; 79 | gcov_var.overread = -1u; 80 | gcov_var.error = 0; 81 | #if !IN_LIBGCOV 82 | gcov_var.endian = 0; 83 | #endif 84 | #if GCOV_LOCKED 85 | if (mode > 0) 86 | fd = open (name, O_RDWR); 87 | else 88 | fd = open (name, O_RDWR | O_CREAT, 0666); 89 | if (fd < 0) 90 | return 0; 91 | 92 | while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) 93 | continue; 94 | 95 | gcov_var.file = fdopen (fd, "r+b"); 96 | if (!gcov_var.file) 97 | { 98 | close (fd); 99 | return 0; 100 | } 101 | 102 | if (mode > 0) 103 | gcov_var.mode = 1; 104 | else if (mode == 0) 105 | { 106 | struct stat st; 107 | 108 | if (fstat (fd, &st) < 0) 109 | { 110 | fclose (gcov_var.file); 111 | gcov_var.file = 0; 112 | return 0; 113 | } 114 | if (st.st_size != 0) 115 | gcov_var.mode = 1; 116 | else 117 | gcov_var.mode = mode * 2 + 1; 118 | } 119 | else 120 | gcov_var.mode = mode * 2 + 1; 121 | #else 122 | if (mode >= 0) 123 | gcov_var.file = fopen (name, "r+b"); 124 | if (gcov_var.file) 125 | gcov_var.mode = 1; 126 | else if (mode <= 0) 127 | { 128 | gcov_var.file = fopen (name, "w+b"); 129 | if (gcov_var.file) 130 | gcov_var.mode = mode * 2 + 1; 131 | } 132 | if (!gcov_var.file) 133 | return 0; 134 | #endif 135 | 136 | setbuf (gcov_var.file, (char *)0); 137 | 138 | return 1; 139 | } 140 | 141 | /* Close the current gcov file. Flushes data to disk. Returns nonzero 142 | on failure or error flag set. */ 143 | 144 | GCOV_LINKAGE int 145 | gcov_close (void) 146 | { 147 | if (gcov_var.file) 148 | { 149 | #if !IN_GCOV 150 | if (gcov_var.offset && gcov_var.mode < 0) 151 | gcov_write_block (gcov_var.offset); 152 | #endif 153 | fclose (gcov_var.file); 154 | gcov_var.file = 0; 155 | gcov_var.length = 0; 156 | } 157 | #if !IN_LIBGCOV 158 | free (gcov_var.buffer); 159 | gcov_var.alloc = 0; 160 | gcov_var.buffer = 0; 161 | #endif 162 | gcov_var.mode = 0; 163 | return gcov_var.error; 164 | } 165 | 166 | #if !IN_LIBGCOV 167 | /* Check if MAGIC is EXPECTED. Use it to determine endianness of the 168 | file. Returns +1 for same endian, -1 for other endian and zero for 169 | not EXPECTED. */ 170 | 171 | GCOV_LINKAGE int 172 | gcov_magic (gcov_unsigned_t magic, gcov_unsigned_t expected) 173 | { 174 | if (magic == expected) 175 | return 1; 176 | magic = (magic >> 16) | (magic << 16); 177 | magic = ((magic & 0xff00ff) << 8) | ((magic >> 8) & 0xff00ff); 178 | if (magic == expected) 179 | { 180 | gcov_var.endian = 1; 181 | return -1; 182 | } 183 | return 0; 184 | } 185 | #endif 186 | 187 | #if !IN_LIBGCOV 188 | static void 189 | gcov_allocate (unsigned length) 190 | { 191 | size_t new_size = gcov_var.alloc; 192 | 193 | if (!new_size) 194 | new_size = GCOV_BLOCK_SIZE; 195 | new_size += length; 196 | new_size *= 2; 197 | 198 | gcov_var.alloc = new_size; 199 | gcov_var.buffer = XRESIZEVAR (gcov_unsigned_t, gcov_var.buffer, new_size << 2); 200 | } 201 | #endif 202 | 203 | #if !IN_GCOV 204 | /* Write out the current block, if needs be. */ 205 | 206 | static void 207 | gcov_write_block (unsigned size) 208 | { 209 | if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1) 210 | gcov_var.error = 1; 211 | gcov_var.start += size; 212 | gcov_var.offset -= size; 213 | } 214 | 215 | /* Allocate space to write BYTES bytes to the gcov file. Return a 216 | pointer to those bytes, or NULL on failure. */ 217 | 218 | static gcov_unsigned_t * 219 | gcov_write_words (unsigned words) 220 | { 221 | gcov_unsigned_t *result; 222 | 223 | gcc_assert (gcov_var.mode < 0); 224 | #if IN_LIBGCOV 225 | if (gcov_var.offset >= GCOV_BLOCK_SIZE) 226 | { 227 | gcov_write_block (GCOV_BLOCK_SIZE); 228 | if (gcov_var.offset) 229 | { 230 | gcc_assert (gcov_var.offset == 1); 231 | memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); 232 | } 233 | } 234 | #else 235 | if (gcov_var.offset + words > gcov_var.alloc) 236 | gcov_allocate (gcov_var.offset + words); 237 | #endif 238 | result = &gcov_var.buffer[gcov_var.offset]; 239 | gcov_var.offset += words; 240 | 241 | return result; 242 | } 243 | 244 | /* Write unsigned VALUE to coverage file. Sets error flag 245 | appropriately. */ 246 | 247 | GCOV_LINKAGE void 248 | gcov_write_unsigned (gcov_unsigned_t value) 249 | { 250 | gcov_unsigned_t *buffer = gcov_write_words (1); 251 | 252 | buffer[0] = value; 253 | } 254 | 255 | /* Write counter VALUE to coverage file. Sets error flag 256 | appropriately. */ 257 | 258 | #if IN_LIBGCOV 259 | GCOV_LINKAGE void 260 | gcov_write_counter (gcov_type value) 261 | { 262 | gcov_unsigned_t *buffer = gcov_write_words (2); 263 | 264 | buffer[0] = (gcov_unsigned_t) value; 265 | if (sizeof (value) > sizeof (gcov_unsigned_t)) 266 | buffer[1] = (gcov_unsigned_t) (value >> 32); 267 | else 268 | buffer[1] = 0; 269 | } 270 | #endif /* IN_LIBGCOV */ 271 | 272 | #if !IN_LIBGCOV 273 | /* Write STRING to coverage file. Sets error flag on file 274 | error, overflow flag on overflow */ 275 | 276 | GCOV_LINKAGE void 277 | gcov_write_string (const char *string) 278 | { 279 | unsigned length = 0; 280 | unsigned alloc = 0; 281 | gcov_unsigned_t *buffer; 282 | 283 | if (string) 284 | { 285 | length = strlen (string); 286 | alloc = (length + 4) >> 2; 287 | } 288 | 289 | buffer = gcov_write_words (1 + alloc); 290 | 291 | buffer[0] = alloc; 292 | buffer[alloc] = 0; 293 | memcpy (&buffer[1], string, length); 294 | } 295 | #endif 296 | 297 | #if !IN_LIBGCOV 298 | /* Write a tag TAG and reserve space for the record length. Return a 299 | value to be used for gcov_write_length. */ 300 | 301 | GCOV_LINKAGE gcov_position_t 302 | gcov_write_tag (gcov_unsigned_t tag) 303 | { 304 | gcov_position_t result = gcov_var.start + gcov_var.offset; 305 | gcov_unsigned_t *buffer = gcov_write_words (2); 306 | 307 | buffer[0] = tag; 308 | buffer[1] = 0; 309 | 310 | return result; 311 | } 312 | 313 | /* Write a record length using POSITION, which was returned by 314 | gcov_write_tag. The current file position is the end of the 315 | record, and is restored before returning. Returns nonzero on 316 | overflow. */ 317 | 318 | GCOV_LINKAGE void 319 | gcov_write_length (gcov_position_t position) 320 | { 321 | unsigned offset; 322 | gcov_unsigned_t length; 323 | gcov_unsigned_t *buffer; 324 | 325 | gcc_assert (gcov_var.mode < 0); 326 | gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset); 327 | gcc_assert (position >= gcov_var.start); 328 | offset = position - gcov_var.start; 329 | length = gcov_var.offset - offset - 2; 330 | buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset]; 331 | buffer[1] = length; 332 | if (gcov_var.offset >= GCOV_BLOCK_SIZE) 333 | gcov_write_block (gcov_var.offset); 334 | } 335 | 336 | #else /* IN_LIBGCOV */ 337 | 338 | /* Write a tag TAG and length LENGTH. */ 339 | 340 | GCOV_LINKAGE void 341 | gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) 342 | { 343 | gcov_unsigned_t *buffer = gcov_write_words (2); 344 | 345 | buffer[0] = tag; 346 | buffer[1] = length; 347 | } 348 | 349 | /* Write a summary structure to the gcov file. Return nonzero on 350 | overflow. */ 351 | 352 | GCOV_LINKAGE void 353 | gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) 354 | { 355 | unsigned ix; 356 | const struct gcov_ctr_summary *csum; 357 | 358 | gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH); 359 | gcov_write_unsigned (summary->checksum); 360 | for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) 361 | { 362 | gcov_write_unsigned (csum->num); 363 | gcov_write_unsigned (csum->runs); 364 | gcov_write_counter (csum->sum_all); 365 | gcov_write_counter (csum->run_max); 366 | gcov_write_counter (csum->sum_max); 367 | } 368 | } 369 | #endif /* IN_LIBGCOV */ 370 | 371 | #endif /*!IN_GCOV */ 372 | 373 | /* Return a pointer to read BYTES bytes from the gcov file. Returns 374 | NULL on failure (read past EOF). */ 375 | 376 | static const gcov_unsigned_t * 377 | gcov_read_words (unsigned words) 378 | { 379 | const gcov_unsigned_t *result; 380 | unsigned excess = gcov_var.length - gcov_var.offset; 381 | 382 | gcc_assert (gcov_var.mode > 0); 383 | if (excess < words) 384 | { 385 | gcov_var.start += gcov_var.offset; 386 | #if IN_LIBGCOV 387 | if (excess) 388 | { 389 | gcc_assert (excess == 1); 390 | memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4); 391 | } 392 | #else 393 | memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4); 394 | #endif 395 | gcov_var.offset = 0; 396 | gcov_var.length = excess; 397 | #if IN_LIBGCOV 398 | gcc_assert (!gcov_var.length || gcov_var.length == 1); 399 | excess = GCOV_BLOCK_SIZE; 400 | #else 401 | if (gcov_var.length + words > gcov_var.alloc) 402 | gcov_allocate (gcov_var.length + words); 403 | excess = gcov_var.alloc - gcov_var.length; 404 | #endif 405 | excess = fread (gcov_var.buffer + gcov_var.length, 406 | 1, excess << 2, gcov_var.file) >> 2; 407 | gcov_var.length += excess; 408 | if (gcov_var.length < words) 409 | { 410 | gcov_var.overread += words - gcov_var.length; 411 | gcov_var.length = 0; 412 | return 0; 413 | } 414 | } 415 | result = &gcov_var.buffer[gcov_var.offset]; 416 | gcov_var.offset += words; 417 | return result; 418 | } 419 | 420 | /* Read unsigned value from a coverage file. Sets error flag on file 421 | error, overflow flag on overflow */ 422 | 423 | GCOV_LINKAGE gcov_unsigned_t 424 | gcov_read_unsigned (void) 425 | { 426 | gcov_unsigned_t value; 427 | const gcov_unsigned_t *buffer = gcov_read_words (1); 428 | 429 | if (!buffer) 430 | return 0; 431 | value = from_file (buffer[0]); 432 | return value; 433 | } 434 | 435 | /* Read counter value from a coverage file. Sets error flag on file 436 | error, overflow flag on overflow */ 437 | 438 | GCOV_LINKAGE gcov_type 439 | gcov_read_counter (void) 440 | { 441 | gcov_type value; 442 | const gcov_unsigned_t *buffer = gcov_read_words (2); 443 | 444 | if (!buffer) 445 | return 0; 446 | value = from_file (buffer[0]); 447 | if (sizeof (value) > sizeof (gcov_unsigned_t)) 448 | value |= ((gcov_type) from_file (buffer[1])) << 32; 449 | else if (buffer[1]) 450 | gcov_var.error = -1; 451 | 452 | return value; 453 | } 454 | 455 | /* Read string from coverage file. Returns a pointer to a static 456 | buffer, or NULL on empty string. You must copy the string before 457 | calling another gcov function. */ 458 | 459 | #if !IN_LIBGCOV 460 | GCOV_LINKAGE const char * 461 | gcov_read_string (void) 462 | { 463 | unsigned length = gcov_read_unsigned (); 464 | 465 | if (!length) 466 | return 0; 467 | 468 | return (const char *) gcov_read_words (length); 469 | } 470 | #endif 471 | 472 | GCOV_LINKAGE void 473 | gcov_read_summary (struct gcov_summary *summary) 474 | { 475 | unsigned ix; 476 | struct gcov_ctr_summary *csum; 477 | 478 | summary->checksum = gcov_read_unsigned (); 479 | for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) 480 | { 481 | csum->num = gcov_read_unsigned (); 482 | csum->runs = gcov_read_unsigned (); 483 | csum->sum_all = gcov_read_counter (); 484 | csum->run_max = gcov_read_counter (); 485 | csum->sum_max = gcov_read_counter (); 486 | } 487 | } 488 | 489 | #if !IN_LIBGCOV 490 | /* Reset to a known position. BASE should have been obtained from 491 | gcov_position, LENGTH should be a record length. */ 492 | 493 | GCOV_LINKAGE void 494 | gcov_sync (gcov_position_t base, gcov_unsigned_t length) 495 | { 496 | gcc_assert (gcov_var.mode > 0); 497 | base += length; 498 | if (base - gcov_var.start <= gcov_var.length) 499 | gcov_var.offset = base - gcov_var.start; 500 | else 501 | { 502 | gcov_var.offset = gcov_var.length = 0; 503 | fseek (gcov_var.file, base << 2, SEEK_SET); 504 | gcov_var.start = ftell (gcov_var.file) >> 2; 505 | } 506 | } 507 | #endif 508 | 509 | #if IN_LIBGCOV 510 | /* Move to a given position in a gcov file. */ 511 | 512 | GCOV_LINKAGE void 513 | gcov_seek (gcov_position_t base) 514 | { 515 | gcc_assert (gcov_var.mode < 0); 516 | if (gcov_var.offset) 517 | gcov_write_block (gcov_var.offset); 518 | fseek (gcov_var.file, base << 2, SEEK_SET); 519 | gcov_var.start = ftell (gcov_var.file) >> 2; 520 | } 521 | #endif 522 | 523 | #if IN_GCOV > 0 524 | /* Return the modification time of the current gcov file. */ 525 | 526 | GCOV_LINKAGE time_t 527 | gcov_time (void) 528 | { 529 | struct stat status; 530 | 531 | if (fstat (fileno (gcov_var.file), &status)) 532 | return 0; 533 | else 534 | return status.st_mtime; 535 | } 536 | #endif /* IN_GCOV */ 537 | -------------------------------------------------------------------------------- /SourceCode/gcc/gcov-io.h: -------------------------------------------------------------------------------- 1 | /* File format for coverage information 2 | Copyright (C) 1996, 1997, 1998, 2000, 2002, 3 | 2003, 2004, 2005, 2008, 2009 Free Software Foundation, Inc. 4 | Contributed by Bob Manson . 5 | Completely remangled by Nathan Sidwell . 6 | 7 | This file is part of GCC. 8 | 9 | GCC is free software; you can redistribute it and/or modify it under 10 | the terms of the GNU General Public License as published by the Free 11 | Software Foundation; either version 3, or (at your option) any later 12 | version. 13 | 14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 | for more details. 18 | 19 | Under Section 7 of GPL version 3, you are granted additional 20 | permissions described in the GCC Runtime Library Exception, version 21 | 3.1, as published by the Free Software Foundation. 22 | 23 | You should have received a copy of the GNU General Public License and 24 | a copy of the GCC Runtime Library Exception along with this program; 25 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 26 | . */ 27 | 28 | 29 | /* Coverage information is held in two files. A notes file, which is 30 | generated by the compiler, and a data file, which is generated by 31 | the program under test. Both files use a similar structure. We do 32 | not attempt to make these files backwards compatible with previous 33 | versions, as you only need coverage information when developing a 34 | program. We do hold version information, so that mismatches can be 35 | detected, and we use a format that allows tools to skip information 36 | they do not understand or are not interested in. 37 | 38 | Numbers are recorded in the 32 bit unsigned binary form of the 39 | endianness of the machine generating the file. 64 bit numbers are 40 | stored as two 32 bit numbers, the low part first. Strings are 41 | padded with 1 to 4 NUL bytes, to bring the length up to a multiple 42 | of 4. The number of 4 bytes is stored, followed by the padded 43 | string. Zero length and NULL strings are simply stored as a length 44 | of zero (they have no trailing NUL or padding). 45 | 46 | int32: byte3 byte2 byte1 byte0 | byte0 byte1 byte2 byte3 47 | int64: int32:low int32:high 48 | string: int32:0 | int32:length char* char:0 padding 49 | padding: | char:0 | char:0 char:0 | char:0 char:0 char:0 50 | item: int32 | int64 | string 51 | 52 | The basic format of the files is 53 | 54 | file : int32:magic int32:version int32:stamp record* 55 | 56 | The magic ident is different for the notes and the data files. The 57 | magic ident is used to determine the endianness of the file, when 58 | reading. The version is the same for both files and is derived 59 | from gcc's version number. The stamp value is used to synchronize 60 | note and data files and to synchronize merging within a data 61 | file. It need not be an absolute time stamp, merely a ticker that 62 | increments fast enough and cycles slow enough to distinguish 63 | different compile/run/compile cycles. 64 | 65 | Although the ident and version are formally 32 bit numbers, they 66 | are derived from 4 character ASCII strings. The version number 67 | consists of the single character major version number, a two 68 | character minor version number (leading zero for versions less than 69 | 10), and a single character indicating the status of the release. 70 | That will be 'e' experimental, 'p' prerelease and 'r' for release. 71 | Because, by good fortune, these are in alphabetical order, string 72 | collating can be used to compare version strings. Be aware that 73 | the 'e' designation will (naturally) be unstable and might be 74 | incompatible with itself. For gcc 3.4 experimental, it would be 75 | '304e' (0x33303465). When the major version reaches 10, the 76 | letters A-Z will be used. Assuming minor increments releases every 77 | 6 months, we have to make a major increment every 50 years. 78 | Assuming major increments releases every 5 years, we're ok for the 79 | next 155 years -- good enough for me. 80 | 81 | A record has a tag, length and variable amount of data. 82 | 83 | record: header data 84 | header: int32:tag int32:length 85 | data: item* 86 | 87 | Records are not nested, but there is a record hierarchy. Tag 88 | numbers reflect this hierarchy. Tags are unique across note and 89 | data files. Some record types have a varying amount of data. The 90 | LENGTH is the number of 4bytes that follow and is usually used to 91 | determine how much data. The tag value is split into 4 8-bit 92 | fields, one for each of four possible levels. The most significant 93 | is allocated first. Unused levels are zero. Active levels are 94 | odd-valued, so that the LSB of the level is one. A sub-level 95 | incorporates the values of its superlevels. This formatting allows 96 | you to determine the tag hierarchy, without understanding the tags 97 | themselves, and is similar to the standard section numbering used 98 | in technical documents. Level values [1..3f] are used for common 99 | tags, values [41..9f] for the notes file and [a1..ff] for the data 100 | file. 101 | 102 | The basic block graph file contains the following records 103 | note: unit function-graph* 104 | unit: header int32:checksum string:source 105 | function-graph: announce_function basic_blocks {arcs | lines}* 106 | announce_function: header int32:ident int32:checksum 107 | string:name string:source int32:lineno 108 | basic_block: header int32:flags* 109 | arcs: header int32:block_no arc* 110 | arc: int32:dest_block int32:flags 111 | lines: header int32:block_no line* 112 | int32:0 string:NULL 113 | line: int32:line_no | int32:0 string:filename 114 | 115 | The BASIC_BLOCK record holds per-bb flags. The number of blocks 116 | can be inferred from its data length. There is one ARCS record per 117 | basic block. The number of arcs from a bb is implicit from the 118 | data length. It enumerates the destination bb and per-arc flags. 119 | There is one LINES record per basic block, it enumerates the source 120 | lines which belong to that basic block. Source file names are 121 | introduced by a line number of 0, following lines are from the new 122 | source file. The initial source file for the function is NULL, but 123 | the current source file should be remembered from one LINES record 124 | to the next. The end of a block is indicated by an empty filename 125 | - this does not reset the current source file. Note there is no 126 | ordering of the ARCS and LINES records: they may be in any order, 127 | interleaved in any manner. The current filename follows the order 128 | the LINES records are stored in the file, *not* the ordering of the 129 | blocks they are for. 130 | 131 | The data file contains the following records. 132 | data: {unit function-data* summary:object summary:program*}* 133 | unit: header int32:checksum 134 | function-data: announce_function arc_counts 135 | announce_function: header int32:ident int32:checksum 136 | arc_counts: header int64:count* 137 | summary: int32:checksum {count-summary}GCOV_COUNTERS 138 | count-summary: int32:num int32:runs int64:sum 139 | int64:max int64:sum_max 140 | 141 | The ANNOUNCE_FUNCTION record is the same as that in the note file, 142 | but without the source location. The ARC_COUNTS gives the counter 143 | values for those arcs that are instrumented. The SUMMARY records 144 | give information about the whole object file and about the whole 145 | program. The checksum is used for whole program summaries, and 146 | disambiguates different programs which include the same 147 | instrumented object file. There may be several program summaries, 148 | each with a unique checksum. The object summary's checksum is zero. 149 | Note that the data file might contain information from several runs 150 | concatenated, or the data might be merged. 151 | 152 | This file is included by both the compiler, gcov tools and the 153 | runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to 154 | distinguish which case is which. If IN_LIBGCOV is nonzero, 155 | libgcov is being built. If IN_GCOV is nonzero, the gcov tools are 156 | being built. Otherwise the compiler is being built. IN_GCOV may be 157 | positive or negative. If positive, we are compiling a tool that 158 | requires additional functions (see the code for knowledge of what 159 | those functions are). */ 160 | 161 | #ifndef GCC_GCOV_IO_H 162 | #define GCC_GCOV_IO_H 163 | 164 | #if IN_LIBGCOV 165 | /* About the target */ 166 | 167 | #if BITS_PER_UNIT == 8 168 | typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI))); 169 | typedef unsigned gcov_position_t __attribute__ ((mode (SI))); 170 | #if LONG_LONG_TYPE_SIZE > 32 171 | typedef signed gcov_type __attribute__ ((mode (DI))); 172 | #else 173 | typedef signed gcov_type __attribute__ ((mode (SI))); 174 | #endif 175 | #else 176 | #if BITS_PER_UNIT == 16 177 | typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI))); 178 | typedef unsigned gcov_position_t __attribute__ ((mode (HI))); 179 | #if LONG_LONG_TYPE_SIZE > 32 180 | typedef signed gcov_type __attribute__ ((mode (SI))); 181 | #else 182 | typedef signed gcov_type __attribute__ ((mode (HI))); 183 | #endif 184 | #else 185 | typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI))); 186 | typedef unsigned gcov_position_t __attribute__ ((mode (QI))); 187 | #if LONG_LONG_TYPE_SIZE > 32 188 | typedef signed gcov_type __attribute__ ((mode (HI))); 189 | #else 190 | typedef signed gcov_type __attribute__ ((mode (QI))); 191 | #endif 192 | #endif 193 | #endif 194 | 195 | 196 | #if defined (TARGET_POSIX_IO) 197 | #define GCOV_LOCKED 1 198 | #else 199 | #define GCOV_LOCKED 0 200 | #endif 201 | 202 | #else /* !IN_LIBGCOV */ 203 | /* About the host */ 204 | 205 | typedef unsigned gcov_unsigned_t; 206 | typedef unsigned gcov_position_t; 207 | /* gcov_type is typedef'd elsewhere for the compiler */ 208 | #if IN_GCOV 209 | #define GCOV_LINKAGE static 210 | typedef HOST_WIDEST_INT gcov_type; 211 | #if IN_GCOV > 0 212 | #include 213 | #endif 214 | #else /*!IN_GCOV */ 215 | #define GCOV_TYPE_SIZE (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32) 216 | #endif 217 | 218 | #if defined (HOST_HAS_F_SETLKW) 219 | #define GCOV_LOCKED 1 220 | #else 221 | #define GCOV_LOCKED 0 222 | #endif 223 | 224 | #endif /* !IN_LIBGCOV */ 225 | 226 | /* In gcov we want function linkage to be static. In the compiler we want 227 | it extern, so that they can be accessed from elsewhere. In libgcov we 228 | need these functions to be extern, so prefix them with __gcov. In 229 | libgcov they must also be hidden so that the instance in the executable 230 | is not also used in a DSO. */ 231 | #if IN_LIBGCOV 232 | 233 | #include "tconfig.h" 234 | 235 | #define gcov_var __gcov_var 236 | #define gcov_open __gcov_open 237 | #define gcov_close __gcov_close 238 | #define gcov_write_tag_length __gcov_write_tag_length 239 | #define gcov_position __gcov_position 240 | #define gcov_seek __gcov_seek 241 | #define gcov_rewrite __gcov_rewrite 242 | #define gcov_is_error __gcov_is_error 243 | #define gcov_write_unsigned __gcov_write_unsigned 244 | #define gcov_write_counter __gcov_write_counter 245 | #define gcov_write_summary __gcov_write_summary 246 | #define gcov_read_unsigned __gcov_read_unsigned 247 | #define gcov_read_counter __gcov_read_counter 248 | #define gcov_read_summary __gcov_read_summary 249 | 250 | /* Poison these, so they don't accidentally slip in. */ 251 | #pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length 252 | #pragma GCC poison gcov_read_string gcov_sync gcov_time gcov_magic 253 | 254 | #ifdef HAVE_GAS_HIDDEN 255 | #define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) 256 | #else 257 | #define ATTRIBUTE_HIDDEN 258 | #endif 259 | 260 | #else 261 | 262 | #define ATTRIBUTE_HIDDEN 263 | 264 | #endif 265 | 266 | #ifndef GCOV_LINKAGE 267 | #define GCOV_LINKAGE extern 268 | #endif 269 | 270 | /* File suffixes. */ 271 | #define GCOV_DATA_SUFFIX ".gcda" 272 | #define GCOV_NOTE_SUFFIX ".gcno" 273 | 274 | /* File magic. Must not be palindromes. */ 275 | #define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461) /* "gcda" */ 276 | #define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f) /* "gcno" */ 277 | 278 | /* gcov-iov.h is automatically generated by the makefile from 279 | version.c, it looks like 280 | #define GCOV_VERSION ((gcov_unsigned_t)0x89abcdef) 281 | */ 282 | #include "gcov-iov.h" 283 | 284 | /* Convert a magic or version number to a 4 character string. */ 285 | #define GCOV_UNSIGNED2STRING(ARRAY,VALUE) \ 286 | ((ARRAY)[0] = (char)((VALUE) >> 24), \ 287 | (ARRAY)[1] = (char)((VALUE) >> 16), \ 288 | (ARRAY)[2] = (char)((VALUE) >> 8), \ 289 | (ARRAY)[3] = (char)((VALUE) >> 0)) 290 | 291 | /* The record tags. Values [1..3f] are for tags which may be in either 292 | file. Values [41..9f] for those in the note file and [a1..ff] for 293 | the data file. The tag value zero is used as an explicit end of 294 | file marker -- it is not required to be present. */ 295 | 296 | #define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000) 297 | #define GCOV_TAG_FUNCTION_LENGTH (2) 298 | #define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000) 299 | #define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM) 300 | #define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH) 301 | #define GCOV_TAG_ARCS ((gcov_unsigned_t)0x01430000) 302 | #define GCOV_TAG_ARCS_LENGTH(NUM) (1 + (NUM) * 2) 303 | #define GCOV_TAG_ARCS_NUM(LENGTH) (((LENGTH) - 1) / 2) 304 | #define GCOV_TAG_LINES ((gcov_unsigned_t)0x01450000) 305 | #define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000) 306 | #define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2) 307 | #define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2) 308 | #define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) 309 | #define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) 310 | #define GCOV_TAG_SUMMARY_LENGTH \ 311 | (1 + GCOV_COUNTERS_SUMMABLE * (2 + 3 * 2)) 312 | 313 | /* Counters that are collected. */ 314 | #define GCOV_COUNTER_ARCS 0 /* Arc transitions. */ 315 | #define GCOV_COUNTERS_SUMMABLE 1 /* Counters which can be 316 | summaried. */ 317 | #define GCOV_FIRST_VALUE_COUNTER 1 /* The first of counters used for value 318 | profiling. They must form a consecutive 319 | interval and their order must match 320 | the order of HIST_TYPEs in 321 | value-prof.h. */ 322 | #define GCOV_COUNTER_V_INTERVAL 1 /* Histogram of value inside an interval. */ 323 | #define GCOV_COUNTER_V_POW2 2 /* Histogram of exact power2 logarithm 324 | of a value. */ 325 | #define GCOV_COUNTER_V_SINGLE 3 /* The most common value of expression. */ 326 | #define GCOV_COUNTER_V_DELTA 4 /* The most common difference between 327 | consecutive values of expression. */ 328 | 329 | #define GCOV_COUNTER_V_INDIR 5 /* The most common indirect address */ 330 | #define GCOV_COUNTER_AVERAGE 6 /* Compute average value passed to the 331 | counter. */ 332 | #define GCOV_COUNTER_IOR 7 /* IOR of the all values passed to 333 | counter. */ 334 | #define GCOV_LAST_VALUE_COUNTER 7 /* The last of counters used for value 335 | profiling. */ 336 | #define GCOV_COUNTERS 8 337 | 338 | /* Number of counters used for value profiling. */ 339 | #define GCOV_N_VALUE_COUNTERS \ 340 | (GCOV_LAST_VALUE_COUNTER - GCOV_FIRST_VALUE_COUNTER + 1) 341 | 342 | /* A list of human readable names of the counters */ 343 | #define GCOV_COUNTER_NAMES {"arcs", "interval", "pow2", "single", \ 344 | "delta","indirect_call", "average", "ior"} 345 | 346 | /* Names of merge functions for counters. */ 347 | #define GCOV_MERGE_FUNCTIONS {"__gcov_merge_add", \ 348 | "__gcov_merge_add", \ 349 | "__gcov_merge_add", \ 350 | "__gcov_merge_single", \ 351 | "__gcov_merge_delta", \ 352 | "__gcov_merge_single", \ 353 | "__gcov_merge_add", \ 354 | "__gcov_merge_ior"} 355 | 356 | /* Convert a counter index to a tag. */ 357 | #define GCOV_TAG_FOR_COUNTER(COUNT) \ 358 | (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17)) 359 | /* Convert a tag to a counter. */ 360 | #define GCOV_COUNTER_FOR_TAG(TAG) \ 361 | ((unsigned)(((TAG) - GCOV_TAG_COUNTER_BASE) >> 17)) 362 | /* Check whether a tag is a counter tag. */ 363 | #define GCOV_TAG_IS_COUNTER(TAG) \ 364 | (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS) 365 | 366 | /* The tag level mask has 1's in the position of the inner levels, & 367 | the lsb of the current level, and zero on the current and outer 368 | levels. */ 369 | #define GCOV_TAG_MASK(TAG) (((TAG) - 1) ^ (TAG)) 370 | 371 | /* Return nonzero if SUB is an immediate subtag of TAG. */ 372 | #define GCOV_TAG_IS_SUBTAG(TAG,SUB) \ 373 | (GCOV_TAG_MASK (TAG) >> 8 == GCOV_TAG_MASK (SUB) \ 374 | && !(((SUB) ^ (TAG)) & ~GCOV_TAG_MASK(TAG))) 375 | 376 | /* Return nonzero if SUB is at a sublevel to TAG. */ 377 | #define GCOV_TAG_IS_SUBLEVEL(TAG,SUB) \ 378 | (GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB)) 379 | 380 | /* Basic block flags. */ 381 | #define GCOV_BLOCK_UNEXPECTED (1 << 1) 382 | 383 | /* Arc flags. */ 384 | #define GCOV_ARC_ON_TREE (1 << 0) 385 | #define GCOV_ARC_FAKE (1 << 1) 386 | #define GCOV_ARC_FALLTHROUGH (1 << 2) 387 | 388 | /* Structured records. */ 389 | 390 | /* Cumulative counter data. */ 391 | struct gcov_ctr_summary 392 | { 393 | gcov_unsigned_t num; /* number of counters. */ 394 | gcov_unsigned_t runs; /* number of program runs */ 395 | gcov_type sum_all; /* sum of all counters accumulated. */ 396 | gcov_type run_max; /* maximum value on a single run. */ 397 | gcov_type sum_max; /* sum of individual run max values. */ 398 | }; 399 | 400 | /* Object & program summary record. */ 401 | struct gcov_summary 402 | { 403 | gcov_unsigned_t checksum; /* checksum of program */ 404 | struct gcov_ctr_summary ctrs[GCOV_COUNTERS_SUMMABLE]; 405 | }; 406 | 407 | /* Structures embedded in coveraged program. The structures generated 408 | by write_profile must match these. */ 409 | 410 | #if IN_LIBGCOV 411 | /* Information about a single function. This uses the trailing array 412 | idiom. The number of counters is determined from the counter_mask 413 | in gcov_info. We hold an array of function info, so have to 414 | explicitly calculate the correct array stride. */ 415 | struct gcov_fn_info 416 | { 417 | gcov_unsigned_t ident; /* unique ident of function */ 418 | gcov_unsigned_t checksum; /* function checksum */ 419 | unsigned n_ctrs[0]; /* instrumented counters */ 420 | }; 421 | 422 | /* Type of function used to merge counters. */ 423 | typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t); 424 | 425 | /* Information about counters. */ 426 | struct gcov_ctr_info 427 | { 428 | gcov_unsigned_t num; /* number of counters. */ 429 | gcov_type *values; /* their values. */ 430 | gcov_merge_fn merge; /* The function used to merge them. */ 431 | }; 432 | 433 | /* Information about a single object file. */ 434 | struct gcov_info 435 | { 436 | gcov_unsigned_t version; /* expected version number */ 437 | struct gcov_info *next; /* link to next, used by libgcov */ 438 | 439 | gcov_unsigned_t stamp; /* uniquifying time stamp */ 440 | const char *filename; /* output file name */ 441 | 442 | unsigned n_functions; /* number of functions */ 443 | const struct gcov_fn_info *functions; /* table of functions */ 444 | 445 | unsigned ctr_mask; /* mask of counters instrumented. */ 446 | struct gcov_ctr_info counts[0]; /* count data. The number of bits 447 | set in the ctr_mask field 448 | determines how big this array 449 | is. */ 450 | }; 451 | 452 | /* Register a new object file module. */ 453 | extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN; 454 | 455 | /* Called before fork, to avoid double counting. */ 456 | extern void __gcov_flush (void) ATTRIBUTE_HIDDEN; 457 | 458 | /* The merge function that just sums the counters. */ 459 | extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; 460 | 461 | /* The merge function to choose the most common value. */ 462 | extern void __gcov_merge_single (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; 463 | 464 | /* The merge function to choose the most common difference between 465 | consecutive values. */ 466 | extern void __gcov_merge_delta (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; 467 | 468 | /* The merge function that just ors the counters together. */ 469 | extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; 470 | 471 | /* The profiler functions. */ 472 | extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned); 473 | extern void __gcov_pow2_profiler (gcov_type *, gcov_type); 474 | extern void __gcov_one_value_profiler (gcov_type *, gcov_type); 475 | extern void __gcov_indirect_call_profiler (gcov_type *, gcov_type, void *, void *); 476 | extern void __gcov_average_profiler (gcov_type *, gcov_type); 477 | extern void __gcov_ior_profiler (gcov_type *, gcov_type); 478 | 479 | #ifndef inhibit_libc 480 | /* The wrappers around some library functions.. */ 481 | extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN; 482 | extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN; 483 | extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN; 484 | extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN; 485 | extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN; 486 | extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN; 487 | extern int __gcov_execve (const char *, char *const [], char *const []) 488 | ATTRIBUTE_HIDDEN; 489 | #endif 490 | 491 | #endif /* IN_LIBGCOV */ 492 | 493 | #if IN_LIBGCOV >= 0 494 | 495 | /* Optimum number of gcov_unsigned_t's read from or written to disk. */ 496 | #define GCOV_BLOCK_SIZE (1 << 10) 497 | 498 | GCOV_LINKAGE struct gcov_var 499 | { 500 | FILE *file; 501 | gcov_position_t start; /* Position of first byte of block */ 502 | unsigned offset; /* Read/write position within the block. */ 503 | unsigned length; /* Read limit in the block. */ 504 | unsigned overread; /* Number of words overread. */ 505 | int error; /* < 0 overflow, > 0 disk error. */ 506 | int mode; /* < 0 writing, > 0 reading */ 507 | #if IN_LIBGCOV 508 | /* Holds one block plus 4 bytes, thus all coverage reads & writes 509 | fit within this buffer and we always can transfer GCOV_BLOCK_SIZE 510 | to and from the disk. libgcov never backtracks and only writes 4 511 | or 8 byte objects. */ 512 | gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1]; 513 | #else 514 | int endian; /* Swap endianness. */ 515 | /* Holds a variable length block, as the compiler can write 516 | strings and needs to backtrack. */ 517 | size_t alloc; 518 | gcov_unsigned_t *buffer; 519 | #endif 520 | } gcov_var ATTRIBUTE_HIDDEN; 521 | 522 | /* Functions for reading and writing gcov files. In libgcov you can 523 | open the file for reading then writing. Elsewhere you can open the 524 | file either for reading or for writing. When reading a file you may 525 | use the gcov_read_* functions, gcov_sync, gcov_position, & 526 | gcov_error. When writing a file you may use the gcov_write 527 | functions, gcov_seek & gcov_error. When a file is to be rewritten 528 | you use the functions for reading, then gcov_rewrite then the 529 | functions for writing. Your file may become corrupted if you break 530 | these invariants. */ 531 | #if IN_LIBGCOV 532 | GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN; 533 | #else 534 | GCOV_LINKAGE int gcov_open (const char */*name*/, int /*direction*/); 535 | GCOV_LINKAGE int gcov_magic (gcov_unsigned_t, gcov_unsigned_t); 536 | #endif 537 | GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN; 538 | 539 | /* Available everywhere. */ 540 | static gcov_position_t gcov_position (void); 541 | static int gcov_is_error (void); 542 | 543 | GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN; 544 | GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN; 545 | GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *) ATTRIBUTE_HIDDEN; 546 | 547 | #if IN_LIBGCOV 548 | /* Available only in libgcov */ 549 | GCOV_LINKAGE void gcov_write_counter (gcov_type) ATTRIBUTE_HIDDEN; 550 | GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t, gcov_unsigned_t) 551 | ATTRIBUTE_HIDDEN; 552 | GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/, 553 | const struct gcov_summary *) 554 | ATTRIBUTE_HIDDEN; 555 | static void gcov_rewrite (void); 556 | GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN; 557 | #else 558 | /* Available outside libgcov */ 559 | GCOV_LINKAGE const char *gcov_read_string (void); 560 | GCOV_LINKAGE void gcov_sync (gcov_position_t /*base*/, 561 | gcov_unsigned_t /*length */); 562 | #endif 563 | 564 | #if !IN_GCOV 565 | /* Available outside gcov */ 566 | GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN; 567 | #endif 568 | 569 | #if !IN_GCOV && !IN_LIBGCOV 570 | /* Available only in compiler */ 571 | GCOV_LINKAGE void gcov_write_string (const char *); 572 | GCOV_LINKAGE gcov_position_t gcov_write_tag (gcov_unsigned_t); 573 | GCOV_LINKAGE void gcov_write_length (gcov_position_t /*position*/); 574 | #endif 575 | 576 | #if IN_GCOV > 0 577 | /* Available in gcov */ 578 | GCOV_LINKAGE time_t gcov_time (void); 579 | #endif 580 | 581 | /* Save the current position in the gcov file. */ 582 | 583 | static inline gcov_position_t 584 | gcov_position (void) 585 | { 586 | gcc_assert (gcov_var.mode > 0); 587 | return gcov_var.start + gcov_var.offset; 588 | } 589 | 590 | /* Return nonzero if the error flag is set. */ 591 | 592 | static inline int 593 | gcov_is_error (void) 594 | { 595 | return gcov_var.file ? gcov_var.error : 1; 596 | } 597 | 598 | #if IN_LIBGCOV 599 | /* Move to beginning of file and initialize for writing. */ 600 | 601 | static inline void 602 | gcov_rewrite (void) 603 | { 604 | gcc_assert (gcov_var.mode > 0); 605 | gcov_var.mode = -1; 606 | gcov_var.start = 0; 607 | gcov_var.offset = 0; 608 | fseek (gcov_var.file, 0L, SEEK_SET); 609 | } 610 | #endif 611 | 612 | #endif /* IN_LIBGCOV >= 0 */ 613 | 614 | #endif /* GCC_GCOV_IO_H */ 615 | -------------------------------------------------------------------------------- /SourceCode/gcc/gcov-iov.c: -------------------------------------------------------------------------------- 1 | /* Generate gcov version string from version.c. See gcov-io.h for 2 | description of how the version string is generated. 3 | Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. 4 | Contributed by Nathan Sidwell 5 | 6 | This file is part of GCC. 7 | 8 | GCC is free software; you can redistribute it and/or modify it under 9 | the terms of the GNU General Public License as published by the Free 10 | Software Foundation; either version 3, or (at your option) any later 11 | version. 12 | 13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY 14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with GCC; see the file COPYING3. If not see 20 | . */ 21 | 22 | #include 23 | #include 24 | 25 | /* Command line arguments are the base GCC version and the development 26 | phase (the latter may be an empty string). */ 27 | 28 | int 29 | main (int argc, char **argv) 30 | { 31 | unsigned int version = 0; 32 | unsigned char v[4]; 33 | unsigned int ix; 34 | unsigned long major; 35 | unsigned long minor = 0; 36 | char phase = 0; 37 | char *ptr; 38 | 39 | if (argc != 3) 40 | { 41 | fprintf (stderr, "usage: %s 'version' 'phase'\n", argv[0]); 42 | return 1; 43 | } 44 | 45 | ptr = argv[1]; 46 | major = strtoul (ptr, &ptr, 10); 47 | 48 | if (*ptr == '.') 49 | minor = strtoul (ptr + 1, 0, 10); 50 | 51 | phase = argv[2][0]; 52 | if (phase == '\0') 53 | phase = '*'; 54 | 55 | v[0] = (major < 10 ? '0' : 'A' - 10) + major; 56 | v[1] = (minor / 10) + '0'; 57 | v[2] = (minor % 10) + '0'; 58 | v[3] = phase; 59 | 60 | for (ix = 0; ix != 4; ix++) 61 | version = (version << 8) | v[ix]; 62 | 63 | printf ("/* Generated automatically by the program `%s'\n", argv[0]); 64 | printf (" from `%s (%lu %lu) and %s (%c)'. */\n", 65 | argv[1], major, minor, argv[2], phase); 66 | printf ("\n"); 67 | printf ("#define GCOV_VERSION ((gcov_unsigned_t)%#08x) /* %.4s */\n", 68 | version, v); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /SourceCode/gcc/gcov.c: -------------------------------------------------------------------------------- 1 | /* Gcov.c: prepend line execution counts and branch probabilities to a 2 | source file. 3 | Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 4 | 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 5 | Free Software Foundation, Inc. 6 | Contributed by James E. Wilson of Cygnus Support. 7 | Mangled by Bob Manson of Cygnus Support. 8 | Mangled further by Nathan Sidwell 9 | 10 | Gcov is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 3, or (at your option) 13 | any later version. 14 | 15 | Gcov is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Gcov; see the file COPYING3. If not see 22 | . */ 23 | 24 | /* ??? Print a list of the ten blocks with the highest execution counts, 25 | and list the line numbers corresponding to those blocks. Also, perhaps 26 | list the line numbers with the highest execution counts, only printing 27 | the first if there are several which are all listed in the same block. */ 28 | 29 | /* ??? Should have an option to print the number of basic blocks, and the 30 | percent of them that are covered. */ 31 | 32 | /* Need an option to show individual block counts, and show 33 | probabilities of fall through arcs. */ 34 | 35 | #include "config.h" 36 | #include "system.h" 37 | #include "coretypes.h" 38 | #include "tm.h" 39 | #include "intl.h" 40 | #include "version.h" 41 | 42 | #include 43 | 44 | #define IN_GCOV 1 45 | #include "gcov-io.h" 46 | #include "gcov-io.c" 47 | 48 | /* The gcno file is generated by -ftest-coverage option. The gcda file is 49 | generated by a program compiled with -fprofile-arcs. Their formats 50 | are documented in gcov-io.h. */ 51 | 52 | /* The functions in this file for creating and solution program flow graphs 53 | are very similar to functions in the gcc source file profile.c. In 54 | some places we make use of the knowledge of how profile.c works to 55 | select particular algorithms here. */ 56 | 57 | /* This is the size of the buffer used to read in source file lines. */ 58 | 59 | #define STRING_SIZE 200 60 | 61 | struct function_info; 62 | struct block_info; 63 | struct source_info; 64 | 65 | /* Describes an arc between two basic blocks. */ 66 | 67 | typedef struct arc_info 68 | { 69 | /* source and destination blocks. */ 70 | struct block_info *src; 71 | struct block_info *dst; 72 | 73 | /* transition counts. */ 74 | gcov_type count; 75 | /* used in cycle search, so that we do not clobber original counts. */ 76 | gcov_type cs_count; 77 | 78 | unsigned int count_valid : 1; 79 | unsigned int on_tree : 1; 80 | unsigned int fake : 1; 81 | unsigned int fall_through : 1; 82 | 83 | /* Arc is for a function that abnormally returns. */ 84 | unsigned int is_call_non_return : 1; 85 | 86 | /* Arc is for catch/setjmp. */ 87 | unsigned int is_nonlocal_return : 1; 88 | 89 | /* Is an unconditional branch. */ 90 | unsigned int is_unconditional : 1; 91 | 92 | /* Loop making arc. */ 93 | unsigned int cycle : 1; 94 | 95 | /* Next branch on line. */ 96 | struct arc_info *line_next; 97 | 98 | /* Links to next arc on src and dst lists. */ 99 | struct arc_info *succ_next; 100 | struct arc_info *pred_next; 101 | } arc_t; 102 | 103 | /* Describes a basic block. Contains lists of arcs to successor and 104 | predecessor blocks. */ 105 | 106 | typedef struct block_info 107 | { 108 | /* Chain of exit and entry arcs. */ 109 | arc_t *succ; 110 | arc_t *pred; 111 | 112 | /* Number of unprocessed exit and entry arcs. */ 113 | gcov_type num_succ; 114 | gcov_type num_pred; 115 | 116 | /* Block execution count. */ 117 | gcov_type count; 118 | unsigned flags : 13; 119 | unsigned count_valid : 1; 120 | unsigned valid_chain : 1; 121 | unsigned invalid_chain : 1; 122 | 123 | /* Block is a call instrumenting site. */ 124 | unsigned is_call_site : 1; /* Does the call. */ 125 | unsigned is_call_return : 1; /* Is the return. */ 126 | 127 | /* Block is a landing pad for longjmp or throw. */ 128 | unsigned is_nonlocal_return : 1; 129 | 130 | union 131 | { 132 | struct 133 | { 134 | /* Array of line numbers and source files. source files are 135 | introduced by a linenumber of zero, the next 'line number' is 136 | the number of the source file. Always starts with a source 137 | file. */ 138 | unsigned *encoding; 139 | unsigned num; 140 | } line; /* Valid until blocks are linked onto lines */ 141 | struct 142 | { 143 | /* Single line graph cycle workspace. Used for all-blocks 144 | mode. */ 145 | arc_t *arc; 146 | unsigned ident; 147 | } cycle; /* Used in all-blocks mode, after blocks are linked onto 148 | lines. */ 149 | } u; 150 | 151 | /* Temporary chain for solving graph, and for chaining blocks on one 152 | line. */ 153 | struct block_info *chain; 154 | 155 | } block_t; 156 | 157 | /* Describes a single function. Contains an array of basic blocks. */ 158 | 159 | typedef struct function_info 160 | { 161 | /* Name of function. */ 162 | char *name; 163 | unsigned ident; 164 | unsigned checksum; 165 | 166 | /* Array of basic blocks. */ 167 | block_t *blocks; 168 | unsigned num_blocks; 169 | unsigned blocks_executed; 170 | 171 | /* Raw arc coverage counts. */ 172 | gcov_type *counts; 173 | unsigned num_counts; 174 | 175 | /* First line number. */ 176 | unsigned line; 177 | struct source_info *src; 178 | 179 | /* Next function in same source file. */ 180 | struct function_info *line_next; 181 | 182 | /* Next function. */ 183 | struct function_info *next; 184 | } function_t; 185 | 186 | /* Describes coverage of a file or function. */ 187 | 188 | typedef struct coverage_info 189 | { 190 | int lines; 191 | int lines_executed; 192 | 193 | int branches; 194 | int branches_executed; 195 | int branches_taken; 196 | 197 | int calls; 198 | int calls_executed; 199 | 200 | char *name; 201 | } coverage_t; 202 | 203 | /* Describes a single line of source. Contains a chain of basic blocks 204 | with code on it. */ 205 | 206 | typedef struct line_info 207 | { 208 | gcov_type count; /* execution count */ 209 | union 210 | { 211 | arc_t *branches; /* branches from blocks that end on this 212 | line. Used for branch-counts when not 213 | all-blocks mode. */ 214 | block_t *blocks; /* blocks which start on this line. Used 215 | in all-blocks mode. */ 216 | } u; 217 | unsigned exists : 1; 218 | } line_t; 219 | 220 | /* Describes a file mentioned in the block graph. Contains an array 221 | of line info. */ 222 | 223 | typedef struct source_info 224 | { 225 | /* Name of source file. */ 226 | char *name; 227 | unsigned index; 228 | time_t file_time; 229 | 230 | /* Array of line information. */ 231 | line_t *lines; 232 | unsigned num_lines; 233 | 234 | coverage_t coverage; 235 | 236 | /* Functions in this source file. These are in ascending line 237 | number order. */ 238 | function_t *functions; 239 | 240 | /* Next source file. */ 241 | struct source_info *next; 242 | } source_t; 243 | 244 | /* Holds a list of function basic block graphs. */ 245 | 246 | static function_t *functions; 247 | 248 | /* This points to the head of the sourcefile structure list. New elements 249 | are always prepended. */ 250 | 251 | static source_t *sources; 252 | 253 | /* Next index for a source file. */ 254 | 255 | static unsigned source_index; 256 | 257 | /* This holds data summary information. */ 258 | 259 | static struct gcov_summary object_summary; 260 | static unsigned program_count; 261 | 262 | /* Modification time of graph file. */ 263 | 264 | static time_t bbg_file_time; 265 | 266 | /* Name and file pointer of the input file for the basic block graph. */ 267 | 268 | static char *bbg_file_name; 269 | 270 | /* Stamp of the bbg file */ 271 | static unsigned bbg_stamp; 272 | 273 | /* Name and file pointer of the input file for the arc count data. */ 274 | 275 | static char *da_file_name; 276 | 277 | /* Data file is missing. */ 278 | 279 | static int no_data_file; 280 | 281 | /* If there is several input files, compute and display results after 282 | reading all data files. This way if two or more gcda file refer to 283 | the same source file (eg inline subprograms in a .h file), the 284 | counts are added. */ 285 | 286 | static int multiple_files = 0; 287 | 288 | /* Output branch probabilities. */ 289 | 290 | static int flag_branches = 0; 291 | 292 | /* Show unconditional branches too. */ 293 | static int flag_unconditional = 0; 294 | 295 | /* Output a gcov file if this is true. This is on by default, and can 296 | be turned off by the -n option. */ 297 | 298 | static int flag_gcov_file = 1; 299 | 300 | /* For included files, make the gcov output file name include the name 301 | of the input source file. For example, if x.h is included in a.c, 302 | then the output file name is a.c##x.h.gcov instead of x.h.gcov. */ 303 | 304 | static int flag_long_names = 0; 305 | 306 | /* Output count information for every basic block, not merely those 307 | that contain line number information. */ 308 | 309 | static int flag_all_blocks = 0; 310 | 311 | /* Output summary info for each function. */ 312 | 313 | static int flag_function_summary = 0; 314 | 315 | /* Object directory file prefix. This is the directory/file where the 316 | graph and data files are looked for, if nonzero. */ 317 | 318 | static char *object_directory = 0; 319 | 320 | /* Preserve all pathname components. Needed when object files and 321 | source files are in subdirectories. '/' is mangled as '#', '.' is 322 | elided and '..' mangled to '^'. */ 323 | 324 | static int flag_preserve_paths = 0; 325 | 326 | /* Output the number of times a branch was taken as opposed to the percentage 327 | of times it was taken. */ 328 | 329 | static int flag_counts = 0; 330 | 331 | /* Forward declarations. */ 332 | static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2; 333 | static int process_args (int, char **); 334 | static void print_usage (int) ATTRIBUTE_NORETURN; 335 | static void print_version (void) ATTRIBUTE_NORETURN; 336 | static void process_file (const char *); 337 | static void generate_results (const char *); 338 | static void create_file_names (const char *); 339 | static source_t *find_source (const char *); 340 | static int read_graph_file (void); 341 | static int read_count_file (void); 342 | static void solve_flow_graph (function_t *); 343 | static void add_branch_counts (coverage_t *, const arc_t *); 344 | static void add_line_counts (coverage_t *, function_t *); 345 | static void function_summary (const coverage_t *, const char *); 346 | static const char *format_gcov (gcov_type, gcov_type, int); 347 | static void accumulate_line_counts (source_t *); 348 | static int output_branch_count (FILE *, int, const arc_t *); 349 | static void output_lines (FILE *, const source_t *); 350 | static char *make_gcov_file_name (const char *, const char *); 351 | static void release_structures (void); 352 | extern int main (int, char **); 353 | 354 | int 355 | main (int argc, char **argv) 356 | { 357 | int argno; 358 | 359 | /* Unlock the stdio streams. */ 360 | unlock_std_streams (); 361 | 362 | gcc_init_libintl (); 363 | 364 | /* Handle response files. */ 365 | expandargv (&argc, &argv); 366 | 367 | argno = process_args (argc, argv); 368 | if (optind == argc) 369 | print_usage (true); 370 | 371 | if (argc - argno > 1) 372 | multiple_files = 1; 373 | 374 | for (; argno != argc; argno++) 375 | process_file (argv[argno]); 376 | 377 | generate_results (multiple_files ? NULL : argv[argc - 1]); 378 | 379 | release_structures (); 380 | 381 | return 0; 382 | } 383 | 384 | static void 385 | fnotice (FILE *file, const char *cmsgid, ...) 386 | { 387 | va_list ap; 388 | 389 | va_start (ap, cmsgid); 390 | vfprintf (file, _(cmsgid), ap); 391 | va_end (ap); 392 | } 393 | 394 | /* Print a usage message and exit. If ERROR_P is nonzero, this is an error, 395 | otherwise the output of --help. */ 396 | 397 | static void 398 | print_usage (int error_p) 399 | { 400 | FILE *file = error_p ? stderr : stdout; 401 | int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 402 | 403 | fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE...\n\n"); 404 | fnotice (file, "Print code coverage information.\n\n"); 405 | fnotice (file, " -h, --help Print this help, then exit\n"); 406 | fnotice (file, " -v, --version Print version number, then exit\n"); 407 | fnotice (file, " -a, --all-blocks Show information for every basic block\n"); 408 | fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n"); 409 | fnotice (file, " -c, --branch-counts Given counts of branches taken\n\ 410 | rather than percentages\n"); 411 | fnotice (file, " -n, --no-output Do not create an output file\n"); 412 | fnotice (file, " -l, --long-file-names Use long output file names for included\n\ 413 | source files\n"); 414 | fnotice (file, " -f, --function-summaries Output summaries for each function\n"); 415 | fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n"); 416 | fnotice (file, " -p, --preserve-paths Preserve all pathname components\n"); 417 | fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n"); 418 | fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", 419 | bug_report_url); 420 | exit (status); 421 | } 422 | 423 | /* Print version information and exit. */ 424 | 425 | static void 426 | print_version (void) 427 | { 428 | fnotice (stdout, "gcov %s%s\n", pkgversion_string, version_string); 429 | fprintf (stdout, "Copyright %s 2009 Free Software Foundation, Inc.\n", 430 | _("(C)")); 431 | fnotice (stdout, 432 | _("This is free software; see the source for copying conditions.\n" 433 | "There is NO warranty; not even for MERCHANTABILITY or \n" 434 | "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); 435 | exit (SUCCESS_EXIT_CODE); 436 | } 437 | 438 | static const struct option options[] = 439 | { 440 | { "help", no_argument, NULL, 'h' }, 441 | { "version", no_argument, NULL, 'v' }, 442 | { "all-blocks", no_argument, NULL, 'a' }, 443 | { "branch-probabilities", no_argument, NULL, 'b' }, 444 | { "branch-counts", no_argument, NULL, 'c' }, 445 | { "no-output", no_argument, NULL, 'n' }, 446 | { "long-file-names", no_argument, NULL, 'l' }, 447 | { "function-summaries", no_argument, NULL, 'f' }, 448 | { "preserve-paths", no_argument, NULL, 'p' }, 449 | { "object-directory", required_argument, NULL, 'o' }, 450 | { "object-file", required_argument, NULL, 'o' }, 451 | { "unconditional-branches", no_argument, NULL, 'u' }, 452 | { 0, 0, 0, 0 } 453 | }; 454 | 455 | /* Process args, return index to first non-arg. */ 456 | 457 | static int 458 | process_args (int argc, char **argv) 459 | { 460 | int opt; 461 | 462 | while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1) 463 | { 464 | switch (opt) 465 | { 466 | case 'a': 467 | flag_all_blocks = 1; 468 | break; 469 | case 'b': 470 | flag_branches = 1; 471 | break; 472 | case 'c': 473 | flag_counts = 1; 474 | break; 475 | case 'f': 476 | flag_function_summary = 1; 477 | break; 478 | case 'h': 479 | print_usage (false); 480 | /* print_usage will exit. */ 481 | case 'l': 482 | flag_long_names = 1; 483 | break; 484 | case 'n': 485 | flag_gcov_file = 0; 486 | break; 487 | case 'o': 488 | object_directory = optarg; 489 | break; 490 | case 'p': 491 | flag_preserve_paths = 1; 492 | break; 493 | case 'u': 494 | flag_unconditional = 1; 495 | break; 496 | case 'v': 497 | print_version (); 498 | /* print_version will exit. */ 499 | default: 500 | print_usage (true); 501 | /* print_usage will exit. */ 502 | } 503 | } 504 | 505 | return optind; 506 | } 507 | 508 | /* Process a single source file. */ 509 | 510 | static void 511 | process_file (const char *file_name) 512 | { 513 | function_t *fn; 514 | function_t *fn_p; 515 | function_t *old_functions; 516 | 517 | /* Save and clear the list of current functions. They will be appended 518 | later. */ 519 | old_functions = functions; 520 | functions = NULL; 521 | 522 | create_file_names (file_name); 523 | if (read_graph_file ()) 524 | return; 525 | 526 | if (!functions) 527 | { 528 | fnotice (stderr, "%s:no functions found\n", bbg_file_name); 529 | return; 530 | } 531 | 532 | if (read_count_file ()) 533 | return; 534 | 535 | for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next) 536 | solve_flow_graph (fn); 537 | 538 | if (fn_p) 539 | fn_p->next = old_functions; 540 | } 541 | 542 | static void 543 | generate_results (const char *file_name) 544 | { 545 | source_t *src; 546 | function_t *fn; 547 | 548 | for (src = sources; src; src = src->next) 549 | src->lines = XCNEWVEC (line_t, src->num_lines); 550 | for (fn = functions; fn; fn = fn->next) 551 | { 552 | coverage_t coverage; 553 | 554 | memset (&coverage, 0, sizeof (coverage)); 555 | coverage.name = fn->name; 556 | add_line_counts (flag_function_summary ? &coverage : NULL, fn); 557 | if (flag_function_summary) 558 | { 559 | function_summary (&coverage, "Function"); 560 | fnotice (stdout, "\n"); 561 | } 562 | } 563 | 564 | for (src = sources; src; src = src->next) 565 | { 566 | accumulate_line_counts (src); 567 | function_summary (&src->coverage, "File"); 568 | if (flag_gcov_file) 569 | { 570 | char *gcov_file_name = make_gcov_file_name (file_name, src->name); 571 | FILE *gcov_file = fopen (gcov_file_name, "w"); 572 | 573 | if (gcov_file) 574 | { 575 | fnotice (stdout, "%s:creating '%s'\n", 576 | src->name, gcov_file_name); 577 | output_lines (gcov_file, src); 578 | if (ferror (gcov_file)) 579 | fnotice (stderr, "%s:error writing output file '%s'\n", 580 | src->name, gcov_file_name); 581 | fclose (gcov_file); 582 | } 583 | else 584 | fnotice (stderr, "%s:could not open output file '%s'\n", 585 | src->name, gcov_file_name); 586 | free (gcov_file_name); 587 | } 588 | fnotice (stdout, "\n"); 589 | } 590 | } 591 | 592 | /* Release all memory used. */ 593 | 594 | static void 595 | release_structures (void) 596 | { 597 | function_t *fn; 598 | source_t *src; 599 | 600 | while ((src = sources)) 601 | { 602 | sources = src->next; 603 | 604 | free (src->name); 605 | free (src->lines); 606 | } 607 | 608 | while ((fn = functions)) 609 | { 610 | unsigned ix; 611 | block_t *block; 612 | 613 | functions = fn->next; 614 | for (ix = fn->num_blocks, block = fn->blocks; ix--; block++) 615 | { 616 | arc_t *arc, *arc_n; 617 | 618 | for (arc = block->succ; arc; arc = arc_n) 619 | { 620 | arc_n = arc->succ_next; 621 | free (arc); 622 | } 623 | } 624 | free (fn->blocks); 625 | free (fn->counts); 626 | } 627 | } 628 | 629 | /* Generate the names of the graph and data files. If OBJECT_DIRECTORY 630 | is not specified, these are looked for in the current directory, 631 | and named from the basename of the FILE_NAME sans extension. If 632 | OBJECT_DIRECTORY is specified and is a directory, the files are in 633 | that directory, but named from the basename of the FILE_NAME, sans 634 | extension. Otherwise OBJECT_DIRECTORY is taken to be the name of 635 | the object *file*, and the data files are named from that. */ 636 | 637 | static void 638 | create_file_names (const char *file_name) 639 | { 640 | char *cptr; 641 | char *name; 642 | int length = strlen (file_name); 643 | int base; 644 | 645 | /* Free previous file names. */ 646 | if (bbg_file_name) 647 | free (bbg_file_name); 648 | if (da_file_name) 649 | free (da_file_name); 650 | da_file_name = bbg_file_name = NULL; 651 | bbg_file_time = 0; 652 | bbg_stamp = 0; 653 | 654 | if (object_directory && object_directory[0]) 655 | { 656 | struct stat status; 657 | 658 | length += strlen (object_directory) + 2; 659 | name = XNEWVEC (char, length); 660 | name[0] = 0; 661 | 662 | base = !stat (object_directory, &status) && S_ISDIR (status.st_mode); 663 | strcat (name, object_directory); 664 | if (base && (! IS_DIR_SEPARATOR (name[strlen (name) - 1]))) 665 | strcat (name, "/"); 666 | } 667 | else 668 | { 669 | name = XNEWVEC (char, length + 1); 670 | name[0] = 0; 671 | base = 1; 672 | } 673 | 674 | if (base) 675 | { 676 | /* Append source file name. */ 677 | const char *cptr = lbasename (file_name); 678 | strcat (name, cptr ? cptr : file_name); 679 | } 680 | 681 | /* Remove the extension. */ 682 | cptr = strrchr (name, '.'); 683 | if (cptr) 684 | *cptr = 0; 685 | 686 | length = strlen (name); 687 | 688 | bbg_file_name = XNEWVEC (char, length + strlen (GCOV_NOTE_SUFFIX) + 1); 689 | strcpy (bbg_file_name, name); 690 | strcpy (bbg_file_name + length, GCOV_NOTE_SUFFIX); 691 | 692 | da_file_name = XNEWVEC (char, length + strlen (GCOV_DATA_SUFFIX) + 1); 693 | strcpy (da_file_name, name); 694 | strcpy (da_file_name + length, GCOV_DATA_SUFFIX); 695 | 696 | free (name); 697 | return; 698 | } 699 | 700 | /* Find or create a source file structure for FILE_NAME. Copies 701 | FILE_NAME on creation */ 702 | 703 | static source_t * 704 | find_source (const char *file_name) 705 | { 706 | source_t *src; 707 | struct stat status; 708 | 709 | if (!file_name) 710 | file_name = ""; 711 | 712 | for (src = sources; src; src = src->next) 713 | if (!strcmp (file_name, src->name)) 714 | break; 715 | 716 | if (!src) 717 | { 718 | src = XCNEW (source_t); 719 | src->name = xstrdup (file_name); 720 | src->coverage.name = src->name; 721 | src->index = source_index++; 722 | src->next = sources; 723 | sources = src; 724 | 725 | if (!stat (file_name, &status)) 726 | src->file_time = status.st_mtime; 727 | } 728 | 729 | if (src->file_time > bbg_file_time) 730 | { 731 | static int info_emitted; 732 | 733 | fnotice (stderr, "%s:source file is newer than graph file '%s'\n", 734 | src->name, bbg_file_name); 735 | if (!info_emitted) 736 | { 737 | fnotice (stderr, 738 | "(the message is only displayed one per source file)\n"); 739 | info_emitted = 1; 740 | } 741 | src->file_time = 0; 742 | } 743 | 744 | return src; 745 | } 746 | 747 | /* Read the graph file. Return nonzero on fatal error. */ 748 | 749 | static int 750 | read_graph_file (void) 751 | { 752 | unsigned version; 753 | unsigned current_tag = 0; 754 | struct function_info *fn = NULL; 755 | function_t *old_functions_head = functions; 756 | source_t *src = NULL; 757 | unsigned ix; 758 | unsigned tag; 759 | 760 | if (!gcov_open (bbg_file_name, 1)) 761 | { 762 | fnotice (stderr, "%s:cannot open graph file\n", bbg_file_name); 763 | return 1; 764 | } 765 | bbg_file_time = gcov_time (); 766 | if (!gcov_magic (gcov_read_unsigned (), GCOV_NOTE_MAGIC)) 767 | { 768 | fnotice (stderr, "%s:not a gcov graph file\n", bbg_file_name); 769 | gcov_close (); 770 | return 1; 771 | } 772 | 773 | version = gcov_read_unsigned (); 774 | if (version != GCOV_VERSION) 775 | { 776 | char v[4], e[4]; 777 | 778 | GCOV_UNSIGNED2STRING (v, version); 779 | GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 780 | 781 | fnotice (stderr, "%s:version '%.4s', prefer '%.4s'\n", 782 | bbg_file_name, v, e); 783 | } 784 | bbg_stamp = gcov_read_unsigned (); 785 | 786 | while ((tag = gcov_read_unsigned ())) 787 | { 788 | unsigned length = gcov_read_unsigned (); 789 | gcov_position_t base = gcov_position (); 790 | 791 | if (tag == GCOV_TAG_FUNCTION) 792 | { 793 | char *function_name; 794 | unsigned ident, checksum, lineno; 795 | source_t *src; 796 | function_t *probe, *prev; 797 | 798 | ident = gcov_read_unsigned (); 799 | checksum = gcov_read_unsigned (); 800 | function_name = xstrdup (gcov_read_string ()); 801 | src = find_source (gcov_read_string ()); 802 | lineno = gcov_read_unsigned (); 803 | 804 | fn = XCNEW (function_t); 805 | fn->name = function_name; 806 | fn->ident = ident; 807 | fn->checksum = checksum; 808 | fn->src = src; 809 | fn->line = lineno; 810 | 811 | fn->next = functions; 812 | functions = fn; 813 | current_tag = tag; 814 | 815 | if (lineno >= src->num_lines) 816 | src->num_lines = lineno + 1; 817 | /* Now insert it into the source file's list of 818 | functions. Normally functions will be encountered in 819 | ascending order, so a simple scan is quick. */ 820 | for (probe = src->functions, prev = NULL; 821 | probe && probe->line > lineno; 822 | prev = probe, probe = probe->line_next) 823 | continue; 824 | fn->line_next = probe; 825 | if (prev) 826 | prev->line_next = fn; 827 | else 828 | src->functions = fn; 829 | } 830 | else if (fn && tag == GCOV_TAG_BLOCKS) 831 | { 832 | if (fn->blocks) 833 | fnotice (stderr, "%s:already seen blocks for '%s'\n", 834 | bbg_file_name, fn->name); 835 | else 836 | { 837 | unsigned ix, num_blocks = GCOV_TAG_BLOCKS_NUM (length); 838 | fn->num_blocks = num_blocks; 839 | 840 | fn->blocks = XCNEWVEC (block_t, fn->num_blocks); 841 | for (ix = 0; ix != num_blocks; ix++) 842 | fn->blocks[ix].flags = gcov_read_unsigned (); 843 | } 844 | } 845 | else if (fn && tag == GCOV_TAG_ARCS) 846 | { 847 | unsigned src = gcov_read_unsigned (); 848 | unsigned num_dests = GCOV_TAG_ARCS_NUM (length); 849 | 850 | if (src >= fn->num_blocks || fn->blocks[src].succ) 851 | goto corrupt; 852 | 853 | while (num_dests--) 854 | { 855 | struct arc_info *arc; 856 | unsigned dest = gcov_read_unsigned (); 857 | unsigned flags = gcov_read_unsigned (); 858 | 859 | if (dest >= fn->num_blocks) 860 | goto corrupt; 861 | arc = XCNEW (arc_t); 862 | 863 | arc->dst = &fn->blocks[dest]; 864 | arc->src = &fn->blocks[src]; 865 | 866 | arc->count = 0; 867 | arc->count_valid = 0; 868 | arc->on_tree = !!(flags & GCOV_ARC_ON_TREE); 869 | arc->fake = !!(flags & GCOV_ARC_FAKE); 870 | arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); 871 | 872 | arc->succ_next = fn->blocks[src].succ; 873 | fn->blocks[src].succ = arc; 874 | fn->blocks[src].num_succ++; 875 | 876 | arc->pred_next = fn->blocks[dest].pred; 877 | fn->blocks[dest].pred = arc; 878 | fn->blocks[dest].num_pred++; 879 | 880 | if (arc->fake) 881 | { 882 | if (src) 883 | { 884 | /* Exceptional exit from this function, the 885 | source block must be a call. */ 886 | fn->blocks[src].is_call_site = 1; 887 | arc->is_call_non_return = 1; 888 | } 889 | else 890 | { 891 | /* Non-local return from a callee of this 892 | function. The destination block is a catch or 893 | setjmp. */ 894 | arc->is_nonlocal_return = 1; 895 | fn->blocks[dest].is_nonlocal_return = 1; 896 | } 897 | } 898 | 899 | if (!arc->on_tree) 900 | fn->num_counts++; 901 | } 902 | } 903 | else if (fn && tag == GCOV_TAG_LINES) 904 | { 905 | unsigned blockno = gcov_read_unsigned (); 906 | unsigned *line_nos = XCNEWVEC (unsigned, length - 1); 907 | 908 | if (blockno >= fn->num_blocks || fn->blocks[blockno].u.line.encoding) 909 | goto corrupt; 910 | 911 | for (ix = 0; ; ) 912 | { 913 | unsigned lineno = gcov_read_unsigned (); 914 | 915 | if (lineno) 916 | { 917 | if (!ix) 918 | { 919 | line_nos[ix++] = 0; 920 | line_nos[ix++] = src->index; 921 | } 922 | line_nos[ix++] = lineno; 923 | if (lineno >= src->num_lines) 924 | src->num_lines = lineno + 1; 925 | } 926 | else 927 | { 928 | const char *file_name = gcov_read_string (); 929 | 930 | if (!file_name) 931 | break; 932 | src = find_source (file_name); 933 | 934 | line_nos[ix++] = 0; 935 | line_nos[ix++] = src->index; 936 | } 937 | } 938 | 939 | fn->blocks[blockno].u.line.encoding = line_nos; 940 | fn->blocks[blockno].u.line.num = ix; 941 | } 942 | else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag)) 943 | { 944 | fn = NULL; 945 | current_tag = 0; 946 | } 947 | gcov_sync (base, length); 948 | if (gcov_is_error ()) 949 | { 950 | corrupt:; 951 | fnotice (stderr, "%s:corrupted\n", bbg_file_name); 952 | gcov_close (); 953 | return 1; 954 | } 955 | } 956 | gcov_close (); 957 | 958 | /* We built everything backwards, so nreverse them all. */ 959 | 960 | /* Reverse sources. Not strictly necessary, but we'll then process 961 | them in the 'expected' order. */ 962 | { 963 | source_t *src, *src_p, *src_n; 964 | 965 | for (src_p = NULL, src = sources; src; src_p = src, src = src_n) 966 | { 967 | src_n = src->next; 968 | src->next = src_p; 969 | } 970 | sources = src_p; 971 | } 972 | 973 | /* Reverse functions. */ 974 | { 975 | function_t *fn, *fn_p, *fn_n; 976 | 977 | for (fn_p = old_functions_head, fn = functions; 978 | fn != old_functions_head; 979 | fn_p = fn, fn = fn_n) 980 | { 981 | unsigned ix; 982 | 983 | fn_n = fn->next; 984 | fn->next = fn_p; 985 | 986 | /* Reverse the arcs. */ 987 | for (ix = fn->num_blocks; ix--;) 988 | { 989 | arc_t *arc, *arc_p, *arc_n; 990 | 991 | for (arc_p = NULL, arc = fn->blocks[ix].succ; arc; 992 | arc_p = arc, arc = arc_n) 993 | { 994 | arc_n = arc->succ_next; 995 | arc->succ_next = arc_p; 996 | } 997 | fn->blocks[ix].succ = arc_p; 998 | 999 | for (arc_p = NULL, arc = fn->blocks[ix].pred; arc; 1000 | arc_p = arc, arc = arc_n) 1001 | { 1002 | arc_n = arc->pred_next; 1003 | arc->pred_next = arc_p; 1004 | } 1005 | fn->blocks[ix].pred = arc_p; 1006 | } 1007 | } 1008 | functions = fn_p; 1009 | } 1010 | return 0; 1011 | } 1012 | 1013 | /* Reads profiles from the count file and attach to each 1014 | function. Return nonzero if fatal error. */ 1015 | 1016 | static int 1017 | read_count_file (void) 1018 | { 1019 | unsigned ix; 1020 | unsigned version; 1021 | unsigned tag; 1022 | function_t *fn = NULL; 1023 | int error = 0; 1024 | 1025 | if (!gcov_open (da_file_name, 1)) 1026 | { 1027 | fnotice (stderr, "%s:cannot open data file, assuming not executed\n", 1028 | da_file_name); 1029 | no_data_file = 1; 1030 | return 0; 1031 | } 1032 | if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC)) 1033 | { 1034 | fnotice (stderr, "%s:not a gcov data file\n", da_file_name); 1035 | cleanup:; 1036 | gcov_close (); 1037 | return 1; 1038 | } 1039 | version = gcov_read_unsigned (); 1040 | if (version != GCOV_VERSION) 1041 | { 1042 | char v[4], e[4]; 1043 | 1044 | GCOV_UNSIGNED2STRING (v, version); 1045 | GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 1046 | 1047 | fnotice (stderr, "%s:version '%.4s', prefer version '%.4s'\n", 1048 | da_file_name, v, e); 1049 | } 1050 | tag = gcov_read_unsigned (); 1051 | if (tag != bbg_stamp) 1052 | { 1053 | fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name); 1054 | goto cleanup; 1055 | } 1056 | 1057 | while ((tag = gcov_read_unsigned ())) 1058 | { 1059 | unsigned length = gcov_read_unsigned (); 1060 | unsigned long base = gcov_position (); 1061 | 1062 | if (tag == GCOV_TAG_OBJECT_SUMMARY) 1063 | gcov_read_summary (&object_summary); 1064 | else if (tag == GCOV_TAG_PROGRAM_SUMMARY) 1065 | program_count++; 1066 | else if (tag == GCOV_TAG_FUNCTION) 1067 | { 1068 | unsigned ident = gcov_read_unsigned (); 1069 | struct function_info *fn_n = functions; 1070 | 1071 | /* Try to find the function in the list. 1072 | To speed up the search, first start from the last function 1073 | found. */ 1074 | for (fn = fn ? fn->next : NULL; ; fn = fn->next) 1075 | { 1076 | if (fn) 1077 | ; 1078 | else if ((fn = fn_n)) 1079 | fn_n = NULL; 1080 | else 1081 | { 1082 | fnotice (stderr, "%s:unknown function '%u'\n", 1083 | da_file_name, ident); 1084 | break; 1085 | } 1086 | if (fn->ident == ident) 1087 | break; 1088 | } 1089 | 1090 | if (!fn) 1091 | ; 1092 | else if (gcov_read_unsigned () != fn->checksum) 1093 | { 1094 | mismatch:; 1095 | fnotice (stderr, "%s:profile mismatch for '%s'\n", 1096 | da_file_name, fn->name); 1097 | goto cleanup; 1098 | } 1099 | } 1100 | else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn) 1101 | { 1102 | if (length != GCOV_TAG_COUNTER_LENGTH (fn->num_counts)) 1103 | goto mismatch; 1104 | 1105 | if (!fn->counts) 1106 | fn->counts = XCNEWVEC (gcov_type, fn->num_counts); 1107 | 1108 | for (ix = 0; ix != fn->num_counts; ix++) 1109 | fn->counts[ix] += gcov_read_counter (); 1110 | } 1111 | gcov_sync (base, length); 1112 | if ((error = gcov_is_error ())) 1113 | { 1114 | fnotice (stderr, error < 0 ? "%s:overflowed\n" : "%s:corrupted\n", 1115 | da_file_name); 1116 | goto cleanup; 1117 | } 1118 | } 1119 | 1120 | gcov_close (); 1121 | return 0; 1122 | } 1123 | 1124 | /* Solve the flow graph. Propagate counts from the instrumented arcs 1125 | to the blocks and the uninstrumented arcs. */ 1126 | 1127 | static void 1128 | solve_flow_graph (function_t *fn) 1129 | { 1130 | unsigned ix; 1131 | arc_t *arc; 1132 | gcov_type *count_ptr = fn->counts; 1133 | block_t *blk; 1134 | block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ 1135 | block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ 1136 | 1137 | if (fn->num_blocks < 2) 1138 | fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n", 1139 | bbg_file_name, fn->name); 1140 | else 1141 | { 1142 | if (fn->blocks[0].num_pred) 1143 | fnotice (stderr, "%s:'%s' has arcs to entry block\n", 1144 | bbg_file_name, fn->name); 1145 | else 1146 | /* We can't deduce the entry block counts from the lack of 1147 | predecessors. */ 1148 | fn->blocks[0].num_pred = ~(unsigned)0; 1149 | 1150 | if (fn->blocks[fn->num_blocks - 1].num_succ) 1151 | fnotice (stderr, "%s:'%s' has arcs from exit block\n", 1152 | bbg_file_name, fn->name); 1153 | else 1154 | /* Likewise, we can't deduce exit block counts from the lack 1155 | of its successors. */ 1156 | fn->blocks[fn->num_blocks - 1].num_succ = ~(unsigned)0; 1157 | } 1158 | 1159 | /* Propagate the measured counts, this must be done in the same 1160 | order as the code in profile.c */ 1161 | for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++) 1162 | { 1163 | block_t const *prev_dst = NULL; 1164 | int out_of_order = 0; 1165 | int non_fake_succ = 0; 1166 | 1167 | for (arc = blk->succ; arc; arc = arc->succ_next) 1168 | { 1169 | if (!arc->fake) 1170 | non_fake_succ++; 1171 | 1172 | if (!arc->on_tree) 1173 | { 1174 | if (count_ptr) 1175 | arc->count = *count_ptr++; 1176 | arc->count_valid = 1; 1177 | blk->num_succ--; 1178 | arc->dst->num_pred--; 1179 | } 1180 | if (prev_dst && prev_dst > arc->dst) 1181 | out_of_order = 1; 1182 | prev_dst = arc->dst; 1183 | } 1184 | if (non_fake_succ == 1) 1185 | { 1186 | /* If there is only one non-fake exit, it is an 1187 | unconditional branch. */ 1188 | for (arc = blk->succ; arc; arc = arc->succ_next) 1189 | if (!arc->fake) 1190 | { 1191 | arc->is_unconditional = 1; 1192 | /* If this block is instrumenting a call, it might be 1193 | an artificial block. It is not artificial if it has 1194 | a non-fallthrough exit, or the destination of this 1195 | arc has more than one entry. Mark the destination 1196 | block as a return site, if none of those conditions 1197 | hold. */ 1198 | if (blk->is_call_site && arc->fall_through 1199 | && arc->dst->pred == arc && !arc->pred_next) 1200 | arc->dst->is_call_return = 1; 1201 | } 1202 | } 1203 | 1204 | /* Sort the successor arcs into ascending dst order. profile.c 1205 | normally produces arcs in the right order, but sometimes with 1206 | one or two out of order. We're not using a particularly 1207 | smart sort. */ 1208 | if (out_of_order) 1209 | { 1210 | arc_t *start = blk->succ; 1211 | unsigned changes = 1; 1212 | 1213 | while (changes) 1214 | { 1215 | arc_t *arc, *arc_p, *arc_n; 1216 | 1217 | changes = 0; 1218 | for (arc_p = NULL, arc = start; (arc_n = arc->succ_next);) 1219 | { 1220 | if (arc->dst > arc_n->dst) 1221 | { 1222 | changes = 1; 1223 | if (arc_p) 1224 | arc_p->succ_next = arc_n; 1225 | else 1226 | start = arc_n; 1227 | arc->succ_next = arc_n->succ_next; 1228 | arc_n->succ_next = arc; 1229 | arc_p = arc_n; 1230 | } 1231 | else 1232 | { 1233 | arc_p = arc; 1234 | arc = arc_n; 1235 | } 1236 | } 1237 | } 1238 | blk->succ = start; 1239 | } 1240 | 1241 | /* Place it on the invalid chain, it will be ignored if that's 1242 | wrong. */ 1243 | blk->invalid_chain = 1; 1244 | blk->chain = invalid_blocks; 1245 | invalid_blocks = blk; 1246 | } 1247 | 1248 | while (invalid_blocks || valid_blocks) 1249 | { 1250 | while ((blk = invalid_blocks)) 1251 | { 1252 | gcov_type total = 0; 1253 | const arc_t *arc; 1254 | 1255 | invalid_blocks = blk->chain; 1256 | blk->invalid_chain = 0; 1257 | if (!blk->num_succ) 1258 | for (arc = blk->succ; arc; arc = arc->succ_next) 1259 | total += arc->count; 1260 | else if (!blk->num_pred) 1261 | for (arc = blk->pred; arc; arc = arc->pred_next) 1262 | total += arc->count; 1263 | else 1264 | continue; 1265 | 1266 | blk->count = total; 1267 | blk->count_valid = 1; 1268 | blk->chain = valid_blocks; 1269 | blk->valid_chain = 1; 1270 | valid_blocks = blk; 1271 | } 1272 | while ((blk = valid_blocks)) 1273 | { 1274 | gcov_type total; 1275 | arc_t *arc, *inv_arc; 1276 | 1277 | valid_blocks = blk->chain; 1278 | blk->valid_chain = 0; 1279 | if (blk->num_succ == 1) 1280 | { 1281 | block_t *dst; 1282 | 1283 | total = blk->count; 1284 | inv_arc = NULL; 1285 | for (arc = blk->succ; arc; arc = arc->succ_next) 1286 | { 1287 | total -= arc->count; 1288 | if (!arc->count_valid) 1289 | inv_arc = arc; 1290 | } 1291 | dst = inv_arc->dst; 1292 | inv_arc->count_valid = 1; 1293 | inv_arc->count = total; 1294 | blk->num_succ--; 1295 | dst->num_pred--; 1296 | if (dst->count_valid) 1297 | { 1298 | if (dst->num_pred == 1 && !dst->valid_chain) 1299 | { 1300 | dst->chain = valid_blocks; 1301 | dst->valid_chain = 1; 1302 | valid_blocks = dst; 1303 | } 1304 | } 1305 | else 1306 | { 1307 | if (!dst->num_pred && !dst->invalid_chain) 1308 | { 1309 | dst->chain = invalid_blocks; 1310 | dst->invalid_chain = 1; 1311 | invalid_blocks = dst; 1312 | } 1313 | } 1314 | } 1315 | if (blk->num_pred == 1) 1316 | { 1317 | block_t *src; 1318 | 1319 | total = blk->count; 1320 | inv_arc = NULL; 1321 | for (arc = blk->pred; arc; arc = arc->pred_next) 1322 | { 1323 | total -= arc->count; 1324 | if (!arc->count_valid) 1325 | inv_arc = arc; 1326 | } 1327 | src = inv_arc->src; 1328 | inv_arc->count_valid = 1; 1329 | inv_arc->count = total; 1330 | blk->num_pred--; 1331 | src->num_succ--; 1332 | if (src->count_valid) 1333 | { 1334 | if (src->num_succ == 1 && !src->valid_chain) 1335 | { 1336 | src->chain = valid_blocks; 1337 | src->valid_chain = 1; 1338 | valid_blocks = src; 1339 | } 1340 | } 1341 | else 1342 | { 1343 | if (!src->num_succ && !src->invalid_chain) 1344 | { 1345 | src->chain = invalid_blocks; 1346 | src->invalid_chain = 1; 1347 | invalid_blocks = src; 1348 | } 1349 | } 1350 | } 1351 | } 1352 | } 1353 | 1354 | /* If the graph has been correctly solved, every block will have a 1355 | valid count. */ 1356 | for (ix = 0; ix < fn->num_blocks; ix++) 1357 | if (!fn->blocks[ix].count_valid) 1358 | { 1359 | fnotice (stderr, "%s:graph is unsolvable for '%s'\n", 1360 | bbg_file_name, fn->name); 1361 | break; 1362 | } 1363 | } 1364 | 1365 | 1366 | 1367 | /* Increment totals in COVERAGE according to arc ARC. */ 1368 | 1369 | static void 1370 | add_branch_counts (coverage_t *coverage, const arc_t *arc) 1371 | { 1372 | if (arc->is_call_non_return) 1373 | { 1374 | coverage->calls++; 1375 | if (arc->src->count) 1376 | coverage->calls_executed++; 1377 | } 1378 | else if (!arc->is_unconditional) 1379 | { 1380 | coverage->branches++; 1381 | if (arc->src->count) 1382 | coverage->branches_executed++; 1383 | if (arc->count) 1384 | coverage->branches_taken++; 1385 | } 1386 | } 1387 | 1388 | /* Format a HOST_WIDE_INT as either a percent ratio, or absolute 1389 | count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places. 1390 | If DP is zero, no decimal point is printed. Only print 100% when 1391 | TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply 1392 | format TOP. Return pointer to a static string. */ 1393 | 1394 | static char const * 1395 | format_gcov (gcov_type top, gcov_type bottom, int dp) 1396 | { 1397 | static char buffer[20]; 1398 | 1399 | if (dp >= 0) 1400 | { 1401 | float ratio = bottom ? (float)top / bottom : 0; 1402 | int ix; 1403 | unsigned limit = 100; 1404 | unsigned percent; 1405 | 1406 | for (ix = dp; ix--; ) 1407 | limit *= 10; 1408 | 1409 | percent = (unsigned) (ratio * limit + (float)0.5); 1410 | if (percent <= 0 && top) 1411 | percent = 1; 1412 | else if (percent >= limit && top != bottom) 1413 | percent = limit - 1; 1414 | ix = sprintf (buffer, "%.*u%%", dp + 1, percent); 1415 | if (dp) 1416 | { 1417 | dp++; 1418 | do 1419 | { 1420 | buffer[ix+1] = buffer[ix]; 1421 | ix--; 1422 | } 1423 | while (dp--); 1424 | buffer[ix + 1] = '.'; 1425 | } 1426 | } 1427 | else 1428 | sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)top); 1429 | 1430 | return buffer; 1431 | } 1432 | 1433 | 1434 | /* Output summary info for a function. */ 1435 | 1436 | static void 1437 | function_summary (const coverage_t *coverage, const char *title) 1438 | { 1439 | fnotice (stdout, "%s '%s'\n", title, coverage->name); 1440 | 1441 | if (coverage->lines) 1442 | fnotice (stdout, "Lines executed:%s of %d\n", 1443 | format_gcov (coverage->lines_executed, coverage->lines, 2), 1444 | coverage->lines); 1445 | else 1446 | fnotice (stdout, "No executable lines\n"); 1447 | 1448 | if (flag_branches) 1449 | { 1450 | if (coverage->branches) 1451 | { 1452 | fnotice (stdout, "Branches executed:%s of %d\n", 1453 | format_gcov (coverage->branches_executed, 1454 | coverage->branches, 2), 1455 | coverage->branches); 1456 | fnotice (stdout, "Taken at least once:%s of %d\n", 1457 | format_gcov (coverage->branches_taken, 1458 | coverage->branches, 2), 1459 | coverage->branches); 1460 | } 1461 | else 1462 | fnotice (stdout, "No branches\n"); 1463 | if (coverage->calls) 1464 | fnotice (stdout, "Calls executed:%s of %d\n", 1465 | format_gcov (coverage->calls_executed, coverage->calls, 2), 1466 | coverage->calls); 1467 | else 1468 | fnotice (stdout, "No calls\n"); 1469 | } 1470 | } 1471 | 1472 | /* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS 1473 | affect name generation. With preserve_paths we create a filename 1474 | from all path components of the source file, replacing '/' with 1475 | '#', without it we simply take the basename component. With 1476 | long_output_names we prepend the processed name of the input file 1477 | to each output name (except when the current source file is the 1478 | input file, so you don't get a double concatenation). The two 1479 | components are separated by '##'. Also '.' filename components are 1480 | removed and '..' components are renamed to '^'. */ 1481 | 1482 | static char * 1483 | make_gcov_file_name (const char *input_name, const char *src_name) 1484 | { 1485 | const char *cptr; 1486 | char *name; 1487 | 1488 | if (flag_long_names && input_name && strcmp (src_name, input_name)) 1489 | { 1490 | name = XNEWVEC (char, strlen (src_name) + strlen (input_name) + 10); 1491 | name[0] = 0; 1492 | /* Generate the input filename part. */ 1493 | cptr = flag_preserve_paths ? NULL : lbasename (input_name); 1494 | strcat (name, cptr ? cptr : input_name); 1495 | strcat (name, "##"); 1496 | } 1497 | else 1498 | { 1499 | name = XNEWVEC (char, strlen (src_name) + 10); 1500 | name[0] = 0; 1501 | } 1502 | 1503 | /* Generate the source filename part. */ 1504 | 1505 | cptr = flag_preserve_paths ? NULL : lbasename (src_name); 1506 | strcat (name, cptr ? cptr : src_name); 1507 | 1508 | if (flag_preserve_paths) 1509 | { 1510 | /* Convert '/' and '\' to '#', remove '/./', convert '/../' to '/^/', 1511 | convert ':' to '~' on DOS based file system. */ 1512 | char *pnew = name, *pold = name; 1513 | 1514 | /* First check for leading drive separator. */ 1515 | 1516 | while (*pold != '\0') 1517 | { 1518 | if (*pold == '/' || *pold == '\\') 1519 | { 1520 | *pnew++ = '#'; 1521 | pold++; 1522 | } 1523 | #if defined (HAVE_DOS_BASED_FILE_SYSTEM) 1524 | else if (*pold == ':') 1525 | { 1526 | *pnew++ = '~'; 1527 | pold++; 1528 | } 1529 | #endif 1530 | else if ((*pold == '/' && strstr (pold, "/./") == pold) 1531 | || (*pold == '\\' && strstr (pold, "\\.\\") == pold)) 1532 | pold += 3; 1533 | else if (*pold == '/' && strstr (pold, "/../") == pold) 1534 | { 1535 | strcpy (pnew, "/^/"); 1536 | pnew += 3; 1537 | pold += 4; 1538 | } 1539 | else if (*pold == '\\' && strstr (pold, "\\..\\") == pold) 1540 | { 1541 | strcpy (pnew, "\\^\\"); 1542 | pnew += 3; 1543 | pold += 4; 1544 | } 1545 | else 1546 | *pnew++ = *pold++; 1547 | } 1548 | 1549 | *pnew = '\0'; 1550 | } 1551 | 1552 | strcat (name, ".gcov"); 1553 | return name; 1554 | } 1555 | 1556 | /* Scan through the bb_data for each line in the block, increment 1557 | the line number execution count indicated by the execution count of 1558 | the appropriate basic block. */ 1559 | 1560 | static void 1561 | add_line_counts (coverage_t *coverage, function_t *fn) 1562 | { 1563 | unsigned ix; 1564 | line_t *line = NULL; /* This is propagated from one iteration to the 1565 | next. */ 1566 | 1567 | /* Scan each basic block. */ 1568 | for (ix = 0; ix != fn->num_blocks; ix++) 1569 | { 1570 | block_t *block = &fn->blocks[ix]; 1571 | unsigned *encoding; 1572 | const source_t *src = NULL; 1573 | unsigned jx; 1574 | 1575 | if (block->count && ix && ix + 1 != fn->num_blocks) 1576 | fn->blocks_executed++; 1577 | for (jx = 0, encoding = block->u.line.encoding; 1578 | jx != block->u.line.num; jx++, encoding++) 1579 | if (!*encoding) 1580 | { 1581 | unsigned src_n = *++encoding; 1582 | 1583 | for (src = sources; src->index != src_n; src = src->next) 1584 | continue; 1585 | jx++; 1586 | } 1587 | else 1588 | { 1589 | line = &src->lines[*encoding]; 1590 | 1591 | if (coverage) 1592 | { 1593 | if (!line->exists) 1594 | coverage->lines++; 1595 | if (!line->count && block->count) 1596 | coverage->lines_executed++; 1597 | } 1598 | line->exists = 1; 1599 | line->count += block->count; 1600 | } 1601 | free (block->u.line.encoding); 1602 | block->u.cycle.arc = NULL; 1603 | block->u.cycle.ident = ~0U; 1604 | 1605 | if (!ix || ix + 1 == fn->num_blocks) 1606 | /* Entry or exit block */; 1607 | else if (flag_all_blocks) 1608 | { 1609 | line_t *block_line = line ? line : &fn->src->lines[fn->line]; 1610 | 1611 | block->chain = block_line->u.blocks; 1612 | block_line->u.blocks = block; 1613 | } 1614 | else if (flag_branches) 1615 | { 1616 | arc_t *arc; 1617 | 1618 | for (arc = block->succ; arc; arc = arc->succ_next) 1619 | { 1620 | arc->line_next = line->u.branches; 1621 | line->u.branches = arc; 1622 | if (coverage && !arc->is_unconditional) 1623 | add_branch_counts (coverage, arc); 1624 | } 1625 | } 1626 | } 1627 | if (!line) 1628 | fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name); 1629 | } 1630 | 1631 | /* Accumulate the line counts of a file. */ 1632 | 1633 | static void 1634 | accumulate_line_counts (source_t *src) 1635 | { 1636 | line_t *line; 1637 | function_t *fn, *fn_p, *fn_n; 1638 | unsigned ix; 1639 | 1640 | /* Reverse the function order. */ 1641 | for (fn = src->functions, fn_p = NULL; fn; 1642 | fn_p = fn, fn = fn_n) 1643 | { 1644 | fn_n = fn->line_next; 1645 | fn->line_next = fn_p; 1646 | } 1647 | src->functions = fn_p; 1648 | 1649 | for (ix = src->num_lines, line = src->lines; ix--; line++) 1650 | { 1651 | if (!flag_all_blocks) 1652 | { 1653 | arc_t *arc, *arc_p, *arc_n; 1654 | 1655 | /* Total and reverse the branch information. */ 1656 | for (arc = line->u.branches, arc_p = NULL; arc; 1657 | arc_p = arc, arc = arc_n) 1658 | { 1659 | arc_n = arc->line_next; 1660 | arc->line_next = arc_p; 1661 | 1662 | add_branch_counts (&src->coverage, arc); 1663 | } 1664 | line->u.branches = arc_p; 1665 | } 1666 | else if (line->u.blocks) 1667 | { 1668 | /* The user expects the line count to be the number of times 1669 | a line has been executed. Simply summing the block count 1670 | will give an artificially high number. The Right Thing 1671 | is to sum the entry counts to the graph of blocks on this 1672 | line, then find the elementary cycles of the local graph 1673 | and add the transition counts of those cycles. */ 1674 | block_t *block, *block_p, *block_n; 1675 | gcov_type count = 0; 1676 | 1677 | /* Reverse the block information. */ 1678 | for (block = line->u.blocks, block_p = NULL; block; 1679 | block_p = block, block = block_n) 1680 | { 1681 | block_n = block->chain; 1682 | block->chain = block_p; 1683 | block->u.cycle.ident = ix; 1684 | } 1685 | line->u.blocks = block_p; 1686 | 1687 | /* Sum the entry arcs. */ 1688 | for (block = line->u.blocks; block; block = block->chain) 1689 | { 1690 | arc_t *arc; 1691 | 1692 | for (arc = block->pred; arc; arc = arc->pred_next) 1693 | { 1694 | if (arc->src->u.cycle.ident != ix) 1695 | count += arc->count; 1696 | if (flag_branches) 1697 | add_branch_counts (&src->coverage, arc); 1698 | } 1699 | 1700 | /* Initialize the cs_count. */ 1701 | for (arc = block->succ; arc; arc = arc->succ_next) 1702 | arc->cs_count = arc->count; 1703 | } 1704 | 1705 | /* Find the loops. This uses the algorithm described in 1706 | Tiernan 'An Efficient Search Algorithm to Find the 1707 | Elementary Circuits of a Graph', CACM Dec 1970. We hold 1708 | the P array by having each block point to the arc that 1709 | connects to the previous block. The H array is implicitly 1710 | held because of the arc ordering, and the block's 1711 | previous arc pointer. 1712 | 1713 | Although the algorithm is O(N^3) for highly connected 1714 | graphs, at worst we'll have O(N^2), as most blocks have 1715 | only one or two exits. Most graphs will be small. 1716 | 1717 | For each loop we find, locate the arc with the smallest 1718 | transition count, and add that to the cumulative 1719 | count. Decrease flow over the cycle and remove the arc 1720 | from consideration. */ 1721 | for (block = line->u.blocks; block; block = block->chain) 1722 | { 1723 | block_t *head = block; 1724 | arc_t *arc; 1725 | 1726 | next_vertex:; 1727 | arc = head->succ; 1728 | current_vertex:; 1729 | while (arc) 1730 | { 1731 | block_t *dst = arc->dst; 1732 | if (/* Already used that arc. */ 1733 | arc->cycle 1734 | /* Not to same graph, or before first vertex. */ 1735 | || dst->u.cycle.ident != ix 1736 | /* Already in path. */ 1737 | || dst->u.cycle.arc) 1738 | { 1739 | arc = arc->succ_next; 1740 | continue; 1741 | } 1742 | 1743 | if (dst == block) 1744 | { 1745 | /* Found a closing arc. */ 1746 | gcov_type cycle_count = arc->cs_count; 1747 | arc_t *cycle_arc = arc; 1748 | arc_t *probe_arc; 1749 | 1750 | /* Locate the smallest arc count of the loop. */ 1751 | for (dst = head; (probe_arc = dst->u.cycle.arc); 1752 | dst = probe_arc->src) 1753 | if (cycle_count > probe_arc->cs_count) 1754 | { 1755 | cycle_count = probe_arc->cs_count; 1756 | cycle_arc = probe_arc; 1757 | } 1758 | 1759 | count += cycle_count; 1760 | cycle_arc->cycle = 1; 1761 | 1762 | /* Remove the flow from the cycle. */ 1763 | arc->cs_count -= cycle_count; 1764 | for (dst = head; (probe_arc = dst->u.cycle.arc); 1765 | dst = probe_arc->src) 1766 | probe_arc->cs_count -= cycle_count; 1767 | 1768 | /* Unwind to the cyclic arc. */ 1769 | while (head != cycle_arc->src) 1770 | { 1771 | arc = head->u.cycle.arc; 1772 | head->u.cycle.arc = NULL; 1773 | head = arc->src; 1774 | } 1775 | /* Move on. */ 1776 | arc = arc->succ_next; 1777 | continue; 1778 | } 1779 | 1780 | /* Add new block to chain. */ 1781 | dst->u.cycle.arc = arc; 1782 | head = dst; 1783 | goto next_vertex; 1784 | } 1785 | /* We could not add another vertex to the path. Remove 1786 | the last vertex from the list. */ 1787 | arc = head->u.cycle.arc; 1788 | if (arc) 1789 | { 1790 | /* It was not the first vertex. Move onto next arc. */ 1791 | head->u.cycle.arc = NULL; 1792 | head = arc->src; 1793 | arc = arc->succ_next; 1794 | goto current_vertex; 1795 | } 1796 | /* Mark this block as unusable. */ 1797 | block->u.cycle.ident = ~0U; 1798 | } 1799 | 1800 | line->count = count; 1801 | } 1802 | 1803 | if (line->exists) 1804 | { 1805 | src->coverage.lines++; 1806 | if (line->count) 1807 | src->coverage.lines_executed++; 1808 | } 1809 | } 1810 | } 1811 | 1812 | /* Output information about ARC number IX. Returns nonzero if 1813 | anything is output. */ 1814 | 1815 | static int 1816 | output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) 1817 | { 1818 | 1819 | if (arc->is_call_non_return) 1820 | { 1821 | if (arc->src->count) 1822 | { 1823 | fnotice (gcov_file, "call %2d returned %s\n", ix, 1824 | format_gcov (arc->src->count - arc->count, 1825 | arc->src->count, -flag_counts)); 1826 | } 1827 | else 1828 | fnotice (gcov_file, "call %2d never executed\n", ix); 1829 | } 1830 | else if (!arc->is_unconditional) 1831 | { 1832 | if (arc->src->count) 1833 | fnotice (gcov_file, "branch %2d taken %s%s\n", ix, 1834 | format_gcov (arc->count, arc->src->count, -flag_counts), 1835 | arc->fall_through ? " (fallthrough)" : ""); 1836 | else 1837 | fnotice (gcov_file, "branch %2d never executed\n", ix); 1838 | } 1839 | else if (flag_unconditional && !arc->dst->is_call_return) 1840 | { 1841 | if (arc->src->count) 1842 | fnotice (gcov_file, "unconditional %2d taken %s\n", ix, 1843 | format_gcov (arc->count, arc->src->count, -flag_counts)); 1844 | else 1845 | fnotice (gcov_file, "unconditional %2d never executed\n", ix); 1846 | } 1847 | else 1848 | return 0; 1849 | return 1; 1850 | 1851 | } 1852 | 1853 | /* Read in the source file one line at a time, and output that line to 1854 | the gcov file preceded by its execution count and other 1855 | information. */ 1856 | 1857 | static void 1858 | output_lines (FILE *gcov_file, const source_t *src) 1859 | { 1860 | FILE *source_file; 1861 | unsigned line_num; /* current line number. */ 1862 | const line_t *line; /* current line info ptr. */ 1863 | char string[STRING_SIZE]; /* line buffer. */ 1864 | char const *retval = ""; /* status of source file reading. */ 1865 | function_t *fn = NULL; 1866 | 1867 | fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name); 1868 | if (!multiple_files) 1869 | { 1870 | fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name); 1871 | fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, 1872 | no_data_file ? "-" : da_file_name); 1873 | fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, 1874 | object_summary.ctrs[GCOV_COUNTER_ARCS].runs); 1875 | } 1876 | fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count); 1877 | 1878 | source_file = fopen (src->name, "r"); 1879 | if (!source_file) 1880 | { 1881 | fnotice (stderr, "%s:cannot open source file\n", src->name); 1882 | retval = NULL; 1883 | } 1884 | else if (src->file_time == 0) 1885 | fprintf (gcov_file, "%9s:%5d:Source is newer than graph\n", "-", 0); 1886 | 1887 | if (flag_branches) 1888 | fn = src->functions; 1889 | 1890 | for (line_num = 1, line = &src->lines[line_num]; 1891 | line_num < src->num_lines; line_num++, line++) 1892 | { 1893 | for (; fn && fn->line == line_num; fn = fn->line_next) 1894 | { 1895 | arc_t *arc = fn->blocks[fn->num_blocks - 1].pred; 1896 | gcov_type return_count = fn->blocks[fn->num_blocks - 1].count; 1897 | 1898 | for (; arc; arc = arc->pred_next) 1899 | if (arc->fake) 1900 | return_count -= arc->count; 1901 | 1902 | fprintf (gcov_file, "function %s", fn->name); 1903 | fprintf (gcov_file, " called %s", 1904 | format_gcov (fn->blocks[0].count, 0, -1)); 1905 | fprintf (gcov_file, " returned %s", 1906 | format_gcov (return_count, fn->blocks[0].count, 0)); 1907 | fprintf (gcov_file, " blocks executed %s", 1908 | format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0)); 1909 | fprintf (gcov_file, "\n"); 1910 | } 1911 | 1912 | /* For lines which don't exist in the .bb file, print '-' before 1913 | the source line. For lines which exist but were never 1914 | executed, print '#####' before the source line. Otherwise, 1915 | print the execution count before the source line. There are 1916 | 16 spaces of indentation added before the source line so that 1917 | tabs won't be messed up. */ 1918 | fprintf (gcov_file, "%9s:%5u:", 1919 | !line->exists ? "-" : !line->count ? "#####" 1920 | : format_gcov (line->count, 0, -1), line_num); 1921 | 1922 | if (retval) 1923 | { 1924 | /* Copy source line. */ 1925 | do 1926 | { 1927 | retval = fgets (string, STRING_SIZE, source_file); 1928 | if (!retval) 1929 | break; 1930 | fputs (retval, gcov_file); 1931 | } 1932 | while (!retval[0] || retval[strlen (retval) - 1] != '\n'); 1933 | } 1934 | if (!retval) 1935 | fputs ("/*EOF*/\n", gcov_file); 1936 | 1937 | if (flag_all_blocks) 1938 | { 1939 | block_t *block; 1940 | arc_t *arc; 1941 | int ix, jx; 1942 | 1943 | for (ix = jx = 0, block = line->u.blocks; block; 1944 | block = block->chain) 1945 | { 1946 | if (!block->is_call_return) 1947 | fprintf (gcov_file, "%9s:%5u-block %2d\n", 1948 | !line->exists ? "-" : !block->count ? "$$$$$" 1949 | : format_gcov (block->count, 0, -1), 1950 | line_num, ix++); 1951 | if (flag_branches) 1952 | for (arc = block->succ; arc; arc = arc->succ_next) 1953 | jx += output_branch_count (gcov_file, jx, arc); 1954 | } 1955 | } 1956 | else if (flag_branches) 1957 | { 1958 | int ix; 1959 | arc_t *arc; 1960 | 1961 | for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next) 1962 | ix += output_branch_count (gcov_file, ix, arc); 1963 | } 1964 | } 1965 | 1966 | /* Handle all remaining source lines. There may be lines after the 1967 | last line of code. */ 1968 | if (retval) 1969 | { 1970 | for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++) 1971 | { 1972 | fprintf (gcov_file, "%9s:%5u:%s", "-", line_num, retval); 1973 | 1974 | while (!retval[0] || retval[strlen (retval) - 1] != '\n') 1975 | { 1976 | retval = fgets (string, STRING_SIZE, source_file); 1977 | if (!retval) 1978 | break; 1979 | fputs (retval, gcov_file); 1980 | } 1981 | } 1982 | } 1983 | 1984 | if (source_file) 1985 | fclose (source_file); 1986 | } 1987 | -------------------------------------------------------------------------------- /example/output/amber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/output/amber.png -------------------------------------------------------------------------------- /example/output/emerald.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/output/emerald.png -------------------------------------------------------------------------------- /example/output/example/index-sort-f.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info - example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - exampleHitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 |

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
test.c 75 |
91.3%91.3%
76 |
91.3 %21 / 23100.0 %2 / 2
83 |
84 |
85 | 86 | 87 | 88 | 89 |
Generated by: LCOV version 1.12
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/output/example/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info - example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - exampleHitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 |

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
test.c 75 |
91.3%91.3%
76 |
91.3 %21 / 23100.0 %2 / 2
83 |
84 |
85 | 86 | 87 | 88 | 89 |
Generated by: LCOV version 1.12
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/output/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info - example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - exampleHitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 |

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
test.c 75 |
91.3%91.3%
76 |
91.3 %21 / 23100.0 %2 / 2
83 |
84 |
85 | 86 | 87 | 88 | 89 |
Generated by: LCOV version 1.12
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/output/example/test.c.func-sort-c.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info - example/test.c - functions 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - example - test.c (source / functions)HitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |

Function Name Sort by function nameHit count Sort by hit count
main1
twoSum1
71 |
72 |
73 | 74 | 75 | 76 |
Generated by: LCOV version 1.12
77 |
78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /example/output/example/test.c.func.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info - example/test.c - functions 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - example - test.c (source / functions)HitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |

Function Name Sort by function nameHit count Sort by hit count
main1
twoSum1
71 |
72 |
73 | 74 | 75 | 76 |
Generated by: LCOV version 1.12
77 |
78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /example/output/example/test.c.gcov.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info - example/test.c 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - example - test.c (source / functions)HitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 | 56 | 57 | 58 | 59 | 60 | 107 | 108 |

61 |
          Line data    Source code
62 |
 63 |        1             : #include<stdio.h>
 64 |        2             : #include<stdlib.h>
 65 |        3             : #include<string.h>
 66 |        4           1 : int* twoSum(int* nums, int numsSize, int target) {
 67 |        5           1 :     int loop = 0;
 68 |        6           1 :     int inloop = 0;
 69 |        7           1 :     int* result = NULL;
 70 |        8           1 :     result =(int*) malloc(2*sizeof(int));
 71 |        9           1 :     memset(result,0,2*sizeof(int));
 72 |       10           1 :     printf("numsSize=%d\n",numsSize);
 73 |       11           1 :     if(NULL == nums || numsSize==0)
 74 |       12             :     {
 75 |       13           0 :         return result;
 76 |       14             :     }
 77 |       15             : 
 78 |       16           1 :     for(loop = 0;loop < numsSize;loop++)
 79 |       17             :     {
 80 |       18           1 :         for(inloop = loop+1;inloop <numsSize;inloop++)
 81 |       19             :         {
 82 |       20           1 :             if(*(nums+loop)+*(nums+inloop) == target)
 83 |       21             :             {
 84 |       22           1 :                 if(NULL != result)
 85 |       23             :                 {
 86 |       24             : 
 87 |       25           1 :                     *result = loop;
 88 |       26           1 :                     *(result+1) = inloop;
 89 |       27             :                 }
 90 |       28           1 :                 return result;
 91 |       29             :             }
 92 |       30             :         }
 93 |       31             :     }
 94 |       32           0 :     return result;
 95 |       33             : }
 96 |       34             : 
 97 |       35           1 : int main(int arg,char argv[])
 98 |       36             : {
 99 |       37           1 :     int nums[4]={2,7,11,15};
100 |       38           1 :     int target = 9;
101 |       39           1 :     int numsSize = 4;
102 |       40           1 :     int* result = twoSum(nums,numsSize,target);
103 |       41           1 :     printf("index1:%d\nindex2:%d\n",*result,*(result+1));
104 |       42             : }
105 | 
106 |
109 |
110 | 111 | 112 | 113 | 114 |
Generated by: LCOV version 1.12
115 |
116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /example/output/gcov.css: -------------------------------------------------------------------------------- 1 | /* All views: initial background and text color */ 2 | body 3 | { 4 | color: #000000; 5 | background-color: #FFFFFF; 6 | } 7 | 8 | /* All views: standard link format*/ 9 | a:link 10 | { 11 | color: #284FA8; 12 | text-decoration: underline; 13 | } 14 | 15 | /* All views: standard link - visited format */ 16 | a:visited 17 | { 18 | color: #00CB40; 19 | text-decoration: underline; 20 | } 21 | 22 | /* All views: standard link - activated format */ 23 | a:active 24 | { 25 | color: #FF0040; 26 | text-decoration: underline; 27 | } 28 | 29 | /* All views: main title format */ 30 | td.title 31 | { 32 | text-align: center; 33 | padding-bottom: 10px; 34 | font-family: sans-serif; 35 | font-size: 20pt; 36 | font-style: italic; 37 | font-weight: bold; 38 | } 39 | 40 | /* All views: header item format */ 41 | td.headerItem 42 | { 43 | text-align: right; 44 | padding-right: 6px; 45 | font-family: sans-serif; 46 | font-weight: bold; 47 | vertical-align: top; 48 | white-space: nowrap; 49 | } 50 | 51 | /* All views: header item value format */ 52 | td.headerValue 53 | { 54 | text-align: left; 55 | color: #284FA8; 56 | font-family: sans-serif; 57 | font-weight: bold; 58 | white-space: nowrap; 59 | } 60 | 61 | /* All views: header item coverage table heading */ 62 | td.headerCovTableHead 63 | { 64 | text-align: center; 65 | padding-right: 6px; 66 | padding-left: 6px; 67 | padding-bottom: 0px; 68 | font-family: sans-serif; 69 | font-size: 80%; 70 | white-space: nowrap; 71 | } 72 | 73 | /* All views: header item coverage table entry */ 74 | td.headerCovTableEntry 75 | { 76 | text-align: right; 77 | color: #284FA8; 78 | font-family: sans-serif; 79 | font-weight: bold; 80 | white-space: nowrap; 81 | padding-left: 12px; 82 | padding-right: 4px; 83 | background-color: #DAE7FE; 84 | } 85 | 86 | /* All views: header item coverage table entry for high coverage rate */ 87 | td.headerCovTableEntryHi 88 | { 89 | text-align: right; 90 | color: #000000; 91 | font-family: sans-serif; 92 | font-weight: bold; 93 | white-space: nowrap; 94 | padding-left: 12px; 95 | padding-right: 4px; 96 | background-color: #A7FC9D; 97 | } 98 | 99 | /* All views: header item coverage table entry for medium coverage rate */ 100 | td.headerCovTableEntryMed 101 | { 102 | text-align: right; 103 | color: #000000; 104 | font-family: sans-serif; 105 | font-weight: bold; 106 | white-space: nowrap; 107 | padding-left: 12px; 108 | padding-right: 4px; 109 | background-color: #FFEA20; 110 | } 111 | 112 | /* All views: header item coverage table entry for ow coverage rate */ 113 | td.headerCovTableEntryLo 114 | { 115 | text-align: right; 116 | color: #000000; 117 | font-family: sans-serif; 118 | font-weight: bold; 119 | white-space: nowrap; 120 | padding-left: 12px; 121 | padding-right: 4px; 122 | background-color: #FF0000; 123 | } 124 | 125 | /* All views: header legend value for legend entry */ 126 | td.headerValueLeg 127 | { 128 | text-align: left; 129 | color: #000000; 130 | font-family: sans-serif; 131 | font-size: 80%; 132 | white-space: nowrap; 133 | padding-top: 4px; 134 | } 135 | 136 | /* All views: color of horizontal ruler */ 137 | td.ruler 138 | { 139 | background-color: #6688D4; 140 | } 141 | 142 | /* All views: version string format */ 143 | td.versionInfo 144 | { 145 | text-align: center; 146 | padding-top: 2px; 147 | font-family: sans-serif; 148 | font-style: italic; 149 | } 150 | 151 | /* Directory view/File view (all)/Test case descriptions: 152 | table headline format */ 153 | td.tableHead 154 | { 155 | text-align: center; 156 | color: #FFFFFF; 157 | background-color: #6688D4; 158 | font-family: sans-serif; 159 | font-size: 120%; 160 | font-weight: bold; 161 | white-space: nowrap; 162 | padding-left: 4px; 163 | padding-right: 4px; 164 | } 165 | 166 | span.tableHeadSort 167 | { 168 | padding-right: 4px; 169 | } 170 | 171 | /* Directory view/File view (all): filename entry format */ 172 | td.coverFile 173 | { 174 | text-align: left; 175 | padding-left: 10px; 176 | padding-right: 20px; 177 | color: #284FA8; 178 | background-color: #DAE7FE; 179 | font-family: monospace; 180 | } 181 | 182 | /* Directory view/File view (all): bar-graph entry format*/ 183 | td.coverBar 184 | { 185 | padding-left: 10px; 186 | padding-right: 10px; 187 | background-color: #DAE7FE; 188 | } 189 | 190 | /* Directory view/File view (all): bar-graph outline color */ 191 | td.coverBarOutline 192 | { 193 | background-color: #000000; 194 | } 195 | 196 | /* Directory view/File view (all): percentage entry for files with 197 | high coverage rate */ 198 | td.coverPerHi 199 | { 200 | text-align: right; 201 | padding-left: 10px; 202 | padding-right: 10px; 203 | background-color: #A7FC9D; 204 | font-weight: bold; 205 | font-family: sans-serif; 206 | } 207 | 208 | /* Directory view/File view (all): line count entry for files with 209 | high coverage rate */ 210 | td.coverNumHi 211 | { 212 | text-align: right; 213 | padding-left: 10px; 214 | padding-right: 10px; 215 | background-color: #A7FC9D; 216 | white-space: nowrap; 217 | font-family: sans-serif; 218 | } 219 | 220 | /* Directory view/File view (all): percentage entry for files with 221 | medium coverage rate */ 222 | td.coverPerMed 223 | { 224 | text-align: right; 225 | padding-left: 10px; 226 | padding-right: 10px; 227 | background-color: #FFEA20; 228 | font-weight: bold; 229 | font-family: sans-serif; 230 | } 231 | 232 | /* Directory view/File view (all): line count entry for files with 233 | medium coverage rate */ 234 | td.coverNumMed 235 | { 236 | text-align: right; 237 | padding-left: 10px; 238 | padding-right: 10px; 239 | background-color: #FFEA20; 240 | white-space: nowrap; 241 | font-family: sans-serif; 242 | } 243 | 244 | /* Directory view/File view (all): percentage entry for files with 245 | low coverage rate */ 246 | td.coverPerLo 247 | { 248 | text-align: right; 249 | padding-left: 10px; 250 | padding-right: 10px; 251 | background-color: #FF0000; 252 | font-weight: bold; 253 | font-family: sans-serif; 254 | } 255 | 256 | /* Directory view/File view (all): line count entry for files with 257 | low coverage rate */ 258 | td.coverNumLo 259 | { 260 | text-align: right; 261 | padding-left: 10px; 262 | padding-right: 10px; 263 | background-color: #FF0000; 264 | white-space: nowrap; 265 | font-family: sans-serif; 266 | } 267 | 268 | /* File view (all): "show/hide details" link format */ 269 | a.detail:link 270 | { 271 | color: #B8D0FF; 272 | font-size:80%; 273 | } 274 | 275 | /* File view (all): "show/hide details" link - visited format */ 276 | a.detail:visited 277 | { 278 | color: #B8D0FF; 279 | font-size:80%; 280 | } 281 | 282 | /* File view (all): "show/hide details" link - activated format */ 283 | a.detail:active 284 | { 285 | color: #FFFFFF; 286 | font-size:80%; 287 | } 288 | 289 | /* File view (detail): test name entry */ 290 | td.testName 291 | { 292 | text-align: right; 293 | padding-right: 10px; 294 | background-color: #DAE7FE; 295 | font-family: sans-serif; 296 | } 297 | 298 | /* File view (detail): test percentage entry */ 299 | td.testPer 300 | { 301 | text-align: right; 302 | padding-left: 10px; 303 | padding-right: 10px; 304 | background-color: #DAE7FE; 305 | font-family: sans-serif; 306 | } 307 | 308 | /* File view (detail): test lines count entry */ 309 | td.testNum 310 | { 311 | text-align: right; 312 | padding-left: 10px; 313 | padding-right: 10px; 314 | background-color: #DAE7FE; 315 | font-family: sans-serif; 316 | } 317 | 318 | /* Test case descriptions: test name format*/ 319 | dt 320 | { 321 | font-family: sans-serif; 322 | font-weight: bold; 323 | } 324 | 325 | /* Test case descriptions: description table body */ 326 | td.testDescription 327 | { 328 | padding-top: 10px; 329 | padding-left: 30px; 330 | padding-bottom: 10px; 331 | padding-right: 30px; 332 | background-color: #DAE7FE; 333 | } 334 | 335 | /* Source code view: function entry */ 336 | td.coverFn 337 | { 338 | text-align: left; 339 | padding-left: 10px; 340 | padding-right: 20px; 341 | color: #284FA8; 342 | background-color: #DAE7FE; 343 | font-family: monospace; 344 | } 345 | 346 | /* Source code view: function entry zero count*/ 347 | td.coverFnLo 348 | { 349 | text-align: right; 350 | padding-left: 10px; 351 | padding-right: 10px; 352 | background-color: #FF0000; 353 | font-weight: bold; 354 | font-family: sans-serif; 355 | } 356 | 357 | /* Source code view: function entry nonzero count*/ 358 | td.coverFnHi 359 | { 360 | text-align: right; 361 | padding-left: 10px; 362 | padding-right: 10px; 363 | background-color: #DAE7FE; 364 | font-weight: bold; 365 | font-family: sans-serif; 366 | } 367 | 368 | /* Source code view: source code format */ 369 | pre.source 370 | { 371 | font-family: monospace; 372 | white-space: pre; 373 | margin-top: 2px; 374 | } 375 | 376 | /* Source code view: line number format */ 377 | span.lineNum 378 | { 379 | background-color: #EFE383; 380 | } 381 | 382 | /* Source code view: format for lines which were executed */ 383 | td.lineCov, 384 | span.lineCov 385 | { 386 | background-color: #CAD7FE; 387 | } 388 | 389 | /* Source code view: format for Cov legend */ 390 | span.coverLegendCov 391 | { 392 | padding-left: 10px; 393 | padding-right: 10px; 394 | padding-bottom: 2px; 395 | background-color: #CAD7FE; 396 | } 397 | 398 | /* Source code view: format for lines which were not executed */ 399 | td.lineNoCov, 400 | span.lineNoCov 401 | { 402 | background-color: #FF6230; 403 | } 404 | 405 | /* Source code view: format for NoCov legend */ 406 | span.coverLegendNoCov 407 | { 408 | padding-left: 10px; 409 | padding-right: 10px; 410 | padding-bottom: 2px; 411 | background-color: #FF6230; 412 | } 413 | 414 | /* Source code view (function table): standard link - visited format */ 415 | td.lineNoCov > a:visited, 416 | td.lineCov > a:visited 417 | { 418 | color: black; 419 | text-decoration: underline; 420 | } 421 | 422 | /* Source code view: format for lines which were executed only in a 423 | previous version */ 424 | span.lineDiffCov 425 | { 426 | background-color: #B5F7AF; 427 | } 428 | 429 | /* Source code view: format for branches which were executed 430 | * and taken */ 431 | span.branchCov 432 | { 433 | background-color: #CAD7FE; 434 | } 435 | 436 | /* Source code view: format for branches which were executed 437 | * but not taken */ 438 | span.branchNoCov 439 | { 440 | background-color: #FF6230; 441 | } 442 | 443 | /* Source code view: format for branches which were not executed */ 444 | span.branchNoExec 445 | { 446 | background-color: #FF6230; 447 | } 448 | 449 | /* Source code view: format for the source code heading line */ 450 | pre.sourceHeading 451 | { 452 | white-space: pre; 453 | font-family: monospace; 454 | font-weight: bold; 455 | margin: 0px; 456 | } 457 | 458 | /* All views: header legend value for low rate */ 459 | td.headerValueLegL 460 | { 461 | font-family: sans-serif; 462 | text-align: center; 463 | white-space: nowrap; 464 | padding-left: 4px; 465 | padding-right: 2px; 466 | background-color: #FF0000; 467 | font-size: 80%; 468 | } 469 | 470 | /* All views: header legend value for med rate */ 471 | td.headerValueLegM 472 | { 473 | font-family: sans-serif; 474 | text-align: center; 475 | white-space: nowrap; 476 | padding-left: 2px; 477 | padding-right: 2px; 478 | background-color: #FFEA20; 479 | font-size: 80%; 480 | } 481 | 482 | /* All views: header legend value for hi rate */ 483 | td.headerValueLegH 484 | { 485 | font-family: sans-serif; 486 | text-align: center; 487 | white-space: nowrap; 488 | padding-left: 2px; 489 | padding-right: 4px; 490 | background-color: #A7FC9D; 491 | font-size: 80%; 492 | } 493 | 494 | /* All views except source code view: legend format for low coverage */ 495 | span.coverLegendCovLo 496 | { 497 | padding-left: 10px; 498 | padding-right: 10px; 499 | padding-top: 2px; 500 | background-color: #FF0000; 501 | } 502 | 503 | /* All views except source code view: legend format for med coverage */ 504 | span.coverLegendCovMed 505 | { 506 | padding-left: 10px; 507 | padding-right: 10px; 508 | padding-top: 2px; 509 | background-color: #FFEA20; 510 | } 511 | 512 | /* All views except source code view: legend format for hi coverage */ 513 | span.coverLegendCovHi 514 | { 515 | padding-left: 10px; 516 | padding-right: 10px; 517 | padding-top: 2px; 518 | background-color: #A7FC9D; 519 | } 520 | -------------------------------------------------------------------------------- /example/output/glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/output/glass.png -------------------------------------------------------------------------------- /example/output/index-sort-f.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top levelHitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 |

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
example 75 |
91.3%91.3%
76 |
91.3 %21 / 23100.0 %2 / 2
83 |
84 |
85 | 86 | 87 | 88 | 89 |
Generated by: LCOV version 1.12
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/output/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top levelHitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 |

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
example 75 |
91.3%91.3%
76 |
91.3 %21 / 23100.0 %2 / 2
83 |
84 |
85 | 86 | 87 | 88 | 89 |
Generated by: LCOV version 1.12
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/output/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - test.info 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top levelHitTotalCoverage
Test:test.infoLines:212391.3 %
Date:2017-10-28 11:14:15Functions:22100.0 %
49 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 |

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
example 75 |
91.3%91.3%
76 |
91.3 %21 / 23100.0 %2 / 2
83 |
84 |
85 | 86 | 87 | 88 | 89 |
Generated by: LCOV version 1.12
90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/output/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/output/ruby.png -------------------------------------------------------------------------------- /example/output/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/output/snow.png -------------------------------------------------------------------------------- /example/output/updown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/output/updown.png -------------------------------------------------------------------------------- /example/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanxiangyfg/gcov/cc38f8043ae4d2a9e446de51c885de7fad76a792/example/test -------------------------------------------------------------------------------- /example/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int* twoSum(int* nums, int numsSize, int target) { 5 | int loop = 0; 6 | int inloop = 0; 7 | int* result = NULL; 8 | result =(int*) malloc(2*sizeof(int)); 9 | memset(result,0,2*sizeof(int)); 10 | printf("numsSize=%d\n",numsSize); 11 | if(NULL == nums || numsSize==0) 12 | { 13 | return result; 14 | } 15 | 16 | for(loop = 0;loop < numsSize;loop++) 17 | { 18 | for(inloop = loop+1;inloop 7 | -: 2:#include 8 | -: 3:#include 9 | 1: 4:int* twoSum(int* nums, int numsSize, int target) { 10 | 1: 5: int loop = 0; 11 | 1: 6: int inloop = 0; 12 | 1: 7: int* result = NULL; 13 | 1: 8: result =(int*) malloc(2*sizeof(int)); 14 | 1: 9: memset(result,0,2*sizeof(int)); 15 | 1: 10: printf("numsSize=%d\n",numsSize); 16 | 1: 11: if(NULL == nums || numsSize==0) 17 | -: 12: { 18 | #####: 13: return result; 19 | -: 14: } 20 | -: 15: 21 | 1: 16: for(loop = 0;loop < numsSize;loop++) 22 | -: 17: { 23 | 1: 18: for(inloop = loop+1;inloop lcov是gcov的图形化的前段工具,这里我们可以将覆盖率信息图形化,生成具体的报告文档。 33 | 34 | - 转换覆盖信息 35 | `lcov -c -o test.info -d .` 36 | - `-c`:生成覆盖率信息 37 | - `-o`:生成目标文件 38 | - `-d`:目录 39 | - `.`:当前目录 40 | 41 | 42 | ![fugailv.png](./picture//fugailv.png) 43 | 会生成`.c.gcov`和`.info`文件 44 | 45 | ![info.png](./picture//info.png) 46 | 47 | - 生成html报告文档 48 | `genhtml test.info -o ./output` 49 | - `test.info`:用来生成报告的源文件 50 | - `-o`:生成结果的目录 51 | 52 | ![shengcheng.png](./picture//shengcheng.png) 53 | 之后产生`ouput`文件夹,里面包含了覆盖率报告 54 | 55 | ![baogao.png](./picture//baogao.png) 56 | 57 | ![daiam.png](./picture//daiam.png) 58 | 59 | # 简介 60 | 61 | ## gcov 62 | gcov是测试代码覆盖率的工具,在使用gcc编译的时候加上`-fprofile-arcs`和`-ftest-coverage`,之后会产生两个文件,`.gcno`和`.gcda`。 63 | - `-ftest-coverage`产生`.gcno`文件,包含了重建基本块图和相应的块的源码的行号信息。 64 | - `-fprofile-arcs`产生`.gcda`文件,包含了弧跳变次数和其他的概要信息。它需要先执行可执行文件才能生成(`./test`)。 65 | 66 | gcov(gcc coverage)是一个测试代码覆盖率工具,可以统计每一行代码的执行次数以及耗时。 67 | 68 | # 插桩原理 69 | ## 编译插桩过程 70 | 分为四个过程:预处理;编译插桩;汇编;链接 71 | 分别生成四种文件:预处理文件;汇编文件;目标文件;可执行文件 72 | ![chazhuang.png](./picture/chazhuang.png) 73 | - 预处理:预处理程序对源文件进行预处理,生成预处理文件(`.i`文件) 74 | - 编译插桩:编译插桩程序对预处理文件进行编译插桩,生成汇编文件(`.s`文件) 75 | - 汇编:汇编程序对编译文件进行汇编,生成目标文件(`.o`文件) 76 | - 链接:链接程序对目标文件进行链接,生成可执行文件(`.out`或`.elf`文件) 77 | 78 | 具体命令; 79 | - `cpp test.c -o test.i`:预处理,传入`.c`文件,生成`.i` 80 | - `gcc -S test.i`:编译插桩:传入`.i`文件,生成`.s`文件 81 | - `as -o test.0 test.s`:汇编:传入`.i`文件,生成`.o`文件 82 | - `gcc -o test test.o`:链接:传入`.o`文件,生成`test`可执行文件 83 | 84 | ## gcov原理 85 | 我们可以知道,无需插桩情况下命令是 86 | ```bash 87 | gcc test.c -o test 88 | ``` 89 | 直接由源文件生成可执行文件 90 | 需要插则是 91 | ```bash 92 | gcc -fprofile-arcs -ftest-coverage test.c -o test 93 | ``` 94 | 可以发现`-fprofile-arcs -ftest-coverage`就是让gcc完成插桩的关键 95 | `-fprofile-arcs `会产生`.gcno`文件,在gcov种,会读取该文件,重组每一个可执行程序的程序流图 96 | `-ftest-coverage`会产生`.gcda`文件,该文件包含每个指令分支的执行次数信息。 97 | 相比与未插桩,插桩时会多出一些上诉的数据文件,基本流程如图: 98 | 99 | ![gcov过程.PNG](./picture/gcov过程.PNG) 100 | 上图中的`.ba`和`.bbg`文件,后期gcc版本变成了`.gcno`文件; 101 | 当我们之后运行可执行文件(`./test`),会产生`.da`文件,后期版本变成了`.gcda`文件。 102 | 103 | 下面将在`.s`汇编文件种比较插桩前后的汇编代码。 104 | 对于源文件`test.c` 105 | ```c 106 | 00001: #include 107 | 00002: 108 | 00003: int main ( void ) 109 | 00004: { 110 | 00005: int i , total ; 111 | 00006: 112 | 00007: total = 0 ; 113 | 00008: 114 | 00009: for ( i = 0 ; i < 10 ; i ++ ) 115 | 00010: total += i ; 116 | 00011: 117 | 00012: if ( total != 45 ) 118 | 00013: printf ( "Failure\n" ); 119 | 00014: else 120 | 00015: printf ( "Success\n" ); 121 | 00016: return 0 ; 122 | 00017: } 123 | 00018: 124 | ``` 125 | 126 | ### gcda文件分析 127 | 128 | gcda中存放了每条指令分支的执行次数,为二进制文件。下面查看其文件内容: 129 | 130 | ```c 131 | # od -t x4 -w16 test.gcda 132 | 0000000 67636461 34303170 c5ecae39 01000000 //'gcda', '401p', timestamp, tag=0x01000000 133 | 0000020 00000002 00000003 eb65a768 01a10000 //length=2, ident=3, checksum, 0x01a10000 134 | 0000040 0000000a 0000000a 00000000 00000000 //length=0xa=10, counter content: 0xa, 0, 1, 0, 1 135 | 0000060 00000000 00000001 00000000 00000000 //8 Bytes for each counter 136 | 0000100 00000000 00000001 00000000 a1000000 // , tag=0xa1000000 137 | 0000120 00000009 00000000 00000005 00000001 //length=9, checksum=0, counts=5, runs=1 138 | 0000140 0000000c 00000000 0000000a 00000000 //sum_all=0xc=12(8 Bytes), run_max=0xa=10(8 Bytes) 139 | 0000160 0000000a 00000000 a3000000 00000009 //sum_max=0xa=10(8 Bytes), tag=a3000000, length=9 140 | 0000200 51924f98 00000005 00000001 0000000c //same as above 141 | 0000220 00000000 0000000a 00000000 0000000a 142 | 0000240 00000000 00000000 143 | 0000250 144 | ``` 145 | 146 | gcov-dump输出结果如下: 147 | 148 | ```c 149 | # /home/zubo/gcc/2011-04-11.gcov-dump/gcov-dump test.gcda 150 | test.gcda:data:magic `gcda':version `401p' 151 | test.gcda:stamp 3320622649 //对应下面的0xc5ecae39 152 | test.gcda: 01000000: 2:FUNCTION ident=3, checksum=0xeb65a768 //tag, length=2, ident, checksum 153 | test.gcda: 01a10000: 10:COUNTERS arcs 5 counts //tag, length=10, 5个COUNTERS 154 | test.gcda: 0 10 0 1 0 1 //此处便是5个counter的值,共40字节 155 | test.gcda: a1000000: 9:OBJECT_SUMMARY checksum=0x00000000 156 | test.gcda: counts=5, runs=1, sum_all=12, run_max=10, sum_max=10 157 | test.gcda: a3000000: 9:PROGRAM_SUMMARY checksum=0x51924f98 158 | test.gcda: 159 | ``` 160 | 161 | ### gcno文件分析 162 | 163 | ```c 164 | # od -t x4 -w16 test.gcno 165 | 0000000 67636e6f 34303170 c5ecae39 01000000 //magic="gcno", version="401p", stamp, tag=0x01000000 166 | 0000020 00000009 00000003 eb65a768 00000002 //length, ident, checksum, length=2 167 | 0000040 6e69616d 00000000 00000002 74736574 //functionname="niam"(8Bytes), length=2, filename= 168 | 0000060 0000632e 00000004 01410000 00000009 //"test.c"(8Bytes), lineno=4, tag=0x01410000, length=9 169 | 0000100 00000000 00000000 00000000 00000000 //9 blocks' content, all is 0 170 | * //* represents all 0 repeated (reference 'man od') 171 | 0000140 00000000 01430000 00000003 00000000 //tag=0x01430000, length=3, src=0, dest=1, flags=5 172 | 0000160 00000001 00000005 01430000 00000003 //tag=0x01430000, length=3, src=1, dest=3, flags=5 173 | 0000200 00000001 00000003 00000005 01430000 //tag=0x01430000, length=3, src=2, dest=3, flags=5 174 | 0000220 00000003 00000002 00000003 00000005 175 | 0000240 01430000 00000005 00000003 00000002 //tag=0x01430000, length=5, src=3, dest1=2, flags1=0 176 | 0000260 00000000 00000004 00000005 01430000 // dest2=4, flags2=5 177 | 0000300 00000005 00000004 00000005 00000004 //tag=0x01430000, length=5, src=4, dest1=5, flags1=4 178 | 0000320 00000006 00000000 01430000 00000005 // dest2=6, flags2=0 179 | 0000340 00000005 00000007 00000004 00000008 //tag=0x01430000, length=5, src=5, dest1=7, flags1=4 180 | 0000360 00000003 01430000 00000005 00000006 // dest2=8, flags2=3 181 | 0000400 00000007 00000004 00000008 00000003 //tag=0x01430000, length=5, src=6, dest1=7, flags1=4 182 | // dest2=8, flags2=3 183 | 0000420 01430000 00000003 00000007 00000008 //tag=0x01430000, length=3, src=7, dest=8, flags=1 184 | 0000440 00000001 01450000 0000000a 00000001 //tag=0x01450000, length=10, blockno=1 185 | 0000460 00000000 00000002 74736574 0000632e //lineno=0, length=2, filename="test.c" 186 | 0000500 00000004 00000007 00000009 00000000 //lineno=4, lineno=7, lineno=9, lineno=0 187 | 0000520 00000000 01450000 00000009 00000002 //lineno=0, tag=0x01450000, length=9, blockno=2 188 | 0000540 00000000 00000002 74736574 0000632e //lineno=0, length=2, filename="test.c" 189 | 0000560 0000000a 00000009 00000000 00000000 //lineno=10, lineno=9, lineno=0, lineno=0 190 | 0000600 01450000 00000008 00000004 00000000 //tag=0x01450000, length=8, blockno=4, lineno=0 191 | 0000620 00000002 74736574 0000632e 0000000c //length=2, filename="test.c", lineno=12 192 | 0000640 00000000 00000000 01450000 00000008 //lineno=0, lineno=0, tag=0x01450000, length=8 193 | 0000660 00000005 00000000 00000002 74736574 //blockno=5, lineno=0, length=2, filename="test.c" 194 | 0000700 0000632e 0000000d 00000000 00000000 // lineno=13, lineno=0, lineno=0 195 | 0000720 01450000 00000008 00000006 00000000 //tag=0x01450000, length=8, blockno=6, lineno=0 196 | 0000740 00000002 74736574 0000632e 0000000f //length=2, filename="test.c", lineno=15 197 | 0000760 00000000 00000000 01450000 00000008 //lineno=0, lineno=0, tag=0x01450000, length=8 198 | 0001000 00000007 00000000 00000002 74736574 //blockno=7, lineno=0, length=2, filename="test.c" 199 | 0001020 0000632e 00000010 00000000 00000000 // , lineno=16, lineno=0, lineno=0 200 | 0001040 201 | ``` 202 | 203 | dump后: 204 | 205 | ```assembly 206 | # /home/zubo/gcc/2011-04-11.gcov-dump/gcov-dump test.gcno 207 | 208 | //magic:version,和stamp,对应下面的0xc5ecae39,与test.gcda一一对应 209 | test.gcno:note:magic `gcno':version `401p' 210 | test.gcno:stamp 3320622649 211 | test.gcno: 01000000: 9:FUNCTION ident=3, checksum=0xeb65a768, `main' test.c:4 212 | //: tag=0x01000000,length=9,tagname=FUNCTION,function的信息(ident,checksum,函数名,文件名,行号) 213 | 214 | //以下为9个BLOCKS记录 215 | //说明具有9个block 216 | test.gcno: 01410000: 9:BLOCKS 9 blocks 217 | test.gcno: 0 0000 0000 0000 0000 0000 0000 0000 0000 //0为序号,每8个blocks为一行 218 | test.gcno: 8 0000 //8为序号,一共9个 219 | 220 | //以下为8个ARCS记录,小写的arcs和block为提示信息,大写的ARCS为tag名字 221 | test.gcno: 01430000: 3:ARCS 1 arcs //tag=0x01430000:length=3:tagname=ARCS n_arcs=1,格式下同 222 | test.gcno: block 0: 1:0005 //blockno=0:dst=1:flags=0005 223 | test.gcno: 01430000: 3:ARCS 1 arcs 224 | test.gcno: block 1: 3:0005 225 | test.gcno: 01430000: 3:ARCS 1 arcs 226 | test.gcno: block 2: 3:0005 227 | test.gcno: 01430000: 5:ARCS 2 arcs //2个arcs 228 | test.gcno: block 3: 2:0000 4:0005 //有两个目的地,格式:blockno=3: dst1=2:flags1 dst2=4:flags2 229 | test.gcno: 01430000: 5:ARCS 2 arcs 230 | test.gcno: block 4: 5:0004 6:0000 231 | test.gcno: 01430000: 5:ARCS 2 arcs 232 | test.gcno: block 5: 7:0004 8:0003 233 | test.gcno: 01430000: 5:ARCS 2 arcs 234 | test.gcno: block 6: 7:0004 8:0003 235 | test.gcno: 01430000: 3:ARCS 1 arcs 236 | test.gcno: block 7: 8:0001 237 | 238 | //说明每个块的具体行 239 | //以下为6个LINES记录,小写的block为提示信息,大写的LINES为tag名字 //说明line分为6部分,分别位于block1,2,4,5,6,7 240 | test.gcno: 01450000: 10:LINES //tag=0x01450000:length=10:tagname=LINES 241 | test.gcno: block 1:`test.c':4, 7, 9 //blockno=1:'文件名':lineno1=4,lineno2=7,lineno3=9 242 | test.gcno: 01450000: 9:LINES 243 | test.gcno: block 2:`test.c':10, 9 244 | test.gcno: 01450000: 8:LINES 245 | test.gcno: block 4:`test.c':12 246 | test.gcno: 01450000: 8:LINES 247 | test.gcno: block 5:`test.c':13 248 | test.gcno: 01450000: 8:LINES 249 | test.gcno: block 6:`test.c':15 250 | test.gcno: 01450000: 8:LINES 251 | test.gcno: block 7:`test.c':16 252 | ``` 253 | 254 | ### 基本块流图 255 | 256 | 这里我们可以发现程序分为了9个block,各个block的arcs关系也列出来了,那么我们可以输出它的程序块流图。 257 | 258 | ![block](.\picture\block.png) 259 | 260 | 其中`block0`和`block8`并没有具体的行数,那么我们简化一下。 261 | 262 | ![blockarcs](./picture/blockarcs.png) 263 | 264 | 这边关于for循环,我们可以发现BB1和BB2都有line9,for循环首先是执行初始化语句,之后执行判断语句,返回true则执行循环体语句,之后执行循环迭代语句,再次进入判断语句。故BB1进行`i=0`初始化,BB2进行`i<10`判断,BB3进行`i++`循环迭代语句和`total+=10`循环体语句。 265 | 266 | ## 插桩对比 267 | 268 | ### 未插桩汇编代码 269 | 270 | ```bash 271 | gcc -s test.i 272 | ``` 273 | 274 | ```assembly 275 | .file "test.c" 276 | .section .rodata 277 | .LC0: 278 | .string "Failure" 279 | .LC1: 280 | .string "Success" 281 | .text 282 | .globl main 283 | .type main, @function 284 | main: 285 | leal 4(%esp), %ecx #这几句就是保护现场 286 | andl $-16, %esp 287 | pushl -4(%ecx) 288 | pushl %ebp 289 | movl %esp, %ebp 290 | pushl %ecx 291 | subl $20, %esp 292 | 293 | movl $0, -8(%ebp) #初始化total=0,total的值在-8(%ebp)中 294 | movl $0, -12(%ebp) #初始化循环变量i=0,i的值在-12(%ebp)中 295 | jmp .L2 296 | .L3: 297 | movl -12(%ebp), %eax #将i的值移到%eax中,即%eax=i 298 | addl %eax, -8(%ebp) #将%eax的值加到-8(%ebp),total=total+i 299 | addl $1, -12(%ebp) #循环变量加1,即i++ 300 | .L2: 301 | cmpl $9, -12(%ebp) #比较循环变量i与9的大小 302 | jle .L3 #如果i<=9,跳到.L3,继续累加 303 | cmpl $45, -8(%ebp) #否则,比较total的值与45的大小 304 | je .L5 #若total=45,跳到.L5 305 | movl $.LC0, (%esp) #否total的值不为45,则将$.LC0放入%esp 306 | call puts #输出Failure 307 | jmp .L7 #跳到.L7 308 | .L5: 309 | movl $.LC1, (%esp) #将$.LC1放入%esp 310 | call puts #输出Success 311 | .L7: 312 | movl $0, %eax #返回值0放入%eax 313 | 314 | addl $20, %esp #这几句恢复现场 315 | popl %ecx 316 | popl %ebp 317 | leal -4(%ecx), %esp 318 | ret 319 | 320 | .size main, .-main 321 | .ident "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)" 322 | .section .note.GNU-stack,"",@progbits 323 | ``` 324 | 325 | ### 插桩后汇编代码 326 | 327 | ```bash 328 | gcc-fprofile-arcs -ftest-coverage-S test.i 329 | ``` 330 | 331 | ```assembly 332 | .file "test.c" 333 | .section .rodata 334 | .LC0: 335 | .string "Failure" 336 | .LC1: 337 | .string "Success" 338 | .text 339 | .globl main 340 | .type main, @function 341 | main: 342 | leal 4(%esp), %ecx #这几句就是保护现场 343 | andl $-16, %esp 344 | pushl -4(%ecx) 345 | pushl %ebp 346 | movl %esp, %ebp 347 | pushl %ecx 348 | subl $20, %esp 349 | 350 | movl $0, -8(%ebp) #初始化total=0,total的值在-8(%ebp)中 351 | movl $0, -12(%ebp) #初始化循环变量i=0,i的值在-12(%ebp)中 352 | jmp .L2 353 | 354 | .L3: 355 | #第一次插桩:以下这几句就是插入的桩代码 356 | movl .LPBX1, %eax #将.LPBX1移到%eax,即%eax=.LPBX1 357 | movl .LPBX1+4, %edx #edx=.LPBX1+4 358 | addl $1, %eax #eax=%eax+1 359 | adcl $0, %edx #edx=%edx+0 360 | movl %eax, .LPBX1 #将%eax移回.LPBX1 361 | movl %edx, .LPBX1+4 #将%edx移回.LPBX1+4 362 | #第一次插桩结束 363 | 364 | #这是BB2的执行代码,故第一次插桩在BB3到BB2中 365 | movl -12(%ebp), %eax #将i的值移到%eax中,即%eax=i 366 | addl %eax, -8(%ebp) #将%eax的值加到-8(%ebp),total=total+i 367 | addl $1, -12(%ebp) #循环变量加1,即i++ 368 | 369 | .L2: 370 | cmpl $9, -12(%ebp) #比较循环变量i与9的大小 371 | jle .L3 #如果i<=9,跳到.L3,继续累加 372 | cmpl $45, -8(%ebp) #否则,比较total的值与45的大小 373 | je .L5 #若total=45,跳到.L5 374 | 375 | #第二次插桩:以下也为桩代码 376 | movl .LPBX1+8, %eax #eax=.LPBX1+8 377 | movl .LPBX1+12, %edx #edx=.LPBX1+12 378 | addl $1, %eax #eax=%eax+1 379 | adcl $0, %edx #edx=%edx+0 380 | movl %eax, .LPBX1+8 #将%eax移回.LPBX1+8 381 | movl %edx, .LPBX1+12 #将%eax移回.LPBX1+12 382 | #第二次结束 383 | #这是BB5的代码,故第二次插桩在BB4到BB5中 384 | movl $.LC0, (%esp) #否total的值不为45,则将$.LC0放入%esp 385 | call puts #输出Failure 386 | 387 | #第三部分插桩:以下也为桩代码,功能同上,不再解释 388 | movl .LPBX1+24, %eax 389 | movl .LPBX1+28, %edx 390 | addl $1, %eax 391 | adcl $0, %edx 392 | movl %eax, .LPBX1+24 393 | movl %edx, .LPBX1+28 394 | #第三部分结束 395 | 396 | #这部分是BB7的代码,故第三次插桩在BB5到BB7中间 397 | jmp .L7 #跳到.L7 398 | 399 | .L5: 400 | #第四:以下也为桩代码,功能同上,不再解释 401 | movl .LPBX1+16, %eax 402 | movl .LPBX1+20, %edx 403 | addl $1, %eax 404 | adcl $0, %edx 405 | movl %eax, .LPBX1+16 406 | movl %edx, .LPBX1+20 407 | #第四结束 408 | 409 | #这是BB6代码,故第四次插桩在BB4到BB6中 410 | movl $.LC1, (%esp) #将$.LC1放入%esp 411 | call puts #输出Success 412 | #第五 413 | #以下也为桩代码,功能同上,不再解释 414 | movl .LPBX1+32, %eax 415 | movl .LPBX1+36, %edx 416 | addl $1, %eax 417 | adcl $0, %edx 418 | movl %eax, .LPBX1+32 419 | movl %edx, .LPBX1+36 420 | # 第五结束 421 | #此部分后为BB7执行代码,故第五次插桩在BB6到BB7之间 422 | .L7: 423 | movl $0, %eax #返回值0放入%eax 424 | 425 | addl $20, %esp #这几句回复现场 426 | popl %ecx 427 | popl %ebp 428 | leal -4(%ecx), %esp 429 | ret 430 | 431 | .size main, .-main 432 | 433 | #以下部分均是加入coverage选项后编译器加入的桩代码 434 | 435 | #定义LPBX1,存放前五段桩代码 436 | .local .LPBX1 437 | .comm .LPBX1,40,32 #申请命名空间,名称为.LPBX1 438 | .section .rodata #只读section 439 | .align 4 #.align的作用在于对指令或者数据的存放地址进行对齐 440 | #LPBX1定义完成 441 | 442 | #定义文件名 443 | .LC2: #文件名常量,只读 444 | .string "/home/zubo/gcc/test/test.gcda" 445 | 446 | .data #data数据段 447 | .align 4 448 | #文件定义完成 449 | 450 | #定义functions结构 451 | .LC3: 452 | .long 3 #ident=3 453 | .long -345659544 #即checksum=0xeb65a768 454 | .long 5 #counters 455 | #functions定义完成 456 | 457 | #定义LPBX0结构 458 | .align 32 459 | .type .LPBX0, @object #.LPBX0是一个对象 460 | .size .LPBX0, 52 #.LPBX0大小为52字节 461 | .LPBX0: #结构的起始地址,即结构名,该结构即为gcov_info结构 462 | .long 875573616 #即version=0x34303170,即版本为4.1p 463 | .long 0 #即next指针,为0 464 | .long -979544300 #即stamp=0xc59d5714 465 | .long .LC2 #filename,值为.LC2的常量 466 | .long 1 #n_functions=1 467 | .long .LC3 #functions指针,指向.LC3 468 | .long 1 #ctr_mask=1 469 | .long 5 #以下3个字段构成gcov_ctr_info结构,该字段num=5,即counter的个数 470 | .long .LPBX1 #values指针,指向.LPBX1,即5个counter的内容在.LPBX1结构中 471 | .long __gcov_merge_add #merge指针,指向__gcov_merge_add函数 472 | .zero 12 #应该是12个0 473 | #定义完成 474 | 475 | #第六段插桩代码 476 | .text #text代码段 477 | .type _GLOBAL__I_0_main, @function #类型是function 478 | _GLOBAL__I_0_main: #以下是函数体 479 | pushl %ebp 480 | movl %esp, %ebp 481 | subl $8, %esp 482 | movl $.LPBX0, (%esp) #将$.LPBX0,即.LPBX0的地址,存入%esp所指单元 483 | #实际上是为下面调用__gcov_init准备参数,即gcov_info结构指针 484 | call __gcov_init #调用__gcov_init 485 | leave 486 | ret 487 | #插桩结束,将LPBX0做参数,调用__gcov_init函数 488 | 489 | .size _GLOBAL__I_0_main, .-_GLOBAL__I_0_main 490 | .section .ctors,"aw",@progbits #该函数位于ctors段 491 | .align 4 492 | .long _GLOBAL__I_0_main 493 | .align 4 494 | .long _GLOBAL__I_0_main 495 | 496 | .ident "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)" 497 | .section .note.GNU-stack,"",@progbits 498 | ``` 499 | 500 | ### 带桩点基本块流图 501 | 502 | 可以发现具体出现了5处插桩代码(其实六处,最后一处先不谈),根据注释的解释,可以发现每个插桩点的位置。 503 | 504 | | 插桩点 | 出发BB | 目的BB | 执行次数 | 插入位置 | 505 | | ----- | ---- | ---- | ---- | ------ | 506 | | stub1 | BB3 | BB2 | 10 | 10行代码前 | 507 | | stub2 | BB4 | BB5 | 0 | 13行代码前 | 508 | | stub3 | BB5 | BB7 | 0 | 13行代码后 | 509 | | stub4 | BB4 | BB6 | 1 | 15行代码前 | 510 | | stub5 | BB6 | BB7 | 1 | 15行代码后 | 511 | 512 | 那么我们可以更进步画出基本块流图。 513 | 514 | ![](./picture/带桩点基本块流图.png) 515 | 516 | ### 桩点分析 517 | 518 | 之前的五处插桩我们发现都很类似,以第一处为例。 519 | 520 | ```assembly 521 | movl .LPBX1, %eax #将.LPBX1移到%eax,即%eax=.LPBX1 522 | movl .LPBX1+4, %edx #edx=.LPBX1+4 523 | addl $1, %eax #eax=%eax+1 524 | adcl $0, %edx #edx=%edx+0 525 | movl %eax, .LPBX1 #将%eax移回.LPBX1 526 | movl %edx, .LPBX1+4 #将%edx移回.LPBX1+4 527 | ``` 528 | 529 | 这里拥有一个.LPBX1的数组,每次执行到这个就将其加1,充当了一个计数器的功能。每一个计数器是.LPBX1和LPBX1+4共计8字节的数组。下方定义了这个数组 530 | 531 | ```assembly 532 | #定义LPBX1,存放前五段桩代码 533 | .local .LPBX1 534 | .comm .LPBX1,40,32 #申请命名空间,名称为.LPBX1 535 | .section .rodata #只读section 536 | .align 4 #.align的作用在于对指令或者数据的存放地址进行对齐 537 | #LPBX1定义完成 538 | ``` 539 | 540 | 其属性只读,长度为40字节,共5个counter,每个counter占8字节,他们以4字节的方式对其。我们在上一节可以知道每个桩点具体的执行次数。 541 | | 插桩点 | 出发BB | 目的BB | 执行次数 | 插入位置 | 在.LPBX1位置 | 542 | | ----- | ---- | ---- | ---- | ------ | ---------- | 543 | | stub1 | BB3 | BB2 | 10 | 10行代码前 | .LPBX1+0处 | 544 | | stub2 | BB4 | BB5 | 0 | 13行代码前 | .LPBX1+8处 | 545 | | stub3 | BB5 | BB7 | 0 | 13行代码后 | .LPBX1+24处 | 546 | | stub4 | BB4 | BB6 | 1 | 15行代码前 | .LPBX1+16处 | 547 | | stub5 | BB6 | BB7 | 1 | 15行代码后 | .LPBX1+32处 | 548 | 549 | 那么我们可以知道.LPBX1数组的具体信息。 550 | 551 | | +0 | +4 | +8 | +12 | +16 | +20 | +24 | +28 | +32 | +36 | 552 | | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 553 | | 10 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 554 | 555 | 然后这些值被作为counter写入test.gcda文件,上文的gcda文件可以发现: 556 | 557 | ```assembly 558 | test.gcda: 01a10000: 10:COUNTERS arcs 5 counts //tag, length=10, 5个COUNTERS 559 | test.gcda: 0 10 0 1 0 1 //此处便是5个counter的值,共40字节 560 | ``` 561 | 562 | 下面看关于最后一段插桩代码分析 563 | 564 | ```assembly 565 | #第六段插桩代码 566 | .text #text代码段 567 | .type _GLOBAL__I_0_main, @function #类型是function 568 | _GLOBAL__I_0_main: #以下是函数体 569 | pushl %ebp 570 | movl %esp, %ebp 571 | subl $8, %esp 572 | movl $.LPBX0, (%esp) #将$.LPBX0,即.LPBX0的地址,存入%esp所指单元 573 | #实际上是为下面调用__gcov_init准备参数,即gcov_info结构指针 574 | call __gcov_init #调用__gcov_init 575 | leave 576 | ret 577 | #插桩结束,将LPBX0做参数,调用__gcov_init函数 578 | ``` 579 | 580 | -------------------------------------------------------------------------------- /reference.md: -------------------------------------------------------------------------------- 1 | # 参考 2 | 3 | 10.27 4 | 5 | [CMake编译项目集成Gcov/Lcov代码覆盖率测试](http://www.itkeyword.com/doc/456802448177261186/C-CMake-lcovC++) 6 | 7 | [关于C++ code coverage tool 的研究,UML.org.cn单篇](http://www.uml.org.cn/Test/201208311.asp) 8 | 9 | 10.28 10 | 11 | [关于C++ code coverage tool 的研究,CSDN综合](http://blog.csdn.net/windone0109/article/details/15814653) 12 | 13 | [测试示例](http://blog.csdn.net/hyb612/article/details/76790613) 14 | 15 | 10.29 16 | 17 | [覆盖率测试工具gcov的前端工具_LCOV_简介](http://blog.csdn.net/21cnbao/article/details/40268617) 18 | 19 | [Linux平台代码覆盖率测试工具GCOV简介](http://www.linuxidc.com/Linux/2011-05/36545.htm) 20 | 21 | [Linux平台代码覆盖率测试-GCC插桩基本概念和原理分析](http://www.linuxidc.com/Linux/2011-05/36572.htm) 22 | 23 | [csdn专栏](http://blog.csdn.net/livelylittlefish?viewmode=contents) 24 | 25 | 10.30 26 | [Linux平台代码覆盖率测试-基本块图、插桩位置及桩代码执行分析](http://www.linuxidc.com/Linux/2011-05/36573.htm) 27 | [Linux平台代码覆盖率测试-GCC插桩前后汇编代码对比分析](http://www.linuxidc.com/Linux/2011-05/36541.htm) --------------------------------------------------------------------------------