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