xref: /minix3/minix/commands/gcov-pull/gcov-pull.c (revision 3ac58492b3d3709bad0ae9c60a137f63a90960b7)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * gcov-pull - Request gcov data from server and write it to gcda files
3433d6423SLionel Sambuc  * Author: Anton Kuijsten
4433d6423SLionel Sambuc */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include <fcntl.h>
7433d6423SLionel Sambuc #include <stdio.h>
8433d6423SLionel Sambuc #include <lib.h>
9433d6423SLionel Sambuc #include <unistd.h>
10433d6423SLionel Sambuc #include <sys/types.h>
11433d6423SLionel Sambuc #include <stdlib.h>
12433d6423SLionel Sambuc #include <string.h>
13433d6423SLionel Sambuc #include <assert.h>
14433d6423SLionel Sambuc #include <minix/gcov.h>
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #define BUFF_SZ (4 * 1024 * 1024)	/* 4MB */
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc int read_int(void);
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc char *buff_p;
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc /* helper function to read int from the buffer */
read_int(void)23433d6423SLionel Sambuc int read_int(void)
24433d6423SLionel Sambuc {
25433d6423SLionel Sambuc 	int res;
26433d6423SLionel Sambuc 	memcpy(&res, buff_p, sizeof(int));
27433d6423SLionel Sambuc 	buff_p += sizeof(int);
28433d6423SLionel Sambuc 	return res;
29433d6423SLionel Sambuc }
30433d6423SLionel Sambuc 
main(int argc,char * argv[])31433d6423SLionel Sambuc int main(int argc, char *argv[])
32433d6423SLionel Sambuc {
33433d6423SLionel Sambuc   FILE *fd = NULL;
34433d6423SLionel Sambuc   int server_nr, command, size, result;
35*3ac58492SDavid van Moolenbroek   static char buff[BUFF_SZ]; /* Buffer for all the metadata and file data */
36433d6423SLionel Sambuc 
37*3ac58492SDavid van Moolenbroek   if (argc != 2) {
38*3ac58492SDavid van Moolenbroek 	fprintf(stderr, "Usage: %s <label>\n", argv[0]);
39433d6423SLionel Sambuc 	return 1;
40433d6423SLionel Sambuc   }
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc   /*
43433d6423SLionel Sambuc     When making a GCOV call to a server, the gcov library linked into
44433d6423SLionel Sambuc     the server will try to write gcov data to disk. This  writing is
45433d6423SLionel Sambuc     normally done with calls to the vfs,  using stdio library calls.
46433d6423SLionel Sambuc     This is not correct behaviour for servers, especially vfs itself.
47433d6423SLionel Sambuc     Therefore, the server catches those attempts.  The messages used for
48433d6423SLionel Sambuc     this communication are stored in a buffer. When the gcov operation
49433d6423SLionel Sambuc     is  done, the buffer is copied from the server to this user space,
50433d6423SLionel Sambuc     from where the calls are finally made to the vfs. GCOV calls to the
51433d6423SLionel Sambuc     various servers are all routed trough vfs. For more information, see
52433d6423SLionel Sambuc     the <minix/gcov.h> header file.
53433d6423SLionel Sambuc   */
54433d6423SLionel Sambuc 
55*3ac58492SDavid van Moolenbroek   /* Fault in the complete buffer, so vm won't have to
56433d6423SLionel Sambuc      manage the pages while flushing
57433d6423SLionel Sambuc    */
58*3ac58492SDavid van Moolenbroek   memset(buff, '\0', sizeof(buff));
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc   buff_p = buff;
61433d6423SLionel Sambuc 
62*3ac58492SDavid van Moolenbroek   result = gcov_flush_svr(argv[1], buff_p, BUFF_SZ);
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc   if(result >= BUFF_SZ) {
65433d6423SLionel Sambuc     fprintf(stderr, "Too much data to hold in buffer: %d\n", result);
66433d6423SLionel Sambuc     fprintf(stderr, "Maximum: %d\n", BUFF_SZ);
67433d6423SLionel Sambuc     return 1;
68433d6423SLionel Sambuc   }
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc   if(result < 0) {
71433d6423SLionel Sambuc     fprintf(stderr, "Call failed\n");
72433d6423SLionel Sambuc     return 1;
73433d6423SLionel Sambuc   }
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc   /* At least GCOVOP_END opcode expected. */
76433d6423SLionel Sambuc   if(result < sizeof(int)) {
77433d6423SLionel Sambuc     fprintf(stderr, "Invalid gcov data from pid %d\n", server_nr);
78433d6423SLionel Sambuc     return 1;
79433d6423SLionel Sambuc   }
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc   /* Only GCOVOP_END is valid but empty. */
82433d6423SLionel Sambuc   if(result == sizeof(int)) {
83433d6423SLionel Sambuc     fprintf(stderr, "no gcov data.\n");
84433d6423SLionel Sambuc     return 0;
85433d6423SLionel Sambuc   }
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc   /* Iterate through the system calls contained in the buffer,
88433d6423SLionel Sambuc    * and execute them
89433d6423SLionel Sambuc    */
90433d6423SLionel Sambuc   while((command=read_int()) != GCOVOP_END) {
91433d6423SLionel Sambuc   	char *fn;
92433d6423SLionel Sambuc 	switch(command) {
93433d6423SLionel Sambuc 		case GCOVOP_OPEN:
94433d6423SLionel Sambuc 			size = read_int();
95433d6423SLionel Sambuc 			fn = buff_p;
96433d6423SLionel Sambuc 			if(strchr(fn, '/')) {
97433d6423SLionel Sambuc 				fn = strrchr(fn, '/');
98433d6423SLionel Sambuc 				assert(fn);
99433d6423SLionel Sambuc 				fn++;
100433d6423SLionel Sambuc 			}
101433d6423SLionel Sambuc 			assert(fn);
102433d6423SLionel Sambuc 			if(!(fd = fopen(fn, "w+"))) {
103433d6423SLionel Sambuc 				perror(buff_p);
104433d6423SLionel Sambuc 				exit(1);
105433d6423SLionel Sambuc 			}
106433d6423SLionel Sambuc 			buff_p += size;
107433d6423SLionel Sambuc 			break;
108433d6423SLionel Sambuc 		case GCOVOP_CLOSE:
109433d6423SLionel Sambuc 			if(!fd) {
110433d6423SLionel Sambuc 				fprintf(stderr, "bogus close\n");
111433d6423SLionel Sambuc 				exit(1);
112433d6423SLionel Sambuc 			}
113433d6423SLionel Sambuc 			fclose(fd);
114433d6423SLionel Sambuc 			fd = NULL;
115433d6423SLionel Sambuc 			break;
116433d6423SLionel Sambuc 		case GCOVOP_WRITE:
117433d6423SLionel Sambuc 			size = read_int();
118433d6423SLionel Sambuc 			fwrite(buff_p, size, 1, fd);
119433d6423SLionel Sambuc 			buff_p += size;
120433d6423SLionel Sambuc 			break;
121433d6423SLionel Sambuc 		default:
122433d6423SLionel Sambuc 			fprintf(stderr, "bogus command %d in buffer.\n",
123433d6423SLionel Sambuc 				command);
124433d6423SLionel Sambuc 			exit(1);
125433d6423SLionel Sambuc 	}
126433d6423SLionel Sambuc   }
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc   return 0;
129433d6423SLionel Sambuc }
130