gcov support, based on work contributed by Anton Kuijsten.
This commit is contained in:
parent
d8466ce31f
commit
5d6c2aae0a
23 changed files with 504 additions and 9 deletions
|
@ -12,7 +12,7 @@ SUBDIR= aal add_route adduser advent arp ash at autil awk \
|
||||||
dhrystone diff dirname dis88 diskctl du dumpcore easypack \
|
dhrystone diff dirname dis88 diskctl du dumpcore easypack \
|
||||||
ed eject elle elvis env expand factor file \
|
ed eject elle elvis env expand factor file \
|
||||||
find finger fingerd fix fold format fortune fsck.mfs \
|
find finger fingerd fix fold format fortune fsck.mfs \
|
||||||
fsck1 ftp101 ftpd200 getty grep gomoku head host \
|
fsck1 ftp101 ftpd200 gcov-pull getty grep gomoku head host \
|
||||||
hostaddr id ifconfig ifdef indent install \
|
hostaddr id ifconfig ifdef indent install \
|
||||||
intr ipcrm ipcs irdpd isoread join kill last leave \
|
intr ipcrm ipcs irdpd isoread join kill last leave \
|
||||||
less lex life loadkeys loadramdisk logger login look lp \
|
less lex life loadkeys loadramdisk logger login look lp \
|
||||||
|
|
4
commands/gcov-pull/Makefile
Normal file
4
commands/gcov-pull/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
PROG=gcov-pull
|
||||||
|
MAN=
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
131
commands/gcov-pull/gcov-pull.c
Normal file
131
commands/gcov-pull/gcov-pull.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* gcov-pull - Request gcov data from server and write it to gcda files
|
||||||
|
* Author: Anton Kuijsten
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <minix/gcov.h>
|
||||||
|
|
||||||
|
#define BUFF_SZ (4 * 1024 * 1024) /* 4MB */
|
||||||
|
|
||||||
|
int read_int(void);
|
||||||
|
|
||||||
|
char *buff_p;
|
||||||
|
|
||||||
|
/* helper function to read int from the buffer */
|
||||||
|
int read_int(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
memcpy(&res, buff_p, sizeof(int));
|
||||||
|
buff_p += sizeof(int);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fd = NULL;
|
||||||
|
int i, server_nr, command, size, result;
|
||||||
|
char buff[BUFF_SZ]; /* Buffer for all the metadata and file data sent */
|
||||||
|
message msg; /* message sent to vfs */
|
||||||
|
|
||||||
|
if(argc!=2 || sscanf(argv[1], "%d", &server_nr)!=1) {
|
||||||
|
fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
When making a GCOV call to a server, the gcov library linked into
|
||||||
|
the server will try to write gcov data to disk. This writing is
|
||||||
|
normally done with calls to the vfs, using stdio library calls.
|
||||||
|
This is not correct behaviour for servers, especially vfs itself.
|
||||||
|
Therefore, the server catches those attempts. The messages used for
|
||||||
|
this communication are stored in a buffer. When the gcov operation
|
||||||
|
is done, the buffer is copied from the server to this user space,
|
||||||
|
from where the calls are finally made to the vfs. GCOV calls to the
|
||||||
|
various servers are all routed trough vfs. For more information, see
|
||||||
|
the <minix/gcov.h> header file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* visit complete buffer, so vm won't has to
|
||||||
|
manage the pages while flushing
|
||||||
|
*/
|
||||||
|
memset(buff, 'a', sizeof(buff));
|
||||||
|
|
||||||
|
buff_p = buff;
|
||||||
|
|
||||||
|
result = gcov_flush_svr(buff_p, BUFF_SZ, server_nr);
|
||||||
|
|
||||||
|
if(result >= BUFF_SZ) {
|
||||||
|
fprintf(stderr, "Too much data to hold in buffer: %d\n", result);
|
||||||
|
fprintf(stderr, "Maximum: %d\n", BUFF_SZ);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
fprintf(stderr, "Call failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At least GCOVOP_END opcode expected. */
|
||||||
|
if(result < sizeof(int)) {
|
||||||
|
fprintf(stderr, "Invalid gcov data from pid %d\n", server_nr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only GCOVOP_END is valid but empty. */
|
||||||
|
if(result == sizeof(int)) {
|
||||||
|
fprintf(stderr, "no gcov data.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate through the system calls contained in the buffer,
|
||||||
|
* and execute them
|
||||||
|
*/
|
||||||
|
while((command=read_int()) != GCOVOP_END) {
|
||||||
|
char *fn;
|
||||||
|
switch(command) {
|
||||||
|
case GCOVOP_OPEN:
|
||||||
|
size = read_int();
|
||||||
|
fn = buff_p;
|
||||||
|
if(strchr(fn, '/')) {
|
||||||
|
fn = strrchr(fn, '/');
|
||||||
|
assert(fn);
|
||||||
|
fn++;
|
||||||
|
}
|
||||||
|
assert(fn);
|
||||||
|
if(!(fd = fopen(fn, "w+"))) {
|
||||||
|
perror(buff_p);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
buff_p += size;
|
||||||
|
break;
|
||||||
|
case GCOVOP_CLOSE:
|
||||||
|
if(!fd) {
|
||||||
|
fprintf(stderr, "bogus close\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
fd = NULL;
|
||||||
|
break;
|
||||||
|
case GCOVOP_WRITE:
|
||||||
|
size = read_int();
|
||||||
|
fwrite(buff_p, size, 1, fd);
|
||||||
|
buff_p += size;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "bogus command %d in buffer.\n",
|
||||||
|
command);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ INCS+= minix/a.out.h minix/bitmap.h minix/callnr.h minix/cdrom.h \
|
||||||
minix/rs.h minix/safecopies.h minix/sched.h minix/sef.h minix/sound.h \
|
minix/rs.h minix/safecopies.h minix/sched.h minix/sef.h minix/sound.h \
|
||||||
minix/spin.h minix/sys_config.h minix/sysinfo.h minix/syslib.h \
|
minix/spin.h minix/sys_config.h minix/sysinfo.h minix/syslib.h \
|
||||||
minix/sysutil.h minix/timers.h minix/tty.h minix/type.h minix/types.h \
|
minix/sysutil.h minix/timers.h minix/tty.h minix/type.h minix/types.h \
|
||||||
minix/u64.h minix/vfsif.h minix/vm.h minix/vtreefs.h \
|
minix/u64.h minix/vfsif.h minix/vm.h minix/vtreefs.h minix/gcov.h \
|
||||||
minix/compiler.h minix/compiler-ack.h minix/sha2.h minix/sha1.h minix/md5.h \
|
minix/compiler.h minix/compiler-ack.h minix/sha2.h minix/sha1.h minix/md5.h \
|
||||||
minix/audio_fw.h
|
minix/audio_fw.h
|
||||||
INCS+= net/hton.h net/if.h net/ioctl.h net/netlib.h
|
INCS+= net/hton.h net/if.h net/ioctl.h net/netlib.h
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#define NCALLS 112 /* number of system calls allowed */
|
#define NCALLS 113 /* number of system calls allowed */
|
||||||
|
|
||||||
#define EXIT 1
|
#define EXIT 1
|
||||||
#define FORK 2
|
#define FORK 2
|
||||||
|
@ -113,6 +113,8 @@
|
||||||
*/
|
*/
|
||||||
#define SRV_KILL 111 /* to PM: special kill call for RS */
|
#define SRV_KILL 111 /* to PM: special kill call for RS */
|
||||||
|
|
||||||
|
#define GCOV_FLUSH 112 /* flush gcov data from server to gcov files */
|
||||||
|
|
||||||
#define TASK_REPLY 121 /* to VFS: reply code from drivers, not
|
#define TASK_REPLY 121 /* to VFS: reply code from drivers, not
|
||||||
* really a standalone call.
|
* really a standalone call.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -864,8 +864,6 @@
|
||||||
* Miscellaneous field names *
|
* Miscellaneous field names *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
||||||
#define COMMON_RQ_BASE 0xE00
|
|
||||||
|
|
||||||
/* PM field names */
|
/* PM field names */
|
||||||
/* BRK */
|
/* BRK */
|
||||||
#define PMBRK_ADDR m1_p1
|
#define PMBRK_ADDR m1_p1
|
||||||
|
@ -891,10 +889,19 @@
|
||||||
#define SEL_ERRORFDS m8_p3
|
#define SEL_ERRORFDS m8_p3
|
||||||
#define SEL_TIMEOUT m8_p4
|
#define SEL_TIMEOUT m8_p4
|
||||||
|
|
||||||
|
#define COMMON_RQ_BASE 0xE00
|
||||||
|
|
||||||
/* Field names for system signals (sent by a signal manager). */
|
/* Field names for system signals (sent by a signal manager). */
|
||||||
#define SIGS_SIGNAL_RECEIVED (COMMON_RQ_BASE+0)
|
#define SIGS_SIGNAL_RECEIVED (COMMON_RQ_BASE+0)
|
||||||
# define SIGS_SIG_NUM m2_i1
|
# define SIGS_SIG_NUM m2_i1
|
||||||
|
|
||||||
|
/* Common request to all processes: gcov data. */
|
||||||
|
#define COMMON_REQ_GCOV_DATA (COMMON_RQ_BASE+1)
|
||||||
|
# define GCOV_GRANT m1_i2
|
||||||
|
# define GCOV_PID m1_i3
|
||||||
|
# define GCOV_BUFF_P m1_p1
|
||||||
|
# define GCOV_BUFF_SZ m1_i1
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Messages for VM server *
|
* Messages for VM server *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
16
include/minix/gcov.h
Normal file
16
include/minix/gcov.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <minix/syslib.h>
|
||||||
|
|
||||||
|
/* opcodes for use in gcov buffer */
|
||||||
|
#define GCOVOP_OPEN 23
|
||||||
|
#define GCOVOP_WRITE 24
|
||||||
|
#define GCOVOP_CLOSE 25
|
||||||
|
#define GCOVOP_END 26
|
||||||
|
|
||||||
|
/* More information on the GCOV Minix Wiki page. */
|
||||||
|
|
||||||
|
int gcov_flush_svr(char *buff, int buff_sz, int server_nr);
|
||||||
|
extern void __gcov_flush (void);
|
||||||
|
int do_gcov_flush_impl(message *msg);
|
|
@ -199,10 +199,12 @@ _PROTOTYPE( int sef_cb_lu_response_rs_reply, (message *m_ptr) );
|
||||||
/* Callback type definitions. */
|
/* Callback type definitions. */
|
||||||
typedef void(*sef_cb_signal_handler_t)(int signo);
|
typedef void(*sef_cb_signal_handler_t)(int signo);
|
||||||
typedef int(*sef_cb_signal_manager_t)(endpoint_t target, int signo);
|
typedef int(*sef_cb_signal_manager_t)(endpoint_t target, int signo);
|
||||||
|
typedef int(*sef_cb_gcov_t)(message *msg);
|
||||||
|
|
||||||
/* Callback registration helpers. */
|
/* Callback registration helpers. */
|
||||||
_PROTOTYPE( void sef_setcb_signal_handler, (sef_cb_signal_handler_t cb));
|
_PROTOTYPE( void sef_setcb_signal_handler, (sef_cb_signal_handler_t cb));
|
||||||
_PROTOTYPE( void sef_setcb_signal_manager, (sef_cb_signal_manager_t cb));
|
_PROTOTYPE( void sef_setcb_signal_manager, (sef_cb_signal_manager_t cb));
|
||||||
|
_PROTOTYPE( void sef_setcb_gcov, (sef_cb_gcov_t cb));
|
||||||
|
|
||||||
/* Predefined callback implementations. */
|
/* Predefined callback implementations. */
|
||||||
_PROTOTYPE( void sef_cb_signal_handler_null, (int signo) );
|
_PROTOTYPE( void sef_cb_signal_handler_null, (int signo) );
|
||||||
|
|
|
@ -57,6 +57,8 @@ SRCS+= \
|
||||||
fts.c \
|
fts.c \
|
||||||
fgetln.c \
|
fgetln.c \
|
||||||
fsversion.c \
|
fsversion.c \
|
||||||
|
gcov.c \
|
||||||
|
gcov_flush.c \
|
||||||
getgrent.c \
|
getgrent.c \
|
||||||
getlogin.c \
|
getlogin.c \
|
||||||
getopt_long.c \
|
getopt_long.c \
|
||||||
|
|
55
lib/libc/other/gcov.c
Normal file
55
lib/libc/other/gcov.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <minix/gcov.h>
|
||||||
|
|
||||||
|
int gcov_flush_svr(char *buff, int buff_sz, int server_nr)
|
||||||
|
{
|
||||||
|
message msg;
|
||||||
|
|
||||||
|
msg.GCOV_BUFF_P = buff;
|
||||||
|
msg.GCOV_BUFF_SZ = buff_sz;
|
||||||
|
msg.GCOV_PID = server_nr;
|
||||||
|
|
||||||
|
/* Make the call to server. It will call the gcov library,
|
||||||
|
* buffer the stdio requests, and copy the buffer to this user
|
||||||
|
* space
|
||||||
|
*/
|
||||||
|
_syscall(VFS_PROC_NR, GCOV_FLUSH, &msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* wrappers for file system calls from gcc libgcov library.
|
||||||
|
Default calls are wrapped. In libsys, an alternative
|
||||||
|
implementation for servers is used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILE *_gcov_fopen(char *name, char *mode){
|
||||||
|
return fopen(name, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t _gcov_fread(void *ptr, size_t itemsize, size_t nitems
|
||||||
|
, FILE *stream){
|
||||||
|
return fread(ptr, itemsize, nitems, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _gcov_fwrite(void *ptr, size_t itemsize, size_t nitems
|
||||||
|
, FILE *stream){
|
||||||
|
return fwrite(ptr, itemsize, nitems, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _gcov_fclose(FILE *stream){
|
||||||
|
return fclose(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _gcov_fseek(FILE *stream, long offset, int ptrname){
|
||||||
|
return fseek(stream, offset, ptrname);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *_gcov_getenv(const char *name){
|
||||||
|
return getenv(name);
|
||||||
|
}
|
||||||
|
|
14
lib/libc/other/gcov_flush.c
Normal file
14
lib/libc/other/gcov_flush.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <minix/gcov.h>
|
||||||
|
|
||||||
|
void __gcov_flush(void)
|
||||||
|
{
|
||||||
|
/* A version of __gcov_flush for cases in which no gcc -lgcov
|
||||||
|
* is given; i.e. non-gcc or gcc without active gcov.
|
||||||
|
*/
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ SRCS= \
|
||||||
sched_start.c \
|
sched_start.c \
|
||||||
sched_stop.c \
|
sched_stop.c \
|
||||||
sef.c \
|
sef.c \
|
||||||
|
sef_gcov.c \
|
||||||
sef_init.c \
|
sef_init.c \
|
||||||
sef_liveupdate.c \
|
sef_liveupdate.c \
|
||||||
sef_ping.c \
|
sef_ping.c \
|
||||||
|
@ -120,7 +121,8 @@ SRCS= \
|
||||||
profile.c \
|
profile.c \
|
||||||
vprintf.c \
|
vprintf.c \
|
||||||
timers.c \
|
timers.c \
|
||||||
spin.c
|
spin.c \
|
||||||
|
gcov.c
|
||||||
|
|
||||||
CPPFLAGS.sched_start.c+= -I${MINIXSRCDIR}
|
CPPFLAGS.sched_start.c+= -I${MINIXSRCDIR}
|
||||||
|
|
||||||
|
|
161
lib/libsys/gcov.c
Normal file
161
lib/libsys/gcov.c
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -151,6 +151,14 @@ PUBLIC int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Intercept GCOV data requests (sent by VFS in vfs/gcov.c). */
|
||||||
|
if(m_ptr->m_type == COMMON_REQ_GCOV_DATA &&
|
||||||
|
m_ptr->m_source == VFS_PROC_NR) {
|
||||||
|
if(do_sef_gcov_request(m_ptr) == OK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we get this far, this is not a valid SEF request, return and
|
/* If we get this far, this is not a valid SEF request, return and
|
||||||
* let the caller deal with that.
|
* let the caller deal with that.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -124,6 +124,7 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
||||||
do_deldma, /* 109 = deldma */
|
do_deldma, /* 109 = deldma */
|
||||||
do_getdma, /* 110 = getdma */
|
do_getdma, /* 110 = getdma */
|
||||||
do_srv_kill, /* 111 = srv_kill */
|
do_srv_kill, /* 111 = srv_kill */
|
||||||
|
no_sys, /* 112 = gcov_flush */
|
||||||
};
|
};
|
||||||
/* This should not fail with "array size is negative": */
|
/* This should not fail with "array size is negative": */
|
||||||
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
|
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
|
||||||
|
|
|
@ -4,7 +4,7 @@ SRCS= main.c open.c read.c write.c pipe.c dmap.c \
|
||||||
path.c device.c mount.c link.c exec.c \
|
path.c device.c mount.c link.c exec.c \
|
||||||
filedes.c stadir.c protect.c time.c \
|
filedes.c stadir.c protect.c time.c \
|
||||||
lock.c misc.c utility.c select.c table.c \
|
lock.c misc.c utility.c select.c table.c \
|
||||||
vnode.c vmnt.c request.c fscall.c
|
vnode.c vmnt.c request.c fscall.c gcov.c
|
||||||
|
|
||||||
DPADD+= ${LIBSYS} ${LIBTIMERS}
|
DPADD+= ${LIBSYS} ${LIBTIMERS}
|
||||||
LDADD+= -lsys -ltimers
|
LDADD+= -lsys -ltimers
|
||||||
|
|
73
servers/vfs/gcov.c
Normal file
73
servers/vfs/gcov.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "fproc.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* do_gcov_flush *
|
||||||
|
*===========================================================================*/
|
||||||
|
PUBLIC int do_gcov_flush()
|
||||||
|
{
|
||||||
|
/* A userland tool has requested the gcov data from another
|
||||||
|
* process (possibly vfs itself). Grant the target process
|
||||||
|
* access to the supplied buffer, and perform the call that
|
||||||
|
* makes the target copy its buffer to the caller (incl vfs
|
||||||
|
* itself).
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
struct fproc *rfp;
|
||||||
|
ssize_t size;
|
||||||
|
cp_grant_id_t grantid;
|
||||||
|
int r;
|
||||||
|
int n;
|
||||||
|
pid_t target;
|
||||||
|
|
||||||
|
size = m_in.GCOV_BUFF_SZ;
|
||||||
|
target = m_in.GCOV_PID;
|
||||||
|
|
||||||
|
/* If the wrong process is sent to, the system hangs;
|
||||||
|
* so make this root-only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!super_user) return(EPERM);
|
||||||
|
|
||||||
|
/* Find target gcov process. */
|
||||||
|
|
||||||
|
for(n = 0; n < NR_PROCS; n++) {
|
||||||
|
if(fproc[n].fp_endpoint != NONE &&
|
||||||
|
fproc[n].fp_pid == target)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n >= NR_PROCS) {
|
||||||
|
printf("VFS: gcov proccess %d not found.\n", target);
|
||||||
|
return ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
rfp = &fproc[n];
|
||||||
|
|
||||||
|
/* Grant target process to requestor's buffer. */
|
||||||
|
|
||||||
|
if((grantid = cpf_grant_magic(rfp->fp_endpoint,
|
||||||
|
who_e, (vir_bytes) m_in.GCOV_BUFF_P,
|
||||||
|
size, CPF_WRITE)) < 0) {
|
||||||
|
printf("VFS: gcov_flush: grant failed\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target == getpid()) {
|
||||||
|
/* Request is for VFS itself. */
|
||||||
|
r = gcov_flush(grantid, size);
|
||||||
|
} else {
|
||||||
|
/* Perform generic GCOV request. */
|
||||||
|
m_out.GCOV_GRANT = grantid;
|
||||||
|
m_out.GCOV_BUFF_SZ = size;
|
||||||
|
r = _taskcall(rfp->fp_endpoint, COMMON_REQ_GCOV_DATA, &m_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpf_revoke(grantid);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -257,6 +257,9 @@ _PROTOTYPE( int check_vrefs, (void) );
|
||||||
/* write.c */
|
/* write.c */
|
||||||
_PROTOTYPE( int do_write, (void) );
|
_PROTOTYPE( int do_write, (void) );
|
||||||
|
|
||||||
|
/* gcov.c */
|
||||||
|
_PROTOTYPE( int do_gcov_flush, (void) );
|
||||||
|
|
||||||
/* select.c */
|
/* select.c */
|
||||||
_PROTOTYPE( int do_select, (void) );
|
_PROTOTYPE( int do_select, (void) );
|
||||||
_PROTOTYPE( int select_callback, (struct filp *, int ops) );
|
_PROTOTYPE( int select_callback, (struct filp *, int ops) );
|
||||||
|
|
|
@ -128,6 +128,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
||||||
no_sys, /* 109 = (deldma) */
|
no_sys, /* 109 = (deldma) */
|
||||||
no_sys, /* 110 = (getdma) */
|
no_sys, /* 110 = (getdma) */
|
||||||
no_sys, /* 111 = (srv_kill) */
|
no_sys, /* 111 = (srv_kill) */
|
||||||
|
do_gcov_flush, /* 112 = gcov_flush */
|
||||||
};
|
};
|
||||||
/* This should not fail with "array size is negative": */
|
/* This should not fail with "array size is negative": */
|
||||||
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
|
extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
|
||||||
|
|
|
@ -7,7 +7,7 @@ FILES= bsd.ack.mk bsd.dep.mk bsd.files.mk \
|
||||||
bsd.gcc.mk bsd.inc.mk \
|
bsd.gcc.mk bsd.inc.mk \
|
||||||
bsd.init.mk bsd.kinc.mk bsd.klinks.mk \
|
bsd.init.mk bsd.kinc.mk bsd.klinks.mk \
|
||||||
bsd.lib.mk bsd.links.mk bsd.man.mk bsd.obj.mk bsd.own.mk \
|
bsd.lib.mk bsd.links.mk bsd.man.mk bsd.obj.mk bsd.own.mk \
|
||||||
bsd.prog.mk bsd.subdir.mk bsd.sys.mk \
|
bsd.prog.mk bsd.subdir.mk bsd.sys.mk bsd.gcov.mk \
|
||||||
sys.mk
|
sys.mk
|
||||||
|
|
||||||
FILESDIR=/usr/share/mk
|
FILESDIR=/usr/share/mk
|
||||||
|
|
12
share/mk/bsd.gcov.mk
Normal file
12
share/mk/bsd.gcov.mk
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
LCOV=lcov.$(PROG)
|
||||||
|
CLEANFILES+= *.gcno *.gcda $(LCOV)
|
||||||
|
|
||||||
|
.if ${MKCOVERAGE} == "yes"
|
||||||
|
CFLAGS+=-fno-builtin -fprofile-arcs -ftest-coverage
|
||||||
|
LDADD+= -lgcov
|
||||||
|
COMPILER_TYPE=gnu
|
||||||
|
CC=gcc
|
||||||
|
.endif
|
||||||
|
|
||||||
|
lcov:
|
||||||
|
lcov -c -d . >$(LCOV)
|
|
@ -749,7 +749,7 @@ ${var}?= yes
|
||||||
#
|
#
|
||||||
_MKVARS.no= \
|
_MKVARS.no= \
|
||||||
MKCRYPTO_IDEA MKCRYPTO_MDC2 MKCRYPTO_RC5 MKDEBUG MKDEBUGLIB \
|
MKCRYPTO_IDEA MKCRYPTO_MDC2 MKCRYPTO_RC5 MKDEBUG MKDEBUGLIB \
|
||||||
MKEXTSRC \
|
MKEXTSRC MKCOVERAGE \
|
||||||
MKMANDOC MKMANZ MKOBJDIRS \
|
MKMANDOC MKMANZ MKOBJDIRS \
|
||||||
MKPCC MKPCCCMDS \
|
MKPCC MKPCCCMDS \
|
||||||
MKSOFTFLOAT MKSTRIPIDENT \
|
MKSOFTFLOAT MKSTRIPIDENT \
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
.ifndef HOSTPROG
|
.ifndef HOSTPROG
|
||||||
|
|
||||||
.include <bsd.init.mk>
|
.include <bsd.init.mk>
|
||||||
|
.include <bsd.gcov.mk>
|
||||||
|
|
||||||
#
|
#
|
||||||
# Definitions and targets shared among all programs built by a single
|
# Definitions and targets shared among all programs built by a single
|
||||||
|
|
Loading…
Reference in a new issue