1 /* 2 * gcov-pull - Request gcov data from server and write it to gcda files 3 * Author: Anton Kuijsten 4 */ 5 6 #include <fcntl.h> 7 #include <stdio.h> 8 #include <lib.h> 9 #include <unistd.h> 10 #include <sys/types.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <assert.h> 14 #include <minix/gcov.h> 15 16 #define BUFF_SZ (4 * 1024 * 1024) /* 4MB */ 17 18 int read_int(void); 19 20 char *buff_p; 21 22 /* helper function to read int from the buffer */ 23 int read_int(void) 24 { 25 int res; 26 memcpy(&res, buff_p, sizeof(int)); 27 buff_p += sizeof(int); 28 return res; 29 } 30 31 int main(int argc, char *argv[]) 32 { 33 FILE *fd = NULL; 34 int server_nr, command, size, result; 35 static char buff[BUFF_SZ]; /* Buffer for all the metadata and file data */ 36 37 if (argc != 2) { 38 fprintf(stderr, "Usage: %s <label>\n", argv[0]); 39 return 1; 40 } 41 42 /* 43 When making a GCOV call to a server, the gcov library linked into 44 the server will try to write gcov data to disk. This writing is 45 normally done with calls to the vfs, using stdio library calls. 46 This is not correct behaviour for servers, especially vfs itself. 47 Therefore, the server catches those attempts. The messages used for 48 this communication are stored in a buffer. When the gcov operation 49 is done, the buffer is copied from the server to this user space, 50 from where the calls are finally made to the vfs. GCOV calls to the 51 various servers are all routed trough vfs. For more information, see 52 the <minix/gcov.h> header file. 53 */ 54 55 /* Fault in the complete buffer, so vm won't have to 56 manage the pages while flushing 57 */ 58 memset(buff, '\0', sizeof(buff)); 59 60 buff_p = buff; 61 62 result = gcov_flush_svr(argv[1], buff_p, BUFF_SZ); 63 64 if(result >= BUFF_SZ) { 65 fprintf(stderr, "Too much data to hold in buffer: %d\n", result); 66 fprintf(stderr, "Maximum: %d\n", BUFF_SZ); 67 return 1; 68 } 69 70 if(result < 0) { 71 fprintf(stderr, "Call failed\n"); 72 return 1; 73 } 74 75 /* At least GCOVOP_END opcode expected. */ 76 if(result < sizeof(int)) { 77 fprintf(stderr, "Invalid gcov data from pid %d\n", server_nr); 78 return 1; 79 } 80 81 /* Only GCOVOP_END is valid but empty. */ 82 if(result == sizeof(int)) { 83 fprintf(stderr, "no gcov data.\n"); 84 return 0; 85 } 86 87 /* Iterate through the system calls contained in the buffer, 88 * and execute them 89 */ 90 while((command=read_int()) != GCOVOP_END) { 91 char *fn; 92 switch(command) { 93 case GCOVOP_OPEN: 94 size = read_int(); 95 fn = buff_p; 96 if(strchr(fn, '/')) { 97 fn = strrchr(fn, '/'); 98 assert(fn); 99 fn++; 100 } 101 assert(fn); 102 if(!(fd = fopen(fn, "w+"))) { 103 perror(buff_p); 104 exit(1); 105 } 106 buff_p += size; 107 break; 108 case GCOVOP_CLOSE: 109 if(!fd) { 110 fprintf(stderr, "bogus close\n"); 111 exit(1); 112 } 113 fclose(fd); 114 fd = NULL; 115 break; 116 case GCOVOP_WRITE: 117 size = read_int(); 118 fwrite(buff_p, size, 1, fd); 119 buff_p += size; 120 break; 121 default: 122 fprintf(stderr, "bogus command %d in buffer.\n", 123 command); 124 exit(1); 125 } 126 } 127 128 return 0; 129 } 130