]> granicus.if.org Git - strace/blob - maint/ioctls_sym.sh
maint: rework workarounds for linux/kvm.h
[strace] / maint / ioctls_sym.sh
1 #!/bin/sh
2 # Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 #    notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 #    notice, this list of conditions and the following disclaimer in the
12 #    documentation and/or other materials provided with the distribution.
13 # 3. The name of the author may not be used to endorse or promote products
14 #    derived from this software without specific prior written permission.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 set -efu
28
29 # This script processes header files containing ioctl command definitions in
30 # symbolic form, assuming that these definitions match the following regular
31 # expressions:
32
33 r_define='^[[:space:]]*#[[:space:]]*define[[:space:]]\+'
34 r_cmd_name='[A-Z][A-Z0-9_]*'
35 r_io='\([A-Z]\+\)\?_S\?\(IO\|IOW\|IOR\|IOWR\|IOC\)'
36 r_value='[[:space:]]\+'"$r_io"'[[:space:]]*([^)]'
37 regexp="${r_define}${r_cmd_name}${r_value}"
38
39 uname_m="$(uname -m)"
40 me="${0##*/}"
41 msg()
42 {
43         printf >&2 '%s\n' "$me: $*"
44 }
45
46 prefix=
47 case $# in
48         1)      inc_dir="$1"; shift
49                 ;;
50         2)      inc_dir="$1"; shift
51                 prefix="$1"; shift
52                 ;;
53         *)      echo >&2 "usage: $me include-directory [prefix]"
54                 exit 1
55                 ;;
56 esac
57
58 [ -z "$prefix" ] ||
59         prefix="${prefix%%/}/"
60
61 tmpdir=
62 cleanup()
63 {
64         trap - EXIT
65         [ -z "$tmpdir" ] ||
66                 rm -rf -- "$tmpdir"
67         exit "$@"
68 }
69
70 trap 'cleanup $?' EXIT
71 trap 'cleanup 1' HUP PIPE INT QUIT TERM
72 tmpdir="$(mktemp -dt "$me.XXXXXX")"
73
74 # list interesting files in $inc_dir.
75 cd "$inc_dir"
76 inc_dir="$(pwd -P)"
77 find . -type f -name '*.h' -print0 |
78         xargs -r0 grep -l "$r_value" -- > "$tmpdir"/headers1.list ||
79                 exit 0
80 cd - > /dev/null
81 sed 's|^\./\(uapi/\)\?||' < "$tmpdir"/headers1.list > "$tmpdir"/headers.list
82 LC_COLLATE=C sort -u -o "$tmpdir"/headers.list "$tmpdir"/headers.list
83
84 msg "processing $(wc -l < "$tmpdir"/headers.list) header files from $inc_dir"
85 failed=0
86
87 CC="${CC:-gcc}"
88 CPP="${CPP:-cpp}"
89 CPPFLAGS="${CPPFLAGS-} -D__EXPORTED_HEADERS__"
90 CFLAGS="${CFLAGS:--Wall -O2} -D__EXPORTED_HEADERS__"
91 LDFLAGS="${LDFLAGS-}"
92 INCLUDES="-I$inc_dir/uapi -I$inc_dir ${INCLUDES-}"
93
94 $CC $INCLUDES $CFLAGS -c -o "$tmpdir"/print_ioctlent.o "${0%/*}"/print_ioctlent.c
95
96 # Hook onto <asm-generic/ioctl.h> and <asm/ioctl.h>
97 for d in asm-generic asm; do
98         mkdir "$tmpdir/$d"
99         cat > "$tmpdir/$d"/ioctl.h <<__EOF__
100 #include_next <$d/ioctl.h>
101 #undef _IOC
102 #define _IOC(dir,type,nr,size) dir, type, nr, size
103 __EOF__
104 done
105
106 INCLUDES="-I$tmpdir $INCLUDES"
107
108 process_file()
109 {
110         local f="$1"; shift
111
112         # Common code for every processed file.
113         cat > "$tmpdir"/printents.c <<__EOF__
114 #include <asm/termbits.h>
115 #include <asm/ioctl.h>
116 #include <linux/types.h>
117 #include <linux/limits.h>
118 #include <linux/major.h>
119
120 #include <sys/types.h>
121 #include <sys/socket.h>
122 #include <stdint.h>
123 #include <stdbool.h>
124
125 #ifndef NULL
126 # define NULL ((void*)0)
127 #endif
128 #ifndef __user
129 # define __user
130 #endif
131 #ifndef __iomem
132 # define __iomem
133 #endif
134 #ifndef __noreturn
135 # define __noreturn __attribute__((noreturn))
136 #endif
137 #ifndef __packed
138 # define __packed __attribute__((packed))
139 #endif
140
141 typedef signed char s8;
142 typedef unsigned char u8;
143 typedef signed short s16;
144 typedef unsigned short u16;
145 typedef signed int s32;
146 typedef unsigned int u32;
147 typedef signed long long s64;
148 typedef unsigned long long u64;
149
150 #include "fixes.h"
151
152 #include <asm/bitsperlong.h>
153 #ifndef BITS_PER_LONG
154 # define BITS_PER_LONG __BITS_PER_LONG
155 #endif
156
157 #include "$f"
158
159 void print_ioctlent(const char *, const char *, unsigned short, unsigned short, unsigned short, unsigned short);
160
161 int main(void)
162 {
163
164 #include "defs.h"
165
166 return 0;
167 }
168 __EOF__
169
170         # Soft pre-include workarounds for some processed files.  Fragile.
171         case "$f" in
172                 *asm/cmb.h)
173                         echo '#include <asm/dasd.h>'
174                         ;;
175                 *asm/ioctls.h)
176                         cat <<'__EOF__'
177 #include <asm/termios.h>
178 #include <linux/serial.h>
179 __EOF__
180                         ;;
181                 drm/sis_drm.h)
182                         echo '#include <drm/drm.h>'
183                         ;;
184                 *drm/*_drm.h)
185                         echo '#include <drm/drm.h>' > "$tmpdir/drm.h"
186                         ;;
187                 fbio.h|*/fbio.h)
188                         cat <<'__EOF__'
189 #include <linux/fb.h>
190 #undef FBIOGETCMAP
191 #undef FBIOPUTCMAP
192 __EOF__
193                         ;;
194                 *linux/atm_zatm.h)
195                         cat <<'__EOF__'
196 #include <linux/atm.h>
197 #ifndef _LINUX_TIME_H
198 # define _LINUX_TIME_H
199 #endif
200 #ifndef _UAPI_LINUX_TIME_H
201 # define _UAPI_LINUX_TIME_H
202 #endif
203 __EOF__
204                         ;;
205                 *linux/atm?*.h)
206                         echo '#include <linux/atm.h>'
207                         ;;
208                 *linux/auto_fs*.h)
209                         echo 'typedef u32 compat_ulong_t;'
210                         ;;
211                 *linux/coda.h|*android_alarm.h)
212                         cat <<'__EOF__'
213 #ifndef _LINUX_TIME_H
214 # define _LINUX_TIME_H
215 #endif
216 #ifndef _UAPI_LINUX_TIME_H
217 # define _UAPI_LINUX_TIME_H
218 #endif
219 __EOF__
220                         ;;
221                 *linux/fs.h|*linux/ncp_fs.h)
222                         cat <<'__EOF__'
223 #include <linux/blktrace_api.h>
224 #include <linux/fiemap.h>
225 __EOF__
226                         ;;
227                 *linux/if_pppox.h)
228                         cat <<'__EOF__'
229 #include <linux/if.h>
230 #include <linux/in.h>
231 #include <linux/in6.h>
232 __EOF__
233                         ;;
234                 *linux/if_tun.h|*linux/ppp-ioctl.h)
235                         echo '#include <linux/filter.h>'
236                         ;;
237                 *linux/isdn_ppp.h|*linux/gsmmux.h)
238                         echo '#include <linux/if.h>'
239                         ;;
240                 *media*/saa6588.h)
241                         echo 'typedef struct poll_table_struct poll_table;'
242                         ;;
243                 *linux/ivtvfb.h|*linux/meye.h|*media/*.h)
244                         echo '#include <linux/videodev2.h>'
245                         ;;
246                 *linux/kvm.h)
247                         case "$uname_m" in
248                                 i?86|x86_64|arm*|ppc*|s390*) ;;
249                                 *) return 0 ;; # not applicable
250                         esac
251                         ;;
252                 *linux/sonet.h)
253                         echo '#include <linux/atmioc.h>'
254                         ;;
255                 *linux/usbdevice_fs.h)
256                         cat <<'__EOF__'
257 struct usbdevfs_ctrltransfer32 { __u32 unused[4]; };
258 struct usbdevfs_bulktransfer32 { __u32 unused[4]; };
259 struct usbdevfs_disconnectsignal32 { __u32 unused[2]; };
260 struct usbdevfs_urb32 { __u8 unused[42]; };
261 struct usbdevfs_ioctl32 { __u32 unused[3]; };
262 __EOF__
263                         ;;
264                 logger.h|*/logger.h)
265                         echo 'typedef __u32 kuid_t;'
266                         ;;
267                 *sound/asequencer.h)
268                         cat <<'__EOF__'
269 #include <sound/asound.h>
270 struct snd_seq_queue_owner { __u32 unused[0]; };
271 __EOF__
272                         ;;
273                 *sound/emu10k1.h)
274                         cat <<'__EOF__'
275 #include <sound/asound.h>
276 #ifndef DECLARE_BITMAP
277 # define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
278 # define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 8 * sizeof(long))
279 # define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)]
280 #endif
281 __EOF__
282                         ;;
283                 *video/sstfb.h)
284                         echo 'struct fb_info;'
285                         ;;
286                 *xen/evtchn.h|*xen/gntdev.h)
287                         cat <<'__EOF__'
288 typedef uint32_t grant_ref_t;
289 typedef uint16_t domid_t;
290 __EOF__
291                         ;;
292                 *xen/interface/*.h)
293                         return 0 # false positives
294                         ;;
295                 *xen/privcmd.h)
296                         return 0 # too much work to make it compileable
297                         ;;
298         esac > "$tmpdir"/fixes.h
299
300         cat > "$tmpdir"/header.in <<__EOF__
301 #include <asm/bitsperlong.h>
302 #ifndef BITS_PER_LONG
303 # define BITS_PER_LONG __BITS_PER_LONG
304 #endif
305 #include "$f"
306 __EOF__
307
308         if [ -f "$inc_dir/uapi/$f" ]; then
309                 s="$inc_dir/uapi/$f"
310         elif [ -f "$inc_dir/$f" ]; then
311                 s="$inc_dir/$f"
312         else
313                 msg "$f: file not found"
314                 return 1
315         fi
316
317         [ -n "${f##*/*}" ] ||
318                 mkdir -p "$tmpdir/${f%/*}"
319         # Hard workarounds for some processed files.  Very fragile.
320         case "$f" in
321                 *acpi/*|*linux/i2o.h|*media*/exynos-fimc.h|*media/v4l2-subdev.h|*net/bluetooth/*|net/nfc/nci_core.h)
322                         # Fetch macros only.
323                         grep "${r_define}${r_cmd_name}" < "$s" > "$tmpdir/$f"
324                         ;;
325                 binder.h|*/binder.h)
326                         # Convert enums to macros.
327                         sed '/^enum binder/,/^};/d' < "$s" > "$tmpdir/$f"
328                         sed -n '/^enum binder/,/^};/ s/^[[:space:]].*/&/p' < "$s" |
329                         sed -e '
330 s/^[[:space:]]*\([A-Z][A-Z_0-9]*\)[[:space:]]*=[[:space:]]*_\(IO\|IOW\|IOR\|IOWR\|IOC\)[[:space:]]*(/#define \1 _\2(/
331 s/^\(#define .*)\),$/\1/
332 s/^\(#define .*,\)$/\1 \\/
333 s/^\([[:space:]]\+[^),]\+)\),$/\1/' >> "$tmpdir/$f"
334                         ;;
335                 *drm/r128_drm.h)
336                         # Filter out the code that references unknown types.
337                         sed '/drm_r128_clear2_t/d' < "$s" > "$tmpdir/$f"
338                         ;;
339                 *drm/sis_drm.h)
340                         # Filter out the code that references unknown types.
341                         sed '/^struct sis_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
342                         ;;
343                 *drm/via_drm.h)
344                         # Create the file it attempts to include.
345                         touch "$tmpdir/via_drmclient.h"
346                         # Filter out the code that references unknown types.
347                         sed '/^struct via_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
348                         ;;
349                 *linux/nilfs2_fs.h)
350                         # Create the file it attempts to include.
351                         touch "$tmpdir/asm/bug.h"
352                         ;;
353                 *linux/vmw_vmci_defs.h)
354                         # Fetch ioctl macros only.
355                         grep "${r_define}I" < "$s" > "$tmpdir/$f"
356                         ;;
357                 *media/v4l2-common.h)
358                         # Fetch one piece of code containing ioctls definitions.
359                         sed -n '/ remaining ioctls/,/ ---/p' < "$s" > "$tmpdir/$f"
360                         ;;
361                 openpromio.h|*/openpromio.h|fbio.h|*/fbio.h)
362                         # Create the file it attempts to include.
363                         mkdir -p "$tmpdir/linux"
364                         touch "$tmpdir/linux/compiler.h"
365         esac
366         if [ -f "$tmpdir/$f" ]; then
367                 s="$tmpdir/$f"
368         fi
369
370         # This may fail if the file includes unavailable headers.
371         # In case of success it outputs both the #define directives
372         # and the result of preprocessing.
373         $CPP $CPPFLAGS -dD $INCLUDES < "$tmpdir"/header.in > "$tmpdir"/header.out
374
375         # Soft post-preprocess workarounds.  Fragile.
376         case "$f" in
377                 *linux/kvm.h)
378                         arm_list='KVM_ARM_PREFERRED_TARGET|KVM_ARM_VCPU_INIT'
379                         ppc_list='KVM_ALLOCATE_RMA|KVM_CREATE_SPAPR_TCE|KVM_CREATE_SPAPR_TCE_64|KVM_PPC_GET_HTAB_FD|KVM_PPC_RTAS_DEFINE_TOKEN'
380                         x86_list='KVM_GET_CPUID2|KVM_GET_DEBUGREGS|KVM_GET_EMULATED_CPUID|KVM_GET_LAPIC|KVM_GET_MSRS|KVM_GET_MSR_INDEX_LIST|KVM_GET_PIT|KVM_GET_PIT2|KVM_GET_SUPPORTED_CPUID|KVM_GET_VCPU_EVENTS|KVM_GET_XCRS|KVM_GET_XSAVE|KVM_SET_CPUID|KVM_SET_CPUID2|KVM_SET_DEBUGREGS|KVM_SET_LAPIC|KVM_SET_MEMORY_ALIAS|KVM_SET_MSRS|KVM_SET_PIT|KVM_SET_PIT2|KVM_SET_VCPU_EVENTS|KVM_SET_XCRS|KVM_SET_XSAVE|KVM_X86_SET_MCE|KVM_XEN_HVM_CONFIG'
381                         case "$uname_m" in
382                                 arm*) list="$ppc_list|$x86_list" ;;
383                                 ppc*) list="$arm_list|$x86_list" ;;
384                                 i?86|x86_64*) list="$arm_list|$ppc_list" ;;
385                                 *) list="$arm_list|$ppc_list|$x86_list" ;;
386                         esac
387                         sed -r -i "/[[:space:]]($list)[[:space:]]/d" "$tmpdir"/header.out
388                         ;;
389         esac
390
391         # Need to exclude ioctl commands defined elsewhere.
392         local_defines='^[[:space:]]*#[[:space:]]*define[[:space:]]\+\('"$r_cmd_name"'\)[[:space:]]'
393         sed -n 's/'"$local_defines"'.*/\1\\/p' "$s" > "$tmpdir"/local_names
394         r_local_names="$(tr '\n' '|' < "$tmpdir"/local_names)"
395         r_local_names="${r_local_names%%|}"
396         r_local_names="${r_local_names%%\\}"
397
398         # Keep this in sync with $regexp by replacing $r_cmd_name with $r_local_names.
399         defs_regexp="${r_define}\($r_local_names\)${r_value}"
400
401         qf="$(echo "$prefix$f" | sed 's/[&\/]/\\&/g')"
402         # This outputs lines in the following format:
403         # print_ioctlent("filename.h", "IOCTL_CMD_NAME", IOCTL_CMD_NAME);
404         sed -n 's/'"$defs_regexp"'.*/print_ioctlent("'"$qf"'", "\1", \1);/p' \
405                 < "$tmpdir"/header.out > "$tmpdir"/defs.h
406
407         # If something is wrong with the file, this will fail.
408         $CC $INCLUDES $CFLAGS -c -o "$tmpdir"/printents.o "$tmpdir"/printents.c
409         $CC $LDFLAGS -o "$tmpdir"/print_ioctlents \
410                 "$tmpdir"/printents.o "$tmpdir"/print_ioctlent.o
411         "$tmpdir"/print_ioctlents > "$tmpdir"/ioctlents
412         cat "$tmpdir"/ioctlents
413         msg "$f: fetched $(grep -c '^{' "$tmpdir"/ioctlents) ioctl entries"
414 }
415
416 while read f; do
417         (process_file "$f" < /dev/null)
418         [ $? -eq 0 ] || {
419                 msg "$f: failed to process"
420                 failed=$((1 + $failed))
421         }
422 done < "$tmpdir"/headers.list
423
424 [ $failed -eq 0 ] ||
425         msg "failed to process $failed file(s)"