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