xref: /minix/minix/commands/gcov-pull/gcov-pull.c (revision 7f5f010b)
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   char buff[BUFF_SZ]; /* Buffer for all the metadata and file data sent */
36 
37   if(argc!=2 || sscanf(argv[1], "%d", &server_nr)!=1) {
38   	fprintf(stderr, "Usage: %s <pid>\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   /* visit complete buffer, so vm won't has to
56      manage the pages while flushing
57    */
58   memset(buff, 'a', sizeof(buff));
59 
60   buff_p = buff;
61 
62   result = gcov_flush_svr(buff_p, BUFF_SZ, server_nr);
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