citrun

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

gl_runtime.cc (6634B)


      1 //
      2 // Copyright (c) 2016, 2017 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/stat.h>
     17 
     18 #include <cassert>		// assert
     19 #include <cstdlib>		// std::getenv
     20 #include <cstring>		// std::memcpy, std::strncmp
     21 #include <csignal>		// kill
     22 #include <err.h>
     23 #include <fstream>		// std::ifstream
     24 #include <iostream>		// std::cerr
     25 #include <sstream>		// std::stringstream
     26 
     27 #include "citrun.h"		// struct citrun_node
     28 #include "gl_runtime.h"		// citrun::gl_transunit, citrun::gl_procfile
     29 
     30 
     31 //
     32 // Take a pointer to a shared memory region and map data structures on top.
     33 // Automatically increments the pointer once we know how big this region is.
     34 //
     35 citrun::gl_transunit::gl_transunit(citrun::mem &m_mem, citrun::gl_font &font,
     36 		glyphy_point_t &draw_pos) :
     37 	m_node(static_cast<struct citrun_node *>(m_mem.get_ptr())),
     38 	m_data((unsigned long long *)(m_node + 1)),
     39 	m_data_buffer(m_node->size)
     40 {
     41 	unsigned int	 size;
     42 
     43 	// Total size is node size plus live execution data size.
     44 	size = sizeof(struct citrun_node);
     45 	size += m_node->size * sizeof(unsigned long long);
     46 	m_mem.increment(size);
     47 
     48 	m_glbuffer.move_to(&draw_pos);
     49 
     50 	std::stringstream tu_info;
     51 	tu_info << "Source file:   " << m_node->comp_file_path << std::endl;
     52 	tu_info << "Lines of code: " << m_node->size << std::endl;
     53 	m_glbuffer.add_text(tu_info.str().c_str(), font, 2);
     54 
     55 	glyphy_point_t cur_pos;
     56 	m_glbuffer.current_point(&cur_pos);
     57 	cur_pos.x = draw_pos.x;
     58 	m_glbuffer.move_to(&cur_pos);
     59 
     60 	std::ifstream file_stream(m_node->abs_file_path);
     61 	if (file_stream.is_open() == 0) {
     62 		std::cerr << "ifstream.open: " << m_node->abs_file_path << std::endl;
     63 		return;
     64 	}
     65 
     66 	std::string line;
     67 	unsigned int i;
     68 	for (i = 1; std::getline(file_stream, line); ++i) {
     69 		m_glbuffer.add_text(line.c_str(), font, 1);
     70 
     71 		m_glbuffer.current_point(&cur_pos);
     72 		cur_pos.x = draw_pos.x;
     73 		m_glbuffer.move_to(&cur_pos);
     74 	}
     75 
     76 	if (i != m_node->size)
     77 		std::cerr << m_node->abs_file_path << " size mismatch: "
     78 			<< i << " vs " << m_node->size << std::endl;
     79 }
     80 
     81 //
     82 // Returns number of lines that citrun_inst processed (whole source file
     83 // ideally)
     84 //
     85 unsigned int
     86 citrun::gl_transunit::num_lines() const
     87 {
     88 	return m_node->size;
     89 }
     90 
     91 //
     92 // Returns the source file path as it was passed to the compiler.
     93 //
     94 std::string
     95 citrun::gl_transunit::comp_file_path() const
     96 {
     97 	return std::string(m_node->comp_file_path);
     98 }
     99 
    100 glyphy_extents_t
    101 citrun::gl_transunit::get_extents()
    102 {
    103 	glyphy_extents_t extents;
    104 	m_glbuffer.extents(NULL, &extents);
    105 
    106 	return extents;
    107 }
    108 
    109 //
    110 // Copy live executions to secondary buffer. Used for computing deltas later.
    111 //
    112 void
    113 citrun::gl_transunit::save_executions()
    114 {
    115 	std::memcpy(&m_data_buffer[0], m_data, m_node->size * sizeof(unsigned long long));
    116 }
    117 
    118 void
    119 citrun::gl_transunit::display()
    120 {
    121 	m_glbuffer.draw();
    122 }
    123 
    124 //
    125 // citrun::gl_procfile
    126 //
    127 // Take a filesystem path and memory map its contents. Map at least a header
    128 // structure on top of it.
    129 //
    130 citrun::gl_procfile::gl_procfile(std::string const &path, citrun::gl_font &font, double const &x_off) :
    131 	m_mem(path)
    132 {
    133 	// Header is always at offset 0.
    134 	m_header = static_cast<struct citrun_header *>(m_mem.get_ptr());
    135 	m_mem.increment(sizeof(struct citrun_header));
    136 
    137 	assert(std::strncmp(m_header->magic, "ctrn", 4) == 0);
    138 	assert(m_header->major == citrun_major);
    139 
    140 	glyphy_point_t orig_pos = { x_off, 0 };
    141 	m_glbuffer.move_to(&orig_pos);
    142 
    143 	std::stringstream maj;
    144 	maj << "Name:              '" << m_header->progname << "'" << std::endl;
    145 	maj << "Translation Units: " << m_header->units << std::endl;
    146 	maj << "Lines of code:     " << m_header->loc << std::endl;
    147 	m_glbuffer.add_text(maj.str().c_str(), font, 3);
    148 
    149 	std::stringstream min;
    150 	min << "Working directory: " << m_header->cwd << std::endl;
    151 	min << "Instrumented with: v" << m_header->major << "." << m_header->minor << std::endl;
    152 	m_glbuffer.add_text(min.str().c_str(), font, 2);
    153 
    154 	glyphy_point_t draw_pos;
    155 	m_glbuffer.current_point(&draw_pos);
    156 
    157 	while (!m_mem.at_end()) {
    158 		m_tus.emplace_back(m_mem, font, draw_pos);
    159 		draw_pos.x += 80;
    160 	}
    161 
    162 	// Make sure internal increment in TranslationUnit works as intended.
    163 	assert(m_mem.at_end_exactly());
    164 }
    165 
    166 //
    167 // Checks if the pid given by the runtime is alive. Prone to race conditions.
    168 //
    169 bool
    170 citrun::gl_procfile::is_alive() const
    171 {
    172 	return kill(m_header->pids[0], 0) == 0;
    173 }
    174 
    175 const citrun::gl_transunit *
    176 citrun::gl_procfile::find_tu(std::string const &srcname) const
    177 {
    178 	for (auto &i : m_tus)
    179 		if (srcname == i.comp_file_path())
    180 			return &i;
    181 	return NULL;
    182 }
    183 
    184 void
    185 citrun::gl_procfile::display()
    186 {
    187 	m_glbuffer.draw();
    188 
    189 	for (auto &t : m_tus)
    190 		t.display();
    191 }
    192 
    193 glyphy_extents_t
    194 citrun::gl_procfile::get_extents()
    195 {
    196 	glyphy_extents_t extents;
    197 	m_glbuffer.extents(NULL, &extents);
    198 
    199 	for (auto &i : m_tus) {
    200 		glyphy_extents_t t = i.get_extents();
    201 		extents.max_x = std::max(extents.max_x, t.max_x);
    202 		extents.max_y = std::max(extents.max_y, t.max_y);
    203 		extents.min_x = std::min(extents.min_x, t.min_x);
    204 		extents.min_y = std::min(extents.min_y, t.min_y);
    205 	}
    206 
    207 	return extents;
    208 }
    209 
    210 
    211 //
    212 // citrun::process_dir
    213 //
    214 citrun::process_dir::process_dir()
    215 {
    216 	if ((m_procdir = std::getenv("CITRUN_PROCDIR")) == NULL)
    217 		m_procdir = "/tmp/citrun/";
    218 
    219 	if ((m_dirp = opendir(m_procdir)) == NULL) {
    220 		if (errno != ENOENT)
    221 			err(1, "opendir '%s'", m_procdir);
    222 
    223 		// Create if there was no such file or directory.
    224 		mkdir(m_procdir, S_IRWXU);
    225 		if ((m_dirp = opendir(m_procdir)) == NULL)
    226 			err(1, "opendir '%s'", m_procdir);
    227 	}
    228 }
    229 
    230 std::vector<std::string>
    231 citrun::process_dir::scan()
    232 {
    233 	std::vector<std::string>	 new_files;
    234 	struct dirent			*dp;
    235 
    236 	rewinddir(m_dirp);
    237 	while ((dp = readdir(m_dirp)) != NULL) {
    238 
    239 		if (std::strcmp(dp->d_name, ".") == 0 ||
    240 		    std::strcmp(dp->d_name, "..") == 0)
    241 			continue;
    242 
    243 		std::string p(m_procdir);
    244 		p.append(dp->d_name);
    245 
    246 		if (m_known_files.find(p) != m_known_files.end())
    247 			// We already know this file.
    248 			continue;
    249 
    250 		m_known_files.insert(p);
    251 		new_files.push_back(p);
    252 	}
    253 
    254 	return new_files;
    255 }