162 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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/gcov.h>
 | 
						|
 | 
						|
static int grant, 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(void *ptr, int size)
 | 
						|
{
 | 
						|
	int r;
 | 
						|
	assert(pos <= gcov_buff_sz);
 | 
						|
 | 
						|
	if(pos+size > gcov_buff_sz) {
 | 
						|
		size = pos - gcov_buff_sz;
 | 
						|
	}
 | 
						|
 | 
						|
	r = sys_safecopyto(VFS_PROC_NR, 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(char *name, 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(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(cp_grant_id_t grantid, int bufsize)
 | 
						|
{
 | 
						|
	/* Initialize global state. */
 | 
						|
	pos=0;
 | 
						|
	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;
 | 
						|
 | 
						|
	/* 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);
 | 
						|
	assert(msg->m_source == VFS_PROC_NR);
 | 
						|
 | 
						|
	replymsg.m_type = gcov_flush(msg->m_lc_vfs_gcov.grant,
 | 
						|
		msg->m_lc_vfs_gcov.buff_sz);
 | 
						|
	return ipc_send(msg->m_source, &replymsg);
 | 
						|
}
 | 
						|
 |