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