1 /* This code can be linked into minix servers that are compiled 2 * with gcc gcov flags. 3 * Author: Anton Kuijsten 4 */ 5 6 #include <lib.h> 7 #include <stdio.h> 8 #include <sys/types.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <fcntl.h> 12 #include <sys/stat.h> 13 #include <unistd.h> 14 #include <assert.h> 15 #include <minix/syslib.h> 16 #include <minix/gcov.h> 17 18 static int grant, pos; /* data-buffer pointer from user space tool */ 19 static int gcov_enable=0; /* nothing will be done with gcov-data if zero */ 20 static int gcov_buff_sz; /* size of user space buffer */ 21 static FILE gcov_file; /* used as fopen() return value. */ 22 static int gcov_opened; 23 24 /* copies <size> bytes from <ptr> to <gcov_buff> */ 25 static void add_buff(void *ptr, int size) 26 { 27 int r; 28 assert(pos <= gcov_buff_sz); 29 30 if(pos+size > gcov_buff_sz) { 31 size = pos - gcov_buff_sz; 32 } 33 34 r = sys_safecopyto(VFS_PROC_NR, grant, pos, (vir_bytes)ptr, size); 35 36 if(r) { 37 printf("libsys: gcov: safecopy failed (%d)\n", r); 38 } 39 40 pos += size; 41 42 assert(pos <= gcov_buff_sz); 43 } 44 45 /* easy wrapper for add_buff */ 46 static void add_int(int value) 47 { 48 add_buff((void *) &value, sizeof(int)); 49 } 50 51 /* These functions are meant to replace standard file 52 * system calls (fopen, etc) 53 */ 54 55 FILE *_gcov_fopen(char *name, char *mode) 56 { 57 if(!gcov_enable) return NULL; 58 59 assert(!gcov_opened); 60 61 /* write information to buffer */ 62 add_int(GCOVOP_OPEN); 63 add_int(strlen(name)+1); 64 add_buff(name, strlen(name)+1); 65 66 gcov_opened = 1; 67 68 /* return dummy FILE *. */ 69 return &gcov_file; 70 } 71 72 73 size_t _gcov_fread(void *ptr, size_t itemsize, size_t nitems, FILE *stream) 74 { 75 return 0; 76 } 77 78 size_t _gcov_fwrite(void *ptr, size_t itemsize, size_t nitems, FILE *stream) 79 { 80 int size = itemsize * nitems; 81 82 if(!gcov_enable) return -1; 83 84 /* only have one file open at a time to ensure writes go 85 * to the right place. 86 */ 87 assert(gcov_opened); 88 assert(stream == &gcov_file); 89 90 /* write information to buffer */ 91 add_int(GCOVOP_WRITE); 92 add_int(size); 93 add_buff(ptr, size); 94 95 return nitems; 96 } 97 98 int _gcov_fclose(FILE *stream) 99 { 100 if(!gcov_enable) return EOF; 101 102 add_int(GCOVOP_CLOSE); 103 assert(gcov_opened); 104 gcov_opened = 0; 105 return 0; 106 } 107 108 int _gcov_fseek(FILE *stream, long offset, int ptrname) 109 { 110 return 0; 111 } 112 113 char *_gcov_getenv(const char *name) 114 { 115 return NULL; 116 } 117 118 int gcov_flush(cp_grant_id_t grantid, int bufsize) 119 { 120 /* Initialize global state. */ 121 pos=0; 122 grant = grantid; 123 gcov_buff_sz = bufsize; 124 assert(!gcov_enable); 125 assert(!gcov_opened); 126 gcov_enable = 1; 127 128 /* Trigger copying. 129 * This function is not always available, but there is a do-nothing 130 * version in libc so that executables can be linked even without 131 * this code ever being activated. 132 */ 133 __gcov_flush(); 134 135 /* Mark the end of the data, stop. */ 136 add_int(GCOVOP_END); 137 assert(!gcov_opened); 138 assert(gcov_enable); 139 gcov_enable = 0; 140 141 /* Return number of bytes used in buffer. */ 142 return pos; 143 } 144 145 /* This function can be called to perform the copying. 146 * It sends its own reply message and can thus be 147 * registered as a SEF * callback. 148 */ 149 int do_gcov_flush_impl(message *msg) 150 { 151 message replymsg; 152 memset(&replymsg, 0, sizeof(replymsg)); 153 154 assert(msg->m_type == COMMON_REQ_GCOV_DATA); 155 assert(msg->m_source == VFS_PROC_NR); 156 157 replymsg.m_type = gcov_flush(msg->m_lc_vfs_gcov.grant, 158 msg->m_lc_vfs_gcov.buff_sz); 159 return ipc_send(msg->m_source, &replymsg); 160 } 161 162