citrun

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

commit d44340316ab167a310e07beb8fb5d368ada4d5dd
parent 2fe1a9f35bcc05cb61faea27c61364574be2acc2
Author: kyle <kyle@getaddrinfo.net>
Date:   Thu, 10 Mar 2016 22:43:41 -0700

add runtime support for multiple source files

- the runtime now sends back data for all of the translation units in the
  application
- send the total number of translation units as the first part of the response
  - then parse that many translation unit records

Diffstat:
MSCV/Viewer.pm | 24+++++++++++++++++-------
Mruntime/runtime.c | 10+++++++++-
Mt/runtime_sanity.t | 11+++++++----
At/runtime_sanity_multisource.t | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 129 insertions(+), 12 deletions(-)

diff --git a/SCV/Viewer.pm b/SCV/Viewer.pm @@ -33,18 +33,28 @@ sub request_data { $client->syswrite("\x00", 1); + # First thing sent back is total number of translation units in the + # instrumentation chain my $buf = read_all($client, 8); - my $file_name_sz = unpack("Q", $buf); + my $num_tus = unpack("Q", $buf); - my $file_name = read_all($client, $file_name_sz); + my %tu_data; + for (1..$num_tus) { + my $buf = read_all($client, 8); + my $file_name_sz = unpack("Q", $buf); - $buf = read_all($client, 8); - my $num_lines = unpack("Q", $buf); + my $file_name = read_all($client, $file_name_sz); - $buf = read_all($client, 8 * $num_lines); - my @data = unpack("Q$num_lines", $buf); + $buf = read_all($client, 8); + my $num_lines = unpack("Q", $buf); - return ({ file_name => $file_name, data => \@data }); + $buf = read_all($client, 8 * $num_lines); + my @data = unpack("Q$num_lines", $buf); + + $tu_data{$file_name} = \@data ; + } + + return \%tu_data; } sub read_all { diff --git a/runtime/runtime.c b/runtime/runtime.c @@ -54,9 +54,17 @@ void walk_nodes(int fd) { size_t file_name_sz; + uint64_t num_tus; - /* Copy node0, don't use it directly */ struct scv_node walk = node0; + + /* Find how many translation units there are in this application */ + for (num_tus = 0; walk.size != 0; num_tus++) + walk = *walk.next; + xwrite(fd, &num_tus, sizeof(num_tus)); + + /* Reset walk back to the start */ + walk = node0; while (walk.size != 0) { file_name_sz = strnlen(walk.file_name, PATH_MAX); diff --git a/t/runtime_sanity.t b/t/runtime_sanity.t @@ -1,7 +1,7 @@ use strict; use SCV::Project; use SCV::Viewer; -use Test::More tests => 37; +use Test::More tests => 38; use Test::Differences; use Time::HiRes qw( usleep ); @@ -57,11 +57,14 @@ $viewer->accept(); usleep(100 * 1000); my $data = $viewer->request_data(); -like ($data->{file_name}, qr/tmp\/.*source_0\.c/, "runtime filename check"); -my @lines = @{ $data->{data} }; +my ($file_name, @others) = keys %$data; +like ($file_name, qr/tmp\/.*source_0\.c/, "runtime filename check"); +is( @others, 0, "runtime check for a single tu" ); -# Check the line counts are something reasonable +my @lines = @{ $data->{$file_name} }; is (scalar(@lines), 33, "runtime lines count"); + +# Do a pretty thorough coverage check is ( $lines[$_], 0, "line $_ check" ) for (0..8); cmp_ok ( $lines[$_], ">", 0, "line $_ check" ) for (9..12); is ( $lines[13], 0, "line 13 check" ); diff --git a/t/runtime_sanity_multisource.t b/t/runtime_sanity_multisource.t @@ -0,0 +1,96 @@ +use strict; +use Data::Dumper; +use SCV::Project; +use SCV::Viewer; +use Test::More tests => 47; +use Test::Differences; + +my $viewer = SCV::Viewer->new(); +my $project = SCV::Project->new(); +unified_diff; + +$project->add_src(<<EOF +#include <err.h> +#include <limits.h> +#include <stdlib.h> /* strtonum */ + +long long factorial(long long); +void print_output(long long); + +int +main(int argc, char *argv[]) +{ + long long n; + const char *errstr = NULL; + + if (argc != 2) + errx(1, "argc != 2"); + + n = strtonum(argv[1], LONG_MIN, LONG_MAX, &errstr); + if (errstr) + err(1, "%s", errstr); + + print_output(factorial(n)); + return 0; +} +EOF +); + +$project->add_src(<<EOF +long long +factorial(long long n) +{ + if (n == 0) + return 1; + + return n * factorial(n - 1); +} +EOF +); + +$project->add_src(<<EOF +#include <stdio.h> + +void +print_output(long long n) +{ + fprintf(stderr, "%lli", n); + return; +} +EOF +); + +$project->compile(); +$project->run(17); + +$viewer->accept(); +my $data = $viewer->request_data(); + +like ($_, qr/tmp\/.*source_.*\.c/, "runtime filename check") for (keys %$data); +my ($src_filename_0, $src_filename_1, $src_filename_2) = sort keys %$data; + +my @lines = @{ $data->{$src_filename_0} }; +is ( $lines[$_], 0, "src 0 line $_ check" ) for (0..13); +is ( $lines[14], 1, "src 0 line 14 check" ); +is ( $lines[$_], 0, "src 0 line $_ check" ) for (15..16); +is ( $lines[$_], 1, "src 0 line $_ check" ) for (17..18); +is ( $lines[$_], 0, "src 0 line $_ check" ) for (19..20); +is ( $lines[21], 2, "src 0 line 21 check" ); +is ( $lines[$_], 0, "src 0 line $_ check" ) for (22..23); + +my @lines = @{ $data->{$src_filename_1} }; +is ( $lines[$_], 0, "src 1 line $_ check" ) for (0..3); +is ( $lines[4], 18, "src 1 line 4 check" ); +is ( $lines[5], 1, "src 1 line 5 check" ); +is ( $lines[6], 0, "src 1 line 6 check" ); +is ( $lines[7], 34, "src 1 line 7 check" ); +is ( $lines[8], 0, "src 1 line 8 check" ); + +my @lines = @{ $data->{$src_filename_2} }; +is ( $lines[$_], 0, "src 2 line $_ check" ) for (0..5); +is ( $lines[6], 1, "src 2 line 6 check" ); +is ( $lines[$_], 0, "src 2 line $_ check" ) for (7..8); + +my ($ret, $err) = $project->wait(); +is( $ret, 0, "instrumented program check return code" ); +is( $err, "355687428096000", "instrumented program check stderr" );