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