
With this patch, it is now possible to generate coverage information for MINIX3 system services with LLVM. In particular, the system can be built with MKCOVERAGE=yes, either with a native "make build" or with crosscompilation. Either way, MKCOVERAGE=yes will build the MINIX3 system services with coverage profiling support, generating a .gcno file for each source module. After a reboot it is possible to obtain runtime coverage data (.gcda files) for individual system services using gcov-pull(8). The combination of the .gcno and .gcda files can then be inspected with llvm-cov(1). For reasons documented in minix.gcov.mk, only system service program modules are supported for now; system service libraries (libsys etc.) are not included. Userland programs are not affected by MKCOVERAGE. The heart of this patch is the libsys code that writes data generated by the LLVM coverage hooks into a serialized format using the routines we already had for GCC GCOV. Unfortunately, the new llvm_gcov.c code is LLVM ABI dependent, and may therefore have to be updated later when we upgrade LLVM. The current implementation should support all LLVM versions 3.x with x >= 4. The rest of this patch is mostly a light cleanup of our existing GCOV infrastructure, with as most visible change that gcov-pull(8) now takes a service label string rather than a PID number. Change-Id: I6de055359d3d2b3f53e426f3fffb17af7877261f
74 lines
2.0 KiB
C
74 lines
2.0 KiB
C
|
|
#include <string.h>
|
|
|
|
#include "fs.h"
|
|
#include "file.h"
|
|
|
|
/*===========================================================================*
|
|
* do_gcov_flush *
|
|
*===========================================================================*/
|
|
int do_gcov_flush(void)
|
|
{
|
|
/* 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).
|
|
*/
|
|
char label[LABEL_MAX];
|
|
vir_bytes labeladdr, buf;
|
|
size_t labellen, size;
|
|
endpoint_t endpt;
|
|
cp_grant_id_t grantid;
|
|
int r;
|
|
message m;
|
|
|
|
/*
|
|
* Something as sensitive as system service coverage information must be
|
|
* call to the target service, and so it is not impossible to deadlock the
|
|
* system with this call.
|
|
*/
|
|
if (!super_user) return(EPERM);
|
|
|
|
labeladdr = job_m_in.m_lc_vfs_gcov.label;
|
|
labellen = job_m_in.m_lc_vfs_gcov.labellen;
|
|
buf = job_m_in.m_lc_vfs_gcov.buf;
|
|
size = job_m_in.m_lc_vfs_gcov.buflen;
|
|
|
|
/* Retrieve and look up the target label. */
|
|
if (labellen >= sizeof(label))
|
|
return EINVAL;
|
|
if ((r = sys_datacopy_wrapper(who_e, labeladdr, SELF, (vir_bytes)label,
|
|
labellen)) != OK)
|
|
return r;
|
|
label[labellen - 1] = '\0';
|
|
|
|
if ((r = ds_retrieve_label_endpt(label, &endpt)) != OK)
|
|
return r;
|
|
|
|
/* Hack: init is the only non-system process with a valid label. */
|
|
if (endpt == INIT_PROC_NR)
|
|
return ENOENT;
|
|
|
|
/* Grant target process to requestor's buffer. */
|
|
if ((grantid = cpf_grant_magic(endpt, who_e, buf, size, CPF_WRITE)) < 0) {
|
|
printf("VFS: gcov_flush: grant failed\n");
|
|
return(ENOMEM);
|
|
}
|
|
|
|
if (endpt == VFS_PROC_NR) {
|
|
/* Request is for VFS itself. */
|
|
r = gcov_flush(VFS_PROC_NR, grantid, size);
|
|
} else {
|
|
/* Perform generic GCOV request. */
|
|
memset(&m, 0, sizeof(m));
|
|
m.m_vfs_lsys_gcov.grant = grantid;
|
|
m.m_vfs_lsys_gcov.size = size;
|
|
r = _taskcall(endpt, COMMON_REQ_GCOV_DATA, &m);
|
|
}
|
|
|
|
cpf_revoke(grantid);
|
|
|
|
return(r);
|
|
}
|