File size: 2,790 Bytes
19605ab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open3;
use Symbol 'gensym'; 
use IO::Handle;
use Test::More qw/ no_plan /;

my $USDT_ARG_MAX = 32;
if ($^O eq 'freebsd') {
    # FreeBSD currently only supports 5 arguments to USDT probes
    $USDT_ARG_MAX = 5;
}

my $arch;
if (scalar @ARGV == 1) {
    $arch = $ARGV[0];
}

my $user_t = ($^O eq 'darwin') ? 'user_addr_t' : 'uintptr_t';

run_tests('c', 'A');
run_tests('i', 1);

sub run_tests {
    my ($type, $start_arg) = @_;
    
    for my $i (0..$USDT_ARG_MAX) {
        my ($t_status, $d_status, $output) = run_dtrace('type'.$type, $i.'arg', split(//, $type x $i));
        is($t_status, 0, 'test exit status is 0');
        is($d_status, 0, 'dtrace exit status is 0');
        like($output, qr/type[ic]:\d+arg/, 'function and name match');

        my $arg = $start_arg;
        for my $j (0..$i - 1) {
            like($output, qr/arg$j:'\Q$arg\E'/, "type '$type' arg $j is $arg");
            if ($type eq 'i') {
                $arg++;
            }
            else {
                $arg = chr(ord($arg) + 1);
            }
        }
    }
}

# --------------------------------------------------------------------------

sub gen_d {
    my (@types) = @_;

    my $d = 'testlibusdt*:::{ ';
    my $i = 0;
    for my $type (@types) {
        if ($type eq 'i') {
            $d .= "printf(\"arg$i:'%i' \", args[$i]); ";
        }
        if ($type eq 'c') {
            $d .= "printf(\"arg$i:'%s' \", copyinstr(($user_t)args[$i])); ";
        }
        $i++;
    }
    $d .= '}';

    return $d;
}
         
sub run_dtrace {
    my ($func, $name, @types) = @_;
    my $d = gen_d(@types);

    my @t_cmd;
    if (defined $arch) {
        @t_cmd = ("./test_usdt$arch", $func, $name, @types);
    }
    else {
        @t_cmd = ("./test_usdt", $func, $name, @types);
    }

    my ($d_wtr, $d_rdr, $d_err);
    my ($t_wtr, $t_rdr, $t_err);

    $d_err = gensym;
    $t_err = gensym;

    #diag(join(' ', @t_cmd));
    my $t_pid = open3($t_wtr, $t_rdr, $t_err, @t_cmd);
    my $enabled = $t_rdr->getline;

    my @d_cmd = ('/usr/sbin/dtrace', '-p', $t_pid, '-n', $d);

    #diag(join(' ', @d_cmd));
    my $d_pid = open3($d_wtr, $d_rdr, $d_err, @d_cmd);
    my $matched = $d_err->getline; # expect "matched 1 probe"

    $t_wtr->print("go\n");
    $t_wtr->flush;
    waitpid( $t_pid, 0 );
    my $t_status = $? >> 8;

    my ($header, $output) = ($d_rdr->getline, $d_rdr->getline);
    chomp $header;
    chomp $output;
    #diag("DTrace header: $header\n");
    #diag("DTrace output: $output\n");
    waitpid( $d_pid, 0 );

    my $d_status = $? >> 8;
    while (!$d_err->eof) {
        my $error = $d_err->getline;
        chomp $error;
        #diag "DTrace error: $error";
    }

    return ($t_status, $d_status, $output || '');
}