summaryrefslogtreecommitdiff
path: root/minix/lib/libsys/gcov.c
blob: ae3857e50015883c54b9c62adb51dff97212f54a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* This code can be linked into minix servers that are compiled 
 * with gcc gcov flags.
 * Author: Anton Kuijsten
 */

#include <lib.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/gcov.h>

static endpoint_t endpt = NONE;   /* endpoint of requesting service, or NONE */
static cp_grant_id_t grant;    /* grant to write results into during request */
static int pos;                  /* data-buffer pointer from user space tool */
static int gcov_enable=0;     /* nothing will be done with gcov-data if zero */
static int gcov_buff_sz;                        /* size of user space buffer */
static FILE gcov_file;                      /* used as fopen() return value. */
static int gcov_opened;

/* copies <size> bytes from <ptr> to <gcov_buff> */
static void add_buff(const void *ptr, int size)
{
	int r;

	assert(endpt != NONE);
	assert(pos <= gcov_buff_sz);

	if(pos+size > gcov_buff_sz) {
		size = pos - gcov_buff_sz;
	}

	r = sys_safecopyto(endpt, grant, pos, (vir_bytes)ptr, size);

	if(r) {
		printf("libsys: gcov: safecopy failed (%d)\n", r);
  	}

	pos += size;

	assert(pos <= gcov_buff_sz);
}

/* easy wrapper for add_buff */
static void add_int(int value)
{
	add_buff((void *) &value, sizeof(int));
}

/* These functions are meant to replace standard file 
 * system calls (fopen, etc)
 */

FILE *_gcov_fopen(const char *name, const char *mode)
{
	if(!gcov_enable) return NULL;

	assert(!gcov_opened);

	/* write information to buffer */
	add_int(GCOVOP_OPEN);
	add_int(strlen(name)+1);
        add_buff(name, strlen(name)+1);

	gcov_opened = 1;

	/* return dummy FILE *. */
        return &gcov_file;
}


size_t _gcov_fread(void *ptr, size_t itemsize, size_t nitems, FILE *stream)
{
        return 0;
}

size_t _gcov_fwrite(const void *ptr, size_t itemsize, size_t nitems,
	FILE *stream)
{
	int size = itemsize * nitems;

	if(!gcov_enable) return -1;

	/* only have one file open at a time to ensure writes go
	 * to the right place.
	 */
	assert(gcov_opened);
	assert(stream == &gcov_file);

	/* write information to buffer */
	add_int(GCOVOP_WRITE);
	add_int(size);
	add_buff(ptr, size);

        return nitems;
}

int _gcov_fclose(FILE *stream)
{
	if(!gcov_enable) return EOF;

	add_int(GCOVOP_CLOSE);
	assert(gcov_opened);
	gcov_opened = 0;
        return 0;
}

int _gcov_fseek(FILE *stream, long offset, int ptrname)
{
        return 0;
}

char *_gcov_getenv(const char *name)
{
        return NULL;
}

int gcov_flush(endpoint_t ep, cp_grant_id_t grantid, size_t bufsize)
{
	/* Initialize global state. */
	pos=0;
	endpt = ep;
	grant = grantid;
	gcov_buff_sz = bufsize;
	assert(!gcov_enable);
	assert(!gcov_opened);
	gcov_enable = 1;

	/* Trigger copying.
	 * This function is not always available, but there is a do-nothing
	 * version in libc so that executables can be linked even without
	 * this code ever being activated.
	 */
	__gcov_flush();

	/* Mark the end of the data, stop. */
	add_int(GCOVOP_END);	 
	assert(!gcov_opened);
	assert(gcov_enable);
	gcov_enable = 0;
	endpt = NONE;

	/* Return number of bytes used in buffer. */
	return pos;
}

/* This function can be called to perform the copying.
 * It sends its own reply message and can thus be
 * registered as a SEF * callback.
 */
int do_gcov_flush_impl(message *msg)
{
	message replymsg;
	memset(&replymsg, 0, sizeof(replymsg));

	assert(msg->m_type == COMMON_REQ_GCOV_DATA);

	replymsg.m_type = gcov_flush(msg->m_source, msg->m_vfs_lsys_gcov.grant,
		msg->m_vfs_lsys_gcov.size);
	return ipc_send(msg->m_source, &replymsg);
}