]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/perl | |
2 | # | |
3 | # Copyright (c) 2006 Apple Computer, Inc. All rights reserved. | |
4 | # | |
5 | # @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
6 | # | |
7 | # This file contains Original Code and/or Modifications of Original Code | |
8 | # as defined in and that are subject to the Apple Public Source License | |
9 | # Version 2.0 (the 'License'). You may not use this file except in | |
10 | # compliance with the License. Please obtain a copy of the License at | |
11 | # http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | # file. | |
13 | # | |
14 | # The Original Code and all software distributed under the License are | |
15 | # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | # Please see the License for the specific language governing rights and | |
20 | # limitations under the License. | |
21 | # | |
22 | # @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
23 | # | |
24 | ########################################################################## | |
25 | # | |
26 | # % create-syscalls.pl syscalls.master custom-directory out-directory | |
27 | # | |
28 | # This script fills the the out-directory with a Makefile.inc and *.s | |
29 | # files to create the double-underbar syscall stubs. It reads the | |
30 | # syscall.master file to get the symbol names and number of arguments, | |
31 | # and whether Libsystem should automatically create the (non-double-underbar) | |
32 | # stubs if Libc doesn't provide a wrapper. Which system calls will get | |
33 | # the automatic treatment is writen to the libsyscall.list file, also | |
34 | # written to the out-directory. | |
35 | # | |
36 | # The custom-directory contains: | |
37 | # 1. SYS.h - used by the automatically created *.s and custom files | |
38 | # 2. custom.s - contains architecture specific additional system calls and | |
39 | # auxilliary routines (like cerror) | |
40 | # 3. special case double-underbar stub files - which are copied into | |
41 | # the out-directory | |
42 | # | |
43 | # The BSDmakefile copies /usr/include/architecture/ppc/emode_independent_asm.h | |
44 | # and /usr/include/architecture/i386/asm_help.h to $(OBJDIR)/include, | |
45 | # replacing .globl with .private_extern. These headers, along with SYS.h | |
46 | # make the double-underbar syscall stub private_extern, so that then become | |
47 | # static in the resulting libSystem.dylib. | |
48 | # | |
49 | ########################################################################## | |
50 | ||
51 | use strict; | |
52 | use File::Basename (); | |
53 | use File::Copy (); | |
54 | use File::Spec; | |
55 | use IO::File; | |
56 | ||
57 | my $MyName = File::Basename::basename($0); | |
58 | ||
59 | my @CustomSrc = qw(custom.s); | |
60 | ||
61 | my @Copy = (qw(SYS.h), @CustomSrc); | |
62 | my $CustomDir; | |
63 | my %NoStub; | |
64 | my $OutDir; | |
65 | my %Stub = ( | |
66 | quota => [4, 0], # unimplemented | |
67 | setquota => [2, 0], # unimplemented | |
68 | syscall => [0, 0], # custom/__syscall.s will be used | |
69 | ); | |
70 | my $StubFile = 'libsyscall.list'; | |
71 | # size in bytes of known types (only used for i386) | |
72 | my %TypeBytes = ( | |
73 | 'caddr_t' => 4, | |
74 | 'gid_t' => 4, | |
75 | 'id_t' => 4, | |
76 | 'idtype_t' => 4, | |
77 | 'int' => 4, | |
78 | 'int32_t' => 4, | |
79 | 'int64_t' => 8, | |
80 | 'key_t' => 4, | |
81 | 'long' => 4, | |
82 | 'mode_t' => 4, | |
83 | 'off_t' => 8, | |
84 | 'pid_t' => 4, | |
85 | 'semun_t' => 4, | |
86 | 'sigset_t' => 4, | |
87 | 'size_t' => 4, | |
88 | 'socklen_t' => 4, | |
89 | 'ssize_t' => 4, | |
90 | 'time_t' => 4, | |
91 | 'u_int' => 4, | |
92 | 'u_long' => 4, | |
93 | 'uid_t' => 4, | |
94 | 'uint32_t' => 4, | |
95 | 'uint64_t' => 8, | |
96 | 'user_addr_t' => 4, | |
97 | 'user_long_t' => 4, | |
98 | 'user_size_t' => 4, | |
99 | 'user_ssize_t' => 4, | |
100 | 'user_ulong_t' => 4, | |
101 | ); | |
102 | ||
103 | ########################################################################## | |
104 | # Make a __xxx.s file: if it exists in the $CustomDir, just copy it, otherwise | |
105 | # create one. We define the macro __SYSCALL_I386_ARG_BYTES so that SYS.h could | |
106 | # use that to define __SYSCALL dependent on the arguments' total size. | |
107 | ########################################################################## | |
108 | sub make_s { | |
109 | my($name, $args, $bytes) = @_; | |
110 | local $_; | |
111 | my $pseudo = $name; | |
112 | $pseudo = '__' . $pseudo unless $pseudo =~ /^__/; | |
113 | my $file = $pseudo . '.s'; | |
114 | my $custom = File::Spec->join($CustomDir, $file); | |
115 | my $path = File::Spec->join($OutDir, $file); | |
116 | if(-f $custom) { | |
117 | File::Copy::copy($custom, $path) || die "$MyName: copy($custom, $path): $!\n"; | |
118 | print "Copying $path\n"; | |
119 | } else { | |
120 | my $f = IO::File->new($path, 'w'); | |
121 | die "$MyName: $path: $!\n" unless defined($f); | |
122 | print $f "#define __SYSCALL_I386_ARG_BYTES $bytes\n\n"; | |
123 | print $f "#include \"SYS.h\"\n\n"; | |
124 | print $f "__SYSCALL($pseudo, $name, $args)\n"; | |
125 | print "Creating $path\n"; | |
126 | } | |
127 | return $file; | |
128 | } | |
129 | ||
130 | sub usage { | |
131 | die "Usage: $MyName syscalls.master custom-directory out-directory\n"; | |
132 | } | |
133 | ||
134 | ########################################################################## | |
135 | # Read the syscall.master file and collect the system call names and number | |
136 | # of arguments. It looks for the NO_SYSCALL_STUB quailifier following the | |
137 | # prototype to determine if no automatic stub should be created by Libsystem. | |
138 | # System call name that are already prefixed with double-underbar are set as | |
139 | # if the NO_SYSCALL_STUB qualifier were specified (whether it is or not). | |
140 | # | |
141 | # For the #if lines in syscall.master, all macros are assumed to be defined, | |
142 | # except COMPAT_GETFSSTAT (assumed undefined). | |
143 | ########################################################################## | |
144 | sub readmaster { | |
145 | my $file = shift; | |
146 | local $_; | |
147 | my $f = IO::File->new($file, 'r'); | |
148 | die "$MyName: $file: $!\n" unless defined($f); | |
149 | my $line = 0; | |
150 | my $skip = 0; | |
151 | while(<$f>) { | |
152 | $line++; | |
153 | if(/^#\s*endif/) { | |
154 | $skip = 0; | |
155 | next; | |
156 | } | |
157 | if(/^#\s*else/) { | |
158 | $skip = -$skip; | |
159 | next; | |
160 | } | |
161 | chomp; | |
162 | if(/^#\s*if\s+(\S+)$/) { | |
163 | $skip = ($1 eq 'COMPAT_GETFSSTAT') ? -1 : 1; | |
164 | next; | |
165 | } | |
166 | next if $skip < 0; | |
167 | next unless /^\d/; | |
168 | s/^[^{]*{\s*//; | |
169 | s/\s*}.*$//; # } | |
170 | die "$MyName: no function prototype on line $line\n" unless length($_) > 0 && /;$/; | |
171 | my $no_syscall_stub = /\)\s*NO_SYSCALL_STUB\s*;/; | |
172 | my($name, $args) = /\s(\S+)\s*\(([^)]*)\)/; | |
173 | next if $name =~ /e?nosys/; | |
174 | $args =~ s/^\s+//; | |
175 | $args =~ s/\s+$//; | |
176 | my $argbytes = 0; | |
177 | my $nargs = 0; | |
178 | if($args ne '' && $args ne 'void') { | |
179 | my @a = split(',', $args); | |
180 | $nargs = scalar(@a); | |
181 | # Calculate the size of all the arguments (only used for i386) | |
182 | for my $type (@a) { | |
183 | $type =~ s/\s*\w+$//; # remove the argument name | |
184 | if($type =~ /\*$/) { | |
185 | $argbytes += 4; # a pointer type | |
186 | } else { | |
187 | $type =~ s/^.*\s//; # remove any type qualifier, like unsigned | |
188 | my $b = $TypeBytes{$type}; | |
189 | die "$MyName: $name: unknown type '$type'\n" unless defined($b); | |
190 | $argbytes += $b; | |
191 | } | |
192 | } | |
193 | } | |
194 | if($no_syscall_stub || $name =~ /^__/) { | |
195 | $NoStub{$name} = [$nargs, $argbytes]; | |
196 | } else { | |
197 | $Stub{$name} = [$nargs, $argbytes]; | |
198 | } | |
199 | } | |
200 | } | |
201 | ||
202 | usage() unless scalar(@ARGV) == 3; | |
203 | $CustomDir = $ARGV[1]; | |
204 | die "$MyName: $CustomDir: No such directory\n" unless -d $CustomDir; | |
205 | $OutDir = $ARGV[2]; | |
206 | die "$MyName: $OutDir: No such directory\n" unless -d $OutDir; | |
207 | ||
208 | readmaster($ARGV[0]); | |
209 | ||
210 | ########################################################################## | |
211 | # copy the files specified in @Copy from the $CustomDir to $OutDir | |
212 | ########################################################################## | |
213 | for(@Copy) { | |
214 | my $custom = File::Spec->join($CustomDir, $_); | |
215 | my $path = File::Spec->join($OutDir, $_); | |
216 | File::Copy::copy($custom, $path) || die "$MyName: copy($custom, $path): $!\n"; | |
217 | } | |
218 | ||
219 | ########################################################################## | |
220 | # make all the *.s files | |
221 | ########################################################################## | |
222 | my @src; | |
223 | my($k, $v); | |
224 | while(($k, $v) = each(%Stub)) { | |
225 | push(@src, make_s($k, @$v)); | |
226 | } | |
227 | while(($k, $v) = each(%NoStub)) { | |
228 | push(@src, make_s($k, @$v)); | |
229 | } | |
230 | ||
231 | ########################################################################## | |
232 | # create the Makefile.inc file from the list for files in @src and @CustomSrc | |
233 | ########################################################################## | |
234 | my $path = File::Spec->join($OutDir, 'Makefile.inc'); | |
235 | my $f = IO::File->new($path, 'w'); | |
236 | die "$MyName: $path: $!\n" unless defined($f); | |
237 | print $f ".PATH: $OutDir\n\n"; | |
238 | print $f "SYSCALLSRCS= " . join(" \\\n\t", sort(@src, @CustomSrc)) . "\n\n"; | |
239 | print $f "MDSRCS+= \$(SYSCALLSRCS)\n\n"; | |
240 | print $f ".for S in \$(SYSCALLSRCS)\n"; | |
241 | print $f "PRECFLAGS-\$(S)+= -I\$(OBJROOT)/include\n"; | |
242 | print $f ".endfor\n"; | |
243 | undef $f; | |
244 | ||
245 | ########################################################################## | |
246 | # create the libsyscall.list file for Libsystem to use. For the one that | |
247 | # should not have auto-generated stubs, the line begins with #. | |
248 | ########################################################################## | |
249 | $path = File::Spec->join($OutDir, $StubFile); | |
250 | $f = IO::File->new($path, 'w'); | |
251 | die "$MyName: $path: $!\n" unless defined($f); | |
252 | # Add the %NoStub entries to %Stub, appending '#' to the name, so we can sort | |
253 | while(($k, $v) = each(%NoStub)) { | |
254 | $k =~ s/^__//; | |
255 | $Stub{"$k#"} = $v; | |
256 | } | |
257 | for(sort(keys(%Stub))) { | |
258 | $k = $_; | |
259 | if($k =~ s/#$//) { | |
260 | printf $f "#___%s\t%s\n", $k, $Stub{$_}->[0]; | |
261 | } else { | |
262 | printf $f "___%s\t%s\n", $_, $Stub{$_}->[0]; | |
263 | } | |
264 | } | |
265 | undef $f; |