1# This file is part of ltrace.
2# Copyright (C) 2014 Petr Machata, Red Hat Inc.
3# Copyright (C) 2006 Yao Qi <qiyao@cn.ibm.com>, IBM Corporation
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as
7# published by the Free Software Foundation; either version 2 of the
8# License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18# 02110-1301 USA
19
20# Objectives: Verify that Ltrace can trace all the system calls in
21# execution.  Note that this test is necessarily noisy.  Dynamic
22# linker adds a bunch of system calls of its own.
23
24set empty [ltraceCompile {} [ltraceSource c {
25    int main (void) { return 0; }
26}]]
27
28set bin [ltraceCompile {} [ltraceSource c {
29    #include <stdio.h>
30    #include <unistd.h>
31    #include <sys/syscall.h>
32    #include <sys/stat.h>
33    #include <errno.h>
34    #include <stdlib.h>
35
36    int
37    main ()
38    {
39      FILE* fp;
40      char s[]="system_calls";
41      char buffer[1024];
42      struct stat state;
43
44      fp = fopen ("system_calls.tmp", "w");
45      if (fp == NULL)
46	{
47	  printf("Can not create system_calls.tmp\n");
48	  exit (0);
49	}
50      fwrite(s, sizeof(s), 1, fp);
51      fseek (fp, 0, SEEK_CUR);
52      fread(buffer, sizeof(s), 1, fp);
53      fclose(fp);
54
55      getcwd (buffer, sizeof buffer);
56      chdir (".");
57      symlink ("system_calls.tmp", "system_calls.link");
58      remove("system_calls.link");
59      rename ("system_calls.tmp", "system_calls.tmp1");
60      stat ("system_calls.tmp", &state);
61      access ("system_calls.tmp", R_OK);
62      remove("system_calls.tmp1");
63
64      mkdir ("system_call_mkdir", 0777);
65      rmdir ("system_call_mkdir");
66
67      return 0;
68    }
69}]]
70
71proc Calls {logfile} {
72    set fp [open $logfile]
73    set ret {}
74
75    while {[gets $fp line] >= 0} {
76	if [regexp -- {^[a-zA-Z0-9]*@SYS} $line] {
77	    set call [lindex [split $line @] 0]
78	    dict incr ret $call
79	}
80    }
81
82    close $fp
83    return $ret
84}
85
86proc GetDefault {d key def} {
87    if {[dict exists $d $key]} {
88	return [dict get $d $key]
89    } else {
90	return $def
91    }
92}
93
94proc Diff {d1 d2} {
95    set keys [lsort -unique [concat [dict keys $d1] [dict keys $d2]]]
96    set ret {}
97    foreach key $keys {
98	set n1 [GetDefault $d1 $key 0]
99	set n2 [GetDefault $d2 $key 0]
100	set sum [expr $n1 - $n2]
101	if {[expr $sum != 0]} {
102		dict set ret $key $sum
103	}
104    }
105    return $ret
106}
107
108proc Match {d patterns} {
109    foreach line $patterns {
110	set pattern [lindex $line 0]
111	set op [lindex $line 1]
112	set expect [lindex $line 2]
113
114	set count 0
115	foreach key [dict keys $d] {
116	    if [regexp -- $pattern $key] {
117		incr count [dict get $d $key]
118	    }
119	}
120
121	set msgMain "$pattern was recorded $count times"
122
123	if {[eval expr $count $op $expect]} {
124	    pass $msgMain
125	} else {
126	    fail "$msgMain, expected $op $expect"
127	}
128    }
129}
130
131Match [Diff [Calls [ltraceRun -L -S -- $bin]] \
132	   [Calls [ltraceRun -L -S -- $empty]]] {
133    { {^write$} == 1 }
134    { {^unlink(at)?$} >= 2 }
135    { {^open(at)?$} == 1 }
136    { {^(new|f)?stat(64)?$} == 1 }
137    { {^close$} == 1 }
138    { {^getcwd$} == 1 }
139    { {^chdir$} == 1 }
140    { {^symlink(at)?$} == 1 }
141    { {^f?access(at)?$} == 1 }
142    { {^rename(at)?$} == 1 }
143    { {^mkdir(at)?$} == 1 }
144}
145
146ltraceDone
147