├── .gitignore ├── LICENSE ├── README.md └── port ├── gcc ├── gcov-counter.def ├── gcov-io.c └── gcov-io.h ├── libgcc ├── libgcov-driver-system.c ├── libgcov-driver.c └── libgcov.h └── src ├── libgcov-embedded.c ├── libgcov-embedded.h └── libgcov-port.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Reetesh Ranjan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libgcov-embedded 2 | Working port of `gcov_exit` to use in embedded systems for capturing code coverage. 3 | ## Compatibility 4 | - [gnu arm toolchain v5-2016-q3-update](https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q3-update) - **NOTE**: things should work in all versions where the gcov data structures are compatible with those in this version. This means both older and newer versions. 5 | 6 | ## How to Generate .gcda Files 7 | ### Working Sample Project 8 | It's very easy to get started if you follow [this sample](https://github.com/reeteshranjan/libgcov-embedded-example). 9 | 10 | It is a Blinky project for stm32f4-discovery board made using [gnu arm eclipse](http://gnuarmeclipse.github.io/) with [eclipse cdt neon.1](http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/neon1a). **NOTE**: if you don't have an stm32f4-discovery board, you can use QEMU emulator for this board with gnu arm eclipse. 11 | 12 | Also, this repository includes sample coverage HTML reports generated using the `.gcda` files generated while running the sample project. 13 | ### From Scratch 14 | #### Include this software 15 | - Copy the `port` directory or all its subdirectories to your project 16 | - Ensure that these paths are included for finding headers - `port/gcc`, `port/libgcc`, `port/src` 17 | - Ensure that all .c files in `port/gcc`, `port/libgcc` and `port/src` are included in your build 18 | 19 | #### Get the compilation working 20 | - Add this preprocessor directive to your makefiles - `ENABLE_LIBGCOV_PORT=1` 21 | - Add `--coverage` compiler option to your c and/or c++ compiler flags 22 | - Add `--coverage` to your linker flags 23 | - Build with your gnu arm gcc compiler and linker and verify that `.gcno` files are created for each source file in your project. **NOTE**: it would be much smoother if you create a separate directory to store your object and coverage files like done by Eclipse projects. 24 | 25 | #### Hook it in 26 | In your main.c or main.cpp add the following. 27 | ``` 28 | #ifdef ENABLE_LIBGCOV_PORT 29 | #include "libgcov-embedded.h" 30 | #endif 31 | ``` 32 | In the `main` function, make this as the beginning: 33 | ``` 34 | #ifdef ENABLE_LIBGCOV_PORT 35 | static_init(); 36 | #endif 37 | ``` 38 | 39 | If you have your own version of `_exit`, comment it out. 40 | 41 | #### Manual .gcda files creation 42 | - Set up a breakpoint at `gcov-io.c:250`. The line has this content `free(gcov_var.gcda_buf);` 43 | - Set a watch expression for this variable `__gcov_var__ported` 44 | - Start your debugging session and do the following each time the above breakpoint hits. It would hit once per source file in your project: 45 | - `__gcov_var__ported.filename` contains the full path of the `.gcda` file to create 46 | - `__gcov_var__ported.gcda_buf` contains the start address of coverage information for corresponding source file 47 | - `__gcov_var__ported.gcda_buf_pos` contains the end address of coverage information for corresponding source file 48 | - On gdb prompt, run `dump binary memory ` e.g. `dump binary memory my-proj/Debug/src/main.gcda 0x20006450 0x20006880`. This would create the `.gcda` file. 49 | 50 | ## Generate HTML visualization 51 | ### For Mac/Linux 52 | - On Mac, install `lcov` using mac ports. On Linux, it should be there or find your Linux flavor specific package. 53 | - Go to your build directory where your object files, `.gcno` files and `.gcda` files are there. 54 | - Run `lcov --capture --output-file main.info --directory . --gcov-tool /usr/local/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-gcov`. **NOTE**: replace the gcov path with your actual system path in case it is installed in a different location. 55 | - Run `genhtml -o html main.info`. It creates HTML visualization inside `html` directory. 56 | 57 | The `index.html` file can be opened in a browser to see graphical visualization per source file. 58 | ## Limitations & Caveats 59 | - If the in-memory coverage information is greater than 8K, it would not be generated. **Fix**: Increase the value of the macro `GCOV_GCDA_BUF_SZ` in `port/gcc/gcov-io.c` to suit your application's needs. For the testing so far, this limit has been more than sufficient. 60 | - The port does not support merging of existing `.gcda` data with a new run's collected coverage information. This is difficult for obvious reason that an existing `.gcda` file on the host system cannot be read by the embedded system. **Fix**: None. So only if your application can benefit with a single run's coverage information, this tool is useful. 61 | 62 | ## Why this repository? 63 | ### Tutorials don't work 64 | Getting code coverage done for stm32f4-discovery using gnu arm toolchain version 5-2016-q3-update (used during October/November 2016) and existing guides like [this](https://mcuoneclipse.com/2014/12/26/code-coverage-for-embedded-target-with-eclipse-gcc-and-gcov/) do not work. 65 | ### What's the issue? 66 | When one calls `__gcov_flush` to run the coverage info generation process, it just hangs forever and we can't get to generating `.gcda` files. 67 | ### How is the issue taken care of? 68 | This port was created and used in a sample project to see what caused the above hang. It was traced to an undocumented bug (causing 3 such points where code would hang indefinitely) in gcc's gcov portions. The only way to get past this issue was to have our own complete source of `__gcov_flush` (or `gcov_exit`, which I went with) with these bugs fixed, which is what exists in this repository. 69 | -------------------------------------------------------------------------------- /port/gcc/gcov-counter.def: -------------------------------------------------------------------------------- 1 | /* Definitions for the gcov counters in the GNU compiler. 2 | Copyright (C) 2001-2015 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 | /* Before including this file, define a macro: 21 | 22 | DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) 23 | 24 | This macro will be expanded to all supported gcov counters, their 25 | names, or the type of handler functions. FN_TYPE will be 26 | expanded to a handler function, like in gcov_merge, it is 27 | expanded to __gcov_merge ## FN_TYPE. */ 28 | 29 | /* Arc transitions. */ 30 | DEF_GCOV_COUNTER(GCOV_COUNTER_ARCS, "arcs", _add) 31 | 32 | /* Histogram of value inside an interval. */ 33 | DEF_GCOV_COUNTER(GCOV_COUNTER_V_INTERVAL, "interval", _add) 34 | 35 | /* Histogram of exact power2 logarithm of a value. */ 36 | DEF_GCOV_COUNTER(GCOV_COUNTER_V_POW2, "pow2", _add) 37 | 38 | /* The most common value of expression. */ 39 | DEF_GCOV_COUNTER(GCOV_COUNTER_V_SINGLE, "single", _single) 40 | 41 | /* The most common difference between consecutive values of expression. */ 42 | DEF_GCOV_COUNTER(GCOV_COUNTER_V_DELTA, "delta", _delta) 43 | 44 | /* The most common indirect address. */ 45 | DEF_GCOV_COUNTER(GCOV_COUNTER_V_INDIR, "indirect_call", _single) 46 | 47 | /* Compute average value passed to the counter. */ 48 | DEF_GCOV_COUNTER(GCOV_COUNTER_AVERAGE, "average", _add) 49 | 50 | /* IOR of the all values passed to counter. */ 51 | DEF_GCOV_COUNTER(GCOV_COUNTER_IOR, "ior", _ior) 52 | 53 | /* Time profile collecting first run of a function */ 54 | DEF_GCOV_COUNTER(GCOV_TIME_PROFILER, "time_profiler", _time_profile) 55 | 56 | /* Top N value tracking for indirect calls. */ 57 | DEF_GCOV_COUNTER(GCOV_COUNTER_ICALL_TOPNV, "indirect_call_topn", _icall_topn) 58 | -------------------------------------------------------------------------------- /port/gcc/gcov-io.c: -------------------------------------------------------------------------------- 1 | /* File format for coverage information 2 | Copyright (C) 1996-2015 Free Software Foundation, Inc. 3 | Contributed by Bob Manson . 4 | Completely remangled 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 | Under Section 7 of GPL version 3, you are granted additional 19 | permissions described in the GCC Runtime Library Exception, version 20 | 3.1, as published by the Free Software Foundation. 21 | 22 | You should have received a copy of the GNU General Public License and 23 | a copy of the GCC Runtime Library Exception along with this program; 24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 25 | . */ 26 | 27 | #ifdef ENABLE_LIBGCOV_PORT 28 | 29 | /* Since this file is no longer included by other C files, we need definitions 30 | * of data structures, macros etc. from the following header files 31 | */ 32 | #include 33 | #include 34 | #include 35 | #include "libgcov-port.h" 36 | #include "libgcov.h" 37 | 38 | #if !IN_GCOV 39 | static void gcov_write_block (unsigned); 40 | static gcov_unsigned_t *gcov_write_words (unsigned); 41 | #endif 42 | 43 | /* @STRIPPED lines 34-37 */ 44 | 45 | /* Optimum number of gcov_unsigned_t's read from or written to disk. */ 46 | #define GCOV_BLOCK_SIZE (1 << 8) 47 | 48 | /* The original definition of this macro is (1 << 10) which results in a 49 | * very large buffer sitting inside gcov_var struct below. In typical usage 50 | * of libgcov/gcov, the purpose of this buffer is to be an in-memory buffer 51 | * of GCDA data before it is full and needs to be flushed to the actual GCDA 52 | * file. 53 | * 54 | * The gcov_var struct and the buffer with static memory using the above macro 55 | * for its size value are used across various functions in this file, which we 56 | * left as is for now to avoid buggy/unstable changes in this iteration of the 57 | * porting effort. In our port, there is no GCDA file to auto flush the in 58 | * memory buffer; however, we have left the in-memory buffer as is. Only the 59 | * point where the in-memory buffer is flushed into the GCDA file is where 60 | * we have made changes to replace the file-based mechanism with our own, which 61 | * is basically another large buffer that can be read by the GDB command 'dump 62 | * binary memory' to manually create the GCDA file on host system. 63 | * 64 | * The idea of changing from 1 << 10 to 1 << 8 is to minimize the buffer size 65 | * for embedded systems so it does not require too much memory, as our port is 66 | * going ahead with keeping this in-memory buffer mechanism. 67 | */ 68 | 69 | 70 | struct gcov_var 71 | { 72 | #ifndef ENABLE_LIBGCOV_PORT 73 | FILE *file; 74 | #else 75 | /* 76 | * The gcov_var struct is kept mostly as is, except the porting change of not 77 | * using a FILE (can't use possibly without POSIX semihosting and more importantly 78 | * we don't intend to use a FILE here for GCDA file, as we are not going to have 79 | * one GCDA file on the embedded system; but only create a GCDA file manually using 80 | * GDB 'dump binary memory' command on the host system 81 | */ 82 | #define GCOV_GCDA_BUF_SZ (1 << 13) /* 8192 bytes for GCDA files */ 83 | 84 | unsigned char * gcda_buf; /* Holds GCDA data in memory */ 85 | unsigned char * gcda_buf_pos; /* Position in above buffer to write to */ 86 | const char * filename; /* Host system GCDA file name */ 87 | #endif 88 | gcov_position_t start; /* Position of first byte of block */ 89 | unsigned offset; /* Read/write position within the block. */ 90 | unsigned length; /* Read limit in the block. */ 91 | unsigned overread; /* Number of words overread. */ 92 | int error; /* < 0 overflow, > 0 disk error. */ 93 | int mode; /* < 0 writing, > 0 reading */ 94 | #if IN_LIBGCOV 95 | /* Holds one block plus 4 bytes, thus all coverage reads & writes 96 | fit within this buffer and we always can transfer GCOV_BLOCK_SIZE 97 | to and from the disk. libgcov never backtracks and only writes 4 98 | or 8 byte objects. */ 99 | gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1]; 100 | #else 101 | int endian; /* Swap endianness. */ 102 | /* Holds a variable length block, as the compiler can write 103 | strings and needs to backtrack. */ 104 | size_t alloc; 105 | gcov_unsigned_t *buffer; 106 | #endif 107 | } gcov_var; 108 | 109 | /* Open a gcov file. NAME is the name of the file to open and MODE 110 | indicates whether a new file should be created, or an existing file 111 | opened. If MODE is >= 0 an existing file will be opened, if 112 | possible, and if MODE is <= 0, a new file will be created. Use 113 | MODE=0 to attempt to reopen an existing file and then fall back on 114 | creating a new one. If MODE < 0, the file will be opened in 115 | read-only mode. Otherwise it will be opened for modification. 116 | Return zero on failure, >0 on opening an existing file and <0 on 117 | creating a new one. */ 118 | 119 | GCOV_LINKAGE int 120 | #if IN_LIBGCOV 121 | gcov_open (const char *name) 122 | #else 123 | gcov_open (const char *name, int mode) 124 | #endif 125 | { 126 | #if IN_LIBGCOV 127 | const int mode = 0; 128 | #endif 129 | #if GCOV_LOCKED 130 | struct flock s_flock; 131 | int fd; 132 | 133 | s_flock.l_whence = SEEK_SET; 134 | s_flock.l_start = 0; 135 | s_flock.l_len = 0; /* Until EOF. */ 136 | s_flock.l_pid = getpid (); 137 | #endif 138 | 139 | #ifndef ENABLE_LIBGCOV_PORT 140 | gcov_nonruntime_assert (!gcov_var.file); 141 | #endif 142 | gcov_var.start = 0; 143 | gcov_var.offset = gcov_var.length = 0; 144 | gcov_var.overread = -1u; 145 | gcov_var.error = 0; 146 | #if !IN_LIBGCOV 147 | gcov_var.endian = 0; 148 | #endif 149 | #if GCOV_LOCKED 150 | if (mode > 0) 151 | { 152 | /* Read-only mode - acquire a read-lock. */ 153 | s_flock.l_type = F_RDLCK; 154 | /* pass mode (ignored) for compatibility */ 155 | fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR); 156 | } 157 | else if (mode < 0) 158 | { 159 | /* Write mode - acquire a write-lock. */ 160 | s_flock.l_type = F_WRLCK; 161 | fd = open (name, O_RDWR | O_CREAT | O_TRUNC, 0666); 162 | } 163 | else /* mode == 0 */ 164 | { 165 | /* Read-Write mode - acquire a write-lock. */ 166 | s_flock.l_type = F_WRLCK; 167 | fd = open (name, O_RDWR | O_CREAT, 0666); 168 | } 169 | if (fd < 0) 170 | return 0; 171 | 172 | while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) 173 | continue; 174 | 175 | gcov_var.file = fdopen (fd, (mode > 0) ? "rb" : "r+b"); 176 | 177 | if (!gcov_var.file) 178 | { 179 | close (fd); 180 | return 0; 181 | } 182 | 183 | if (mode > 0) 184 | gcov_var.mode = 1; 185 | else if (mode == 0) 186 | { 187 | struct stat st; 188 | 189 | if (fstat (fd, &st) < 0) 190 | { 191 | fclose (gcov_var.file); 192 | gcov_var.file = 0; 193 | return 0; 194 | } 195 | if (st.st_size != 0) 196 | gcov_var.mode = 1; 197 | else 198 | gcov_var.mode = mode * 2 + 1; 199 | } 200 | else 201 | gcov_var.mode = mode * 2 + 1; 202 | #else 203 | #ifndef ENABLE_LIBGCOV_PORT 204 | if (mode >= 0) 205 | gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b"); 206 | 207 | if (gcov_var.file) 208 | gcov_var.mode = 1; 209 | else if (mode <= 0) 210 | { 211 | gcov_var.file = fopen (name, "w+b"); 212 | if (gcov_var.file) 213 | gcov_var.mode = mode * 2 + 1; 214 | } 215 | if (!gcov_var.file) 216 | return 0; 217 | #else 218 | gcov_var.filename = name; 219 | gcov_var.gcda_buf = (unsigned char*)calloc(GCOV_GCDA_BUF_SZ, 1); 220 | if (! gcov_var.gcda_buf) 221 | return 0; 222 | gcov_var.gcda_buf_pos = gcov_var.gcda_buf; 223 | #endif 224 | #endif 225 | 226 | #ifndef ENABLE_LIBGCOV_PORT 227 | setbuf (gcov_var.file, (char *)0); 228 | #endif 229 | 230 | return 1; 231 | } 232 | 233 | /* Close the current gcov file. Flushes data to disk. Returns nonzero 234 | on failure or error flag set. */ 235 | 236 | GCOV_LINKAGE int 237 | gcov_close (void) 238 | { 239 | #ifndef ENABLE_LIBGCOV_PORT 240 | if (gcov_var.file) 241 | { 242 | #endif 243 | #if !IN_GCOV 244 | if (gcov_var.offset /* @NO_GCDA_FILE && gcov_var.mode < 0*/) 245 | gcov_write_block (gcov_var.offset); 246 | #endif 247 | #ifndef ENABLE_LIBGCOV_PORT 248 | fclose (gcov_var.file); 249 | gcov_var.file = 0; 250 | #else 251 | free(gcov_var.gcda_buf); 252 | gcov_var.gcda_buf = gcov_var.gcda_buf_pos = 0; 253 | gcov_var.filename = NULL; 254 | #endif 255 | gcov_var.length = 0; 256 | #ifndef ENABLE_LIBGCOV_PORT 257 | } 258 | #endif 259 | #if !IN_LIBGCOV 260 | free (gcov_var.buffer); 261 | gcov_var.alloc = 0; 262 | gcov_var.buffer = 0; 263 | #endif 264 | gcov_var.mode = 0; 265 | return gcov_var.error; 266 | } 267 | 268 | static void 269 | gcov_write_block (unsigned size) 270 | { 271 | #ifndef ENABLE_LIBGCOV_PORT 272 | if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1) 273 | gcov_var.error = 1; 274 | #else 275 | if(((gcov_var.gcda_buf_pos + (size << 2)) - gcov_var.gcda_buf) > GCOV_GCDA_BUF_SZ) 276 | gcov_var.error = 1; 277 | else { 278 | memcpy(gcov_var.gcda_buf_pos, gcov_var.buffer, (size << 2)); 279 | gcov_var.gcda_buf_pos += (size << 2); 280 | } 281 | #endif 282 | gcov_var.start += size; 283 | gcov_var.offset -= size; 284 | } 285 | 286 | /* Allocate space to write BYTES bytes to the gcov file. Return a 287 | pointer to those bytes, or NULL on failure. */ 288 | 289 | static gcov_unsigned_t * 290 | gcov_write_words (unsigned words) 291 | { 292 | gcov_unsigned_t *result; 293 | 294 | gcov_nonruntime_assert (gcov_var.mode < 0); 295 | #if IN_LIBGCOV 296 | if (gcov_var.offset >= GCOV_BLOCK_SIZE) 297 | { 298 | gcov_write_block (GCOV_BLOCK_SIZE); 299 | if (gcov_var.offset) 300 | { 301 | memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); 302 | } 303 | } 304 | #else 305 | if (gcov_var.offset + words > gcov_var.alloc) 306 | gcov_allocate (gcov_var.offset + words); 307 | #endif 308 | result = &gcov_var.buffer[gcov_var.offset]; 309 | gcov_var.offset += words; 310 | 311 | return result; 312 | } 313 | 314 | /* Write unsigned VALUE to coverage file. Sets error flag 315 | appropriately. */ 316 | 317 | GCOV_LINKAGE void 318 | gcov_write_unsigned (gcov_unsigned_t value) 319 | { 320 | gcov_unsigned_t *buffer = gcov_write_words (1); 321 | 322 | buffer[0] = value; 323 | } 324 | 325 | /* Write counter VALUE to coverage file. Sets error flag 326 | appropriately. */ 327 | 328 | #if IN_LIBGCOV 329 | GCOV_LINKAGE void 330 | gcov_write_counter (gcov_type value) 331 | { 332 | gcov_unsigned_t *buffer = gcov_write_words (2); 333 | 334 | buffer[0] = (gcov_unsigned_t) value; 335 | if (sizeof (value) > sizeof (gcov_unsigned_t)) 336 | buffer[1] = (gcov_unsigned_t) (value >> 32); 337 | else 338 | buffer[1] = 0; 339 | } 340 | #endif /* IN_LIBGCOV */ 341 | 342 | /* Write a tag TAG and length LENGTH. */ 343 | 344 | GCOV_LINKAGE void 345 | gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) 346 | { 347 | gcov_unsigned_t *buffer = gcov_write_words (2); 348 | 349 | buffer[0] = tag; 350 | buffer[1] = length; 351 | } 352 | 353 | /* Write a summary structure to the gcov file. Return nonzero on 354 | overflow. */ 355 | 356 | GCOV_LINKAGE void 357 | gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) 358 | { 359 | unsigned ix, h_ix, bv_ix, h_cnt = 0; 360 | const struct gcov_ctr_summary *csum; 361 | unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE]; 362 | 363 | /* Count number of non-zero histogram entries, and fill in a bit vector 364 | of non-zero indices. The histogram is only currently computed for arc 365 | counters. */ 366 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) 367 | histo_bitvector[bv_ix] = 0; 368 | csum = &summary->ctrs[GCOV_COUNTER_ARCS]; 369 | for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) 370 | { 371 | if (csum->histogram[h_ix].num_counters > 0) 372 | { 373 | histo_bitvector[h_ix / 32] |= 1 << (h_ix % 32); 374 | h_cnt++; 375 | } 376 | } 377 | gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH (h_cnt)); 378 | gcov_write_unsigned (summary->checksum); 379 | for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) 380 | { 381 | gcov_write_unsigned (csum->num); 382 | gcov_write_unsigned (csum->runs); 383 | gcov_write_counter (csum->sum_all); 384 | gcov_write_counter (csum->run_max); 385 | gcov_write_counter (csum->sum_max); 386 | if (ix != GCOV_COUNTER_ARCS) 387 | { 388 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) 389 | gcov_write_unsigned (0); 390 | continue; 391 | } 392 | for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) 393 | gcov_write_unsigned (histo_bitvector[bv_ix]); 394 | for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) 395 | { 396 | if (!csum->histogram[h_ix].num_counters) 397 | continue; 398 | gcov_write_unsigned (csum->histogram[h_ix].num_counters); 399 | gcov_write_counter (csum->histogram[h_ix].min_value); 400 | gcov_write_counter (csum->histogram[h_ix].cum_value); 401 | } 402 | } 403 | } 404 | 405 | #if IN_LIBGCOV 406 | /* Move to a given position in a gcov file. */ 407 | 408 | GCOV_LINKAGE void 409 | gcov_seek (gcov_position_t base) 410 | { 411 | if (gcov_var.offset) 412 | gcov_write_block (gcov_var.offset); 413 | #ifndef ENABLE_LIBGCOV_PORT 414 | fseek (gcov_var.file, base << 2, SEEK_SET); 415 | gcov_var.start = ftell (gcov_var.file) >> 2; 416 | #else 417 | gcov_var.gcda_buf_pos = gcov_var.gcda_buf + (base << 2); 418 | gcov_var.start = base; 419 | #endif 420 | } 421 | #endif 422 | 423 | #if !IN_GCOV 424 | /* Determine the index into histogram for VALUE. */ 425 | 426 | #if IN_LIBGCOV 427 | /* @NO_INCLUDE_SRC static */ unsigned 428 | #else 429 | GCOV_LINKAGE unsigned 430 | #endif 431 | gcov_histo_index (gcov_type value) 432 | { 433 | gcov_type_unsigned v = (gcov_type_unsigned)value; 434 | unsigned r = 0; 435 | unsigned prev2bits = 0; 436 | 437 | /* Find index into log2 scale histogram, where each of the log2 438 | sized buckets is divided into 4 linear sub-buckets for better 439 | focus in the higher buckets. */ 440 | 441 | /* Find the place of the most-significant bit set. */ 442 | if (v > 0) 443 | { 444 | #if IN_LIBGCOV 445 | /* When building libgcov we don't include system.h, which includes 446 | hwint.h (where floor_log2 is declared). However, libgcov.a 447 | is built by the bootstrapped compiler and therefore the builtins 448 | are always available. */ 449 | r = sizeof (long long) * __CHAR_BIT__ - 1 - __builtin_clzll (v); 450 | #else 451 | /* We use floor_log2 from hwint.c, which takes a HOST_WIDE_INT 452 | that is 64 bits and gcov_type_unsigned is 64 bits. */ 453 | r = floor_log2 (v); 454 | #endif 455 | } 456 | 457 | /* If at most the 2 least significant bits are set (value is 458 | 0 - 3) then that value is our index into the lowest set of 459 | four buckets. */ 460 | if (r < 2) 461 | return (unsigned)value; 462 | 463 | gcov_nonruntime_assert (r < 64); 464 | 465 | /* Find the two next most significant bits to determine which 466 | of the four linear sub-buckets to select. */ 467 | prev2bits = (v >> (r - 2)) & 0x3; 468 | /* Finally, compose the final bucket index from the log2 index and 469 | the next 2 bits. The minimum r value at this point is 2 since we 470 | returned above if r was 2 or more, so the minimum bucket at this 471 | point is 4. */ 472 | return (r - 1) * 4 + prev2bits; 473 | } 474 | 475 | /* Merge SRC_HISTO into TGT_HISTO. The counters are assumed to be in 476 | the same relative order in both histograms, and are matched up 477 | and merged in reverse order. Each counter is assigned an equal portion of 478 | its entry's original cumulative counter value when computing the 479 | new merged cum_value. */ 480 | 481 | /* @NO_INCLUDE_SRC static */ void gcov_histogram_merge (gcov_bucket_type *tgt_histo, 482 | gcov_bucket_type *src_histo) 483 | { 484 | int src_i, tgt_i, tmp_i = 0; 485 | unsigned src_num, tgt_num, merge_num; 486 | gcov_type src_cum, tgt_cum, merge_src_cum, merge_tgt_cum, merge_cum; 487 | gcov_type merge_min; 488 | gcov_bucket_type tmp_histo[GCOV_HISTOGRAM_SIZE]; 489 | int src_done = 0; 490 | 491 | memset (tmp_histo, 0, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); 492 | 493 | /* Assume that the counters are in the same relative order in both 494 | histograms. Walk the histograms from largest to smallest entry, 495 | matching up and combining counters in order. */ 496 | src_num = 0; 497 | src_cum = 0; 498 | src_i = GCOV_HISTOGRAM_SIZE - 1; 499 | for (tgt_i = GCOV_HISTOGRAM_SIZE - 1; tgt_i >= 0 && !src_done; tgt_i--) 500 | { 501 | tgt_num = tgt_histo[tgt_i].num_counters; 502 | tgt_cum = tgt_histo[tgt_i].cum_value; 503 | /* Keep going until all of the target histogram's counters at this 504 | position have been matched and merged with counters from the 505 | source histogram. */ 506 | while (tgt_num > 0 && !src_done) 507 | { 508 | /* If this is either the first time through this loop or we just 509 | exhausted the previous non-zero source histogram entry, look 510 | for the next non-zero source histogram entry. */ 511 | if (!src_num) 512 | { 513 | /* Locate the next non-zero entry. */ 514 | while (src_i >= 0 && !src_histo[src_i].num_counters) 515 | src_i--; 516 | /* If source histogram has fewer counters, then just copy over the 517 | remaining target counters and quit. */ 518 | if (src_i < 0) 519 | { 520 | tmp_histo[tgt_i].num_counters += tgt_num; 521 | tmp_histo[tgt_i].cum_value += tgt_cum; 522 | if (!tmp_histo[tgt_i].min_value || 523 | tgt_histo[tgt_i].min_value < tmp_histo[tgt_i].min_value) 524 | tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value; 525 | while (--tgt_i >= 0) 526 | { 527 | tmp_histo[tgt_i].num_counters 528 | += tgt_histo[tgt_i].num_counters; 529 | tmp_histo[tgt_i].cum_value += tgt_histo[tgt_i].cum_value; 530 | if (!tmp_histo[tgt_i].min_value || 531 | tgt_histo[tgt_i].min_value 532 | < tmp_histo[tgt_i].min_value) 533 | tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value; 534 | } 535 | 536 | src_done = 1; 537 | break; 538 | } 539 | 540 | src_num = src_histo[src_i].num_counters; 541 | src_cum = src_histo[src_i].cum_value; 542 | } 543 | 544 | /* The number of counters to merge on this pass is the minimum 545 | of the remaining counters from the current target and source 546 | histogram entries. */ 547 | merge_num = tgt_num; 548 | if (src_num < merge_num) 549 | merge_num = src_num; 550 | 551 | /* The merged min_value is the sum of the min_values from target 552 | and source. */ 553 | merge_min = tgt_histo[tgt_i].min_value + src_histo[src_i].min_value; 554 | 555 | /* Compute the portion of source and target entries' cum_value 556 | that will be apportioned to the counters being merged. 557 | The total remaining cum_value from each entry is divided 558 | equally among the counters from that histogram entry if we 559 | are not merging all of them. */ 560 | merge_src_cum = src_cum; 561 | if (merge_num < src_num) 562 | merge_src_cum = merge_num * src_cum / src_num; 563 | merge_tgt_cum = tgt_cum; 564 | if (merge_num < tgt_num) 565 | merge_tgt_cum = merge_num * tgt_cum / tgt_num; 566 | /* The merged cum_value is the sum of the source and target 567 | components. */ 568 | merge_cum = merge_src_cum + merge_tgt_cum; 569 | 570 | /* Update the remaining number of counters and cum_value left 571 | to be merged from this source and target entry. */ 572 | src_cum -= merge_src_cum; 573 | tgt_cum -= merge_tgt_cum; 574 | src_num -= merge_num; 575 | tgt_num -= merge_num; 576 | 577 | /* The merged counters get placed in the new merged histogram 578 | at the entry for the merged min_value. */ 579 | tmp_i = gcov_histo_index (merge_min); 580 | gcov_nonruntime_assert (tmp_i < GCOV_HISTOGRAM_SIZE); 581 | tmp_histo[tmp_i].num_counters += merge_num; 582 | tmp_histo[tmp_i].cum_value += merge_cum; 583 | if (!tmp_histo[tmp_i].min_value || 584 | merge_min < tmp_histo[tmp_i].min_value) 585 | tmp_histo[tmp_i].min_value = merge_min; 586 | 587 | /* Ensure the search for the next non-zero src_histo entry starts 588 | at the next smallest histogram bucket. */ 589 | if (!src_num) 590 | src_i--; 591 | } 592 | } 593 | 594 | gcov_nonruntime_assert (tgt_i < 0); 595 | 596 | /* In the case where there were more counters in the source histogram, 597 | accumulate the remaining unmerged cumulative counter values. Add 598 | those to the smallest non-zero target histogram entry. Otherwise, 599 | the total cumulative counter values in the histogram will be smaller 600 | than the sum_all stored in the summary, which will complicate 601 | computing the working set information from the histogram later on. */ 602 | if (src_num) 603 | src_i--; 604 | while (src_i >= 0) 605 | { 606 | src_cum += src_histo[src_i].cum_value; 607 | src_i--; 608 | } 609 | /* At this point, tmp_i should be the smallest non-zero entry in the 610 | tmp_histo. */ 611 | gcov_nonruntime_assert (tmp_i >= 0 && tmp_i < GCOV_HISTOGRAM_SIZE 612 | && tmp_histo[tmp_i].num_counters > 0); 613 | tmp_histo[tmp_i].cum_value += src_cum; 614 | 615 | /* Finally, copy the merged histogram into tgt_histo. */ 616 | memcpy (tgt_histo, tmp_histo, 617 | sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); 618 | } 619 | #endif /* !IN_GCOV */ 620 | 621 | #endif /* ENABLE_LIBGCOV_PORT */ 622 | -------------------------------------------------------------------------------- /port/gcc/gcov-io.h: -------------------------------------------------------------------------------- 1 | /* File format for coverage information 2 | Copyright (C) 1996-2015 Free Software Foundation, Inc. 3 | Contributed by Bob Manson . 4 | Completely remangled 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 | Under Section 7 of GPL version 3, you are granted additional 19 | permissions described in the GCC Runtime Library Exception, version 20 | 3.1, as published by the Free Software Foundation. 21 | 22 | You should have received a copy of the GNU General Public License and 23 | a copy of the GCC Runtime Library Exception along with this program; 24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 25 | . */ 26 | 27 | 28 | /* Coverage information is held in two files. A notes file, which is 29 | generated by the compiler, and a data file, which is generated by 30 | the program under test. Both files use a similar structure. We do 31 | not attempt to make these files backwards compatible with previous 32 | versions, as you only need coverage information when developing a 33 | program. We do hold version information, so that mismatches can be 34 | detected, and we use a format that allows tools to skip information 35 | they do not understand or are not interested in. 36 | 37 | Numbers are recorded in the 32 bit unsigned binary form of the 38 | endianness of the machine generating the file. 64 bit numbers are 39 | stored as two 32 bit numbers, the low part first. Strings are 40 | padded with 1 to 4 NUL bytes, to bring the length up to a multiple 41 | of 4. The number of 4 bytes is stored, followed by the padded 42 | string. Zero length and NULL strings are simply stored as a length 43 | of zero (they have no trailing NUL or padding). 44 | 45 | int32: byte3 byte2 byte1 byte0 | byte0 byte1 byte2 byte3 46 | int64: int32:low int32:high 47 | string: int32:0 | int32:length char* char:0 padding 48 | padding: | char:0 | char:0 char:0 | char:0 char:0 char:0 49 | item: int32 | int64 | string 50 | 51 | The basic format of the files is 52 | 53 | file : int32:magic int32:version int32:stamp record* 54 | 55 | The magic ident is different for the notes and the data files. The 56 | magic ident is used to determine the endianness of the file, when 57 | reading. The version is the same for both files and is derived 58 | from gcc's version number. The stamp value is used to synchronize 59 | note and data files and to synchronize merging within a data 60 | file. It need not be an absolute time stamp, merely a ticker that 61 | increments fast enough and cycles slow enough to distinguish 62 | different compile/run/compile cycles. 63 | 64 | Although the ident and version are formally 32 bit numbers, they 65 | are derived from 4 character ASCII strings. The version number 66 | consists of the single character major version number, a two 67 | character minor version number (leading zero for versions less than 68 | 10), and a single character indicating the status of the release. 69 | That will be 'e' experimental, 'p' prerelease and 'r' for release. 70 | Because, by good fortune, these are in alphabetical order, string 71 | collating can be used to compare version strings. Be aware that 72 | the 'e' designation will (naturally) be unstable and might be 73 | incompatible with itself. For gcc 3.4 experimental, it would be 74 | '304e' (0x33303465). When the major version reaches 10, the 75 | letters A-Z will be used. Assuming minor increments releases every 76 | 6 months, we have to make a major increment every 50 years. 77 | Assuming major increments releases every 5 years, we're ok for the 78 | next 155 years -- good enough for me. 79 | 80 | A record has a tag, length and variable amount of data. 81 | 82 | record: header data 83 | header: int32:tag int32:length 84 | data: item* 85 | 86 | Records are not nested, but there is a record hierarchy. Tag 87 | numbers reflect this hierarchy. Tags are unique across note and 88 | data files. Some record types have a varying amount of data. The 89 | LENGTH is the number of 4bytes that follow and is usually used to 90 | determine how much data. The tag value is split into 4 8-bit 91 | fields, one for each of four possible levels. The most significant 92 | is allocated first. Unused levels are zero. Active levels are 93 | odd-valued, so that the LSB of the level is one. A sub-level 94 | incorporates the values of its superlevels. This formatting allows 95 | you to determine the tag hierarchy, without understanding the tags 96 | themselves, and is similar to the standard section numbering used 97 | in technical documents. Level values [1..3f] are used for common 98 | tags, values [41..9f] for the notes file and [a1..ff] for the data 99 | file. 100 | 101 | The notes file contains the following records 102 | note: unit function-graph* 103 | unit: header int32:checksum string:source 104 | function-graph: announce_function basic_blocks {arcs | lines}* 105 | announce_function: header int32:ident 106 | int32:lineno_checksum int32:cfg_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 summary:object summary:program* function-data*}* 133 | unit: header int32:checksum 134 | function-data: announce_function present counts 135 | announce_function: header int32:ident 136 | int32:lineno_checksum int32:cfg_checksum 137 | present: header int32:present 138 | counts: header int64:count* 139 | summary: int32:checksum {count-summary}GCOV_COUNTERS_SUMMABLE 140 | count-summary: int32:num int32:runs int64:sum 141 | int64:max int64:sum_max histogram 142 | histogram: {int32:bitvector}8 histogram-buckets* 143 | histogram-buckets: int32:num int64:min int64:sum 144 | 145 | The ANNOUNCE_FUNCTION record is the same as that in the note file, 146 | but without the source location. The COUNTS gives the 147 | counter values for instrumented features. The about the whole 148 | program. The checksum is used for whole program summaries, and 149 | disambiguates different programs which include the same 150 | instrumented object file. There may be several program summaries, 151 | each with a unique checksum. The object summary's checksum is 152 | zero. Note that the data file might contain information from 153 | several runs concatenated, or the data might be merged. 154 | 155 | This file is included by both the compiler, gcov tools and the 156 | runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to 157 | distinguish which case is which. If IN_LIBGCOV is nonzero, 158 | libgcov is being built. If IN_GCOV is nonzero, the gcov tools are 159 | being built. Otherwise the compiler is being built. IN_GCOV may be 160 | positive or negative. If positive, we are compiling a tool that 161 | requires additional functions (see the code for knowledge of what 162 | those functions are). */ 163 | 164 | #ifndef GCC_GCOV_IO_H 165 | #define GCC_GCOV_IO_H 166 | 167 | /* @STRIPPED lines 167-192 */ 168 | 169 | #ifndef GCOV_LINKAGE 170 | #define GCOV_LINKAGE extern 171 | #endif 172 | 173 | #if IN_LIBGCOV 174 | #define gcov_nonruntime_assert(EXPR) ((void)(0 && (EXPR))) 175 | #else 176 | #define gcov_nonruntime_assert(EXPR) gcc_assert (EXPR) 177 | #define gcov_error(...) fatal_error (input_location, __VA_ARGS__) 178 | #endif 179 | 180 | /* File suffixes. */ 181 | #define GCOV_DATA_SUFFIX ".gcda" 182 | #define GCOV_NOTE_SUFFIX ".gcno" 183 | 184 | /* File magic. Must not be palindromes. */ 185 | #define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461) /* "gcda" */ 186 | #define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f) /* "gcno" */ 187 | 188 | /* 189 | * We did not have any gcov-iov.h generated which contains the version. 190 | * Figured with gcov complaints about an invalid version in our manually 191 | * generated GCDA versions. The version that gcov from this version of 192 | * GNU ARM gcc needs is '504r' (0x35303472), and so what could have been in 193 | * gcov-iov.h is directly mentioned here 194 | */ 195 | #define GCOV_VERSION ((gcov_unsigned_t)0x35303472) 196 | 197 | /* Convert a magic or version number to a 4 character string. */ 198 | #define GCOV_UNSIGNED2STRING(ARRAY,VALUE) \ 199 | ((ARRAY)[0] = (char)((VALUE) >> 24), \ 200 | (ARRAY)[1] = (char)((VALUE) >> 16), \ 201 | (ARRAY)[2] = (char)((VALUE) >> 8), \ 202 | (ARRAY)[3] = (char)((VALUE) >> 0)) 203 | 204 | /* The record tags. Values [1..3f] are for tags which may be in either 205 | file. Values [41..9f] for those in the note file and [a1..ff] for 206 | the data file. The tag value zero is used as an explicit end of 207 | file marker -- it is not required to be present. */ 208 | 209 | #define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000) 210 | #define GCOV_TAG_FUNCTION_LENGTH (3) 211 | #define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000) 212 | #define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM) 213 | #define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH) 214 | #define GCOV_TAG_ARCS ((gcov_unsigned_t)0x01430000) 215 | #define GCOV_TAG_ARCS_LENGTH(NUM) (1 + (NUM) * 2) 216 | #define GCOV_TAG_ARCS_NUM(LENGTH) (((LENGTH) - 1) / 2) 217 | #define GCOV_TAG_LINES ((gcov_unsigned_t)0x01450000) 218 | #define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000) 219 | #define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2) 220 | #define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2) 221 | #define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) /* Obsolete */ 222 | #define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) 223 | #define GCOV_TAG_SUMMARY_LENGTH(NUM) \ 224 | (1 + GCOV_COUNTERS_SUMMABLE * (10 + 3 * 2) + (NUM) * 5) 225 | #define GCOV_TAG_AFDO_FILE_NAMES ((gcov_unsigned_t)0xaa000000) 226 | #define GCOV_TAG_AFDO_FUNCTION ((gcov_unsigned_t)0xac000000) 227 | #define GCOV_TAG_AFDO_WORKING_SET ((gcov_unsigned_t)0xaf000000) 228 | 229 | 230 | /* Counters that are collected. */ 231 | 232 | #define DEF_GCOV_COUNTER(COUNTER, NAME, MERGE_FN) COUNTER, 233 | enum { 234 | #include "gcov-counter.def" 235 | GCOV_COUNTERS 236 | }; 237 | #undef DEF_GCOV_COUNTER 238 | 239 | /* Counters which can be summaried. */ 240 | #define GCOV_COUNTERS_SUMMABLE (GCOV_COUNTER_ARCS + 1) 241 | 242 | /* The first of counters used for value profiling. They must form a 243 | consecutive interval and their order must match the order of 244 | HIST_TYPEs in value-prof.h. */ 245 | #define GCOV_FIRST_VALUE_COUNTER GCOV_COUNTERS_SUMMABLE 246 | 247 | /* The last of counters used for value profiling. */ 248 | #define GCOV_LAST_VALUE_COUNTER (GCOV_COUNTERS - 1) 249 | 250 | /* Number of counters used for value profiling. */ 251 | #define GCOV_N_VALUE_COUNTERS \ 252 | (GCOV_LAST_VALUE_COUNTER - GCOV_FIRST_VALUE_COUNTER + 1) 253 | 254 | /* The number of hottest callees to be tracked. */ 255 | #define GCOV_ICALL_TOPN_VAL 2 256 | 257 | /* The number of counter entries per icall callsite. */ 258 | #define GCOV_ICALL_TOPN_NCOUNTS (1 + GCOV_ICALL_TOPN_VAL * 4) 259 | 260 | /* Convert a counter index to a tag. */ 261 | #define GCOV_TAG_FOR_COUNTER(COUNT) \ 262 | (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17)) 263 | /* Convert a tag to a counter. */ 264 | #define GCOV_COUNTER_FOR_TAG(TAG) \ 265 | ((unsigned)(((TAG) - GCOV_TAG_COUNTER_BASE) >> 17)) 266 | /* Check whether a tag is a counter tag. */ 267 | #define GCOV_TAG_IS_COUNTER(TAG) \ 268 | (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS) 269 | 270 | /* The tag level mask has 1's in the position of the inner levels, & 271 | the lsb of the current level, and zero on the current and outer 272 | levels. */ 273 | #define GCOV_TAG_MASK(TAG) (((TAG) - 1) ^ (TAG)) 274 | 275 | /* Return nonzero if SUB is an immediate subtag of TAG. */ 276 | #define GCOV_TAG_IS_SUBTAG(TAG,SUB) \ 277 | (GCOV_TAG_MASK (TAG) >> 8 == GCOV_TAG_MASK (SUB) \ 278 | && !(((SUB) ^ (TAG)) & ~GCOV_TAG_MASK (TAG))) 279 | 280 | /* Return nonzero if SUB is at a sublevel to TAG. */ 281 | #define GCOV_TAG_IS_SUBLEVEL(TAG,SUB) \ 282 | (GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB)) 283 | 284 | /* Basic block flags. */ 285 | #define GCOV_BLOCK_UNEXPECTED (1 << 1) 286 | 287 | /* Arc flags. */ 288 | #define GCOV_ARC_ON_TREE (1 << 0) 289 | #define GCOV_ARC_FAKE (1 << 1) 290 | #define GCOV_ARC_FALLTHROUGH (1 << 2) 291 | 292 | /* Structured records. */ 293 | 294 | /* Structure used for each bucket of the log2 histogram of counter values. */ 295 | typedef struct 296 | { 297 | /* Number of counters whose profile count falls within the bucket. */ 298 | gcov_unsigned_t num_counters; 299 | /* Smallest profile count included in this bucket. */ 300 | gcov_type min_value; 301 | /* Cumulative value of the profile counts in this bucket. */ 302 | gcov_type cum_value; 303 | } gcov_bucket_type; 304 | 305 | /* For a log2 scale histogram with each range split into 4 306 | linear sub-ranges, there will be at most 64 (max gcov_type bit size) - 1 log2 307 | ranges since the lowest 2 log2 values share the lowest 4 linear 308 | sub-range (values 0 - 3). This is 252 total entries (63*4). */ 309 | 310 | #define GCOV_HISTOGRAM_SIZE 252 311 | 312 | /* How many unsigned ints are required to hold a bit vector of non-zero 313 | histogram entries when the histogram is written to the gcov file. 314 | This is essentially a ceiling divide by 32 bits. */ 315 | #define GCOV_HISTOGRAM_BITVECTOR_SIZE (GCOV_HISTOGRAM_SIZE + 31) / 32 316 | 317 | /* Cumulative counter data. */ 318 | struct gcov_ctr_summary 319 | { 320 | gcov_unsigned_t num; /* number of counters. */ 321 | gcov_unsigned_t runs; /* number of program runs */ 322 | gcov_type sum_all; /* sum of all counters accumulated. */ 323 | gcov_type run_max; /* maximum value on a single run. */ 324 | gcov_type sum_max; /* sum of individual run max values. */ 325 | gcov_bucket_type histogram[GCOV_HISTOGRAM_SIZE]; /* histogram of 326 | counter values. */ 327 | }; 328 | 329 | /* Object & program summary record. */ 330 | struct gcov_summary 331 | { 332 | gcov_unsigned_t checksum; /* checksum of program */ 333 | struct gcov_ctr_summary ctrs[GCOV_COUNTERS_SUMMABLE]; 334 | }; 335 | 336 | 337 | /* Functions for reading and writing gcov files. In libgcov you can 338 | open the file for reading then writing. Elsewhere you can open the 339 | file either for reading or for writing. When reading a file you may 340 | use the gcov_read_* functions, gcov_sync, gcov_position, & 341 | gcov_error. When writing a file you may use the gcov_write 342 | functions, gcov_seek & gcov_error. When a file is to be rewritten 343 | you use the functions for reading, then gcov_rewrite then the 344 | functions for writing. Your file may become corrupted if you break 345 | these invariants. */ 346 | 347 | /* 348 | * This section of gcov-io.h is heavily changed in our libgcov port. 349 | * The function prototypes mentioned here are those used outside 350 | * gcov-io.c, in libgcov-driver.c and libgcov-driver-system.c. Since we 351 | * no longer follow the model of "including" gcov-io.c in our port, we 352 | * have made these prototypes available to the 2 C files. 353 | */ 354 | 355 | GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN; 356 | 357 | GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN; 358 | 359 | GCOV_LINKAGE void gcov_seek (gcov_position_t base) ATTRIBUTE_HIDDEN; 360 | 361 | GCOV_LINKAGE void gcov_write_unsigned (gcov_unsigned_t) ATTRIBUTE_HIDDEN; 362 | 363 | GCOV_LINKAGE void gcov_write_counter (gcov_type value) ATTRIBUTE_HIDDEN; 364 | 365 | GCOV_LINKAGE void gcov_write_tag_length (gcov_unsigned_t tag, gcov_unsigned_t length) ATTRIBUTE_HIDDEN; 366 | 367 | GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) ATTRIBUTE_HIDDEN; 368 | 369 | GCOV_LINKAGE unsigned gcov_histo_index (gcov_type value); 370 | 371 | GCOV_LINKAGE void gcov_histogram_merge (gcov_bucket_type *tgt_histo, 372 | gcov_bucket_type *src_histo); 373 | 374 | #endif /* GCC_GCOV_IO_H */ 375 | -------------------------------------------------------------------------------- /port/libgcc/libgcov-driver-system.c: -------------------------------------------------------------------------------- 1 | /* Routines required for instrumenting a program. */ 2 | /* Compile this one with gcc. */ 3 | /* Copyright (C) 1989-2015 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 | Under Section 7 of GPL version 3, you are granted additional 18 | permissions described in the GCC Runtime Library Exception, version 19 | 3.1, as published by the Free Software Foundation. 20 | 21 | You should have received a copy of the GNU General Public License and 22 | a copy of the GCC Runtime Library Exception along with this program; 23 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 | . */ 25 | 26 | #ifdef ENABLE_LIBGCOV_PORT 27 | 28 | #include "libgcov-port.h" 29 | #include "libgcov.h" 30 | 31 | /* @STRIPPED lines 26-129 */ 32 | 33 | /* Open a gcda file specified by GI_FILENAME. 34 | Return -1 on error. Return 0 on success. */ 35 | 36 | /* @NO_INCLUDE_SRC static */ int 37 | gcov_exit_open_gcda_file (struct gcov_info *gi_ptr 38 | /* @NO_AUTO_GCDA_CREATION struct gcov_filename *gf */) 39 | { 40 | const char *fname = gi_ptr->filename; 41 | /* @NO_AUTO_GCDA_CREATION char *dst = gf->filename + gf->prefix; */ 42 | 43 | fname = gi_ptr->filename; 44 | 45 | #if 0 /* @NO_AUTO_GCDA_CREATION */ 46 | /* Build relocated filename, stripping off leading 47 | directories from the initial filename if requested. */ 48 | if (gf->strip > 0) 49 | { 50 | const char *probe = fname; 51 | int level; 52 | 53 | /* Remove a leading separator, without counting it. */ 54 | if (IS_DIR_SEPARATOR (*probe)) 55 | probe++; 56 | 57 | /* Skip selected directory levels. If we fall off the end, we 58 | keep the final part. */ 59 | for (level = gf->strip; *probe && level; probe++) 60 | if (IS_DIR_SEPARATOR (*probe)) 61 | { 62 | fname = probe; 63 | level--; 64 | } 65 | } 66 | 67 | /* Update complete filename with stripped original. */ 68 | if (gf->prefix) 69 | { 70 | /* Avoid to add multiple drive letters into combined path. */ 71 | if (HAS_DRIVE_SPEC(fname)) 72 | fname += 2; 73 | 74 | if (!IS_DIR_SEPARATOR (*fname)) 75 | *dst++ = '/'; 76 | } 77 | strcpy (dst, fname); 78 | 79 | #endif // NO_AUTO_GCDA_CREATION 80 | 81 | /* The GCDA file name with path is available in gi_ptr->filename 82 | * so we take it from there and pass. We use this file name for 83 | * help in dumping binary data into the corresponding GCDA file 84 | * using GDB commands 85 | */ 86 | if (!gcov_open (fname /* gf->filename */)) 87 | { 88 | #if 0 /* @NO_AUTO_GCDA_CREATION */ 89 | /* Open failed likely due to missed directory. 90 | Create directory and retry to open file. */ 91 | if (create_file_directory (gf->filename)) 92 | { 93 | fprintf (stderr, "profiling:%s:Skip\n", gf->filename); 94 | return -1; 95 | } 96 | if (!gcov_open (gf->filename)) 97 | { 98 | fprintf (stderr, "profiling:%s:Cannot open\n", gf->filename); 99 | return -1; 100 | } 101 | #endif // NO_AUTO_GCDA_CREATION 102 | return -1; 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | #endif // ENABLE_LIBGCOV_PORT 109 | -------------------------------------------------------------------------------- /port/libgcc/libgcov-driver.c: -------------------------------------------------------------------------------- 1 | /* Routines required for instrumenting a program. */ 2 | /* Compile this one with gcc. */ 3 | /* Copyright (C) 1989-2015 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 | Under Section 7 of GPL version 3, you are granted additional 18 | permissions described in the GCC Runtime Library Exception, version 19 | 3.1, as published by the Free Software Foundation. 20 | 21 | You should have received a copy of the GNU General Public License and 22 | a copy of the GCC Runtime Library Exception along with this program; 23 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 | . */ 25 | 26 | #ifdef ENABLE_LIBGCOV_PORT 27 | 28 | #include 29 | #include 30 | #include "libgcov-port.h" 31 | #include "libgcov.h" 32 | 33 | GCOV_LINKAGE /* @NO_INCLUDE_SRC static */ int gcov_exit_open_gcda_file (struct gcov_info *gi_ptr 34 | /* @NO_AUTO_GCDA_CREATION , struct gcov_filename *gf*/); 35 | 36 | 37 | struct gcov_fn_buffer 38 | { 39 | struct gcov_fn_buffer *next; 40 | unsigned fn_ix; 41 | struct gcov_fn_info info; 42 | /* note gcov_fn_info ends in a trailing array. */ 43 | }; 44 | 45 | struct gcov_summary_buffer 46 | { 47 | struct gcov_summary_buffer *next; 48 | struct gcov_summary summary; 49 | }; 50 | 51 | static struct gcov_fn_buffer * 52 | free_fn_data (const struct gcov_info *gi_ptr, struct gcov_fn_buffer *buffer, 53 | unsigned limit) 54 | { 55 | struct gcov_fn_buffer *next; 56 | unsigned ix, n_ctr = 0; 57 | 58 | if (!buffer) 59 | return 0; 60 | next = buffer->next; 61 | 62 | for (ix = 0; ix != limit; ix++) 63 | if (gi_ptr->merge[ix]) 64 | free (buffer->info.ctrs[n_ctr++].values); 65 | free (buffer); 66 | return next; 67 | } 68 | 69 | static gcov_unsigned_t 70 | crc32_unsigned (gcov_unsigned_t crc32, gcov_unsigned_t value) 71 | { 72 | unsigned ix; 73 | 74 | for (ix = 32; ix--; value <<= 1) 75 | { 76 | unsigned feedback; 77 | 78 | feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; 79 | crc32 <<= 1; 80 | crc32 ^= feedback; 81 | } 82 | 83 | return crc32; 84 | } 85 | 86 | /* Insert counter VALUE into HISTOGRAM. */ 87 | 88 | static void 89 | gcov_histogram_insert(gcov_bucket_type *histogram, gcov_type value) 90 | { 91 | unsigned i; 92 | 93 | i = gcov_histo_index(value); 94 | histogram[i].num_counters++; 95 | histogram[i].cum_value += value; 96 | if (value < histogram[i].min_value) 97 | histogram[i].min_value = value; 98 | } 99 | 100 | /* Computes a histogram of the arc counters to place in the summary SUM. */ 101 | 102 | static void 103 | gcov_compute_histogram (struct gcov_info *list, struct gcov_summary *sum) 104 | { 105 | struct gcov_info *gi_ptr; 106 | const struct gcov_fn_info *gfi_ptr; 107 | const struct gcov_ctr_info *ci_ptr; 108 | struct gcov_ctr_summary *cs_ptr; 109 | unsigned t_ix, f_ix, ctr_info_ix, ix; 110 | /* 111 | * @GCOV_INFO_LIST_CIRCULAR_FIX 112 | * The gcov_info * list being parsed in several places is assumed to be a 113 | * non-circular singly linked list. However; it turns out that it is a circular 114 | * one! Because of this the loops were not exiting at all. This was the main 115 | * reason why __gcov_flush when used directly, not using this port, was never 116 | * ending. 117 | */ 118 | unsigned break_loop_counter = 0; 119 | int h_ix; 120 | 121 | /* This currently only applies to arc counters. */ 122 | t_ix = GCOV_COUNTER_ARCS; 123 | 124 | /* First check if there are any counts recorded for this counter. */ 125 | cs_ptr = &(sum->ctrs[t_ix]); 126 | if (!cs_ptr->num) 127 | return; 128 | 129 | for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) 130 | { 131 | cs_ptr->histogram[h_ix].num_counters = 0; 132 | cs_ptr->histogram[h_ix].min_value = cs_ptr->run_max; 133 | cs_ptr->histogram[h_ix].cum_value = 0; 134 | } 135 | 136 | /* Walk through all the per-object structures and record each of 137 | the count values in histogram. */ 138 | /* 139 | * @GCOV_INFO_LIST_CIRCULAR_FIX 140 | * The gcov_info * list being parsed in several places is assumed to be a 141 | * non-circular singly linked list. However; it turns out that it is a circular 142 | * one! Because of this the loops were not exiting at all. This was the main 143 | * reason why __gcov_flush when used directly, not using this port, was never 144 | * ending. 145 | */ 146 | for (gi_ptr = list; gi_ptr && !(gi_ptr == list && break_loop_counter); gi_ptr = gi_ptr->next, break_loop_counter++) 147 | { 148 | if (!gi_ptr->merge[t_ix]) 149 | continue; 150 | 151 | /* Find the appropriate index into the gcov_ctr_info array 152 | for the counter we are currently working on based on the 153 | existence of the merge function pointer for this object. */ 154 | for (ix = 0, ctr_info_ix = 0; ix < t_ix; ix++) 155 | { 156 | if (gi_ptr->merge[ix]) 157 | ctr_info_ix++; 158 | } 159 | for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++) 160 | { 161 | gfi_ptr = gi_ptr->functions[f_ix]; 162 | 163 | if (!gfi_ptr || gfi_ptr->key != gi_ptr) 164 | continue; 165 | 166 | ci_ptr = &gfi_ptr->ctrs[ctr_info_ix]; 167 | for (ix = 0; ix < ci_ptr->num; ix++) 168 | gcov_histogram_insert (cs_ptr->histogram, ci_ptr->values[ix]); 169 | } 170 | } 171 | } 172 | 173 | /* buffer for the fn_data from another program. */ 174 | static struct gcov_fn_buffer *fn_buffer; 175 | /* buffer for summary from other programs to be written out. */ 176 | static struct gcov_summary_buffer *sum_buffer; 177 | 178 | /* This function computes the program level summary and the histo-gram. 179 | It computes and returns CRC32 and stored summary in THIS_PRG. 180 | Also determines the longest filename length of the info files. */ 181 | 182 | #if !IN_GCOV_TOOL 183 | static 184 | #endif 185 | gcov_unsigned_t 186 | compute_summary (struct gcov_info *list, struct gcov_summary *this_prg 187 | /* @NO_GCDA_FILE , size_t *max_length*/) 188 | { 189 | struct gcov_info *gi_ptr; 190 | const struct gcov_fn_info *gfi_ptr; 191 | struct gcov_ctr_summary *cs_ptr; 192 | const struct gcov_ctr_info *ci_ptr; 193 | int f_ix; 194 | unsigned t_ix; 195 | gcov_unsigned_t c_num; 196 | gcov_unsigned_t crc32 = 0; 197 | /* 198 | * @GCOV_INFO_LIST_CIRCULAR_FIX 199 | * The gcov_info * list being parsed in several places is assumed to be a 200 | * non-circular singly linked list. However; it turns out that it is a circular 201 | * one! Because of this the loops were not exiting at all. This was the main 202 | * reason why __gcov_flush when used directly, not using this port, was never 203 | * ending. 204 | */ 205 | unsigned break_loop_counter = 0; 206 | 207 | /* Find the totals for this execution. */ 208 | memset (this_prg, 0, sizeof (*this_prg)); 209 | #ifndef ENABLE_LIBGCOV_PORT 210 | *max_length = 0; 211 | #endif 212 | /* 213 | * @GCOV_INFO_LIST_CIRCULAR_FIX 214 | * The gcov_info * list being parsed in several places is assumed to be a 215 | * non-circular singly linked list. However; it turns out that it is a circular 216 | * one! Because of this the loops were not exiting at all. This was the main 217 | * reason why __gcov_flush when used directly, not using this port, was never 218 | * ending. 219 | */ 220 | for (gi_ptr = list; gi_ptr && !(gi_ptr == list && break_loop_counter); gi_ptr = gi_ptr->next, break_loop_counter++) 221 | { 222 | #ifndef ENABLE_LIBGCOV_PORT 223 | /* @NO_GCDA_FILE */ 224 | size_t len = strlen (gi_ptr->filename); 225 | if (len > *max_length) 226 | *max_length = len; 227 | #endif 228 | 229 | crc32 = crc32_unsigned (crc32, gi_ptr->stamp); 230 | crc32 = crc32_unsigned (crc32, gi_ptr->n_functions); 231 | 232 | for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) 233 | { 234 | gfi_ptr = gi_ptr->functions[f_ix]; 235 | 236 | if (gfi_ptr && gfi_ptr->key != gi_ptr) 237 | gfi_ptr = 0; 238 | 239 | crc32 = crc32_unsigned (crc32, gfi_ptr ? gfi_ptr->cfg_checksum : 0); 240 | crc32 = crc32_unsigned (crc32, 241 | gfi_ptr ? gfi_ptr->lineno_checksum : 0); 242 | if (!gfi_ptr) 243 | continue; 244 | 245 | ci_ptr = gfi_ptr->ctrs; 246 | for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++) 247 | { 248 | if (!gi_ptr->merge[t_ix]) 249 | continue; 250 | 251 | cs_ptr = &(this_prg->ctrs[t_ix]); 252 | cs_ptr->num += ci_ptr->num; 253 | crc32 = crc32_unsigned (crc32, ci_ptr->num); 254 | 255 | for (c_num = 0; c_num < ci_ptr->num; c_num++) 256 | { 257 | cs_ptr->sum_all += ci_ptr->values[c_num]; 258 | if (cs_ptr->run_max < ci_ptr->values[c_num]) 259 | cs_ptr->run_max = ci_ptr->values[c_num]; 260 | } 261 | ci_ptr++; 262 | } 263 | } 264 | } 265 | gcov_compute_histogram (list, this_prg); 266 | return crc32; 267 | } 268 | 269 | /* Write counters in GI_PTR and the summary in PRG to a gcda file. In 270 | the case of appending to an existing file, SUMMARY_POS will be non-zero. 271 | We will write the file starting from SUMMAY_POS. */ 272 | 273 | static void 274 | write_one_data (const struct gcov_info *gi_ptr, 275 | const struct gcov_summary *prg_p, 276 | const gcov_position_t eof_pos, 277 | const gcov_position_t summary_pos) 278 | { 279 | unsigned f_ix; 280 | struct gcov_summary_buffer *next_sum_buffer; 281 | 282 | /* Write out the data. */ 283 | if (!eof_pos) 284 | { 285 | gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); 286 | gcov_write_unsigned (gi_ptr->stamp); 287 | } 288 | 289 | if (summary_pos) 290 | gcov_seek (summary_pos); 291 | 292 | /* Generate whole program statistics. */ 293 | gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, prg_p); 294 | 295 | /* Rewrite all the summaries that were after the summary we merged 296 | into. This is necessary as the merged summary may have a different 297 | size due to the number of non-zero histogram entries changing after 298 | merging. */ 299 | 300 | while (sum_buffer) 301 | { 302 | gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary); 303 | next_sum_buffer = sum_buffer->next; 304 | free (sum_buffer); 305 | sum_buffer = next_sum_buffer; 306 | } 307 | 308 | /* Write execution counts for each function. */ 309 | for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++) 310 | { 311 | unsigned buffered = 0; 312 | const struct gcov_fn_info *gfi_ptr; 313 | const struct gcov_ctr_info *ci_ptr; 314 | gcov_unsigned_t length; 315 | unsigned t_ix; 316 | 317 | if (fn_buffer && fn_buffer->fn_ix == f_ix) 318 | { 319 | /* Buffered data from another program. */ 320 | buffered = 1; 321 | gfi_ptr = &fn_buffer->info; 322 | length = GCOV_TAG_FUNCTION_LENGTH; 323 | } 324 | else 325 | { 326 | gfi_ptr = gi_ptr->functions[f_ix]; 327 | if (gfi_ptr && gfi_ptr->key == gi_ptr) 328 | length = GCOV_TAG_FUNCTION_LENGTH; 329 | else 330 | length = 0; 331 | } 332 | 333 | gcov_write_tag_length (GCOV_TAG_FUNCTION, length); 334 | if (!length) 335 | continue; 336 | 337 | gcov_write_unsigned (gfi_ptr->ident); 338 | gcov_write_unsigned (gfi_ptr->lineno_checksum); 339 | gcov_write_unsigned (gfi_ptr->cfg_checksum); 340 | 341 | ci_ptr = gfi_ptr->ctrs; 342 | for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++) 343 | { 344 | gcov_unsigned_t n_counts; 345 | gcov_type *c_ptr; 346 | 347 | if (!gi_ptr->merge[t_ix]) 348 | continue; 349 | 350 | n_counts = ci_ptr->num; 351 | gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), 352 | GCOV_TAG_COUNTER_LENGTH (n_counts)); 353 | c_ptr = ci_ptr->values; 354 | while (n_counts--) 355 | gcov_write_counter (*c_ptr++); 356 | ci_ptr++; 357 | } 358 | if (buffered) 359 | fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 360 | } 361 | 362 | gcov_write_unsigned (0); 363 | } 364 | 365 | /* Helper function for merging summary. 366 | Return -1 on error. Return 0 on success. */ 367 | 368 | static int 369 | merge_summary (/* @NO_GCDA_FILE const char *filename, */ int run_counted, 370 | const struct gcov_info *gi_ptr, struct gcov_summary *prg, 371 | struct gcov_summary *this_prg, gcov_unsigned_t crc32, 372 | struct gcov_summary *all_prg __attribute__ ((unused))) 373 | { 374 | struct gcov_ctr_summary *cs_prg, *cs_tprg; 375 | unsigned t_ix; 376 | #if !GCOV_LOCKED 377 | /* summary for all instances of program. */ 378 | struct gcov_ctr_summary *cs_all; 379 | #endif 380 | 381 | /* Merge the summaries. */ 382 | for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) 383 | { 384 | cs_prg = &(prg->ctrs[t_ix]); 385 | cs_tprg = &(this_prg->ctrs[t_ix]); 386 | 387 | if (gi_ptr->merge[t_ix]) 388 | { 389 | int first = !cs_prg->runs; 390 | 391 | if (!run_counted) 392 | cs_prg->runs++; 393 | if (first) 394 | cs_prg->num = cs_tprg->num; 395 | cs_prg->sum_all += cs_tprg->sum_all; 396 | if (cs_prg->run_max < cs_tprg->run_max) 397 | cs_prg->run_max = cs_tprg->run_max; 398 | cs_prg->sum_max += cs_tprg->run_max; 399 | if (first) 400 | memcpy (cs_prg->histogram, cs_tprg->histogram, 401 | sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); 402 | else 403 | gcov_histogram_merge (cs_prg->histogram, cs_tprg->histogram); 404 | } 405 | else if (cs_prg->runs) 406 | { 407 | #ifndef ENABLE_LIBGCOV_PORT 408 | gcov_error ("profiling:%s:Merge mismatch for summary.\n", 409 | filename); 410 | #endif 411 | return -1; 412 | } 413 | #if !GCOV_LOCKED 414 | cs_all = &all_prg->ctrs[t_ix]; 415 | if (!cs_all->runs && cs_prg->runs) 416 | { 417 | cs_all->num = cs_prg->num; 418 | cs_all->runs = cs_prg->runs; 419 | cs_all->sum_all = cs_prg->sum_all; 420 | cs_all->run_max = cs_prg->run_max; 421 | cs_all->sum_max = cs_prg->sum_max; 422 | } 423 | else if (!all_prg->checksum 424 | /* Don't compare the histograms, which may have slight 425 | variations depending on the order they were updated 426 | due to the truncating integer divides used in the 427 | merge. */ 428 | && (cs_all->num != cs_prg->num 429 | || cs_all->runs != cs_prg->runs 430 | || cs_all->sum_all != cs_prg->sum_all 431 | || cs_all->run_max != cs_prg->run_max 432 | || cs_all->sum_max != cs_prg->sum_max)) 433 | { 434 | #ifndef ENABLE_LIBGCOV_PORT 435 | gcov_error ("profiling:%s:Data file mismatch - some " 436 | "data files may have been concurrently " 437 | "updated without locking support\n", filename); 438 | #endif 439 | all_prg->checksum = ~0u; 440 | } 441 | #endif 442 | } 443 | 444 | prg->checksum = crc32; 445 | 446 | return 0; 447 | } 448 | 449 | 450 | /* Sort N entries in VALUE_ARRAY in descending order. 451 | Each entry in VALUE_ARRAY has two values. The sorting 452 | is based on the second value. */ 453 | 454 | GCOV_LINKAGE void 455 | gcov_sort_n_vals (gcov_type *value_array, int n) 456 | { 457 | int j, k; 458 | 459 | for (j = 2; j < n; j += 2) 460 | { 461 | gcov_type cur_ent[2]; 462 | 463 | cur_ent[0] = value_array[j]; 464 | cur_ent[1] = value_array[j + 1]; 465 | k = j - 2; 466 | while (k >= 0 && value_array[k + 1] < cur_ent[1]) 467 | { 468 | value_array[k + 2] = value_array[k]; 469 | value_array[k + 3] = value_array[k+1]; 470 | k -= 2; 471 | } 472 | value_array[k + 2] = cur_ent[0]; 473 | value_array[k + 3] = cur_ent[1]; 474 | } 475 | } 476 | 477 | /* Sort the profile counters for all indirect call sites. Counters 478 | for each call site are allocated in array COUNTERS. */ 479 | 480 | static void 481 | gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters) 482 | { 483 | int i; 484 | gcov_type *values; 485 | int n = counters->num; 486 | 487 | gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS)); 488 | values = counters->values; 489 | 490 | for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS) 491 | { 492 | gcov_type *value_array = &values[i + 1]; 493 | gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1); 494 | } 495 | } 496 | 497 | /* Sort topn indirect_call profile counters in GI_PTR. */ 498 | 499 | static void 500 | gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr) 501 | { 502 | unsigned int i; 503 | int f_ix; 504 | const struct gcov_fn_info *gfi_ptr; 505 | const struct gcov_ctr_info *ci_ptr; 506 | 507 | if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV]) 508 | return; 509 | 510 | for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++) 511 | { 512 | gfi_ptr = gi_ptr->functions[f_ix]; 513 | ci_ptr = gfi_ptr->ctrs; 514 | for (i = 0; i < GCOV_COUNTERS; i++) 515 | { 516 | if (!gi_ptr->merge[i]) 517 | continue; 518 | if (i == GCOV_COUNTER_ICALL_TOPNV) 519 | { 520 | gcov_sort_icall_topn_counter (ci_ptr); 521 | break; 522 | } 523 | ci_ptr++; 524 | } 525 | } 526 | } 527 | 528 | /* Dump the coverage counts for one gcov_info object. We merge with existing 529 | counts when possible, to avoid growing the .da files ad infinitum. We use 530 | this program's checksum to make sure we only accumulate whole program 531 | statistics to the correct summary. An object file might be embedded 532 | in two separate programs, and we must keep the two program 533 | summaries separate. */ 534 | 535 | static void 536 | dump_one_gcov (struct gcov_info *gi_ptr, /* @NO_GCDA_FILE struct gcov_filename *gf, */ 537 | unsigned run_counted, 538 | gcov_unsigned_t crc32, struct gcov_summary *all_prg, 539 | struct gcov_summary *this_prg) 540 | { 541 | struct gcov_summary prg; /* summary for this object over all program. */ 542 | int error; 543 | #ifndef ENABLE_LIBGCOV_PORT 544 | gcov_unsigned_t tag; 545 | #endif 546 | gcov_position_t summary_pos = 0; 547 | gcov_position_t eof_pos = 0; 548 | 549 | fn_buffer = 0; 550 | sum_buffer = 0; 551 | 552 | gcov_sort_topn_counter_arrays (gi_ptr); 553 | 554 | error = gcov_exit_open_gcda_file (gi_ptr/* @NO_GCDA_FILE, gf*/); 555 | if (error == -1) 556 | return; 557 | 558 | #ifndef ENABLE_LIBGCOV_PORT 559 | /* 560 | * For this version of the libgcov port, we have assumed that we don't need 561 | * to merge existing GCDA, and we need to generate and store fresh coverage 562 | * data alone. Hence this whole logic of reading existing GCDA files, and merging 563 | * the read data into this run's counters is disabled as of now. 564 | */ 565 | tag = gcov_read_unsigned (); 566 | if (tag) 567 | { 568 | /* Merge data from file. */ 569 | if (tag != GCOV_DATA_MAGIC) 570 | { 571 | gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename); 572 | goto read_fatal; 573 | } 574 | error = merge_one_data (gf->filename, gi_ptr, &prg, this_prg, 575 | &summary_pos, &eof_pos, crc32); 576 | if (error == -1) 577 | goto read_fatal; 578 | } 579 | 580 | gcov_rewrite (); 581 | #endif /* !ENABLE_LIBGCOV_PORT */ 582 | 583 | if (!summary_pos) 584 | { 585 | memset (&prg, 0, sizeof (prg)); 586 | summary_pos = eof_pos; 587 | } 588 | 589 | error = merge_summary (/* @NO_GCDA_FILE gf->filename, */ run_counted, gi_ptr, &prg, this_prg, 590 | crc32, all_prg); 591 | if (error == -1) 592 | goto read_fatal; 593 | 594 | write_one_data (gi_ptr, &prg, eof_pos, summary_pos); 595 | /* fall through */ 596 | 597 | read_fatal:; 598 | while (fn_buffer) 599 | fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 600 | 601 | if ((error = gcov_close ())) 602 | #ifndef ENABLE_LIBGCOV_PORT 603 | gcov_error (error < 0 ? 604 | "profiling:%s:Overflow writing\n" : 605 | "profiling:%s:Error writing\n", 606 | gf->filename); 607 | #else 608 | { } 609 | #endif 610 | } 611 | 612 | 613 | /* Dump all the coverage counts for the program. It first computes program 614 | summary and then traverses gcov_list list and dumps the gcov_info 615 | objects one by one. */ 616 | 617 | #if !IN_GCOV_TOOL 618 | static 619 | #endif 620 | void 621 | gcov_do_dump (struct gcov_info *list, int run_counted) 622 | { 623 | struct gcov_info *gi_ptr; 624 | #ifndef ENABLE_LIBGCOV_PORT 625 | struct gcov_filename gf; 626 | #endif 627 | gcov_unsigned_t crc32; 628 | /* 629 | * @GCOV_INFO_LIST_CIRCULAR_FIX 630 | * The gcov_info * list being parsed in several places is assumed to be a 631 | * non-circular singly linked list. However; it turns out that it is a circular 632 | * one! Because of this the loops were not exiting at all. This was the main 633 | * reason why __gcov_flush when used directly, not using this port, was never 634 | * ending. 635 | */ 636 | gcov_unsigned_t break_loop_counter = 0; 637 | struct gcov_summary all_prg; 638 | struct gcov_summary this_prg; 639 | 640 | crc32 = compute_summary (list, &this_prg /* @NO_GCDA_FILE , &gf.max_length*/); 641 | 642 | #ifndef ENABLE_LIBGCOV_PORT 643 | allocate_filename_struct (&gf); 644 | #endif 645 | 646 | #if !GCOV_LOCKED 647 | memset (&all_prg, 0, sizeof (all_prg)); 648 | #endif 649 | 650 | /* Now merge each file. */ 651 | /* 652 | * @GCOV_INFO_LIST_CIRCULAR_FIX 653 | * The gcov_info * list being parsed in several places is assumed to be a 654 | * non-circular singly linked list. However; it turns out that it is a circular 655 | * one! Because of this the loops were not exiting at all. This was the main 656 | * reason why __gcov_flush when used directly, not using this port, was never 657 | * ending. 658 | */ 659 | for (gi_ptr = list; gi_ptr && !(gi_ptr == list && break_loop_counter); gi_ptr = gi_ptr->next, break_loop_counter++) 660 | dump_one_gcov (gi_ptr, /* @NO_GCDA_FILE &gf,*/ run_counted, crc32, &all_prg, &this_prg); 661 | 662 | #ifndef ENABLE_LIBGCOV_PORT 663 | free (gf.filename); 664 | #endif 665 | } 666 | 667 | #if !IN_GCOV_TOOL 668 | void 669 | __gcov_dump_one (struct gcov_root *root) 670 | { 671 | if (root->dumped) 672 | return; 673 | 674 | gcov_do_dump (root->list, root->run_counted); 675 | 676 | root->dumped = 1; 677 | root->run_counted = 1; 678 | } 679 | 680 | #ifndef ENABLE_LIBGCOV_PORT 681 | /* 682 | * The following two are the main gcov counter variables, which are already 683 | * available and populated by the gcov instrumentation. We are only going to 684 | * read these variables, and hence these are not defined by the port 685 | */ 686 | 687 | /* Per-dynamic-object gcov state. */ 688 | struct gcov_root __gcov_root; 689 | 690 | /* Exactly one of these will be live in the process image. */ 691 | struct gcov_master __gcov_master = 692 | {GCOV_VERSION, 0}; 693 | 694 | #endif 695 | 696 | void 697 | gcov_exit (void) 698 | { 699 | __gcov_dump_one (&__gcov_root); 700 | if (__gcov_root.next) 701 | __gcov_root.next->prev = __gcov_root.prev; 702 | if (__gcov_root.prev) 703 | __gcov_root.prev->next = __gcov_root.next; 704 | else 705 | __gcov_master.root = __gcov_root.next; 706 | } 707 | 708 | #endif /* !IN_GCOV_TOOL */ 709 | 710 | #endif /* ENABLE_LIBGCOV_PORT */ 711 | -------------------------------------------------------------------------------- /port/libgcc/libgcov.h: -------------------------------------------------------------------------------- 1 | /* Header file for libgcov-*.c. 2 | Copyright (C) 1996-2015 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 | Under Section 7 of GPL version 3, you are granted additional 17 | permissions described in the GCC Runtime Library Exception, version 18 | 3.1, as published by the Free Software Foundation. 19 | 20 | You should have received a copy of the GNU General Public License and 21 | a copy of the GCC Runtime Library Exception along with this program; 22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 | . */ 24 | 25 | #ifndef GCC_LIBGCOV_H 26 | #define GCC_LIBGCOV_H 27 | 28 | /* work around the poisoned malloc/calloc in system.h. */ 29 | #ifndef xmalloc 30 | #define xmalloc malloc 31 | #endif 32 | #ifndef xcalloc 33 | #define xcalloc calloc 34 | #endif 35 | 36 | #ifndef IN_GCOV_TOOL 37 | 38 | #if BITS_PER_UNIT == 8 39 | typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI))); 40 | typedef unsigned gcov_position_t __attribute__ ((mode (SI))); 41 | #if LONG_LONG_TYPE_SIZE > 32 42 | typedef signed gcov_type __attribute__ ((mode (DI))); 43 | typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI))); 44 | #else 45 | typedef signed gcov_type __attribute__ ((mode (SI))); 46 | typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI))); 47 | #endif 48 | #else 49 | #if BITS_PER_UNIT == 16 50 | typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI))); 51 | typedef unsigned gcov_position_t __attribute__ ((mode (HI))); 52 | #if LONG_LONG_TYPE_SIZE > 32 53 | typedef signed gcov_type __attribute__ ((mode (SI))); 54 | typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI))); 55 | #else 56 | typedef signed gcov_type __attribute__ ((mode (HI))); 57 | typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI))); 58 | #endif 59 | #else 60 | typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI))); 61 | typedef unsigned gcov_position_t __attribute__ ((mode (QI))); 62 | #if LONG_LONG_TYPE_SIZE > 32 63 | typedef signed gcov_type __attribute__ ((mode (HI))); 64 | typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI))); 65 | #else 66 | typedef signed gcov_type __attribute__ ((mode (QI))); 67 | typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI))); 68 | #endif 69 | #endif 70 | #endif 71 | 72 | #if defined (TARGET_POSIX_IO) 73 | #define GCOV_LOCKED 1 74 | #else 75 | #define GCOV_LOCKED 0 76 | #endif 77 | 78 | /* In libgcov we need these functions to be extern, so prefix them with 79 | __gcov. In libgcov they must also be hidden so that the instance in 80 | the executable is not also used in a DSO. */ 81 | #define gcov_var __gcov_var__ported 82 | #define gcov_open __gcov_open__ported 83 | #define gcov_close __gcov_close__ported 84 | #define gcov_write_tag_length __gcov_write_tag_length__ported 85 | #define gcov_seek __gcov_seek__ported 86 | #define gcov_write_unsigned __gcov_write_unsigned__ported 87 | #define gcov_write_counter __gcov_write_counter__ported 88 | #define gcov_write_summary __gcov_write_summary__ported 89 | #define gcov_sort_n_vals __gcov_sort_n_vals__ported 90 | #define gcov_exit gcov_exit__ported 91 | #define __gcov_dump_one __gcov_dump_one__ported 92 | 93 | /* @STRIPPED lines 105-136 */ 94 | 95 | #endif /* !IN_GCOV_TOOL */ 96 | 97 | /* @STRIPPED lines 140-151 */ 98 | 99 | #ifdef HAVE_GAS_HIDDEN 100 | #define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) 101 | #else 102 | #define ATTRIBUTE_HIDDEN 103 | #endif 104 | 105 | #include "gcov-io.h" 106 | 107 | /* Structures embedded in coveraged program. The structures generated 108 | by write_profile must match these. */ 109 | 110 | /* Information about counters for a single function. */ 111 | struct gcov_ctr_info 112 | { 113 | gcov_unsigned_t num; /* number of counters. */ 114 | gcov_type *values; /* their values. */ 115 | }; 116 | 117 | /* Information about a single function. This uses the trailing array 118 | idiom. The number of counters is determined from the merge pointer 119 | array in gcov_info. The key is used to detect which of a set of 120 | comdat functions was selected -- it points to the gcov_info object 121 | of the object file containing the selected comdat function. */ 122 | 123 | struct gcov_fn_info 124 | { 125 | const struct gcov_info *key; /* comdat key */ 126 | gcov_unsigned_t ident; /* unique ident of function */ 127 | gcov_unsigned_t lineno_checksum; /* function lineo_checksum */ 128 | gcov_unsigned_t cfg_checksum; /* function cfg checksum */ 129 | struct gcov_ctr_info ctrs[1]; /* instrumented counters */ 130 | }; 131 | 132 | /* Type of function used to merge counters. */ 133 | typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t); 134 | 135 | /* Information about a single object file. */ 136 | struct gcov_info 137 | { 138 | gcov_unsigned_t version; /* expected version number */ 139 | struct gcov_info *next; /* link to next, used by libgcov */ 140 | 141 | gcov_unsigned_t stamp; /* uniquifying time stamp */ 142 | const char *filename; /* output file name */ 143 | 144 | gcov_merge_fn merge[GCOV_COUNTERS]; /* merge functions (null for 145 | unused) */ 146 | 147 | unsigned n_functions; /* number of functions */ 148 | 149 | #ifndef IN_GCOV_TOOL 150 | const struct gcov_fn_info *const *functions; /* pointer to pointers 151 | to function information */ 152 | #else 153 | const struct gcov_fn_info **functions; 154 | #endif /* !IN_GCOV_TOOL */ 155 | }; 156 | 157 | /* Root of a program/shared-object state */ 158 | struct gcov_root 159 | { 160 | struct gcov_info *list; 161 | unsigned dumped : 1; /* counts have been dumped. */ 162 | unsigned run_counted : 1; /* run has been accounted for. */ 163 | struct gcov_root *next; 164 | struct gcov_root *prev; 165 | }; 166 | 167 | extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN; 168 | 169 | struct gcov_master 170 | { 171 | gcov_unsigned_t version; 172 | struct gcov_root *root; 173 | }; 174 | 175 | /* Exactly one of these will be active in the process. */ 176 | extern struct gcov_master __gcov_master; 177 | 178 | /* Dump a set of gcov objects. */ 179 | extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN; 180 | 181 | /* @STRIPPED lines 235-344 */ 182 | 183 | #endif /* LIBGCOV_H_ */ 184 | -------------------------------------------------------------------------------- /port/src/libgcov-embedded.c: -------------------------------------------------------------------------------- 1 | /* 2 | * coverage-support.c 3 | * 4 | * We need only few basic things from the article http://tinyurl.com/jkegjzh 5 | * These are - static_init and the get_stackpointer 6 | */ 7 | 8 | #ifdef ENABLE_LIBGCOV_PORT 9 | 10 | #include 11 | #include 12 | #include "libgcov-embedded.h" 13 | #include "libgcov.h" 14 | 15 | /* call the coverage initializers if not done by startup code */ 16 | void static_init(void) { 17 | void (**p)(void); 18 | extern uint32_t __init_array_start, __init_array_end; /* linker defined symbols, array of function pointers */ 19 | uint32_t beg = (uint32_t)&__init_array_start; 20 | uint32_t end = (uint32_t)&__init_array_end; 21 | 22 | while(beg 5 | * 6 | * This file contains the additional/modified data structures, prototypes etc. 7 | * that are needed and do not exist in/belong to other files that were ported 8 | * already 9 | */ 10 | 11 | #ifndef LIBGCOV_PORT_H 12 | #define LIBGCOV_PORT_H 13 | 14 | /* This preprocessor directive is manually defined here. */ 15 | #define IN_LIBGCOV 1 16 | 17 | /* 18 | * IMPORTANT 19 | * Do not define this! 20 | */ 21 | /* 22 | #define IN_GCOV 1 23 | */ 24 | 25 | /* 26 | * This is defined by gcc sources as 8 and should not need any change 27 | * for most platforms. This value works when compiling with GNU ARM 28 | * toolchain for the test project where this port was verified. 29 | */ 30 | #define BITS_PER_UNIT 8 31 | 32 | /* 33 | * This is defined for each platform/architecture in gcc code. The value 34 | * for most architectures is 64. The aarch64.h file by ARM which is part 35 | * of GCC defines it as 64. The GNU ARM Eclipse test project that we used 36 | * uses Aarch32 toolchain and not Aarch64; however, sizeof(long long) 37 | * returns 64, so we went with 64 as the value. 38 | */ 39 | #define LONG_LONG_TYPE_SIZE 64 40 | 41 | /* 42 | * IMPORTANT 43 | * Do not define this! 44 | * 45 | * TARGET_POSIX_IO is defined only for standard OSes like Linux in GCC. 46 | * This is a very important macro as GCOV_LOCKED macro gets different 47 | * values based on whether this is defined or not. 48 | * 49 | * I made our decision of not defining this macro as follows: 50 | * - Our port of libgcov uses no file handling (POSIX IO) 51 | */ 52 | /* 53 | #define TARGET_POSIX_IO 54 | */ 55 | 56 | 57 | /* 58 | * This is copied from gcc/system.h as opposed to bringing that file here 59 | * as this was the only macro needed from that file 60 | */ 61 | 62 | #if ENABLE_ASSERT_CHECKING 63 | #define gcc_assert(EXPR) \ 64 | ((void)(!(EXPR) ? fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0 : 0)) 65 | #elif (GCC_VERSION >= 4005) 66 | #define gcc_assert(EXPR) \ 67 | ((void)(__builtin_expect (!(EXPR), 0) ? __builtin_unreachable (), 0 : 0)) 68 | #else 69 | /* Include EXPR, so that unused variable warnings do not occur. */ 70 | #define gcc_assert(EXPR) ((void)(0 && (EXPR))) 71 | #endif 72 | 73 | #endif // LIBGCOV_PORT_H 74 | --------------------------------------------------------------------------------