1 /*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\
3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 |* See https://llvm.org/LICENSE.txt for license information.
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 |*===----------------------------------------------------------------------===*|
9 |* This file implements the call back routines for the gcov profiling
10 |* instrumentation pass. Link against this library when running code through
11 |* the -insert-gcov-profiling LLVM pass.
13 |* We emit files in a corrupt version of GCOV's "gcda" file format. These files
14 |* are only close enough that LCOV will happily parse them. Anything that lcov
15 |* ignores is missing.
17 |* TODO: gcov is multi-process safe by having each exit open the existing file
18 |* and append to it. We'd like to achieve that and be thread-safe too.
20 \*===----------------------------------------------------------------------===*/
22 #if !defined(__Fuchsia__)
32 #define WIN32_LEAN_AND_MEAN
34 #include "WindowsMMap.h"
38 #include <sys/types.h>
42 #include "InstrProfiling.h"
43 #include "InstrProfilingUtil.h"
45 /* #define DEBUG_GCDAPROFILING */
48 GCOV_DATA_MAGIC
= 0x67636461, // "gcda"
50 GCOV_TAG_FUNCTION
= 0x01000000,
51 GCOV_TAG_COUNTER_ARCS
= 0x01a10000,
52 // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
53 GCOV_TAG_OBJECT_SUMMARY
= 0xa1000000,
54 GCOV_TAG_PROGRAM_SUMMARY
= 0xa3000000,
58 * --- GCOV file format I/O primitives ---
62 * The current file name we're outputting. Used primarily for error logging.
64 static char *filename
= NULL
;
67 * The current file we're outputting.
69 static FILE *output_file
= NULL
;
72 * Buffer that we write things into.
74 #define WRITE_BUFFER_SIZE (128 * 1024)
75 static unsigned char *write_buffer
= NULL
;
76 static uint64_t cur_buffer_size
= 0;
77 static uint64_t cur_pos
= 0;
78 static uint64_t file_size
= 0;
79 static int new_file
= 0;
80 static int gcov_version
;
82 static HANDLE mmap_handle
= NULL
;
86 typedef void (*fn_ptr
)(void);
88 typedef void* dynamic_object_id
;
89 // The address of this variable identifies a given dynamic object.
90 static dynamic_object_id current_id
;
91 #define CURRENT_ID (¤t_id)
100 struct fn_node
*head
, *tail
;
104 * A list of functions to write out the data, shared between all dynamic objects.
106 struct fn_list writeout_fn_list
;
109 * A list of reset functions, shared between all dynamic objects.
111 struct fn_list reset_fn_list
;
113 static void fn_list_insert(struct fn_list
* list
, fn_ptr fn
) {
114 struct fn_node
* new_node
= malloc(sizeof(struct fn_node
));
116 new_node
->next
= NULL
;
117 new_node
->id
= CURRENT_ID
;
120 list
->head
= list
->tail
= new_node
;
122 list
->tail
->next
= new_node
;
123 list
->tail
= new_node
;
127 static void fn_list_remove(struct fn_list
* list
) {
128 struct fn_node
* curr
= list
->head
;
129 struct fn_node
* prev
= NULL
;
130 struct fn_node
* next
= NULL
;
135 if (curr
->id
== CURRENT_ID
) {
136 if (curr
== list
->head
) {
140 if (curr
== list
->tail
) {
157 static void resize_write_buffer(uint64_t size
) {
158 if (!new_file
) return;
160 if (size
<= cur_buffer_size
) return;
161 size
= (size
- 1) / WRITE_BUFFER_SIZE
+ 1;
162 size
*= WRITE_BUFFER_SIZE
;
163 write_buffer
= realloc(write_buffer
, size
);
164 cur_buffer_size
= size
;
167 static void write_bytes(const char *s
, size_t len
) {
168 resize_write_buffer(len
);
169 memcpy(&write_buffer
[cur_pos
], s
, len
);
173 static void write_32bit_value(uint32_t i
) {
174 write_bytes((char*)&i
, 4);
177 static void write_64bit_value(uint64_t i
) {
178 // GCOV uses a lo-/hi-word format even on big-endian systems.
179 // See also GCOVBuffer::readInt64 in LLVM.
180 uint32_t lo
= (uint32_t) i
;
181 uint32_t hi
= (uint32_t) (i
>> 32);
182 write_32bit_value(lo
);
183 write_32bit_value(hi
);
186 static uint32_t read_32bit_value(void) {
192 val
= *(uint32_t*)&write_buffer
[cur_pos
];
197 static uint64_t read_64bit_value(void) {
198 // GCOV uses a lo-/hi-word format even on big-endian systems.
199 // See also GCOVBuffer::readInt64 in LLVM.
200 uint32_t lo
= read_32bit_value();
201 uint32_t hi
= read_32bit_value();
202 return ((uint64_t)hi
<< 32) | ((uint64_t)lo
);
205 static char *mangle_filename(const char *orig_filename
) {
209 const char *prefix
= lprofGetPathPrefix(&prefix_strip
, &prefix_len
);
212 return strdup(orig_filename
);
214 new_filename
= malloc(prefix_len
+ 1 + strlen(orig_filename
) + 1);
215 lprofApplyPathPrefix(new_filename
, orig_filename
, prefix
, prefix_len
,
221 static int map_file(void) {
222 fseek(output_file
, 0L, SEEK_END
);
223 file_size
= ftell(output_file
);
225 /* A size of 0 means the file has been created just now (possibly by another
226 * process in lock-after-open race condition). No need to mmap. */
233 mmap_fd
= INVALID_HANDLE_VALUE
;
235 mmap_fd
= (HANDLE
)_get_osfhandle(fd
);
237 mmap_handle
= CreateFileMapping(mmap_fd
, NULL
, PAGE_READWRITE
, DWORD_HI(file_size
), DWORD_LO(file_size
), NULL
);
238 if (mmap_handle
== NULL
) {
239 fprintf(stderr
, "profiling: %s: cannot create file mapping: %lu\n",
240 filename
, GetLastError());
244 write_buffer
= MapViewOfFile(mmap_handle
, FILE_MAP_WRITE
, 0, 0, file_size
);
245 if (write_buffer
== NULL
) {
246 fprintf(stderr
, "profiling: %s: cannot map: %lu\n", filename
,
248 CloseHandle(mmap_handle
);
252 write_buffer
= mmap(0, file_size
, PROT_READ
| PROT_WRITE
,
253 MAP_FILE
| MAP_SHARED
, fd
, 0);
254 if (write_buffer
== (void *)-1) {
256 fprintf(stderr
, "profiling: %s: cannot map: %s\n", filename
,
265 static void unmap_file(void) {
267 if (!UnmapViewOfFile(write_buffer
)) {
268 fprintf(stderr
, "profiling: %s: cannot unmap mapped view: %lu\n", filename
,
272 if (!CloseHandle(mmap_handle
)) {
273 fprintf(stderr
, "profiling: %s: cannot close file mapping handle: %lu\n",
274 filename
, GetLastError());
279 if (munmap(write_buffer
, file_size
) == -1) {
281 fprintf(stderr
, "profiling: %s: cannot munmap: %s\n", filename
,
291 * --- LLVM line counter API ---
294 /* A file in this case is a translation unit. Each .o file built with line
295 * profiling enabled will emit to a different file. Only one file may be
298 COMPILER_RT_VISIBILITY
299 void llvm_gcda_start_file(const char *orig_filename
, uint32_t version
,
301 const char *mode
= "r+b";
302 filename
= mangle_filename(orig_filename
);
304 /* Try just opening the file. */
305 fd
= open(filename
, O_RDWR
| O_BINARY
);
308 /* Try creating the file. */
309 fd
= open(filename
, O_RDWR
| O_CREAT
| O_EXCL
| O_BINARY
, 0644);
313 /* Try creating the directories first then opening the file. */
314 __llvm_profile_recursive_mkdir(filename
);
315 fd
= open(filename
, O_RDWR
| O_CREAT
| O_EXCL
| O_BINARY
, 0644);
319 /* Another process may have created the file just now.
320 * Try opening it without O_CREAT and O_EXCL. */
321 fd
= open(filename
, O_RDWR
| O_BINARY
);
323 /* Bah! It's hopeless. */
325 fprintf(stderr
, "profiling: %s: cannot open: %s\n", filename
,
333 /* Try to flock the file to serialize concurrent processes writing out to the
334 * same GCDA. This can fail if the filesystem doesn't support it, but in that
335 * case we'll just carry on with the old racy behaviour and hope for the best.
338 output_file
= fdopen(fd
, mode
);
340 /* Initialize the write buffer. */
346 if (map_file() == -1) {
347 /* The file has been created just now (file_size == 0) or mmap failed
348 * unexpectedly. In the latter case, try to recover by clobbering. */
351 resize_write_buffer(WRITE_BUFFER_SIZE
);
352 memset(write_buffer
, 0, WRITE_BUFFER_SIZE
);
355 /* gcda file, version, stamp checksum. */
357 uint8_t c3
= version
>> 24;
358 uint8_t c2
= (version
>> 16) & 255;
359 uint8_t c1
= (version
>> 8) & 255;
360 gcov_version
= c3
>= 'A' ? (c3
- 'A') * 100 + (c2
- '0') * 10 + c1
- '0'
361 : (c3
- '0') * 10 + c1
- '0';
363 write_32bit_value(GCOV_DATA_MAGIC
);
364 write_32bit_value(version
);
365 write_32bit_value(checksum
);
367 #ifdef DEBUG_GCDAPROFILING
368 fprintf(stderr
, "llvmgcda: [%s]\n", orig_filename
);
372 COMPILER_RT_VISIBILITY
373 void llvm_gcda_emit_function(uint32_t ident
, uint32_t func_checksum
,
374 uint32_t cfg_checksum
) {
376 int use_extra_checksum
= gcov_version
>= 47;
378 if (use_extra_checksum
)
380 #ifdef DEBUG_GCDAPROFILING
381 fprintf(stderr
, "llvmgcda: function id=0x%08x\n", ident
);
383 if (!output_file
) return;
386 write_32bit_value(GCOV_TAG_FUNCTION
);
387 write_32bit_value(len
);
388 write_32bit_value(ident
);
389 write_32bit_value(func_checksum
);
390 if (use_extra_checksum
)
391 write_32bit_value(cfg_checksum
);
394 COMPILER_RT_VISIBILITY
395 void llvm_gcda_emit_arcs(uint32_t num_counters
, uint64_t *counters
) {
397 uint64_t *old_ctrs
= NULL
;
399 uint64_t save_cur_pos
= cur_pos
;
401 if (!output_file
) return;
403 val
= read_32bit_value();
405 if (val
!= (uint32_t)-1) {
406 /* There are counters present in the file. Merge them. */
407 if (val
!= GCOV_TAG_COUNTER_ARCS
) {
408 fprintf(stderr
, "profiling: %s: cannot merge previous GCDA file: "
409 "corrupt arc tag (0x%08x)\n",
414 val
= read_32bit_value();
415 if (val
== (uint32_t)-1 || val
/ 2 != num_counters
) {
416 fprintf(stderr
, "profiling: %s: cannot merge previous GCDA file: "
417 "mismatched number of counters (%d)\n",
422 old_ctrs
= malloc(sizeof(uint64_t) * num_counters
);
423 for (i
= 0; i
< num_counters
; ++i
)
424 old_ctrs
[i
] = read_64bit_value();
427 cur_pos
= save_cur_pos
;
429 /* Counter #1 (arcs) tag */
430 write_32bit_value(GCOV_TAG_COUNTER_ARCS
);
431 write_32bit_value(num_counters
* 2);
432 for (i
= 0; i
< num_counters
; ++i
) {
433 counters
[i
] += (old_ctrs
? old_ctrs
[i
] : 0);
434 write_64bit_value(counters
[i
]);
439 #ifdef DEBUG_GCDAPROFILING
440 fprintf(stderr
, "llvmgcda: %u arcs\n", num_counters
);
441 for (i
= 0; i
< num_counters
; ++i
)
442 fprintf(stderr
, "llvmgcda: %llu\n", (unsigned long long)counters
[i
]);
446 COMPILER_RT_VISIBILITY
447 void llvm_gcda_summary_info(void) {
449 static uint32_t run_counted
= 0; // We only want to increase the run count once.
451 uint64_t save_cur_pos
= cur_pos
;
453 if (!output_file
) return;
455 val
= read_32bit_value();
457 if (val
!= (uint32_t)-1) {
458 /* There are counters present in the file. Merge them. */
460 gcov_version
>= 90 ? GCOV_TAG_OBJECT_SUMMARY
: GCOV_TAG_PROGRAM_SUMMARY
;
461 if (val
!= gcov_tag
) {
463 "profiling: %s: cannot merge previous run count: "
464 "corrupt object tag (0x%08x)\n",
469 val
= read_32bit_value(); /* length */
471 if (gcov_version
< 90) {
474 prev_runs
= read_32bit_value();
476 prev_runs
= read_32bit_value();
479 for (uint32_t i
= gcov_version
< 90 ? 3 : 2; i
< val
; ++i
)
481 /* Add previous run count to new counter, if not already counted before. */
482 runs
= run_counted
? prev_runs
: prev_runs
+ 1;
485 cur_pos
= save_cur_pos
;
487 if (gcov_version
>= 90) {
488 write_32bit_value(GCOV_TAG_OBJECT_SUMMARY
);
489 write_32bit_value(2);
490 write_32bit_value(runs
);
491 write_32bit_value(0); // sum_max
493 // Before gcov 4.8 (r190952), GCOV_TAG_SUMMARY_LENGTH was 9. r190952 set
494 // GCOV_TAG_SUMMARY_LENGTH to 22. We simply use the smallest length which
495 // can make gcov read "Runs:".
496 write_32bit_value(GCOV_TAG_PROGRAM_SUMMARY
);
497 write_32bit_value(3);
498 write_32bit_value(0);
499 write_32bit_value(0);
500 write_32bit_value(runs
);
505 #ifdef DEBUG_GCDAPROFILING
506 fprintf(stderr
, "llvmgcda: %u runs\n", runs
);
510 COMPILER_RT_VISIBILITY
511 void llvm_gcda_end_file(void) {
512 /* Write out EOF record. */
514 write_bytes("\0\0\0\0\0\0\0\0", 8);
517 fwrite(write_buffer
, cur_pos
, 1, output_file
);
531 #ifdef DEBUG_GCDAPROFILING
532 fprintf(stderr
, "llvmgcda: -----\n");
536 COMPILER_RT_VISIBILITY
537 void llvm_register_writeout_function(fn_ptr fn
) {
538 fn_list_insert(&writeout_fn_list
, fn
);
541 COMPILER_RT_VISIBILITY
542 void llvm_writeout_files(void) {
543 struct fn_node
*curr
= writeout_fn_list
.head
;
546 if (curr
->id
== CURRENT_ID
) {
554 // __attribute__((destructor)) and destructors whose priorities are greater than
555 // 100 run before this function and can thus be tracked. The priority is
556 // compatible with GCC 7 onwards.
558 #pragma GCC diagnostic ignored "-Wprio-ctor-dtor"
560 __attribute__((destructor(100)))
562 static void llvm_writeout_and_clear(void) {
563 llvm_writeout_files();
564 fn_list_remove(&writeout_fn_list
);
567 COMPILER_RT_VISIBILITY
568 void llvm_register_reset_function(fn_ptr fn
) {
569 fn_list_insert(&reset_fn_list
, fn
);
572 COMPILER_RT_VISIBILITY
573 void llvm_delete_reset_function_list(void) { fn_list_remove(&reset_fn_list
); }
575 COMPILER_RT_VISIBILITY
576 void llvm_reset_counters(void) {
577 struct fn_node
*curr
= reset_fn_list
.head
;
580 if (curr
->id
== CURRENT_ID
) {
587 #if !defined(_WIN32) && !defined(__wasm__)
588 COMPILER_RT_VISIBILITY
589 pid_t
__gcov_fork() {
590 pid_t parent_pid
= getpid();
594 pid_t child_pid
= getpid();
595 if (child_pid
!= parent_pid
) {
596 // The pid changed so we've a fork (one could have its own fork function)
597 // Just reset the counters for this child process
599 llvm_reset_counters();
606 COMPILER_RT_VISIBILITY
607 void llvm_gcov_init(fn_ptr wfn
, fn_ptr rfn
) {
608 static int atexit_ran
= 0;
611 llvm_register_writeout_function(wfn
);
614 llvm_register_reset_function(rfn
);
616 if (atexit_ran
== 0) {
619 /* Make sure we write out the data and delete the data structures. */
620 lprofAtExit(llvm_delete_reset_function_list
);
622 lprofAtExit(llvm_writeout_and_clear
);
628 COMPILER_RT_VISIBILITY
__attribute__((constructor
)) void
629 __llvm_profile_gcov_initialize() {
630 const __llvm_gcov_init_func_struct
*InitFuncStart
=
631 __llvm_profile_begin_covinit();
632 const __llvm_gcov_init_func_struct
*InitFuncEnd
=
633 __llvm_profile_end_covinit();
635 for (const __llvm_gcov_init_func_struct
*Ptr
= InitFuncStart
;
636 Ptr
!= InitFuncEnd
; ++Ptr
) {
637 fn_ptr wfn
= (fn_ptr
)Ptr
->WriteoutFunction
;
638 fn_ptr rfn
= (fn_ptr
)Ptr
->ResetFunction
;
641 llvm_gcov_init(wfn
, rfn
);
646 void __gcov_dump(void) {
647 for (struct fn_node
*f
= writeout_fn_list
.head
; f
; f
= f
->next
)
651 void __gcov_reset(void) {
652 for (struct fn_node
*f
= reset_fn_list
.head
; f
; f
= f
->next
)