xref: /minix3/minix/lib/libsys/gcov.c (revision 117b6ea00345c1559dda32fe246e18bcddea9322)
1  /* This code can be linked into minix servers that are compiled
2   * with gcc gcov flags.
3   * Author: Anton Kuijsten
4   */
5  
6  #include <lib.h>
7  #include <stdio.h>
8  #include <sys/types.h>
9  #include <stdlib.h>
10  #include <string.h>
11  #include <fcntl.h>
12  #include <sys/stat.h>
13  #include <unistd.h>
14  #include <assert.h>
15  #include <minix/syslib.h>
16  #include <minix/sysutil.h>
17  #include <minix/gcov.h>
18  
19  static endpoint_t endpt = NONE;   /* endpoint of requesting service, or NONE */
20  static cp_grant_id_t grant;    /* grant to write results into during request */
21  static int pos;                  /* data-buffer pointer from user space tool */
22  static int gcov_enable=0;     /* nothing will be done with gcov-data if zero */
23  static int gcov_buff_sz;                        /* size of user space buffer */
24  static FILE gcov_file;                      /* used as fopen() return value. */
25  static int gcov_opened;
26  
27  /* copies <size> bytes from <ptr> to <gcov_buff> */
28  static void add_buff(const void *ptr, int size)
29  {
30  	int r;
31  
32  	assert(endpt != NONE);
33  	assert(pos <= gcov_buff_sz);
34  
35  	if(pos+size > gcov_buff_sz) {
36  		size = pos - gcov_buff_sz;
37  	}
38  
39  	r = sys_safecopyto(endpt, grant, pos, (vir_bytes)ptr, size);
40  
41  	if(r) {
42  		printf("libsys: gcov: safecopy failed (%d)\n", r);
43    	}
44  
45  	pos += size;
46  
47  	assert(pos <= gcov_buff_sz);
48  }
49  
50  /* easy wrapper for add_buff */
51  static void add_int(int value)
52  {
53  	add_buff((void *) &value, sizeof(int));
54  }
55  
56  /* These functions are meant to replace standard file
57   * system calls (fopen, etc)
58   */
59  
60  FILE *_gcov_fopen(const char *name, const char *mode)
61  {
62  	if(!gcov_enable) return NULL;
63  
64  	assert(!gcov_opened);
65  
66  	/* write information to buffer */
67  	add_int(GCOVOP_OPEN);
68  	add_int(strlen(name)+1);
69          add_buff(name, strlen(name)+1);
70  
71  	gcov_opened = 1;
72  
73  	/* return dummy FILE *. */
74          return &gcov_file;
75  }
76  
77  
78  size_t _gcov_fread(void *ptr, size_t itemsize, size_t nitems, FILE *stream)
79  {
80          return 0;
81  }
82  
83  size_t _gcov_fwrite(const void *ptr, size_t itemsize, size_t nitems,
84  	FILE *stream)
85  {
86  	int size = itemsize * nitems;
87  
88  	if(!gcov_enable) return -1;
89  
90  	/* only have one file open at a time to ensure writes go
91  	 * to the right place.
92  	 */
93  	assert(gcov_opened);
94  	assert(stream == &gcov_file);
95  
96  	/* write information to buffer */
97  	add_int(GCOVOP_WRITE);
98  	add_int(size);
99  	add_buff(ptr, size);
100  
101          return nitems;
102  }
103  
104  int _gcov_fclose(FILE *stream)
105  {
106  	if(!gcov_enable) return EOF;
107  
108  	add_int(GCOVOP_CLOSE);
109  	assert(gcov_opened);
110  	gcov_opened = 0;
111          return 0;
112  }
113  
114  int _gcov_fseek(FILE *stream, long offset, int ptrname)
115  {
116          return 0;
117  }
118  
119  char *_gcov_getenv(const char *name)
120  {
121          return NULL;
122  }
123  
124  int gcov_flush(endpoint_t ep, cp_grant_id_t grantid, size_t bufsize)
125  {
126  	/* Initialize global state. */
127  	pos=0;
128  	endpt = ep;
129  	grant = grantid;
130  	gcov_buff_sz = bufsize;
131  	assert(!gcov_enable);
132  	assert(!gcov_opened);
133  	gcov_enable = 1;
134  
135  	/* Trigger copying.
136  	 * This function is not always available, but there is a do-nothing
137  	 * version in libc so that executables can be linked even without
138  	 * this code ever being activated.
139  	 */
140  	__gcov_flush();
141  
142  	/* Mark the end of the data, stop. */
143  	add_int(GCOVOP_END);
144  	assert(!gcov_opened);
145  	assert(gcov_enable);
146  	gcov_enable = 0;
147  	endpt = NONE;
148  
149  	/* Return number of bytes used in buffer. */
150  	return pos;
151  }
152  
153  /* This function can be called to perform the copying.
154   * It sends its own reply message and can thus be
155   * registered as a SEF * callback.
156   */
157  int do_gcov_flush_impl(message *msg)
158  {
159  	message replymsg;
160  	memset(&replymsg, 0, sizeof(replymsg));
161  
162  	assert(msg->m_type == COMMON_REQ_GCOV_DATA);
163  
164  	replymsg.m_type = gcov_flush(msg->m_source, msg->m_vfs_lsys_gcov.grant,
165  		msg->m_vfs_lsys_gcov.size);
166  	return ipc_send(msg->m_source, &replymsg);
167  }
168