minix/lib/libsys/gcov.c
2010-09-13 15:50:54 +00:00

161 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_fd=0; /* file descriptor for writing gcov data */
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, D);
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 NULL;
/* 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->GCOV_GRANT, msg->GCOV_BUFF_SZ);
return send(msg->m_source, &replymsg);
}