gcov-glue.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <stdint.h> 4 #include <bootstate.h> 5 #include <cbmem.h> 6 7 typedef struct file { 8 uint32_t magic; 9 struct file *next; 10 char *filename; 11 char *data; 12 int offset; 13 int len; 14 } FILE; 15 16 #define SEEK_SET 0 /* Seek from beginning of file. */ 17 18 #define DIR_SEPARATOR '/' 19 #define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) 20 #define HAS_DRIVE_SPEC(f) (0) 21 22 #define COVERAGE_SIZE (32*1024) 23 24 #define COVERAGE_MAGIC 0x584d4153 25 26 static FILE *current_file = NULL; 27 static FILE *previous_file = NULL; 28 29 static FILE *fopen(const char *path, const char *mode) 30 { 31 #if CONFIG(DEBUG_COVERAGE) 32 printk(BIOS_DEBUG, "%s %s with mode %s\n", __func__, path, mode); 33 #endif 34 if (!current_file) { 35 current_file = cbmem_add(CBMEM_ID_COVERAGE, 32*1024); 36 } else { 37 previous_file = current_file; 38 current_file = 39 (FILE *)(ALIGN_UP(((unsigned long)previous_file->data 40 + previous_file->len), 16)); 41 } 42 43 // TODO check if we're at the end of the CBMEM region (ENOMEM) 44 if (current_file) { 45 current_file->magic = COVERAGE_MAGIC; 46 current_file->next = NULL; 47 if (previous_file) 48 previous_file->next = current_file; 49 current_file->filename = (char *)¤t_file[1]; 50 strcpy(current_file->filename, path); 51 current_file->data = 52 (char *)ALIGN_UP(((unsigned long)current_file->filename 53 + strlen(path) + 1), 16); 54 current_file->offset = 0; 55 current_file->len = 0; 56 } 57 58 return current_file; 59 } 60 61 static int fclose(FILE *stream) 62 { 63 #if CONFIG(DEBUG_COVERAGE) 64 printk(BIOS_DEBUG, "%s %s\n", __func__, stream->filename); 65 #endif 66 return 0; 67 } 68 69 static int fseek(FILE *stream, long offset, int whence) 70 { 71 /* fseek should only be called with offset==0 and whence==SEEK_SET 72 * to a freshly opened file. */ 73 gcc_assert(offset == 0 && whence == SEEK_SET); 74 #if CONFIG(DEBUG_COVERAGE) 75 printk(BIOS_DEBUG, "%s %s offset=%ld whence=%d\n", 76 __func__, stream->filename, offset, whence); 77 #endif 78 return 0; 79 } 80 81 static long ftell(FILE *stream) 82 { 83 /* ftell should currently not be called */ 84 BUG(); 85 #if CONFIG(DEBUG_COVERAGE) 86 printk(BIOS_DEBUG, "%s %s\n", __func__, stream->filename); 87 #endif 88 return 0; 89 } 90 91 static size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 92 { 93 #if CONFIG(DEBUG_COVERAGE) 94 printk(BIOS_DEBUG, "%s: ptr=%p size=%zd nmemb=%zd FILE*=%p\n", 95 __func__, ptr, size, nmemb, stream); 96 #endif 97 return 0; 98 } 99 100 static size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 101 { 102 #if CONFIG(DEBUG_COVERAGE) 103 printk(BIOS_DEBUG, "%s: %zd * %zd bytes to file %s\n", 104 __func__, nmemb, size, stream->filename); 105 #endif 106 // TODO check if file is last opened file and fail otherwise. 107 108 memcpy(stream->data + stream->offset, ptr, size * nmemb); 109 stream->len += (nmemb * size) - (stream->len - stream->offset); 110 stream->offset += nmemb * size; 111 return nmemb; 112 } 113 114 static void setbuf(FILE *stream, char *buf) 115 { 116 gcc_assert(buf == 0); 117 } 118 119 static void coverage_init(void *unused) 120 { 121 extern long __CTOR_LIST__; 122 typedef void (*func_ptr)(void); 123 func_ptr *ctor = (func_ptr *) &__CTOR_LIST__; 124 if (ctor == NULL) 125 return; 126 127 for (; *ctor != (func_ptr) 0; ctor++) 128 (*ctor)(); 129 } 130 131 void __gcov_flush(void); 132 static void coverage_exit(void *unused) 133 { 134 #if CONFIG(DEBUG_COVERAGE) 135 printk(BIOS_DEBUG, "Syncing coverage data.\n"); 136 #endif 137 __gcov_flush(); 138 } 139 140 BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, coverage_init, NULL); 141 BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, coverage_exit, NULL); 142 BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, coverage_exit, NULL);