citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

unix.c (3554B)


      1 /*
      2  * Copyright (c) 2016 Kyle Milz <kyle@0x30.net>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 #include <sys/mman.h>		/* mmap */
     17 #include <sys/stat.h>		/* S_IRUSR, S_IWUSR */
     18 
     19 #include <assert.h>
     20 #include <err.h>
     21 #include <fcntl.h>		/* O_CREAT */
     22 #include <stdlib.h>		/* getprogname */
     23 #include <string.h>		/* strlcpy */
     24 #include <unistd.h>		/* execlp, fork, lseek, get* */
     25 
     26 #include "citrun.h"		/* struct citrun_header */
     27 #include "os.h"
     28 
     29 #define UNIX_MMAP_FILE		"/tmp/citrun.out"
     30 
     31 
     32 /*
     33  * Implementation of os.h interface for at least:
     34  * - OpenBSD
     35  * - Darwin
     36  * - Linux
     37  */
     38 
     39 /*
     40  * Rounds up the second argument to a multiple of the system page size, which
     41  * makes working with mmap nicer.
     42  *
     43  * Get the current mapping length, extend it by truncation and then extend the
     44  * memory mapping.
     45  *
     46  * If this function fails the instrumented program will exit nonzero.
     47  */
     48 void *
     49 citrun_extend(int fd, size_t req_bytes)
     50 {
     51 	size_t	 page_mask, aligned_bytes;
     52 	off_t	 len;
     53 	int	 prot;
     54 	void	*mem;
     55 
     56 	page_mask = getpagesize() - 1;
     57 	aligned_bytes = (req_bytes + page_mask) & ~page_mask;
     58 
     59 	/* Get current file length. */
     60 	if ((len = lseek(fd, 0, SEEK_END)) < 0)
     61 		err(1, "lseek");
     62 
     63 	/* Increase file length, filling with zeros. */
     64 	if (ftruncate(fd, len + aligned_bytes) < 0)
     65 		err(1, "ftruncate from %lld to %llu", len, len + aligned_bytes);
     66 
     67 	/* Increase memory mapping length. */
     68 	prot = PROT_READ | PROT_WRITE;
     69 	mem = mmap(NULL, req_bytes, prot, MAP_SHARED, fd, len);
     70 
     71 	if (mem == MAP_FAILED)
     72 		err(1, "mmap %zu bytes @ %llu", req_bytes, len);
     73 
     74 	return mem;
     75 }
     76 
     77 /*
     78  * If this function fails the instrumented program will exit nonzero.
     79  */
     80 int
     81 citrun_open_fd()
     82 {
     83 	int	flags, mode, fd;
     84 
     85 	flags = O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC;
     86 	mode = S_IRUSR | S_IWUSR;
     87 
     88 	if ((fd = open(UNIX_MMAP_FILE, flags, mode)) < 0)
     89 		err(1, "open: %s", UNIX_MMAP_FILE);
     90 
     91 	return fd;
     92 }
     93 
     94 /*
     95  * Fills in the following fields:
     96  * - process id
     97  * - parent process id
     98  * - process group
     99  * - program name
    100  * - current working directory
    101  *
    102  * This function does not fail.
    103  */
    104 void
    105 citrun_os_info(struct citrun_header *h)
    106 {
    107 	h->pids[0] = getpid();
    108 	h->pids[1] = getppid();
    109 	h->pids[2] = getpgrp();
    110 
    111 	strlcpy(h->progname, getprogname(), sizeof(h->progname));
    112 
    113 	if (getcwd(h->cwd, sizeof(h->cwd)) == NULL)
    114 		strncpy(h->cwd, "", sizeof(h->cwd));
    115 }
    116 
    117 /*
    118  * Tries to exec 'citrun_gl' which must be on the path.
    119  * If fork() fails, the intstrumented program will also fail.
    120  */
    121 void
    122 citrun_start_viewer()
    123 {
    124 	pid_t	pid;
    125 
    126 	pid = fork();
    127 	if (pid < 0)
    128 		err(1, "fork");
    129 	else if (pid > 0)
    130 		/* In parent process. */
    131 		return;
    132 
    133 	/*
    134 	 * Use a different name than the instrumented program this library is
    135 	 * linked to for better diagnostics in error messages.
    136 	 */
    137 	setprogname("libcitrun");
    138 
    139 	/* In child process, exec the viewer. */
    140 	if (execlp("citrun_gl", "citrun_gl", NULL))
    141 		err(1, "exec citrun_gl");
    142 }