From f92619e1ce441846447b429a0c9e7b4702ccd710 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Thu, 15 Feb 2018 02:43:02 +0000 Subject: Add NetBSD syscall hooks skeleton in sanitizers Summary: Implement the skeleton of NetBSD syscall hooks for use with sanitizers. Add a script that generates the rules to handle syscalls on NetBSD: generate_netbsd_syscalls.awk. It has been written in NetBSD awk(1) (patched nawk) and is compatible with gawk. Generate lib/sanitizer_common/sanitizer_platform_limits_netbsd.h that is a public header for applications, and included as: . Generate sanitizer_syscalls_netbsd.inc that defines all the syscall rules for NetBSD. This file is modeled after the Linux specific file: sanitizer_common_syscalls.inc. Start recognizing NetBSD syscalls with existing sanitizers: ASan, ESan, HWASan, TSan, MSan. Sponsored by Reviewers: joerg, vitalybuka, kcc, dvyukov, eugenis Reviewed By: vitalybuka Subscribers: hintonda, kubamracek, mgorny, llvm-commits, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D42048 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@325206 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/generate_netbsd_syscalls.awk | 416 +++++++++++++++++++++++++++++++++++++ 1 file changed, 416 insertions(+) create mode 100755 utils/generate_netbsd_syscalls.awk (limited to 'utils') diff --git a/utils/generate_netbsd_syscalls.awk b/utils/generate_netbsd_syscalls.awk new file mode 100755 index 000000000..9406c4ff2 --- /dev/null +++ b/utils/generate_netbsd_syscalls.awk @@ -0,0 +1,416 @@ +#!/usr/bin/awk -f + +#===-- generate_netbsd_syscalls.awk ----------------------------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# This file is a generator of: +# - include/sanitizer/netbsd_syscall_hooks.h +# - lib/sanitizer_common/sanitizer_syscalls_netbsd.inc +# +# This script accepts on the input syscalls.master by default located in the +# /usr/src/sys/kern/syscalls.master path in the NetBSD distribution. +# +# NetBSD version 8.0. +# +#===------------------------------------------------------------------------===# + +BEGIN { + # harcode the script name + script_name = "generate_netbsd_syscalls.awk" + outputh = "../include/sanitizer/netbsd_syscall_hooks.h" + outputinc = "../lib/sanitizer_common/sanitizer_syscalls_netbsd.inc" + + # assert that we are in the directory with scripts + in_utils = system("test -f " script_name " && exit 1 || exit 0") + if (in_utils == 0) { + usage() + } + + # assert 1 argument passed + if (ARGC != 2) { + usage() + } + + # assert argument is a valid file path to syscall.master + if (system("test -f " ARGV[1]) != 0) { + usage() + } + + # sanity check that the path ends with "syscall.master" + if (ARGV[1] !~ /syscalls\.master$/) { + usage() + } + + # accept overloading CLANGFORMAT from environment + clangformat = "clang-format" + if ("CLANGFORMAT" in ENVIRON) { + clangformat = ENVIRON["CLANGFORMAT"] + } + + # parsing specific symbols + parsingheader=1 + + parsedsyscalls=0 + + # Hardcoded in algorithm + SYS_MAXSYSARGS=8 +} + +# Parse the RCS ID from syscall.master +parsingheader == 1 && NR == 1 { + if (match($0, /\$[^$]+\$/)) { + # trim initial 'NetBSD: ' and trailing ' $' + syscallmasterversion = substr($0, RSTART + 9, RLENGTH - 11) + } else { + # wrong file? + usage() + } +} + +# skip the following lines +# - empty +NF == 0 { + next +} +# - comment +$1 == ";" { + next +} + +# separator between the header and table with syscalls +$0 == "%%" { + parsingheader = 0 + next +} + +# preserve 'if/elif/else/endif' C preprocessor as-is +parsingheader == 0 && $0 ~ /^#/ { + if (parsedsyscalls in ifelifelseendif) { + ifelifelseendif[parsedsyscalls] = ifelifelseendif[parsedsyscalls] "\n" $0 + } else { + ifelifelseendif[parsedsyscalls] = $0 + } + next +} + +# parsing of syscall definitions +parsingheader == 0 && $1 ~ /^[0-9]+$/ { + # first join multiple lines into single one + while (sub(/\\$/, "")) { + getline line + $0 = $0 "" line + } + + # Skip unwanted syscalls + skip=0 + if ($0 ~ /OBSOL/ || $0 ~ /EXCL/ || $0 ~ /UNIMPL/) { + skip=1 + } + + # Compose the syscall name + # - compat? + compat="" + if (match($0, /COMPAT_[0-9]+/)) { + compat = tolower(substr($0, RSTART, RLENGTH)) + } + # - alias name? + alias="" + if ($(NF) != "}" && !skip) { + alias = alias "" $(NF) + } + # - compat version? + compatver="" + if (match($0, /\|[0-9]+\|/)) { + compatver = tolower(substr($0, RSTART + 1, RLENGTH - 2)) + } + # - basename? + basename="" + if (skip) { + basename = $1 + } else { + if (match($0, /\|[_a-z0-9]+\(/)) { + basename = tolower(substr($0, RSTART + 1, RLENGTH - 2)) + } + } + + syscallname="" + + if (skip) { + syscallname= syscallname "$" + } + + if (length(compat) > 0) { + syscallname = syscallname "" compat "_" + } + if (length(alias) > 0) { + syscallname = syscallname "" alias + } else { + if (length(compatver) > 0) { + syscallname = syscallname "__" basename "" compatver + } else { + syscallname = syscallname "" basename + } + } + + # Store the syscallname + syscalls[parsedsyscalls]=syscallname + + # Extract syscall arguments + if (match($0, /\([^)]+\)/)) { + args = substr($0, RSTART + 1, RLENGTH - 2) + + if (args == "void") { + syscallargs[parsedsyscalls] = "void" + syscallfullargs[parsedsyscalls] = "void" + } else { + # Normalize 'type * argument' to 'type *argument' + gsub("\\*[ \t]+", "*", args) + + n = split(args, a, ",") + + # Handle the first argument + match(a[1], /[*_a-z0-9\[\]]+$/) + syscallfullargs[parsedsyscalls] = substr(a[1], RSTART) "_" + + gsub(".+[ *]", "", a[1]) + syscallargs[parsedsyscalls] = a[1] + + # Handle the rest of arguments + for (i = 2; i <= n; i++) { + match(a[i], /[*_a-zA-Z0-9\[\]]+$/) + fs = substr(a[i], RSTART) + if (fs ~ /\[/) { + sub(/\[/, "_[", fs) + } else { + fs = fs "_" + } + syscallfullargs[parsedsyscalls] = syscallfullargs[parsedsyscalls] "$" fs + gsub(".+[ *]", "", a[i]) + syscallargs[parsedsyscalls] = syscallargs[parsedsyscalls] "$" a[i] + } + + # Handle array arguments for syscall(2) and __syscall(2) + nargs = "arg0$arg1$arg2$arg3$arg4$arg5$arg6$arg7" + gsub(/args\[SYS_MAXSYSARGS\]/, nargs, syscallargs[parsedsyscalls]) + } + } + + parsedsyscalls++ + + # Done with this line + next +} + + +END { + # empty file? + if (NR < 1 && !abnormal_exit) { + usage() + } + + # Handle abnormal exit + if (abnormal_exit) { + exit(abnormal_exit) + } + + # Generate sanitizer_syscalls_netbsd.inc + + # open pipe + cmd = clangformat " > " outputh + + pcmd("//===-- netbsd_syscall_hooks.h --------------------------------------------===//") + pcmd("//") + pcmd("// The LLVM Compiler Infrastructure") + pcmd("//") + pcmd("// This file is distributed under the University of Illinois Open Source") + pcmd("// License. See LICENSE.TXT for details.") + pcmd("//") + pcmd("//===----------------------------------------------------------------------===//") + pcmd("//") + pcmd("// This file is a part of public sanitizer interface.") + pcmd("//") + pcmd("// System call handlers.") + pcmd("//") + pcmd("// Interface methods declared in this header implement pre- and post- syscall") + pcmd("// actions for the active sanitizer.") + pcmd("// Usage:") + pcmd("// __sanitizer_syscall_pre_getfoo(...args...);") + pcmd("// long long res = syscall(SYS_getfoo, ...args...);") + pcmd("// __sanitizer_syscall_post_getfoo(res, ...args...);") + pcmd("//") + pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") + pcmd("//") + pcmd("// Generated with: " script_name) + pcmd("// Generated date: " strftime("%F")) + pcmd("// Generated from: " syscallmasterversion) + pcmd("//") + pcmd("//===----------------------------------------------------------------------===//") + pcmd("#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H") + pcmd("#define SANITIZER_NETBSD_SYSCALL_HOOKS_H") + pcmd("") + + # TODO + + pcmd("") + pcmd("#ifdef __cplusplus") + pcmd("extern \"C\" {") + pcmd("#endif") + pcmd("") + pcmd("// Private declarations. Do not call directly from user code. Use macros above.") + pcmd("") + pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") + pcmd("") + + # TODO + + pcmd("") + pcmd("#ifdef __cplusplus") + pcmd("} // extern \"C\"") + pcmd("#endif") + + pcmd("") + pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") + pcmd("") + + pcmd("#endif // SANITIZER_NETBSD_SYSCALL_HOOKS_H") + + close(cmd) + + # Generate sanitizer_syscalls_netbsd.inc + + # open pipe + cmd = clangformat " > " outputinc + + pcmd("//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===//") + pcmd("//") + pcmd("// The LLVM Compiler Infrastructure") + pcmd("//") + pcmd("// This file is distributed under the University of Illinois Open Source") + pcmd("// License. See LICENSE.TXT for details.") + pcmd("//") + pcmd("//===----------------------------------------------------------------------===//") + pcmd("//") + pcmd("// Common syscalls handlers for tools like AddressSanitizer,") + pcmd("// ThreadSanitizer, MemorySanitizer, etc.") + pcmd("//") + pcmd("// This file should be included into the tool's interceptor file,") + pcmd("// which has to define it's own macros:") + pcmd("// COMMON_SYSCALL_PRE_READ_RANGE") + pcmd("// Called in prehook for regions that will be read by the kernel and") + pcmd("// must be initialized.") + pcmd("// COMMON_SYSCALL_PRE_WRITE_RANGE") + pcmd("// Called in prehook for regions that will be written to by the kernel") + pcmd("// and must be addressable. The actual write range may be smaller than") + pcmd("// reported in the prehook. See POST_WRITE_RANGE.") + pcmd("// COMMON_SYSCALL_POST_READ_RANGE") + pcmd("// Called in posthook for regions that were read by the kernel. Does") + pcmd("// not make much sense.") + pcmd("// COMMON_SYSCALL_POST_WRITE_RANGE") + pcmd("// Called in posthook for regions that were written to by the kernel") + pcmd("// and are now initialized.") + pcmd("// COMMON_SYSCALL_ACQUIRE(addr)") + pcmd("// Acquire memory visibility from addr.") + pcmd("// COMMON_SYSCALL_RELEASE(addr)") + pcmd("// Release memory visibility to addr.") + pcmd("// COMMON_SYSCALL_FD_CLOSE(fd)") + pcmd("// Called before closing file descriptor fd.") + pcmd("// COMMON_SYSCALL_FD_ACQUIRE(fd)") + pcmd("// Acquire memory visibility from fd.") + pcmd("// COMMON_SYSCALL_FD_RELEASE(fd)") + pcmd("// Release memory visibility to fd.") + pcmd("// COMMON_SYSCALL_PRE_FORK()") + pcmd("// Called before fork syscall.") + pcmd("// COMMON_SYSCALL_POST_FORK(long long res)") + pcmd("// Called after fork syscall.") + pcmd("//") + pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!") + pcmd("//") + pcmd("// Generated with: " script_name) + pcmd("// Generated date: " strftime("%F")) + pcmd("// Generated from: " syscallmasterversion) + pcmd("//") + pcmd("//===----------------------------------------------------------------------===//") + pcmd("") + pcmd("#include \"sanitizer_platform.h\"") + pcmd("#if SANITIZER_NETBSD") + pcmd("") + pcmd("#include \"sanitizer_libc.h\"") + pcmd("") + pcmd("#define PRE_SYSCALL(name) \\") + pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name") + pcmd("#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)") + pcmd("#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)") + pcmd("") + pcmd("#define POST_SYSCALL(name) \\") + pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name") + pcmd("#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)") + pcmd("#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_ACQUIRE") + pcmd("# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))") + pcmd("#endif") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_RELEASE") + pcmd("# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))") + pcmd("#endif") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_FD_CLOSE") + pcmd("# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))") + pcmd("#endif") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_FD_ACQUIRE") + pcmd("# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))") + pcmd("#endif") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_FD_RELEASE") + pcmd("# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))") + pcmd("#endif") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_PRE_FORK") + pcmd("# define COMMON_SYSCALL_PRE_FORK() {}") + pcmd("#endif") + pcmd("") + pcmd("#ifndef COMMON_SYSCALL_POST_FORK") + pcmd("# define COMMON_SYSCALL_POST_FORK(res) {}") + pcmd("#endif") + pcmd("") + pcmd("// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).") + pcmd("") + pcmd("extern \"C\" {") + + # TODO + + pcmd("} // extern \"C\"") + pcmd("") + pcmd("#undef PRE_SYSCALL") + pcmd("#undef PRE_READ") + pcmd("#undef PRE_WRITE") + pcmd("#undef POST_SYSCALL") + pcmd("#undef POST_READ") + pcmd("#undef POST_WRITE") + pcmd("") + pcmd("#endif // SANITIZER_NETBSD") + + close(cmd) + + # Hack for preprocessed code + system("sed -i 's,^ \\([^ ]\\), \\1,' " outputinc) +} + +function usage() +{ + print "Usage: " script_name " syscalls.master" + abnormal_exit = 1 + exit 1 +} + +function pcmd(string) +{ + print string | cmd +} -- cgit v1.2.3