xref: /minix3/minix/lib/libsys/gcov.c (revision 08cbf5a04d9d252f1eec34cb0fea3101e5fa9b88)
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