citrun

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

citrun.c (4817B)


      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 <stdlib.h>		/* exit */
     17 #include <stdio.h>		/* fprintf, stderr */
     18 #include <string.h>		/* strncpy */
     19 
     20 #include "citrun.h"		/* struct citrun_header, struct citrun_node */
     21 #include "os.h"			/* citrun_{extend,os_info,open_fd} */
     22 
     23 
     24 /*
     25  * The purpose of the instrumentation runtime is to create a file in a well
     26  * known location and constantly write counter information to it.
     27  *
     28  * Once the file is initially created it does not change in size. There is one
     29  * `struct citrun_node` per instrumented translation unit. The file is
     30  * structured like the following:
     31  *
     32  *   /tmp/citrun.out:
     33  *
     34  *   +-----------------------+
     35  *   | struct citrun_header  |
     36  *   | - citrun version      |
     37  *   | - process ids         |
     38  *   | - program name        |
     39  *   | - working directory   |
     40  *   | padding               |
     41  *   +-----------------------+
     42  *   | struct citrun_node 1  |
     43  *   | - source file paths   |
     44  *   | - counter buffer      | <-- size ~ lines in source file
     45  *   | padding               |
     46  *   +-----------------------+
     47  *   | struct citrun_node .. |
     48  *   | - source file paths   |
     49  *   | - counter buffer      |
     50  *   | padding               |
     51  *   + ----------------------+------
     52  *   | struct citrun_node N  |     ^
     53  *   | - source file paths   |     |-- sized for efficient memory access
     54  *   | - counter buffer      |     |
     55  *   | padding               |     v
     56  *   +-----------------------+------
     57  */
     58 
     59 /*
     60  * Internal function that extends the file descriptor given as the first
     61  * argument and fills the extended space with version and runtime information.
     62  *
     63  * Returns a pointer to the beginning of the extended region on success.
     64  * The instrumented program will exit nonzero on failure.
     65  */
     66 static struct citrun_header *
     67 citrun_add_header(int fd)
     68 {
     69 	struct citrun_header	*new_header;
     70 
     71 	new_header = citrun_extend(fd, sizeof(struct citrun_header));
     72 
     73 	strncpy(new_header->magic, "ctrn", sizeof(new_header->magic));
     74 	new_header->major = citrun_major;
     75 	new_header->minor = citrun_minor;
     76 
     77 	/* Fill in various runtime information fields. */
     78 	citrun_os_info(new_header);
     79 
     80 	return new_header;
     81 }
     82 
     83 /*
     84  * Public function called by code inserted into each translation unit. Takes a
     85  * version major and minor as the first two arguments and a pointer to an
     86  * existing `struct citrun_node` as the third argument.
     87  *
     88  * If the passed version numbers don't exactly match the version numbers this
     89  * library was compiled with a runtime error occurs. This means all instrumented
     90  * object files must be generated by the same citrun tools.
     91  *
     92  * The passed in `struct citrun_node` gets its fields copied to the runtime
     93  * file, and extra counter buffer space is allocated.
     94  *
     95  * Instrumented program will exit nonzero on failure.
     96  */
     97 void
     98 citrun_node_add(unsigned int major, unsigned int minor, struct citrun_node *n)
     99 {
    100 	size_t				 sz;
    101 	struct citrun_node		*new;
    102 	static struct citrun_header	*header = NULL;
    103 	static int			 fd = 0;
    104 
    105 	/* Binary compatibility between versions not guaranteed. */
    106 	if (major != citrun_major || minor != citrun_minor) {
    107 		fprintf(stderr, "libcitrun %i.%i: incompatible version %i.%i.\n"
    108 			"Try cleaning and rebuilding your project.\n",
    109 			citrun_major, citrun_minor, major, minor);
    110 		exit(1);
    111 	}
    112 
    113 	if (header == NULL) {
    114 		fd = citrun_open_fd();
    115 		header = citrun_add_header(fd);
    116 		citrun_start_viewer();
    117 	}
    118 
    119 	/* Allocate enough room for node and live execution buffers. */
    120 	sz = sizeof(struct citrun_node);
    121 	sz += n->size * sizeof(unsigned long long);
    122 	new = citrun_extend(fd, sz);
    123 
    124 	/* Increment accumulation fields in header. */
    125 	header->units++;
    126 	header->loc += n->size;
    127 
    128 	/* Copy these fields from incoming node verbatim. */
    129 	new->size = n->size;
    130 	strncpy(new->comp_file_path, n->comp_file_path, CITRUN_PATH_MAX);
    131 	strncpy(new->abs_file_path,  n->abs_file_path, CITRUN_PATH_MAX);
    132 	new->comp_file_path[CITRUN_PATH_MAX - 1] = '\0';
    133 	new->abs_file_path[CITRUN_PATH_MAX - 1] = '\0';
    134 
    135 	/* Set incoming nodes data pointer to allocated space after struct. */
    136 	n->data = (unsigned long long *)(new + 1);
    137 }