xref: /minix3/minix/commands/gcov-pull/gcov-pull.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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